Newer
Older
// 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 HTML from "./elements.js"
const TEST_ROOM = "imperial"
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 }) => {
})
room.addEventListener("userJoin", ({ detail: id }) => {
if (HTML.connectedPeers.children.length == 0) {
Moritz Langenstein
committed
HTML.connectedPeers.innerHTML = ""
}
insertHTMLPeerElement(id)
})
room.addEventListener("userLeave", ({ detail: id }) => {
forPeerWithId(id, (peerElem) => {
HTML.connectedPeers.removeChild(peerElem)
})
Moritz Langenstein
committed
if (HTML.connectedPeers.children.length == 0) {
Moritz Langenstein
committed
HTML.connectedPeers.innerHTML = "No peers are connected"
}
room.addEventListener("weSyncedWithPeer", ({ detail: id }) => {
forPeerWithId(id, (peerElem) => {
peerElem.children[1].className = "peer-status synced"
})
})
room.addEventListener("waitingForSyncStep", ({ detail: id }) => {
forPeerWithId(id, (peerElem) => {
peerElem.children[2].className = "peer-status negotiating"
})
})
room.addEventListener("peerSyncedWithUs", ({ detail: id }) => {
forPeerWithId(id, (peerElem) => {
peerElem.children[2].className = "peer-status synced"
})
})
room.addEventListener("addOrUpdatePath", ({ detail: { id, points } }) => {
const tryRoomConnect = async (roomID) => {
return await connect(roomID)
.then(onRoomConnect)
.catch((err) => alert(`Error connecting to a room:\n${err}`))
}
Moritz Langenstein
committed
const ERASER_RADIUS = 10
const tools = {
PEN: Symbol("pen"),
ERASER: Symbol("eraser"),
}
let currentTool = tools.PEN
const pathIDsByPointerID = new Map()
Moritz Langenstein
committed
HTML.penButton.addEventListener("click", () => {
if (currentTool == tools.PEN) {
} else {
currentTool = tools.PEN
HTML.penButton.classList.add("selected")
HTML.eraserButton.classList.remove("selected")
}
})
})
window.addEventListener("click", (event) => {
if (event.target == HTML.penProperties) {
hideElement(HTML.penProperties)
hideElement(HTML.palette)
hideElement(HTML.penProperties)
Moritz Langenstein
committed
const svg = HTML.wheel.children
for (let i = 1; i < svg.length; i++) {
svg[i].addEventListener("click", (event) => {
const paletteColour = event.target.getAttribute("fill")
HTML.rectangle.style.backgroundColor = paletteColour
HTML.picker.value = paletteColour
HTML.labelColour.style.backgroundColor = paletteColour
function showElement(element) {
element.style.display = "block"
}
function hideElement(element) {
element.style.display = "none"
}
HTML.picker.addEventListener("change", () => {
HTML.labelColour.style.backgroundColor = paletteColour
HTML.eraserButton.addEventListener("click", () => {
currentTool = tools.ERASER
HTML.penButton.classList.remove("selected")
HTML.eraserButton.classList.add("selected")
})
Moritz Langenstein
committed
HTML.peerButton.addEventListener("click", () => {
const peerID = HTML.peerIDElem.value
if (room == null || peerID == "") {
return
room.inviteUser(peerID)
HTML.peerIDElem.value = ""
})
Moritz Langenstein
committed
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"
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
const insertHTMLPeerElement = (id) => {
const peerElem = document.createElement("li")
const peerId = document.createElement("div")
peerId.style.display = "inline"
peerId.innerHTML = id
const ourStatus = document.createElement("div")
ourStatus.className = "peer-status unsynced"
const theirStatus = document.createElement("div")
theirStatus.className = "peer-status unsynced"
peerElem.appendChild(peerId)
peerElem.appendChild(ourStatus)
peerElem.appendChild(theirStatus)
HTML.connectedPeers.appendChild(peerElem)
}
const forPeerWithId = (id, doThis) => {
for (const peerElem of HTML.connectedPeers.children) {
const peerId = peerElem.children[0].innerHTML
if (peerId == id) {
doThis(peerElem)
}
}
}
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
}
room.addPath([...mousePos, e.pressure, canvas.getStrokeColour()]),
} 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
}
room.extendPath(pathIDsByPointerID.get(e.pointerId), [
...mousePos,
e.pressure,
} else if (currentTool == tools.ERASER) {
erasePoint(mousePos)
}