<html> <head> <style> #grid-canvas { border-collapse: collapse; } #grid-canvas td { width: 20px; height: 20px; padding: 0; border: 1px solid black; } </style> <script> const GRID_WIDTH = 20 const GRID_HEIGHT = 20 // The <input type='color'> used to select the drawing color let colorInput // The <table> used to display the pixel art let grid // The WebSocket let socket // Rectangles are drawn by clicking and dragging. // These store the row and column of the cell that was clicked. let startRow let startCol // Sends a `set-color` message with the current color. // Called when the page loads and whenever `colorInput` changes. function sendColor() { const message = {type: 'set-color', color: colorInput.value} socket.send(JSON.stringify(message)) } // Sends a `draw` message to create a rectangle // from `startRow` and `startCol` to the given row and column function sendRectangle(row, col) { const message = { type: 'draw', // Using Math.min() and Math.abs() // since the rectangle could have been drawn in any direction row: Math.min(startRow, row), col: Math.min(startCol, col), rows: Math.abs(startRow - row) + 1, cols: Math.abs(startCol - col) + 1 } socket.send(JSON.stringify(message)) } // Adds the table cell elements to `grid` and attaches // `mousedown` and `mouseup` event handlers to them function makeGrid() { // Build a grid of <tr> and <td> elements, like in Minesweeper for (let row = 0; row < GRID_HEIGHT; row++) { const gridRow = document.createElement('tr') for (let col = 0; col < GRID_WIDTH; col++) { const cell = document.createElement('td') // Handles the click of a click-and-drag cell.onmousedown = () => { startRow = row startCol = col } // Handles the release of a click-and-drag cell.onmouseup = () => sendRectangle(row, col) gridRow.append(cell) } grid.append(gridRow) } } // Handles a `draw` message from the server. // `{color, ..., cols}` unpacks the message's fields. function draw({color, row, col, rows, cols}) { // For each cell in the rectangle, update its background color for (let i = 0; i < rows; i++) { const gridRow = grid.children[row + i] for (let j = 0; j < cols; j++) { const gridCell = gridRow.children[col + j] gridCell.style.background = color } } } // We need to run code that accesses HTML elements after // the rest of the HTML is parsed (signaled by the `load` event) window.onload = () => { // Retrieve HTML elements colorInput = document.getElementById('color') grid = document.getElementById('grid-canvas') colorInput.onchange = sendColor makeGrid() // Create a WebSocket connection socket = new WebSocket('ws://localhost') // As soon as socket opens, send the initial color (black) socket.onopen = sendColor // Handles `draw` messages from the server. // `event.data` is the JSON string received. socket.onmessage = event => draw(JSON.parse(event.data)) } </script> </head> <body> <input type='color' id='color' /> <table id='grid-canvas'></table> </body> </html>