From 32c195c2a11e8fcce4be03d0db50da7987e9d8e0 Mon Sep 17 00:00:00 2001 From: Moritz Langenstein <ml5717@ic.ac.uk> Date: Thu, 10 Oct 2019 15:47:49 +0100 Subject: [PATCH] (ml5717) (alh1717) (gc4117) Synchronisation of line adding using CRDT Map and Array --- package-lock.json | 23 ++++----- package.json | 3 +- public/index.html | 53 +++------------------ public/js/.gitkeep | 0 src/app.js | 107 ++++++++++++++++++++++++++++++++++++++---- src/y-webrtc/index.js | 16 +++---- 6 files changed, 126 insertions(+), 76 deletions(-) create mode 100644 public/js/.gitkeep diff --git a/package-lock.json b/package-lock.json index c2a7af6..d1bb9ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1547,11 +1547,6 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" - }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -4669,6 +4664,11 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, "v8-compile-cache": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", @@ -4929,19 +4929,16 @@ "resolved": "https://registry.npmjs.org/y-array/-/y-array-10.1.4.tgz", "integrity": "sha1-4TGlsDDW3LyhAmjUKT7PRL2uezQ=" }, + "y-map": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/y-map/-/y-map-10.1.3.tgz", + "integrity": "sha1-oVgCztusNp5Qa5b2je+PCi6DYZY=" + }, "y-memory": { "version": "8.0.9", "resolved": "https://registry.npmjs.org/y-memory/-/y-memory-8.0.9.tgz", "integrity": "sha512-OrcReh6DgZhz5R7JGXqAH53T0Ygw24qcxKj4jN9w2DIi2eIiKFCD5Y6apBTTNxiw2FaVP15F+M8phRRIMXFGBQ==" }, - "y-text": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/y-text/-/y-text-9.5.1.tgz", - "integrity": "sha512-uwNLY4LeLLR7Cu4xfvh9ZY4gmOYyjii4irDHYRuhPDs1XFcm6krVaALeggA42LevTQ+k5q1eHpdv5jnJha8r6g==", - "requires": { - "fast-diff": "^1.1.1" - } - }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", diff --git a/package.json b/package.json index df286f3..c717ce0 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,10 @@ "http-server": "^0.11.1", "peer": "git+https://github.com/peers/peerjs-server.git", "peerjs": "^1.1.0", + "uuid": "^3.3.3", "y-array": "^10.1.4", + "y-map": "^10.1.3", "y-memory": "^8.0.9", - "y-text": "^9.5.1", "yjs": "^12.3.3" }, "devDependencies": { diff --git a/public/index.html b/public/index.html index 338342d..4f47abd 100644 --- a/public/index.html +++ b/public/index.html @@ -16,52 +16,13 @@ <ul id="connected-peers"></ul> </div> - <textarea style="width: 100%; height: 500px" id="textfield"></textarea> - <script src="js/app.js"></script> - - <svg id="whiteboard" width="100%" height="100%"></svg> - <script> - var whiteboard = document.getElementById("whiteboard") - - var painting = false - var path - - whiteboard.onmousedown = function(e) { - painting = true - - var mouse = { - x: e.offsetX, - y: e.offsetY, - } - - path = document.createElementNS("http://www.w3.org/2000/svg", "path") + <svg + id="whiteboard" + width="100%" + height="100%" + style="position: fixed" + ></svg> - path.setAttribute("d", "M" + mouse.x + " " + mouse.y) - path.setAttribute("stroke", "blue") - path.setAttribute("stroke-width", 3) - path.setAttribute("fill", "none") - path.setAttribute("pointer-events", "none") - - whiteboard.appendChild(path) - } - - whiteboard.onmouseup = function(e) { - painting = false - } - - whiteboard.onmousemove = function(e) { - var mouse = { - x: e.offsetX, - y: e.offsetY, - } - - if (painting) { - path.setAttribute( - "d", - path.getAttribute("d") + " L" + mouse.x + " " + mouse.y, - ) - } - } - </script> + <script src="js/app.js"></script> </body> </html> diff --git a/public/js/.gitkeep b/public/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/app.js b/src/app.js index 978f335..9d426d0 100644 --- a/src/app.js +++ b/src/app.js @@ -1,25 +1,25 @@ const Y = require("yjs") require("y-memory")(Y) +require("y-map")(Y) require("y-array")(Y) -require("y-text")(Y) require("./y-webrtc")(Y) +const uuidv4 = require("uuid/v4") + Y({ db: { - name: "memory" + name: "memory", }, connector: { name: "webrtc", host: "localhost", port: 3000, - path: "/api" + path: "/api", }, share: { - textfield: "Text" - } -}).then(y => { - y.share.textfield.bind(document.getElementById("textfield")) - + drawing: "Map", + }, +}).then((y) => { const userIDElem = document.getElementById("user-id") const peerIDElem = document.getElementById("peer-id") const peerButton = document.getElementById("peer-connect") @@ -58,4 +58,95 @@ Y({ peerIDElem.value = "" } + + const whiteboard = document.getElementById("whiteboard") + + var painting = false + var paths = new Map() + var pathID + + function createOrUpdatePath(uid, points) { + 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 + } + + var pathString = "M" + points[0][0] + " " + points[0][1] + + for (var i = 1; i < points.length; i++) { + pathString += " L" + points[i][0] + " " + points[i][1] + } + + path.setAttribute("d", pathString) + + return path + } + + whiteboard.onmousedown = function(e) { + painting = true + + const mouse = { + x: e.offsetX, + y: e.offsetY, + } + + pathID = uuidv4() + + const sharedPath = y.share.drawing.set(pathID, Y.Array) + sharedPath.push([[mouse.x, mouse.y]]) + } + + whiteboard.onmouseup = function() { + painting = false + } + + whiteboard.onmousemove = function(e) { + const mouse = { + x: e.offsetX, + y: e.offsetY, + } + + if (painting) { + const sharedPath = y.share.drawing.get(pathID) + sharedPath.push([[mouse.x, mouse.y]]) + } + } + + 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": + console.log(pointEvent) + createOrUpdatePath(lineID, pointEvent.object) + break + } + }) + + break + } + }) }) diff --git a/src/y-webrtc/index.js b/src/y-webrtc/index.js index 0d2f040..17e0eba 100644 --- a/src/y-webrtc/index.js +++ b/src/y-webrtc/index.js @@ -2,7 +2,7 @@ "use strict" var { - peerjs: { Peer } + peerjs: { Peer }, } = require("peerjs") function extend(Y) { @@ -23,7 +23,7 @@ function extend(Y) { var peer = new Peer({ host: this.webrtcOptions.host, port: this.webrtcOptions.port, - path: this.webrtcOptions.path + path: this.webrtcOptions.path, }) this.peer = peer @@ -31,7 +31,7 @@ function extend(Y) { this.peers = new Map() peer.on("open", function(id) { - console.log("My peer ID is: " + id) + //console.log("My peer ID is: " + id) for (var f of self.userEventListeners) { f({ action: "userID", id: id }) @@ -53,20 +53,20 @@ function extend(Y) { var self = this dataConnection.on("open", function() { - console.log("Connected to peer " + dataConnection.peer) + //console.log("Connected to peer " + dataConnection.peer) self.peers.set(dataConnection.peer, dataConnection) self.userJoined(dataConnection.peer, "master") }) dataConnection.on("data", function(data) { - console.log("Message from peer " + dataConnection.peer + ":", data) + //console.log("Message from peer " + dataConnection.peer + ":", data) self.receiveMessage(dataConnection.peer, data) }) dataConnection.on("close", function() { - console.log("Disconnected from peer " + dataConnection.peer) + //console.log("Disconnected from peer " + dataConnection.peer) self.peers.delete(dataConnection.peer) self.userLeft(dataConnection.peer) @@ -87,7 +87,7 @@ function extend(Y) { } send(uid, message) { - console.log("Sending message", message, "to " + uid) + //console.log("Sending message", message, "to " + uid) var self = this @@ -109,7 +109,7 @@ function extend(Y) { } broadcast(message) { - console.log("Broadcasting message", message) + //console.log("Broadcasting message", message) for (const uid of this.peers.keys()) { this.send(uid, message) -- GitLab