diff --git a/public/cursor.svg b/public/cursor.svg index fc03e3b03768ec61ce2291253aea5720e2c5f51e..3e2a4ddd3db9a2ba6b630ea0e05ca9097b7037a4 100644 --- a/public/cursor.svg +++ b/public/cursor.svg @@ -1,3 +1,3 @@ -<svg viewBox="-2 -2 6 6" xmlns="http://www.w3.org/2000/svg"> - <circle cx="2" cy="2" r="2"/> +<svg viewBox="-10 -10 30 30" xmlns="http://www.w3.org/2000/svg"> + <circle cx="10" cy="10" r="10"/> </svg> \ No newline at end of file diff --git a/public/styles.css b/public/styles.css index 97e8aaeab48e9d6bd032953d6237fd262533c1d2..c1592d0cf4a41c78a0330e6b4660a38ea34d9c72 100644 --- a/public/styles.css +++ b/public/styles.css @@ -1,7 +1,8 @@ html, body { height: 100%; - cursor: crosshair; + cursor: url(cursor.svg) 15 15, pointer; + /* /crosshair; */ } body { diff --git a/src/app.js b/src/app.js index 46fc45992e0e7265dd825e944253bfbc7776c192..ac6cb5b5be7f1185dc13098f87aea1c5973b2735 100644 --- a/src/app.js +++ b/src/app.js @@ -25,13 +25,13 @@ const STROKECOLOUR = "blue" const STROKERADIUS = 2 const ERASERRADIUS = STROKERADIUS * 10 -function interpolatedCoordinate(start, end, length) { - const dx = end[0] - start[0] - const dy = end[1] - start[1] - const dist = getDistance(start, end) - const ratio = length / dist - return [start[0] + dx * ratio, start[1] + dy * ratio] -} +// function interpolatedCoordinate(start, end, length) { +// const dx = end[0] - start[0] +// const dy = end[1] - start[1] +// const dist = getDistance(start, end) +// const ratio = length / dist +// return [start[0] + dx * ratio, start[1] + dy * ratio] +// } function eraseAt(x, y, room) { let mousePos = [x, y] @@ -47,11 +47,10 @@ function eraseAt(x, y, room) { detail: { id: pathID, points }, }), ) - points.forEach((point, i) => { + points.forEach((point) => { const distanceToPoint = getDistance(mousePos, point) if (distanceToPoint <= ERASERRADIUS) { - room.erasePoint(pathID, i) - + // room.erasePoint(pathID, i) // let prev, next // if (i > 0) { // prev = i - 1 @@ -59,7 +58,6 @@ function eraseAt(x, y, room) { // if (i < points.length - 1) { // next = i + 1 // } - // if (prev !== undefined) { // const interpolatedPoint = interpolatedCoordinate( // point, @@ -68,7 +66,6 @@ function eraseAt(x, y, room) { // ) // room.insertIntoPath(pathID, prev, interpolatedPoint) // } - // if (next !== undefined) { // const interpolatedPoint = interpolatedCoordinate( // point, @@ -93,9 +90,9 @@ const SVG = { }, } -let TEST_ERASE_INTERVAL = {} // { 0: [[0.1, 0.3], [0.4, 0.8]] } +let TEST_ERASE_INTERVAL = {} -function erasurePoints(pointA, pointB, start, fin) { +function erasurePoints(pointA, pointB, [start, fin]) { if (start >= fin) return if (start <= 0) start = 0 if (fin >= 1) fin = 1 @@ -110,7 +107,7 @@ function erasurePoints(pointA, pointB, start, fin) { return [start, fin].map(pointOnLine) } -const addOrUpdatePathElem = (pathElems, id, points) => { +function getOrAddPathElem(pathElems, id) { let pathElem = pathElems.get(id) if (pathElem == null) { @@ -128,92 +125,101 @@ const addOrUpdatePathElem = (pathElems, id, points) => { } pathElem.innerHTML = "" + return pathElem +} - if (points.length == 0) { - return pathElem - } +function generateSvgPoint(subPath) { + const subpathElem = SVG.create.circle() + + subpathElem.setAttribute("stroke", "none") + subpathElem.setAttribute("fill", STROKECOLOUR) + subpathElem.setAttribute("cx", subPath[0][0]) + subpathElem.setAttribute("cy", subPath[0][1]) + subpathElem.setAttribute("r", STROKERADIUS) + + return subpathElem +} +function generateSvgPath(subPath) { + const subpathElem = SVG.create.path() + subpathElem.setAttribute("d", lineFn(subPath)) + return subpathElem +} + +function generateSvgForSubpath(subPath) { + return subPath.length === 1 + ? generateSvgPoint(subPath) + : generateSvgPath(subPath) +} + +function isInvalidPoint(point) { + return point[0] === undefined +} + +function isEndPoint(point) { + return point[2] === "end" +} + +function getEraseIntervals(pathID, pointID) { + const eraseIntervalsForPath = TEST_ERASE_INTERVAL[pathID] + if (!eraseIntervalsForPath) return undefined + return eraseIntervalsForPath[pointID] +} + +function generatePointsForPathElem(pathElem, pathID, dataPoints) { + const points = dataPoints // Push a fake path split to generate the last path - points.push([-1, -1, false]) + points.push([-1, -1, "end"]) let subPath = [] - let toAdd = undefined for (let i = 0; i < points.length; i++) { const point = points[i] - if (toAdd) { - subPath.push(toAdd) - toAdd = undefined - } - - if (point[0] === undefined) { + if (isInvalidPoint(point)) { continue } - if (point[2] === false) { + if (isEndPoint(point)) { // End of subpath - if (subPath.length == 1) { - const subpathElem = SVG.create.circle() - - subpathElem.setAttribute("stroke", "none") - subpathElem.setAttribute("fill", STROKECOLOUR) - subpathElem.setAttribute("cx", subPath[0][0]) - subpathElem.setAttribute("cy", subPath[0][1]) - subpathElem.setAttribute("r", STROKERADIUS) - - pathElem.appendChild(subpathElem) - } else if (subPath.length > 0) { - const subpathElem = SVG.create.path() - - subpathElem.setAttribute("d", lineFn(subPath)) - + if (subPath.length) { + const subpathElem = generateSvgForSubpath(subPath) pathElem.appendChild(subpathElem) + subPath = [] } - - subPath = [] - continue } // Valid point inside a subpath subPath.push(point) - - const eraseIntervalsForPath = TEST_ERASE_INTERVAL[id] - if (!eraseIntervalsForPath) continue - const eraseIntervals = TEST_ERASE_INTERVAL[id][i] - if (!eraseIntervals) continue - if (i === points.length - 1) { - continue - } - const nextPoint = points[i + 1] + const eraseIntervals = getEraseIntervals(pathID, i) + if (!eraseIntervals || nextPoint === undefined) continue for (const eraseInterval of eraseIntervals) { - if (eraseInterval) { - if (toAdd) { - subPath.push(toAdd) - toAdd = undefined - } - - const erp = erasurePoints( - point, - nextPoint, - eraseInterval[0], - eraseInterval[1], - ) - if (!(erp && erp.length)) continue - const [start, fin] = erp - - subPath.push(start) - - const subpathElem = SVG.create.path() - subpathElem.setAttribute("d", lineFn(subPath)) - pathElem.appendChild(subpathElem) - subPath = [] + if (!eraseInterval) continue - toAdd = fin - } + const erasedIntervalBounds = erasurePoints( + point, + nextPoint, + eraseInterval, + ) + if (!(erasedIntervalBounds && erasedIntervalBounds.length)) continue + const [endOfDrawnSegment, startOfNewSegment] = erasedIntervalBounds + + subPath.push(endOfDrawnSegment) + const subpathElem = generateSvgPath(subPath) + pathElem.appendChild(subpathElem) + + subPath = [startOfNewSegment] } } +} + +const addOrUpdatePathElem = (pathElems, id, points) => { + const pathElem = getOrAddPathElem(pathElems, id) + if (!points.length) { + return pathElem + } + generatePointsForPathElem(pathElem, id, points) return pathElem }