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,
|
pointDistanceSq,
|
||||||
clamp,
|
clamp,
|
||||||
radians,
|
radians,
|
||||||
|
vectorScale,
|
||||||
|
pointFromVector,
|
||||||
|
vectorRotate,
|
||||||
|
vectorNormalize,
|
||||||
|
pointDistance,
|
||||||
} from "../../math";
|
} from "../../math";
|
||||||
import { segmentIntersectRectangleElement } from "../../utils/geometry/shape";
|
import { segmentIntersectRectangleElement } from "../../utils/geometry/shape";
|
||||||
import { distanceToBindableElement } from "./distance";
|
import { distanceToBindableElement } from "./distance";
|
||||||
|
@ -1425,7 +1430,7 @@ const determineFocusPoint = (
|
||||||
GAPoint.from(adjecentPoint),
|
GAPoint.from(adjecentPoint),
|
||||||
);
|
);
|
||||||
const reverseRelateToCenter = GA.reverse(relateToCenter);
|
const reverseRelateToCenter = GA.reverse(relateToCenter);
|
||||||
let point;
|
let p: GA.Point;
|
||||||
switch (element.type) {
|
switch (element.type) {
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
case "image":
|
case "image":
|
||||||
|
@ -1435,14 +1440,18 @@ const determineFocusPoint = (
|
||||||
case "embeddable":
|
case "embeddable":
|
||||||
case "frame":
|
case "frame":
|
||||||
case "magicframe":
|
case "magicframe":
|
||||||
point = findFocusPointForRectangulars(element, focus, adjecentPointRel);
|
p = findFocusPointForRectanguloidElement(
|
||||||
|
element,
|
||||||
|
focus,
|
||||||
|
adjecentPointRel,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case "ellipse":
|
case "ellipse":
|
||||||
point = findFocusPointForEllipse(element, focus, adjecentPointRel);
|
p = findFocusPointForEllipse(element, focus, adjecentPointRel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return pointFromPair(
|
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);
|
return GA.point(x, (-m * x - 1) / n);
|
||||||
};
|
};
|
||||||
|
|
||||||
const findFocusPointForRectangulars = (
|
const findFocusPointForRectanguloidElement = (
|
||||||
element:
|
element:
|
||||||
| ExcalidrawRectangleElement
|
| ExcalidrawRectangleElement
|
||||||
| ExcalidrawImageElement
|
| ExcalidrawImageElement
|
||||||
|
@ -1705,23 +1714,34 @@ const findFocusPointForRectangulars = (
|
||||||
relativeDistance: number,
|
relativeDistance: number,
|
||||||
// The point for which we're trying to find the focus point, relative
|
// The point for which we're trying to find the focus point, relative
|
||||||
// to the element center.
|
// to the element center.
|
||||||
point: GA.Point,
|
gaPoint: GA.Point,
|
||||||
): GA.Point => {
|
): GA.Point => {
|
||||||
const relativeDistanceAbs = Math.abs(relativeDistance);
|
const relP = pointFromPair<GlobalPoint>(GAPoint.toTuple(gaPoint));
|
||||||
const orientation = Math.sign(relativeDistance);
|
const center = point<GlobalPoint>(
|
||||||
const corners = getCorners(element, relativeDistanceAbs);
|
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;
|
return GA.point(ret[0] - center[0], ret[1] - center[1]);
|
||||||
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!;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bindingProperties: Set<BindableProp | BindingProp> = new Set([
|
export const bindingProperties: Set<BindableProp | BindingProp> = new Set([
|
||||||
"boundElements",
|
"boundElements",
|
||||||
"frameId",
|
"frameId",
|
||||||
|
|
|
@ -46,8 +46,11 @@ export function pointFromPair<Point extends GenericPoint>(
|
||||||
* @param v The vector to convert
|
* @param v The vector to convert
|
||||||
* @returns The point the vector points at with origin 0,0
|
* @returns The point the vector points at with origin 0,0
|
||||||
*/
|
*/
|
||||||
export function pointFromVector<P extends GenericPoint>(v: Vector): P {
|
export function pointFromVector<P extends GenericPoint>(
|
||||||
return v as unknown as P;
|
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,
|
[cx, cy]: Point,
|
||||||
angle: Radians,
|
angle: Radians,
|
||||||
): Point {
|
): Point {
|
||||||
|
const cos = Math.cos(angle);
|
||||||
|
const sin = Math.sin(angle);
|
||||||
|
|
||||||
return point(
|
return point(
|
||||||
(x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
|
(x - cx) * cos - (y - cy) * sin + cx,
|
||||||
(x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy,
|
(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.
|
* 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);
|
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