diff --git a/src/canvas.js b/src/canvas.js index 2173bc72b9698e4a39e0007ac90e0f3c80fc1802..05e47fd424990d935021dfa1b04888b50ab3d1c4 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -200,9 +200,13 @@ const applyErasureIntervals = (pathID, points, erasureIntervals) => { pathID, i, ) - if (!eraseIntervals || nextPoint === undefined) { + + if (!eraseIntervals) { subpath.push(point) continue + } else if (nextPoint === undefined) { + if (JSON.stringify(eraseIntervals) != "[[0,0]]") subpath.push(point) + continue } if (!pointWasErased(eraseIntervals) || subpath.length) { diff --git a/src/erasure.js b/src/erasure.js index 6347634f4f44e5d8674cbc7ba9c9fcd51c9ea33a..10fbb9bbb60fee775b0b38b51385d07e644b711d 100644 --- a/src/erasure.js +++ b/src/erasure.js @@ -45,14 +45,19 @@ function project([x1, y1], [x2, y2], [x3, y3]) { } function erasureInterval(lineStart, lineEnd, erasureCenter, erasureRadius) { - if (!(lineStart && lineEnd && erasureCenter)) return + if (!(lineStart && erasureCenter)) return undefined + + if (!lineEnd) { + const dist2ToSingularity = distanceSquared(erasureCenter, lineStart) + return dist2ToSingularity <= erasureRadius ** 2 ? [0, 0] : undefined + } const distToSegment2 = distToSegmentSquared(lineStart, lineEnd, erasureCenter) - if (erasureRadius ** 2 < distToSegment2) return + if (erasureRadius ** 2 < distToSegment2) return undefined const lineLength = distance(lineStart, lineEnd) if (lineLength === 0) { - return distToSegment2 <= erasureRadius ** 2 ? [0, 1] : [0, 0] + return distToSegment2 <= erasureRadius ** 2 ? [0, 1] : undefined } const projT = project(lineStart, lineEnd, erasureCenter) @@ -98,7 +103,6 @@ function overlaps([s1, e1], [, e2]) { function mergeIntervals(...intervals) { if (!intervals.length) return [] - const sorted = intervals.sort(([a], [b]) => a > b) const stack = [sorted[0]] sorted.forEach((x) => { @@ -121,3 +125,38 @@ export function combineErasureIntervals(i1, i2) { }) return { ...i2, ..._i1 } } + +export function spreadErasureIntervals(intervals) { + const spread = [] + + intervals.forEach(([l, u]) => { + if (u > l) { + for (let li = Math.floor(l); li < u; li++) { + const list = spread[li] || [] + + const [il, iu] = [Math.max(li, l), Math.min(li + 1, u)] + + list.push([il % 1, iu == li + 1 ? 1 : iu % 1]) + + spread[li] = list + } + } else { + spread[Math.floor(l)] = [[l % 1, u % 1]] + } + }) + + return spread +} + +export function flattenErasureIntervals(intervals) { + const flatten = [] + + for (const idx in intervals) { + if (intervals[idx]) + flatten.push( + intervals[idx].map(([l, u]) => [parseInt(idx) + l, parseInt(idx) + u]), + ) + } + + return flatten.flat() +} diff --git a/src/room.js b/src/room.js index e53af9713be6180a6edf2df82c2ca9ce8fcdd492..dcea9357f47f992805e52d95a9ec0505a035b5a9 100644 --- a/src/room.js +++ b/src/room.js @@ -11,6 +11,12 @@ yMap(Y) yArray(Y) yWebrtc(Y) +import { + combineErasureIntervals, + spreadErasureIntervals, + flattenErasureIntervals, +} from "./erasure.js" + class Room extends EventTarget { constructor(name) { super() @@ -37,23 +43,22 @@ class Room extends EventTarget { extendErasureIntervals(pathID, pointID, newIntervals) { const self = this - const afterJSON = JSON.stringify(newIntervals) - + // eslint-disable-next-line require-yield this._y.db.requestTransaction(function* requestTransaction() { - const pathIntervals = yield* JSON.parse( - self.sharedMergeIntervals.get(pathID) || "{}", - ) + const prevJSON = self.sharedMergeIntervals.get(pathID) || "[]" + const pathIntervals = JSON.parse(prevJSON) + + const combinedIntervals = combineErasureIntervals( + [pathIntervals], + [flattenErasureIntervals({ [pointID]: newIntervals })], + )[0] + const postJSON = JSON.stringify(combinedIntervals) - if (afterJSON == JSON.stringify(pathIntervals[pointID])) { + if (prevJSON == postJSON) { return } - pathIntervals[pointID] = newIntervals - - yield* self.sharedMergeIntervals.set( - pathID, - JSON.stringify(pathIntervals), - ) + self.sharedMergeIntervals.set(pathID, postJSON) }) } @@ -88,8 +93,10 @@ class Room extends EventTarget { _generateRemovedIntervals(id) { const intervals = this.sharedMergeIntervals.get(id) + if (!intervals) return [] - return JSON.parse(intervals) + + return spreadErasureIntervals(JSON.parse(intervals)) } inviteUser(id) {