From 33761fc2227458acf36a5cc4b1f08eaae6e58695 Mon Sep 17 00:00:00 2001
From: eleanor-park <eleanor_park@brown.edu>
Date: Tue, 11 Jun 2024 11:15:25 -0400
Subject: some changes

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 170 +++++++++++++--------
 1 file changed, 103 insertions(+), 67 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 d22b3569e..e66dbd796 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -144,7 +144,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             : this._props.childPointerEvents?.() ??
                   (this._props.viewDefDivClick || //
                   (this.layoutEngine === computePassLayout.name && !this._props.isSelected()) ||
-                  this.isContentActive() === false
+                  this.isContentActive() === false ||
+                  Doc.ActiveTool === InkTool.RadiusEraser ||
+                  Doc.ActiveTool === InkTool.SegmentEraser ||
+                  Doc.ActiveTool === InkTool.StrokeEraser
                       ? 'none'
                       : this._props.pointerEvents?.());
     }
@@ -501,27 +504,24 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 const hit = this._clusters.handlePointerDown(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY));
                 switch (Doc.ActiveTool) {
                     case InkTool.Highlighter:
-                        break;
                     case InkTool.Write:
-                        break;
                     case InkTool.Pen:
                         break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
                     case InkTool.StrokeEraser:
                     case InkTool.SegmentEraser:
-                        this._batch = UndoManager.StartBatch('collectionErase');
-                        this._eraserPts.length = 0;
-                        setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, emptyFunction, hit !== -1, false);
-                        break;
                     case InkTool.RadiusEraser:
                         this._batch = UndoManager.StartBatch('collectionErase');
                         this._eraserPts.length = 0;
-                        setupMoveUpEvents(this, e, this.onRadiusEraserMove, this.onEraserUp, emptyFunction, hit !== -1, false);
+                        setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, this.onEraserClick, hit !== -1);
+                        e.stopPropagation();
                         break;
                     case InkTool.SmartDraw:
-                        setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, this.createDrawing, hit !== -1, false);
+                        setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, this.createDrawing, hit !== -1);
+                        e.stopPropagation();
                     case InkTool.None:
                         if (!(this._props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) {
-                            setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, hit !== -1, false);
+                            setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, hit !== -1);
+                            e.stopPropagation();
                         }
                         break;
                     default:
@@ -608,50 +608,83 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     _eraserLock = 0;
     _eraserPts: number[][] = []; // keep track of the last few eraserPts to make the eraser circle 'stretch'
 
-    /**
-     * Erases strokes by intersecting them with an invisible "eraser stroke".
-     *  By default this iterates through all intersected ink strokes, determines their segmentation, draws back the non-intersected segments,
-     * and deletes the original stroke.
-     */
-    @action
-    onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => {
+    erase = (e: PointerEvent, delta: number[]) => {
         const currPoint = { X: e.clientX, Y: e.clientY };
         this._eraserPts.push([currPoint.X, currPoint.Y]);
         this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5));
-        // if (this._eraserLock) return false; // leaving this commented out in case the idea is revisited in the future
-        this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => {
-            if (!this._deleteList.includes(intersect.inkView)) {
-                this._deleteList.push(intersect.inkView);
-                SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1');
-                SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black');
-                // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
-                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
-                    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 = InkField.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',
+        if (Doc.ActiveTool === InkTool.RadiusEraser) {
+            const strokeMap: Map<DocumentView, number[]> = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint);
+
+            strokeMap.forEach((intersects, stroke) => {
+                if (!this._deleteList.includes(stroke)) {
+                    this._deleteList.push(stroke);
+                    SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1');
+                    SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black');
+                    const segments = this.radiusErase(stroke, intersects.sort());
+                    segments?.forEach(segment =>
+                        this.forceStrokeGesture(
+                            e,
+                            Gestures.Stroke,
+                            segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[])
+                        )
+                    );
+                }
+                stroke.layoutDoc.opacity = 0;
+                stroke.layoutDoc.dontIntersect = true;
+            });
+        } else {
+            this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => {
+                if (!this._deleteList.includes(intersect.inkView)) {
+                    this._deleteList.push(intersect.inkView);
+                    SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1');
+                    SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black');
+                    // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
+                    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
+                        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 = InkField.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--);
+                                inkWidth
+                            );
+                        });
+                        newStrokes && this.addDocument?.(newStrokes);
+                        // setTimeout(() => this._eraserLock--);
+                    }
+                    // Lower ink opacity to give the user a visual indicator of deletion.
+                    intersect.inkView.layoutDoc.opacity = 0;
+                    intersect.inkView.layoutDoc.dontIntersect = true;
                 }
-                // Lower ink opacity to give the user a visual indicator of deletion.
-                intersect.inkView.layoutDoc.opacity = 0;
-                intersect.inkView.layoutDoc.dontIntersect = true;
-            }
-        });
+            });
+        }
+        return false;
+    };
+
+    /**
+     * Erases strokes by intersecting them with an invisible "eraser stroke".
+     *  By default this iterates through all intersected ink strokes, determines their segmentation, draws back the non-intersected segments,
+     * and deletes the original stroke.
+     */
+    @action
+    onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => {
+        this.erase(e, delta);
+        // if (this._eraserLock) return false; // leaving this commented out in case the idea is revisited in the future
+        return false;
+    };
+
+    @action
+    onEraserClick = (e: PointerEvent, doubleTap?: boolean) => {
+        this.erase(e, [0, 0]);
         return false;
     };
 
@@ -720,7 +753,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         // increase radius slightly based on the erased stroke's width, added to make eraser look more realistic
         const radius = ActiveEraserWidth() + 5 + inkStrokeWidth * 0.1; // add 5 to prevent eraser from being too small
         const c = 0.551915024494; // circle tangent length to side ratio
-        const movement = { x: endInkCoordsIn.X - startInkCoordsIn.X, y: endInkCoordsIn.Y - startInkCoordsIn.Y };
+        const movement = { x: Math.max(endInkCoordsIn.X - startInkCoordsIn.X, 1), y: Math.max(endInkCoordsIn.Y - startInkCoordsIn.Y, 1) };
         const moveLen = Math.sqrt(movement.x ** 2 + movement.y ** 2);
         const direction = { x: (movement.x / moveLen) * radius, y: (movement.y / moveLen) * radius };
         const normal    = { x: -direction.y, y: direction.x }; // prettier-ignore
@@ -1232,28 +1265,29 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     createDrawing = (e: PointerEvent, doubleTap?: boolean) => {
-        SmartDrawHandler.Instance.displaySmartDrawHandler(e.pageX, e.pageY);
-        if (SmartDrawHandler.Instance.strokes.length > 0) {
-            const strokeList: InkData[] = SmartDrawHandler.Instance.strokes;
-            strokeList.forEach(coords => {
-                // const stroke = new InkField(coords);
-                // const points = coords.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.X, Y: p.Y }) ?? { X: 0, Y: 0 }), [] as PointData[]);
-                const bounds = InkField.getBounds(coords);
-                const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
-                const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale;
-                const inkDoc = Docs.Create.InkDocument(
-                    coords,
-                    { title: 'stroke',
+        SmartDrawHandler.Instance.displaySmartDrawHandler(e.pageX, e.pageY, this.createInkStroke);
+    };
+
+    @action
+    createInkStroke = (strokeList: InkData[]) => {
+        strokeList.forEach(coords => {
+            // const stroke = new InkField(coords);
+            // const points = coords.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.X, Y: p.Y }) ?? { X: 0, Y: 0 }), [] as PointData[]);
+            const bounds = InkField.getBounds(coords);
+            const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
+            const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale;
+            const inkDoc = Docs.Create.InkDocument(
+                coords,
+                { 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
-                );
-                this.addDocument(inkDoc);
-            });
-        }
+                inkWidth
+            );
+            this.addDocument(inkDoc);
+        });
     };
 
     @action
@@ -1849,8 +1883,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     onCursorMove = (e: React.PointerEvent) => {
-        this._eraserX = e.clientX;
-        this._eraserY = e.clientY;
+        const locPt = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY);
+        this._eraserX = locPt[0];
+        this._eraserY = locPt[1];
+        // Doc.ActiveTool === InkTool.RadiusEraser ? this._childPointerEvents = 'none' : this._childPointerEvents = 'all'
         //  super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
     };
 
@@ -2161,8 +2197,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                         onPointerMove={this.onCursorMove}
                         style={{
                             position: 'fixed',
-                            left: this._eraserX - 60,
-                            top: this._eraserY - 100,
+                            left: this._eraserX,
+                            top: this._eraserY,
                             width: (ActiveEraserWidth() + 5) * 2,
                             height: (ActiveEraserWidth() + 5) * 2,
                             borderRadius: '50%',
-- 
cgit v1.2.3-70-g09d2

