From 4a332476db24555260820b8c5e268acc2000041c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 9 May 2024 11:15:46 -0400
Subject: tweaks to make eraser deletion more efficient

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 67 ++++++++++++----------
 1 file changed, 38 insertions(+), 29 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2e174be30..ca9a9974a 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';
@@ -693,7 +691,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();
     };
@@ -756,13 +754,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.
@@ -872,17 +880,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);
@@ -894,8 +902,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;
                 }
             }
@@ -950,7 +957,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?.()))
@@ -964,7 +971,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     eraserMax.X >= inkViewBounds.left &&
                     eraserMax.Y >= inkViewBounds.top
             );
-        console.log("itersectnig strokes", intersectingStrokes);
+
         intersectingStrokes.forEach(({ inkStroke, inkView }) => {
             const { inkData } = inkStroke.inkScaledData();
             const prevPointInkSpace = inkStroke.ptFromScreen(lastPoint);
@@ -1007,7 +1014,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 }
             }
         });
-        console.log("strokeToTVals", strokeToTVals);
         return strokeToTVals;
     };
 
@@ -1024,8 +1030,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));
             }
             if (currSegment.length > 0) {
@@ -1042,18 +1049,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;
@@ -1071,7 +1078,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);
                 }
             }
@@ -1191,7 +1199,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);
@@ -2128,6 +2136,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);
     });
-- 
cgit v1.2.3-70-g09d2

