Browse Source

fix: Arrow eraser precision arrow selection (#10006)

Márk Tolmács 1 tháng trước cách đây
mục cha
commit
a89a03c66c
2 tập tin đã thay đổi với 53 bổ sung20 xóa
  1. 36 12
      packages/element/src/bounds.ts
  2. 17 8
      packages/excalidraw/eraser/index.ts

+ 36 - 12
packages/element/src/bounds.ts

@@ -42,6 +42,7 @@ import {
   isBoundToContainer,
   isFreeDrawElement,
   isLinearElement,
+  isLineElement,
   isTextElement,
 } from "./typeChecks";
 
@@ -321,19 +322,42 @@ export const getElementLineSegments = (
 
   if (shape.type === "polycurve") {
     const curves = shape.data;
-    const points = curves
-      .map((curve) => pointsOnBezierCurves(curve, 10))
-      .flat();
-    let i = 0;
+    const pointsOnCurves = curves.map((curve) =>
+      pointsOnBezierCurves(curve, 10),
+    );
+
     const segments: LineSegment<GlobalPoint>[] = [];
-    while (i < points.length - 1) {
-      segments.push(
-        lineSegment(
-          pointFrom(points[i][0], points[i][1]),
-          pointFrom(points[i + 1][0], points[i + 1][1]),
-        ),
-      );
-      i++;
+
+    if (
+      (isLineElement(element) && !element.polygon) ||
+      isArrowElement(element)
+    ) {
+      for (const points of pointsOnCurves) {
+        let i = 0;
+
+        while (i < points.length - 1) {
+          segments.push(
+            lineSegment(
+              pointFrom(points[i][0], points[i][1]),
+              pointFrom(points[i + 1][0], points[i + 1][1]),
+            ),
+          );
+          i++;
+        }
+      }
+    } else {
+      const points = pointsOnCurves.flat();
+      let i = 0;
+
+      while (i < points.length - 1) {
+        segments.push(
+          lineSegment(
+            pointFrom(points[i][0], points[i][1]),
+            pointFrom(points[i + 1][0], points[i + 1][1]),
+          ),
+        );
+        i++;
+      }
     }
 
     return segments;

+ 17 - 8
packages/excalidraw/eraser/index.ts

@@ -2,10 +2,10 @@ import { arrayToMap, easeOut, THEME } from "@excalidraw/common";
 
 import {
   computeBoundTextPosition,
-  distanceToElement,
   doBoundsIntersect,
   getBoundTextElement,
   getElementBounds,
+  getElementLineSegments,
   getFreedrawOutlineAsSegments,
   getFreedrawOutlinePoints,
   intersectElementWithLineSegment,
@@ -265,19 +265,28 @@ const eraserTest = (
     }
 
     return false;
-  } else if (
-    isArrowElement(element) ||
-    (isLineElement(element) && !element.polygon)
-  ) {
+  }
+
+  const boundTextElement = getBoundTextElement(element, elementsMap);
+
+  if (isArrowElement(element) || (isLineElement(element) && !element.polygon)) {
     const tolerance = Math.max(
       element.strokeWidth,
       (element.strokeWidth * 2) / zoom,
     );
 
-    return distanceToElement(element, elementsMap, lastPoint) <= tolerance;
-  }
+    // If the eraser movement is so fast that a large distance is covered
+    // between the last two points, the distanceToElement miss, so we test
+    // agaist each segment of the linear element
+    const segments = getElementLineSegments(element, elementsMap);
+    for (const seg of segments) {
+      if (lineSegmentsDistance(seg, pathSegment) <= tolerance) {
+        return true;
+      }
+    }
 
-  const boundTextElement = getBoundTextElement(element, elementsMap);
+    return false;
+  }
 
   return (
     intersectElementWithLineSegment(element, elementsMap, pathSegment, 0, true)