"use strict"; (() => { const drawElement = document.getElementById("drawDiv"); if (!drawElement) { throw new Error("canvas not found"); } const drawEmitter = mitt(); let drawing = false; const socketUrl = "/draw/ws"; let socket = new WebSocket(socketUrl); socket.onerror = console.error; socket.onclose = console.warn; const serializeDraw = ({ from, to }) => `${from.x},${from.y},${to.x},${to.y}`; const deserializeDraw = (message) => { const parts = message.split(","); return { from: { x: Number(parts[0]), y: Number(parts[1]), }, to: { x: Number(parts[2]), y: Number(parts[3]), }, }; }; drawEmitter.on("draw", (e) => sendMessage(e)); const sendMessage = (e) => { if (socket.readyState !== socket.OPEN) { socket = new WebSocket(socketUrl); } socket.send(serializeDraw(e)); }; const mouseDown = () => { drawing = true; previous = null; }; const mouseUp = () => { drawing = false; }; let previous = null; const mouseMove = (e) => { if (!drawing) return; if (previous) { drawEmitter.emit("draw", { from: previous, to: { x: e.offsetX, y: e.offsetY }, }); } previous = { x: e.offsetX, y: e.offsetY }; }; const touchMove = (e) => { e.preventDefault(); mouseMove({ offsetX: e.touches[0].clientX - drawElement.offsetLeft, offsetY: e.touches[0].clientY - drawElement.offsetTop, }); }; drawElement.addEventListener("mousedown", mouseDown); drawElement.addEventListener("mouseup", mouseUp); drawElement.addEventListener("mousemove", mouseMove); drawElement.addEventListener("touchstart", mouseDown); drawElement.addEventListener("touchend", mouseUp); drawElement.addEventListener("touchmove", touchMove); const receiveCanvas = document.getElementById("receiveCanvas"); const recCtx = receiveCanvas?.getContext("2d"); if (!recCtx || !receiveCanvas) { throw new Error("canvas not found"); } //@ts-expect-error window.ctx = recCtx; setTimeout(() => { recCtx.lineWidth = 2; recCtx.lineCap = "round"; recCtx.strokeStyle = "white"; }, 10); socket.addEventListener("message", (event) => { if (event.data === "ping" || event.data.startsWith('pong')) return; const { from, to } = deserializeDraw(event.data); recCtx.beginPath(); recCtx.moveTo(from.x, from.y); recCtx.lineTo(to.x, to.y); recCtx.closePath(); recCtx.stroke(); console.log(from, to); }); setInterval(() => { if (socket.readyState !== socket.OPEN) { socket = new WebSocket(socketUrl); } socket.send("ping"); }, 10000); const resizeObserver = new ResizeObserver((entries) => { const entry = entries.at(0); receiveCanvas.height = entry?.contentRect.height ?? 500; receiveCanvas.width = entry?.contentRect.width ?? 500; }); resizeObserver.observe(drawElement); })();