diff options
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 65 |
1 files changed, 38 insertions, 27 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ab47c105e..622189b80 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,5 @@ -import { inside } from '@turf/turf'; import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { validationResult } from 'express-validator'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; @@ -695,7 +693,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; @action onEraserUp = (e: PointerEvent): void => { - this._deleteList.forEach(ink => ink._props.removeDocument?.(ink.Document)); + this._deleteList.lastElement()?._props.removeDocument?.(this._deleteList.map(ink => ink.Document)); this._deleteList = []; this._batch?.end(); }; @@ -759,13 +757,23 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (Doc.ActiveTool !== InkTool.StrokeEraser) { this._eraserLock++; const segments = this.segmentErase(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it - segments?.forEach(segment => - this.forceStrokeGesture( - e, - GestureUtils.Gestures.Stroke, - segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]) - ) - ); + const newStrokes = segments?.map(segment => { + const points = segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]); + const bounds = GestureOverlay.getBounds(points); + const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height); + const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale; + return Docs.Create.InkDocument( + points, + { title: 'stroke', + x: B.x - inkWidth / 2, + y: B.y - inkWidth / 2, + _width: B.width + inkWidth, + _height: B.height + inkWidth, + stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore + inkWidth + ); + }); + newStrokes && this.addDocument?.(newStrokes); setTimeout(() => this._eraserLock--); } // Lower ink opacity to give the user a visual indicator of deletion. @@ -877,17 +885,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection /** * Ray-tracing algorithm to determine whether a point is inside the eraser outline - * @param eraserOutline - * @param point - * @returns + * @param eraserOutline + * @param point + * @returns */ insideEraserOutline = (eraserOutline: InkData, point: { X: number; Y: number }) => { var isInside = false; if (!isNaN(eraserOutline[0].X) && !isNaN(eraserOutline[0].Y)) { - var minX = eraserOutline[0].X, maxX = eraserOutline[0].X; - var minY = eraserOutline[0].Y, maxY = eraserOutline[0].Y; - for (var i = 1; i < eraserOutline.length; i++) { - const currPoint: {X: number, Y: number} = eraserOutline[i]; + let minX = eraserOutline[0].X, maxX = eraserOutline[0].X; // prettier-ignore + let minY = eraserOutline[0].Y, maxY = eraserOutline[0].Y; // prettier-ignore + for (let i = 1; i < eraserOutline.length; i++) { + const currPoint: { X: number; Y: number } = eraserOutline[i]; minX = Math.min(currPoint.X, minX); maxX = Math.max(currPoint.X, maxX); minY = Math.min(currPoint.Y, minY); @@ -899,8 +907,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } for (var i = 0, j = eraserOutline.length - 1; i < eraserOutline.length; j = i, i++) { - if ((eraserOutline[i].Y > point.Y) != (eraserOutline[j].Y > point.Y) && - point.X < (eraserOutline[j].X - eraserOutline[i].X) * (point.Y - eraserOutline[i].Y) / (eraserOutline[j].Y - eraserOutline[i].Y) + eraserOutline[i].X ) { + if (eraserOutline[i].Y > point.Y != eraserOutline[j].Y > point.Y && point.X < ((eraserOutline[j].X - eraserOutline[i].X) * (point.Y - eraserOutline[i].Y)) / (eraserOutline[j].Y - eraserOutline[i].Y) + eraserOutline[i].X) { isInside = !isInside; } } @@ -955,7 +962,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection getRadiusEraserIntersections = (lastPoint: { X: number; Y: number }, currPoint: { X: number; Y: number }) => { const eraserRadius = ActiveEraserWidth() + 3; const eraserMin = { X: Math.min(lastPoint.X, currPoint.X) - eraserRadius, Y: Math.min(lastPoint.Y, currPoint.Y) - eraserRadius }; - const eraserMax = { X: Math.max(lastPoint.X, currPoint.X) + eraserRadius, Y: Math.max(lastPoint.Y, currPoint.Y) + eraserRadius}; + const eraserMax = { X: Math.max(lastPoint.X, currPoint.X) + eraserRadius, Y: Math.max(lastPoint.Y, currPoint.Y) + eraserRadius }; const strokeToTVals = new Map<DocumentView, number[]>(); const intersectingStrokes = this.childDocs .map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) @@ -969,6 +976,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection eraserMax.X >= inkViewBounds.left && eraserMax.Y >= inkViewBounds.top ); + intersectingStrokes.forEach(({ inkStroke, inkView }) => { const { inkData } = inkStroke.inkScaledData(); const prevPointInkSpace = inkStroke.ptFromScreen(lastPoint); @@ -1027,8 +1035,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const inkStroke = ink?.ComponentView as InkingStroke; const { inkData } = inkStroke.inkScaledData(); var currSegment: Segment = []; - if (tVals.length % 2 !== 0) { // should always have even tVals - for (var i = 0; i < inkData.length - 3; i +=4) { + if (tVals.length % 2 !== 0) { + // should always have even tVals + for (var i = 0; i < inkData.length - 3; i += 4) { currSegment.push(InkField.Segment(inkData, i)); } segments.push(currSegment); @@ -1047,18 +1056,18 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } for (var i = 0; i < inkData.length - 3; i += 4) { - const currCurveT = Math.floor(i/4); + const currCurveT = Math.floor(i / 4); const inkBezier: Bezier = InkField.Segment(inkData, i); const segmentTs = tVals.filter(t => t >= currCurveT && t < currCurveT + 1); if (segmentTs.length > 0) { for (var j = 0; j < segmentTs.length; j++) { // if the first end of the segment is within the eraser - if (segmentTs[j] === 0 ) { + if (segmentTs[j] === 0) { continueErasing = true; } else if (segmentTs[j] === Math.floor(inkData.length / 4) + 1) { break; - }else { + } else { if (!continueErasing) { currSegment.push(inkBezier.split(0, segmentTs[j] - currCurveT)); continueErasing = true; @@ -1076,7 +1085,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } } } else { - if (!continueErasing) { // push the bezier piece if not in the eraser circle + if (!continueErasing) { + // push the bezier piece if not in the eraser circle currSegment.push(inkBezier); } } @@ -1199,7 +1209,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection hasSplit = true; } else if (currCurveT === splitSegment1) { segment1.push(inkSegment.split(0, intersections[closestTs[0]] - currCurveT)); - hasSplit = true; + hasSplit = true; } else { if ((isClosedCurve && hasSplit) || (!isClosedCurve && !hasSplit)) { segment1.push(inkSegment); @@ -2138,6 +2148,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) { this._renderCutoffData.set(layout_unrendered[i][Id] + '', true); } + layout_unrendered.forEach(lu => lu.stroke && this._renderCutoffData.set(lu[Id] + '', true)); } this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); }); |