mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Fix single element bounding box bug (#2008)
Co-authored-by: Michal Srb <xixixao@seznam.cz> Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
a96406f505
commit
296e3677cf
3 changed files with 189 additions and 15 deletions
|
@ -26,18 +26,15 @@ import { getShapeForElement } from "../renderer/renderElement";
|
|||
|
||||
const isElementDraggableFromInside = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
appState: AppState,
|
||||
): boolean => {
|
||||
if (element.type === "arrow") {
|
||||
return false;
|
||||
}
|
||||
const dragFromInside =
|
||||
element.backgroundColor !== "transparent" ||
|
||||
appState.selectedElementIds[element.id];
|
||||
const isDraggableFromInside = element.backgroundColor !== "transparent";
|
||||
if (element.type === "line" || element.type === "draw") {
|
||||
return dragFromInside && isPathALoop(element.points);
|
||||
return isDraggableFromInside && isPathALoop(element.points);
|
||||
}
|
||||
return dragFromInside;
|
||||
return isDraggableFromInside;
|
||||
};
|
||||
|
||||
export const hitTest = (
|
||||
|
@ -48,16 +45,51 @@ export const hitTest = (
|
|||
): boolean => {
|
||||
// How many pixels off the shape boundary we still consider a hit
|
||||
const threshold = 10 / appState.zoom;
|
||||
const point: Point = [x, y];
|
||||
|
||||
if (isElementSelected(appState, element)) {
|
||||
return doesPointHitElementBoundingBox(element, point, threshold);
|
||||
}
|
||||
|
||||
const check =
|
||||
element.type === "text"
|
||||
? isStrictlyInside
|
||||
: isElementDraggableFromInside(element, appState)
|
||||
: isElementDraggableFromInside(element)
|
||||
? isInsideCheck
|
||||
: isNearCheck;
|
||||
const point: Point = [x, y];
|
||||
return hitTestPointAgainstElement({ element, point, threshold, check });
|
||||
};
|
||||
|
||||
const isElementSelected = (
|
||||
appState: AppState,
|
||||
element: NonDeleted<ExcalidrawElement>,
|
||||
) => appState.selectedElementIds[element.id];
|
||||
|
||||
const doesPointHitElementBoundingBox = (
|
||||
element: NonDeleted<ExcalidrawElement>,
|
||||
[x, y]: Point,
|
||||
threshold: number,
|
||||
) => {
|
||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||
const elementCenterX = (x1 + x2) / 2;
|
||||
const elementCenterY = (y1 + y2) / 2;
|
||||
// reverse rotate to take element's angle into account.
|
||||
const [rotatedX, rotatedY] = rotate(
|
||||
x,
|
||||
y,
|
||||
elementCenterX,
|
||||
elementCenterY,
|
||||
-element.angle,
|
||||
);
|
||||
|
||||
return (
|
||||
rotatedX > x1 - threshold &&
|
||||
rotatedX < x2 + threshold &&
|
||||
rotatedY > y1 - threshold &&
|
||||
rotatedY < y2 + threshold
|
||||
);
|
||||
};
|
||||
|
||||
export const bindingBorderTest = (
|
||||
element: NonDeleted<ExcalidrawBindableElement>,
|
||||
{ x, y }: { x: number; y: number },
|
||||
|
@ -235,7 +267,7 @@ const hitTestLinear = (args: HitTestArgs): boolean => {
|
|||
|
||||
if (args.check === isInsideCheck) {
|
||||
const hit = shape.some((subshape) =>
|
||||
hitTestCurveInside(subshape, relX, relY, threshold),
|
||||
hitTestCurveInside(subshape, relX, relY),
|
||||
);
|
||||
if (hit) {
|
||||
return true;
|
||||
|
@ -656,12 +688,7 @@ const pointInBezierEquation = (
|
|||
return false;
|
||||
};
|
||||
|
||||
const hitTestCurveInside = (
|
||||
drawable: Drawable,
|
||||
x: number,
|
||||
y: number,
|
||||
lineThreshold: number,
|
||||
) => {
|
||||
const hitTestCurveInside = (drawable: Drawable, x: number, y: number) => {
|
||||
const ops = getCurvePathOps(drawable);
|
||||
const points: Point[] = [];
|
||||
for (const operation of ops) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue