| const backgroundCanvas = document.getElementById("background-canvas"); | |
| const drawingCanvas = document.getElementById("drawing-canvas"); | |
| const bgCtx = backgroundCanvas.getContext("2d"); | |
| const drawCtx = drawingCanvas.getContext("2d"); | |
| const colorPicker = document.getElementById("color-picker"); | |
| const sizeSlider = document.getElementById("size-slider"); | |
| const clearBtn = document.getElementById("clear-btn"); | |
| let isDrawing = false; | |
| let currentPath = []; | |
| function resizeCanvases() { | |
| const container = document.getElementById("canvas-container"); | |
| const width = container.clientWidth; | |
| const height = container.clientHeight; | |
| backgroundCanvas.width = width; | |
| backgroundCanvas.height = height; | |
| drawingCanvas.width = width; | |
| drawingCanvas.height = height; | |
| } | |
| resizeCanvases(); | |
| const ws = new WebSocket(`ws://${window.location.host}/ws`); | |
| ws.onmessage = (event) => { | |
| const message = JSON.parse(event.data); | |
| if (message.Update) { | |
| redrawWhiteboard(message.Update); | |
| } else if (message.Clear) { | |
| bgCtx.clearRect(0, 0, backgroundCanvas.width, backgroundCanvas.height); | |
| } | |
| }; | |
| function redrawWhiteboard(actions) { | |
| bgCtx.clearRect(0, 0, backgroundCanvas.width, backgroundCanvas.height); | |
| for (const action of actions) { | |
| drawPath(bgCtx, action); | |
| } | |
| } | |
| function drawPath(context, action) { | |
| context.beginPath(); | |
| context.strokeStyle = action.color; | |
| context.lineWidth = action.size; | |
| context.lineCap = "round"; | |
| context.lineJoin = "round"; | |
| for (let i = 0; i < action.points.length; i++) { | |
| const point = action.points[i]; | |
| if (i === 0) { | |
| context.moveTo(point.x, point.y); | |
| } else { | |
| context.lineTo(point.x, point.y); | |
| } | |
| } | |
| context.stroke(); | |
| } | |
| drawingCanvas.addEventListener("mousedown", startDrawing); | |
| drawingCanvas.addEventListener("mousemove", draw); | |
| drawingCanvas.addEventListener("mouseup", stopDrawing); | |
| drawingCanvas.addEventListener("mouseout", stopDrawing); | |
| function startDrawing(e) { | |
| isDrawing = true; | |
| currentPath = []; | |
| const point = getPoint(e); | |
| currentPath.push(point); | |
| drawCtx.beginPath(); | |
| drawCtx.moveTo(point.x, point.y); | |
| } | |
| function draw(e) { | |
| if (!isDrawing) return; | |
| const point = getPoint(e); | |
| currentPath.push(point); | |
| drawCtx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height); | |
| drawPath(drawCtx, { | |
| color: colorPicker.value, | |
| size: parseFloat(sizeSlider.value), | |
| points: currentPath, | |
| }); | |
| } | |
| function stopDrawing() { | |
| if (!isDrawing) return; | |
| isDrawing = false; | |
| const action = { | |
| color: colorPicker.value, | |
| size: parseFloat(sizeSlider.value), | |
| points: currentPath, | |
| }; | |
| ws.send(JSON.stringify({ Draw: action })); | |
| drawCtx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height); | |
| drawPath(bgCtx, action); | |
| currentPath = []; | |
| } | |
| function getPoint(e) { | |
| const rect = drawingCanvas.getBoundingClientRect(); | |
| return { | |
| x: e.clientX - rect.left, | |
| y: e.clientY - rect.top, | |
| }; | |
| } | |
| clearBtn.addEventListener("click", () => { | |
| ws.send(JSON.stringify({ Clear: null })); | |
| }); | |
| window.addEventListener("resize", () => { | |
| resizeCanvases(); | |
| redrawWhiteboard([]); | |
| }); | |