Fix linting

This commit is contained in:
Mathias Krafft 2025-04-07 13:59:50 +00:00
parent ac37d0a5be
commit 37412cd68a
2 changed files with 59 additions and 31 deletions

View file

@ -245,18 +245,20 @@ export const isPointWithinBounds = <P extends GlobalPoint | LocalPoint>(
export const perpendicularDistance = <P extends GlobalPoint | LocalPoint>(
p: P,
start: P,
end: P):
number => {
end: P,
): number => {
const dx = end[0] - start[0];
const dy = end[1] - start[1];
if (dx === 0 && dy === 0) {
return Math.hypot(p[0] - start[0], p[1] - start[1]);
}
// Equation of line distance
const numerator = Math.abs(dy * p[0] - dx * p[1] + end[0] * start[1] - end[1] * start[0]);
const numerator = Math.abs(
dy * p[0] - dx * p[1] + end[0] * start[1] - end[1] * start[0],
);
const denom = Math.hypot(dx, dy);
return numerator / denom;
}
};
/** * Calculates the angle between three points in degrees.
* The angle is calculated at the first point (p0) using the second (p1) and third (p2) points.
@ -266,7 +268,7 @@ export const perpendicularDistance = <P extends GlobalPoint | LocalPoint>(
* @param p1 The vertex point where the angle is calculated.
* @param p2 The second point used to form the angle.
* @returns The angle in degrees between the three points.
**/
**/
export const angleBetween = <P extends GlobalPoint | LocalPoint>(
p0: P,
p1: P,
@ -276,8 +278,12 @@ export const angleBetween = <P extends GlobalPoint | LocalPoint>(
const v2 = vectorFromPoint(p1, p2);
// dot and cross product
const magnitude1 = Math.hypot(v1[0], v1[1]), magnitude2 = Math.hypot(v2[0], v2[1]);
if (magnitude1 === 0 || magnitude2 === 0) return 0 as Degrees;
const magnitude1 = Math.hypot(v1[0], v1[1]);
const magnitude2 = Math.hypot(v2[0], v2[1]);
if (magnitude1 === 0 || magnitude2 === 0) {
return 0 as Degrees;
}
const dot = vectorDot(v1, v2);
@ -287,4 +293,4 @@ export const angleBetween = <P extends GlobalPoint | LocalPoint>(
const rad = Math.acos(cos) as Radians;
return radiansToDegrees(rad);
}
};

View file

@ -1,3 +1,23 @@
import {
getCenterForBounds,
getCommonBoundingBox,
} from "@excalidraw/element/bounds";
import {
newArrowElement,
newElement,
newLinearElement,
} from "@excalidraw/element/newElement";
import {
angleBetween,
perpendicularDistance,
pointDistance,
} from "@excalidraw/math";
import { ROUNDNESS } from "@excalidraw/common";
import type { LocalPoint } from "@excalidraw/math";
import type { BoundingBox, Bounds } from "@excalidraw/element/bounds";
import type {
ExcalidrawArrowElement,
ExcalidrawDiamondElement,
@ -7,11 +27,6 @@ import type {
ExcalidrawLinearElement,
ExcalidrawRectangleElement,
} from "@excalidraw/element/types";
import type { BoundingBox, Bounds } from "@excalidraw/element/bounds";
import { getCenterForBounds, getCommonBoundingBox } from "@excalidraw/element/bounds";
import { newArrowElement, newElement, newLinearElement } from "@excalidraw/element/newElement";
import { angleBetween, GlobalPoint, LocalPoint, perpendicularDistance, pointDistance } from "@excalidraw/math";
import { ROUNDNESS } from "@excalidraw/common";
type Shape =
| ExcalidrawRectangleElement["type"]
@ -53,7 +68,6 @@ const DEFAULT_OPTIONS = {
ellipseRadiusVarianceThreshold: 0.5,
} as const; // Use 'as const' for stricter typing of default values
// Options for shape recognition, allowing partial overrides
type ShapeRecognitionOptions = typeof DEFAULT_OPTIONS;
type PartialShapeRecognitionOptions = Partial<ShapeRecognitionOptions>;
@ -94,10 +108,9 @@ function simplifyRDP(
const right = simplifyRDP(points.slice(index), epsilon);
// Concatenate results (omit duplicate point at junction)
return left.slice(0, -1).concat(right);
} else {
// Not enough deviation, return straight line segment (keep only endpoints)
return [first, last];
}
// Not enough deviation, return straight line segment (keep only endpoints)
return [first, last];
}
/**
@ -238,7 +251,10 @@ function checkArrow(
const tipAngle = angleBetween(arrowTip, arrowBase, arrowTailEnd);
if (tipAngle <= options.arrowMinTipAngle || tipAngle >= options.arrowMaxTipAngle) {
if (
tipAngle <= options.arrowMinTipAngle ||
tipAngle >= options.arrowMaxTipAngle
) {
return null;
}
@ -296,10 +312,9 @@ function checkQuadrilateral(
if (isAxisAligned(segments, options.rectangleOrientationAngleThreshold)) {
return "rectangle";
} else {
// Not axis-aligned, but quadrilateral => classify as diamond
return "diamond";
}
// Not axis-aligned, but quadrilateral => classify as diamond
return "diamond";
}
/** Checks if the points form an ellipse shape. */
@ -345,13 +360,18 @@ export const recognizeShape = (
}
const boundingBoxDiagonal = Math.hypot(boundingBox.width, boundingBox.height);
const rdpTolerance = boundingBoxDiagonal * (options.rdpTolerancePercent / 100);
const rdpTolerance =
boundingBoxDiagonal * (options.rdpTolerancePercent / 100);
const simplifiedPoints = simplifyRDP(points, rdpTolerance);
const isClosed = isShapeClosed(simplifiedPoints, boundingBoxDiagonal, options);
const isClosed = isShapeClosed(
simplifiedPoints,
boundingBoxDiagonal,
options,
);
// --- Shape check order matters here ---
let recognizedType: Shape =
const recognizedType: Shape =
checkLine(simplifiedPoints, isClosed) ??
checkArrow(simplifiedPoints, isClosed, options) ??
checkQuadrilateral(simplifiedPoints, isClosed, options) ??
@ -365,7 +385,6 @@ export const recognizeShape = (
};
};
/**
* Converts a freedraw element to the detected shape
*/
@ -375,7 +394,9 @@ export const convertToShape = (
const recognizedShape = recognizeShape(freeDrawElement);
switch (recognizedShape.type) {
case "rectangle": case "diamond": case "ellipse": {
case "rectangle":
case "diamond":
case "ellipse": {
return newElement({
...freeDrawElement,
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
@ -392,9 +413,9 @@ export const convertToShape = (
type: recognizedShape.type,
points: [
recognizedShape.simplified[0],
recognizedShape.simplified[recognizedShape.simplified.length - 2]
recognizedShape.simplified[recognizedShape.simplified.length - 2],
],
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS }
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
});
}
case "line": {
@ -403,11 +424,12 @@ export const convertToShape = (
type: recognizedShape.type,
points: [
recognizedShape.simplified[0],
recognizedShape.simplified[recognizedShape.simplified.length - 1]
recognizedShape.simplified[recognizedShape.simplified.length - 1],
],
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS }
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
});
}
default: return freeDrawElement
default:
return freeDrawElement;
}
};