import { line, curveBasis } from "d3-shape" import uuidv4 from "uuid/v4" import yMemory from "y-memory" import yMap from "y-map" import yArray from "y-array" import Y from "yjs" import yWebrtc from "./y-webrtc/index.js" yMemory(Y) yMap(Y) yArray(Y) yWebrtc(Y) Y({ db: { name: "memory", }, connector: { name: "webrtc", url: "/", room: "imperial", }, share: { drawing: "Map", }, }).then((y) => { const userIDElem = document.getElementById("user-id") const peerIDElem = document.getElementById("peer-id") const peerButton = document.getElementById("peer-connect") const connectedP = document.getElementById("connected-peers") const penButton = document.getElementById("pen") const eraserButton = document.getElementById("eraser") userIDElem.value = y.db.userId y.connector.onUserEvent(function(event) { switch (event.action) { case "userID": userIDElem.value = event.id break case "userJoined": var peerElem = document.createElement("li") peerElem.innerHTML = event.user connectedP.appendChild(peerElem) break case "userLeft": for (var peer of connectedP.children) { if (peer.innerHTML == event.user) { connectedP.removeChild(peer) } } break } }) peerButton.onclick = function() { const peerID = peerIDElem.value if (peerID == "") { return } y.connector.connectToPeer(peerID) peerIDElem.value = "" } // Used to check what kind of tool is selected var addingLine = true var removingLine = false const CHECKRADIUS = 10 penButton.onclick = function() { // If pen tool selected if (!addingLine) { addingLine = true removingLine = false } } eraserButton.onclick = function() { // If eraser tool selected if (!removingLine) { removingLine = true addingLine = false } } const whiteboard = document.getElementById("whiteboard") var input = false var paths = new Map() var pathID function createOrUpdatePath(uid, points) { const lineFn = line() .x((d) => d[0]) .y((d) => d[1]) .curve(curveBasis) var path = paths.get(uid) if (path === undefined) { path = document.createElementNS("http://www.w3.org/2000/svg", "path") path.setAttribute("stroke", "blue") path.setAttribute("stroke-width", 3) path.setAttribute("fill", "none") path.setAttribute("pointer-events", "none") whiteboard.appendChild(path) paths.set(uid, path) } points = points.toArray().filter((point) => point !== undefined) if (points.length <= 0) { path.removeAttribute("d") return path } path.setAttribute("d", lineFn(points)) console.log(points) console.log(path) return path } function removeOrUpdatePath(uid) { var path = paths.get(uid) if (path !== undefined) { paths.delete(path) } } whiteboard.onmousedown = function(e) { input = true const mouse = { x: e.offsetX, y: e.offsetY, } if (addingLine) { pathID = uuidv4() const sharedPath = y.share.drawing.set(pathID, Y.Array) sharedPath.push([[mouse.x, mouse.y, true]]) } else if (removingLine) { // Iterate over all the possible paths in the Map const mapPaths = y.share.drawing.keys() for (var mapPath of mapPaths) { var found = false // Get the array of coordinates var mouseYArray = y.share.drawing.get(mapPath) var mouseArray = mouseYArray.toArray() // Check the array for current position for (var i = 0; i < mouseArray.length; i++) { var point = mouseArray[i] if (checkRadius(point, mouse)) { // Delete point point[2] = false // Update map mouseYArray.insert(i, point) y.share.drawing.set(mapPath, mouseYArray) found = true break } } if (found) { break } } } } /* Helper function that checks whether a point is within the mouse radius */ function checkRadius(mouseMap, mouse) { var mouseMapX = mouseMap[0] var mouseMapY = mouseMap[1] var mouseX = mouse.x var mouseY = mouse.y for (var i = 0; i < CHECKRADIUS; i++) { // Chech x-axis if (mouseX + i == mouseMapX) { return true } else if (mouseX - i == mouseMapX) { return true } // Check y-axis if (mouseY + i == mouseMapY) { return true } else if (mouseY - i == mouseMapY) { return true } } return false } whiteboard.onmouseup = function() { input = false } whiteboard.onmousemove = function(e) { const mouse = { x: e.offsetX, y: e.offsetY, } if (input) { if (addingLine) { const sharedPath = y.share.drawing.get(pathID) sharedPath.push([[mouse.x, mouse.y, true]]) } else if (removingLine) { // Iterate over all the possible paths in the Map const mapPaths = y.share.drawing.keys() for (var mapPath of mapPaths) { var found = false // Get the array of coordinates var mouseYArray = y.share.drawing.get(mapPath) var mouseArray = mouseYArray.toArray() // Check the array for current position for (var i = 0; i < mouseArray.length; i++) { var point = mouseArray[i] if (checkRadius(point, mouse)) { // Delete point point[2] = false // Update map mouseYArray.insert(i, point) y.share.drawing.set(mapPath, mouseYArray) found = true break } } if (found) { break } } } } } y.share.drawing.observe(function(lineEvent) { const lineID = lineEvent.name switch (lineEvent.type) { case "add": createOrUpdatePath(lineID, lineEvent.value) lineEvent.value.observe(function(pointEvent) { switch (pointEvent.type) { case "insert": createOrUpdatePath(lineID, pointEvent.object) break } }) break case "update": removeOrUpdatePath(lineID) lineEvent.value.observe(function(pointEvent) { switch (pointEvent.type) { case "insert": removeOrUpdatePath(lineID) break } }) break } }) })