// Room connection and synchronisation. // Translate local canvas input events to draw messages and send to the room. // Get back room updates and invoke the local canvas renderer. import * as canvas from "./canvas.js" import * as HTML from "./elements.js" import { connect } from "./room.js" const TEST_ROOM = "imperial" let room = null const onRoomConnect = (room_) => { room = room_ HTML.connectedRoomID.textContent = room.name HTML.connectedRoomInfoContainer.style.display = "block" HTML.userIDElem.value = room.ownID || "" room.addEventListener("allocateOwnID", ({ detail: id }) => { HTML.userIDElem.value = id }) room.addEventListener("userJoin", ({ detail: id }) => { if (HTML.connectedPeers.children.length == 0) { HTML.connectedPeers.innerHTML = "" } const peerElem = document.createElement("li") peerElem.innerHTML = id HTML.connectedPeers.appendChild(peerElem) }) room.addEventListener("userLeave", ({ detail: id }) => { for (const peerElem of HTML.connectedPeers.children) { if (peerElem.innerHTML == id) { HTML.connectedPeers.removeChild(peerElem) } } if (HTML.connectedPeers.children.length == 0) { HTML.connectedPeers.innerHTML = "No peers are connected" } }) room.addEventListener("addOrUpdatePath", ({ detail: { id, points } }) => { canvas.renderPath(id, points) }) } const tryRoomConnect = async (roomID) => { return await connect(roomID) .then(onRoomConnect) .catch((err) => alert(`Error connecting to a room:\n${err}`)) } const ERASER_RADIUS = canvas.STROKE_RADIUS * 2 const tools = { PEN: Symbol("pen"), ERASER: Symbol("eraser"), } let currentTool = tools.PEN const pathIDsByPointerID = new Map() HTML.penButton.addEventListener("click", () => { currentTool = tools.PEN HTML.penButton.classList.add("selected") HTML.eraserButton.classList.remove("selected") }) HTML.eraserButton.addEventListener("click", () => { currentTool = tools.ERASER HTML.penButton.classList.remove("selected") HTML.eraserButton.classList.add("selected") }) HTML.peerButton.addEventListener("click", () => { const peerID = HTML.peerIDElem.value if (room == null || peerID == "") { return } room.inviteUser(peerID) HTML.peerIDElem.value = "" }) HTML.roomConnectButton.addEventListener("click", () => { const selectedRoomID = HTML.roomIDElem.value if (!selectedRoomID || selectedRoomID == room.name) { return } if (room != null) { room.disconnect() room = null } canvas.clear() HTML.connectedPeers.innerHTML = "No peers are connected" tryRoomConnect(selectedRoomID) }) const getDistance = (a, b) => { return Math.sqrt( (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]), ) } const erasePoint = ([x, y]) => { if (room == null) { return } room.getPaths().forEach((points, pathID) => { points.forEach((point, i) => { if (getDistance([x, y], point) <= ERASER_RADIUS) { room.erasePoint(pathID, i) } }) }) } canvas.input.addEventListener("strokestart", ({ detail: e }) => { if (room == null) { return } const mousePos = [e.offsetX, e.offsetY] if (currentTool == tools.PEN) { pathIDsByPointerID.set(e.pointerId, room.addPath(mousePos)) } else if (currentTool == tools.ERASER) { erasePoint(mousePos) } }) canvas.input.addEventListener("strokeend", ({ detail: e }) => { pathIDsByPointerID.delete(e.pointerId) }) canvas.input.addEventListener("strokemove", ({ detail: e }) => { if (room == null) { return } const mousePos = [e.offsetX, e.offsetY] if (currentTool == tools.PEN) { room.extendPath(pathIDsByPointerID.get(e.pointerId), mousePos) } else if (currentTool == tools.ERASER) { erasePoint(mousePos) } }) tryRoomConnect(TEST_ROOM)