mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Attempt at optimizing focus point calc
This commit is contained in:
parent
5cbd6e63a0
commit
34ec751501
3 changed files with 63 additions and 24 deletions
|
@ -73,6 +73,11 @@ import {
|
|||
pointDistanceSq,
|
||||
clamp,
|
||||
radians,
|
||||
vectorScale,
|
||||
pointFromVector,
|
||||
vectorRotate,
|
||||
vectorNormalize,
|
||||
pointDistance,
|
||||
} from "../../math";
|
||||
import { segmentIntersectRectangleElement } from "../../utils/geometry/shape";
|
||||
import { distanceToBindableElement } from "./distance";
|
||||
|
@ -1425,7 +1430,7 @@ const determineFocusPoint = (
|
|||
GAPoint.from(adjecentPoint),
|
||||
);
|
||||
const reverseRelateToCenter = GA.reverse(relateToCenter);
|
||||
let point;
|
||||
let p: GA.Point;
|
||||
switch (element.type) {
|
||||
case "rectangle":
|
||||
case "image":
|
||||
|
@ -1435,14 +1440,18 @@ const determineFocusPoint = (
|
|||
case "embeddable":
|
||||
case "frame":
|
||||
case "magicframe":
|
||||
point = findFocusPointForRectangulars(element, focus, adjecentPointRel);
|
||||
p = findFocusPointForRectanguloidElement(
|
||||
element,
|
||||
focus,
|
||||
adjecentPointRel,
|
||||
);
|
||||
break;
|
||||
case "ellipse":
|
||||
point = findFocusPointForEllipse(element, focus, adjecentPointRel);
|
||||
p = findFocusPointForEllipse(element, focus, adjecentPointRel);
|
||||
break;
|
||||
}
|
||||
return pointFromPair(
|
||||
GAPoint.toTuple(GATransform.apply(reverseRelateToCenter, point)),
|
||||
GAPoint.toTuple(GATransform.apply(reverseRelateToCenter, p)),
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1692,7 +1701,7 @@ const findFocusPointForEllipse = (
|
|||
return GA.point(x, (-m * x - 1) / n);
|
||||
};
|
||||
|
||||
const findFocusPointForRectangulars = (
|
||||
const findFocusPointForRectanguloidElement = (
|
||||
element:
|
||||
| ExcalidrawRectangleElement
|
||||
| ExcalidrawImageElement
|
||||
|
@ -1705,23 +1714,34 @@ const findFocusPointForRectangulars = (
|
|||
relativeDistance: number,
|
||||
// The point for which we're trying to find the focus point, relative
|
||||
// to the element center.
|
||||
point: GA.Point,
|
||||
gaPoint: GA.Point,
|
||||
): GA.Point => {
|
||||
const relativeDistanceAbs = Math.abs(relativeDistance);
|
||||
const orientation = Math.sign(relativeDistance);
|
||||
const corners = getCorners(element, relativeDistanceAbs);
|
||||
const relP = pointFromPair<GlobalPoint>(GAPoint.toTuple(gaPoint));
|
||||
const center = point<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const p = point<GlobalPoint>(center[0] + relP[0], center[1] + relP[1]);
|
||||
const ret = pointFromVector(
|
||||
vectorScale(
|
||||
vectorRotate(
|
||||
vectorNormalize(vectorFromPoint(p, center)),
|
||||
radians(Math.PI / 2),
|
||||
),
|
||||
Math.sign(relativeDistance) *
|
||||
Math.min(
|
||||
pointDistance(point<GlobalPoint>(element.x, element.y), center) *
|
||||
Math.abs(relativeDistance),
|
||||
element.width / 2,
|
||||
element.height / 2,
|
||||
),
|
||||
),
|
||||
center,
|
||||
);
|
||||
|
||||
let maxDistance = 0;
|
||||
let tangentPoint: null | GA.Point = null;
|
||||
corners.forEach((corner) => {
|
||||
const distance = orientation * GALine.through(point, corner)[1];
|
||||
if (distance > maxDistance) {
|
||||
maxDistance = distance;
|
||||
tangentPoint = corner;
|
||||
}
|
||||
});
|
||||
return tangentPoint!;
|
||||
return GA.point(ret[0] - center[0], ret[1] - center[1]);
|
||||
};
|
||||
|
||||
export const bindingProperties: Set<BindableProp | BindingProp> = new Set([
|
||||
"boundElements",
|
||||
"frameId",
|
||||
|
|
|
@ -46,8 +46,11 @@ export function pointFromPair<Point extends GenericPoint>(
|
|||
* @param v The vector to convert
|
||||
* @returns The point the vector points at with origin 0,0
|
||||
*/
|
||||
export function pointFromVector<P extends GenericPoint>(v: Vector): P {
|
||||
return v as unknown as P;
|
||||
export function pointFromVector<P extends GenericPoint>(
|
||||
v: Vector,
|
||||
offset: P = point(0, 0),
|
||||
): P {
|
||||
return point<P>(offset[0] + v[0], offset[1] + v[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,9 +99,12 @@ export function pointRotateRads<Point extends GenericPoint>(
|
|||
[cx, cy]: Point,
|
||||
angle: Radians,
|
||||
): Point {
|
||||
const cos = Math.cos(angle);
|
||||
const sin = Math.sin(angle);
|
||||
|
||||
return point(
|
||||
(x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
|
||||
(x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy,
|
||||
(x - cx) * cos - (y - cy) * sin + cx,
|
||||
(x - cx) * sin + (y - cy) * cos + cy,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { GenericPoint, Vector } from "./types";
|
||||
import type { GenericPoint, Radians, Vector } from "./types";
|
||||
|
||||
/**
|
||||
* Create a vector from the x and y coordiante elements.
|
||||
|
@ -139,3 +139,16 @@ export const vectorNormalize = (v: Vector): Vector => {
|
|||
|
||||
return vector(v[0] / m, v[1] / m);
|
||||
};
|
||||
|
||||
/**
|
||||
* Rotate a vector by the given radians
|
||||
* @param v Target vector
|
||||
* @param a Angle to rotate in radians
|
||||
* @returns The rotated vector
|
||||
*/
|
||||
export const vectorRotate = (v: Vector, a: Radians): Vector => {
|
||||
const cos = Math.cos(a);
|
||||
const sin = Math.sin(a);
|
||||
|
||||
return vector(v[0] * cos - v[1] * sin, v[0] * sin + v[1] * cos);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue