Skip to content
Snippets Groups Projects
Commit ad78eac9 authored by Giovanni Caruso's avatar Giovanni Caruso
Browse files

Merge master into colouredlines

parents d67fe65e 34fdf76f
No related branches found
No related tags found
No related merge requests found
......@@ -1074,8 +1074,7 @@
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
"dev": true
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"base64id": {
"version": "2.0.0",
......@@ -1297,31 +1296,21 @@
}
},
"bser": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz",
"integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
"integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
"dev": true,
"requires": {
"node-int64": "^0.4.0"
}
},
"buffer": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true,
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz",
"integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
}
"ieee754": "^1.1.4"
}
},
"buffer-from": {
......@@ -1871,9 +1860,9 @@
},
"dependencies": {
"whatwg-url": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
"integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
"dev": true,
"requires": {
"lodash.sortby": "^4.7.0",
......@@ -2390,12 +2379,12 @@
}
},
"eslint-utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
"integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
"integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
"dev": true,
"requires": {
"eslint-visitor-keys": "^1.0.0"
"eslint-visitor-keys": "^1.1.0"
}
},
"eslint-visitor-keys": {
......@@ -2405,13 +2394,13 @@
"dev": true
},
"espree": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz",
"integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz",
"integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==",
"dev": true,
"requires": {
"acorn": "^7.0.0",
"acorn-jsx": "^5.0.2",
"acorn": "^7.1.0",
"acorn-jsx": "^5.1.0",
"eslint-visitor-keys": "^1.1.0"
}
},
......@@ -3527,9 +3516,9 @@
}
},
"glob": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
"integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
......@@ -3591,9 +3580,9 @@
"dev": true
},
"graceful-fs": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
"integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"dev": true
},
"growly": {
......@@ -3621,9 +3610,9 @@
}
},
"handlebars": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.3.tgz",
"integrity": "sha512-B0W4A2U1ww3q7VVthTKfh+epHx+q4mCt6iK+zEAzbMBpWQAwxCeKxEGpj/1oQTpzPXDNSOG7hmG14TsISH50yw==",
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.5.tgz",
"integrity": "sha512-0Ce31oWVB7YidkaTq33ZxEbN+UDxMMgThvCe8ptgQViymL5DPis9uLdTA13MiRPhgvqyxIegugrP97iK3JeBHg==",
"dev": true,
"requires": {
"neo-async": "^2.6.0",
......@@ -3832,8 +3821,7 @@
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
"dev": true
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"iferr": {
"version": "0.1.5",
......@@ -4874,9 +4862,11 @@
"filetransfer": "^2.0.4",
"hark": "^1.2.0",
"mockconsole": "0.0.1",
"pako": "^1.0.10",
"rtcpeerconnection": "file:src/rtcpeerconnection",
"socket.io-client": "^2.3.0",
"webrtc-adapter": "^7.3.0",
"what-the-pack": "^2.0.3",
"wildemitter": "^1.2.0"
}
},
......@@ -5335,6 +5325,23 @@
"vm-browserify": "^1.0.1"
},
"dependencies": {
"buffer": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true,
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
......@@ -5654,8 +5661,7 @@
"pako": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
"integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==",
"dev": true
"integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw=="
},
"parallel-transform": {
"version": "1.2.0",
......@@ -5857,6 +5863,11 @@
"integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==",
"dev": true
},
"pretty-bytes": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz",
"integrity": "sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg=="
},
"pretty-format": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz",
......@@ -6037,9 +6048,9 @@
}
},
"react-is": {
"version": "16.10.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz",
"integrity": "sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==",
"version": "16.11.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz",
"integrity": "sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==",
"dev": true
},
"read-pkg": {
......@@ -7396,9 +7407,9 @@
"dev": true
},
"uglify-js": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.3.tgz",
"integrity": "sha512-KfQUgOqTkLp2aZxrMbCuKCDGW9slFYu2A23A36Gs7sGzTLcRBDORdOi5E21KWHFIfkY8kzgi/Pr1cXCh0yIp5g==",
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.4.tgz",
"integrity": "sha512-9Yc2i881pF4BPGhjteCXQNaXx1DCwm3dtOyBaG2hitHjLWOczw/ki8vD1bqyT3u6K0Ms/FpCShkmfg+FtlOfYA==",
"dev": true,
"optional": true,
"requires": {
......@@ -7823,6 +7834,15 @@
"sdp": "^2.10.0"
}
},
"what-the-pack": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/what-the-pack/-/what-the-pack-2.0.3.tgz",
"integrity": "sha512-vJFrS6U6acWUgkKu9dLuMsQnnHEzIpop1VDMc142h+zU+jUcS+FZlRO/BDJ9/S9cvp2sQWygImBDwl0WN9aadw==",
"requires": {
"buffer": "^5.2.1",
"pretty-bytes": "^5.1.0"
}
},
"whatwg-encoding": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
......
......@@ -54,7 +54,7 @@ const tryRoomConnect = async (roomID) => {
.catch((err) => alert(`Error connecting to a room:\n${err}`))
}
const ERASER_RADIUS = canvas.STROKE_RADIUS * 2
const ERASER_RADIUS = 10
const tools = {
PEN: Symbol("pen"),
ERASER: Symbol("eraser"),
......@@ -160,10 +160,7 @@ canvas.input.addEventListener("strokestart", ({ detail: e }) => {
const mousePos = [e.offsetX, e.offsetY]
if (currentTool == tools.PEN) {
pathIDsByPointerID.set(
e.pointerId,
room.addPath(mousePos, canvas.stroke_colour),
)
pathIDsByPointerID.set(e.pointerId, room.addPath([...mousePos, e.pressure]))
} else if (currentTool == tools.ERASER) {
erasePoint(mousePos)
}
......@@ -182,8 +179,8 @@ canvas.input.addEventListener("strokemove", ({ detail: e }) => {
if (currentTool == tools.PEN) {
room.extendPath(pathIDsByPointerID.get(e.pointerId), [
mousePos,
canvas.stroke_colour,
...mousePos,
e.pressure,
])
} else if (currentTool == tools.ERASER) {
erasePoint(mousePos)
......
......@@ -6,118 +6,118 @@ import { line, curveLinear } from "d3-shape"
import { canvas } from "./elements.js"
const SVG_URL = "http://www.w3.org/2000/svg"
// TODO: switch to curve interpolation that respects mouse points based on velocity
const lineFn = line()
.x((d) => d[0])
.y((d) => d[1])
.curve(curveLinear)
const pathElems = new Map()
const pathGroupElems = new Map()
export var stroke_colour = "blue"
export const STROKE_RADIUS = 2
export const MIN_STROKE_RADIUS = 0.1
export const MAX_STROKE_RADIUS = 3.9
export const input = new EventTarget()
const getStrokeRadius = (pressure) => {
return MIN_STROKE_RADIUS + pressure * (MAX_STROKE_RADIUS - MIN_STROKE_RADIUS)
}
export const renderPath = (id, points) => {
let pathElem = pathElems.get(id)
export const input = new EventTarget()
if (pathElem == null) {
pathElem = document.createElementNS("http://www.w3.org/2000/svg", "g")
const createPathElem = (d, width) => {
const pathGroupElem = document.createElementNS(SVG_URL, "path")
pathGroupElem.setAttribute("stroke-width", width)
pathGroupElem.setAttribute("d", d)
return pathGroupElem
}
pathElem.setAttribute("stroke", stroke_colour)
pathElem.setAttribute("stroke-width", STROKE_RADIUS * 2)
pathElem.setAttribute("fill", "none")
pathElem.setAttribute("stroke-linecap", "round")
pathElem.setAttribute("pointer-events", "none")
export const renderPath = (id, points) => {
points = points.filter(([x]) => x != null)
canvas.appendChild(pathElem)
pathElems.set(id, pathElem)
// Split up points into completely non-erased segments.
let segments = [[]]
for (const point of points) {
if (point[3] != false) {
segments[segments.length - 1].push(point)
} else {
segments.push([])
}
}
segments = segments.filter((a) => a.length > 0)
pathElem.innerHTML = ""
let pathGroupElem = pathGroupElems.get(id)
if (points.length == 0) {
return pathElem
if (segments.length == 0) {
if (pathGroupElem != null) {
canvas.removeChild(pathGroupElem)
pathGroupElems.delete(id)
}
return
}
// Push a fake path split to generate the last path
points.push([-1, -1, false])
let subpath = []
for (const point of points) {
if (point[0] === undefined) {
continue
}
if (pathGroupElem == null) {
pathGroupElem = document.createElementNS(SVG_URL, "g")
pathGroupElem.setAttribute("stroke", stroke_colour)
pathGroupElem.setAttribute("fill", "none")
pathGroupElem.setAttribute("stroke-linecap", "round")
pathGroupElem.setAttribute("pointer-events", "none")
canvas.appendChild(pathGroupElem)
pathGroupElems.set(id, pathGroupElem)
}
if (point[2] === false) {
if (subpath.length == 1) {
const subpathElem = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle",
)
subpathElem.setAttribute("stroke", "none")
subpathElem.setAttribute("fill", stroke_colour)
subpathElem.setAttribute("cx", subpath[0][0])
subpathElem.setAttribute("cy", subpath[0][1])
subpathElem.setAttribute("r", STROKE_RADIUS)
pathElem.appendChild(subpathElem)
} else if (subpath.length > 0) {
const subpathElem = document.createElementNS(
"http://www.w3.org/2000/svg",
"path",
)
subpathElem.setAttribute("d", lineFn(subpath))
pathElem.appendChild(subpathElem)
pathGroupElem.innerHTML = ""
for (const subpath of segments) {
if (subpath.length == 1) {
const circleElem = document.createElementNS(SVG_URL, "circle")
circleElem.setAttribute("stroke", "none")
circleElem.setAttribute("fill", stroke_colour)
circleElem.setAttribute("cx", subpath[0][0])
circleElem.setAttribute("cy", subpath[0][1])
circleElem.setAttribute("r", getStrokeRadius(subpath[0][2]))
pathGroupElem.appendChild(circleElem)
} else {
// Further split up segments based on thickness.
const subpath_ = subpath.slice()
let w = subpath_[0][2]
for (let i = 1; i < subpath_.length; i++) {
if (subpath_[i][2] != w) {
const d = lineFn([...subpath_.splice(0, i), subpath_[0]])
pathGroupElem.appendChild(createPathElem(d, getStrokeRadius(w) * 2))
w = subpath_[0][2]
i = 1
}
}
subpath = []
continue
const d = lineFn(subpath_)
pathGroupElem.appendChild(createPathElem(d, getStrokeRadius(w) * 2))
}
subpath.push(point)
}
return pathElem
}
export const clear = () => {
pathElems.clear()
pathGroupElems.clear()
canvas.innerHTML = ""
}
// Note that the PointerEvent is passed as the detail in these 'stroke events'.
canvas.addEventListener("pointerdown", (e) => {
if (e.buttons & 1) {
input.dispatchEvent(new CustomEvent("strokestart", { detail: e }))
}
})
canvas.addEventListener("pointerenter", (e) => {
if (e.buttons & 1) {
input.dispatchEvent(new CustomEvent("strokestart", { detail: e }))
}
})
canvas.addEventListener("pointerup", (e) => {
if (e.buttons & 1) {
input.dispatchEvent(new CustomEvent("strokeend", { detail: e }))
}
})
canvas.addEventListener("pointerleave", (e) => {
if (e.buttons & 1) {
input.dispatchEvent(new CustomEvent("strokeend", { detail: e }))
}
})
canvas.addEventListener("pointermove", (e) => {
if (e.buttons & 1) {
input.dispatchEvent(new CustomEvent("strokemove", { detail: e }))
// Necessary since buttons property is non standard on iOS versions < 13.2
function checkValidPointerEvent(e) {
return e.buttons & 1 || e.pointerType === "touch"
}
const dispatchPointerEvent = (name) => (e) => {
if (checkValidPointerEvent(e)) {
input.dispatchEvent(new CustomEvent(name, { detail: e }))
}
})
}
// Note that the PointerEvent is passed as the detail in these 'stroke events'.
canvas.addEventListener("pointerdown", dispatchPointerEvent("strokestart"))
canvas.addEventListener("pointerenter", dispatchPointerEvent("strokestart"))
canvas.addEventListener("pointerup", dispatchPointerEvent("strokeend"))
canvas.addEventListener("pointerleave", dispatchPointerEvent("strokeend"))
canvas.addEventListener("pointermove", dispatchPointerEvent("strokemove"))
canvas.addEventListener("touchmove", (e) => e.preventDefault())
export function setStrokeColour(colour) {
......
......@@ -23,14 +23,14 @@ class Room extends EventTarget {
this._y.destroy()
}
addPath([x, y]) {
addPath([x, y, w]) {
const id = uuidv4()
this._y.share.strokeAdd.set(id, Y.Array).push([[x, y]])
this._y.share.strokeAdd.set(id, Y.Array).push([[x, y, w]])
return id
}
extendPath(id, [x, y]) {
this._y.share.strokeAdd.get(id).push([[x, y]])
extendPath(id, [x, y, w]) {
this._y.share.strokeAdd.get(id).push([[x, y, w]])
}
getPaths() {
......@@ -65,7 +65,7 @@ class Room extends EventTarget {
return addSet
.toArray()
.map((p = [], i) => [p[0], p[1], !eraseSet.get(i.toString())])
.map((p = [], i) => [p[0], p[1], p[2], !eraseSet.get(i.toString())])
}
inviteUser(id) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment