Skip to content

Commit

Permalink
Fix drag multiple elements bug (excalidraw#2023)
Browse files Browse the repository at this point in the history
Co-authored-by: dwelle <[email protected]>
  • Loading branch information
Jnforja and dwelle authored Aug 26, 2020
1 parent 4718c31 commit e7d186b
Show file tree
Hide file tree
Showing 9 changed files with 7,573 additions and 2,479 deletions.
285 changes: 225 additions & 60 deletions src/components/App.tsx

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const CURSOR_TYPE = {
CROSSHAIR: "crosshair",
GRABBING: "grabbing",
POINTER: "pointer",
MOVE: "move",
AUTO: "",
};
export const POINTER_BUTTON = {
MAIN: 0,
Expand Down
28 changes: 26 additions & 2 deletions src/element/collision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,33 @@ export const hitTest = (
const point: Point = [x, y];

if (isElementSelected(appState, element)) {
return doesPointHitElementBoundingBox(element, point, threshold);
return isPointHittingElementBoundingBox(element, point, threshold);
}

return isHittingElementNotConsideringBoundingBox(element, appState, point);
};

export const isHittingElementBoundingBoxWithoutHittingElement = (
element: NonDeletedExcalidrawElement,
appState: AppState,
x: number,
y: number,
): boolean => {
const threshold = 10 / appState.zoom;

return (
!isHittingElementNotConsideringBoundingBox(element, appState, [x, y]) &&
isPointHittingElementBoundingBox(element, [x, y], threshold)
);
};

const isHittingElementNotConsideringBoundingBox = (
element: NonDeletedExcalidrawElement,
appState: AppState,
point: Point,
): boolean => {
const threshold = 10 / appState.zoom;

const check =
element.type === "text"
? isStrictlyInside
Expand All @@ -65,7 +89,7 @@ const isElementSelected = (
element: NonDeleted<ExcalidrawElement>,
) => appState.selectedElementIds[element.id];

const doesPointHitElementBoundingBox = (
const isPointHittingElementBoundingBox = (
element: NonDeleted<ExcalidrawElement>,
[x, y]: Point,
threshold: number,
Expand Down
5 changes: 4 additions & 1 deletion src/element/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ export {
getTransformHandlesFromCoords,
getTransformHandles,
} from "./transformHandles";
export { hitTest } from "./collision";
export {
hitTest,
isHittingElementBoundingBoxWithoutHittingElement,
} from "./collision";
export {
resizeTest,
getCursorForResizingElement,
Expand Down
2 changes: 1 addition & 1 deletion src/element/linearElementEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export class LinearElementEditor {
scenePointer: { x: number; y: number },
): {
didAddPoint: boolean;
hitElement: ExcalidrawElement | null;
hitElement: NonDeleted<ExcalidrawElement> | null;
} {
const ret: ReturnType<typeof LinearElementEditor["handlePointerDown"]> = {
didAddPoint: false,
Expand Down
13 changes: 13 additions & 0 deletions src/scene/comparisons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export const getElementAtPosition = (
) => {
let hitElement = null;
// We need to to hit testing from front (end of the array) to back (beginning of the array)
// because array is ordered from lower z-index to highest and we want element z-index
// with higher z-index
for (let i = elements.length - 1; i >= 0; --i) {
const element = elements[i];
if (element.isDeleted) {
Expand All @@ -48,6 +50,17 @@ export const getElementAtPosition = (
return hitElement;
};

export const getElementsAtPosition = (
elements: readonly NonDeletedExcalidrawElement[],
isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean,
) => {
// The parameter elements comes ordered from lower z-index to higher.
// We want to preserve that order on the returned array.
return elements.filter(
(element) => !element.isDeleted && isAtPositionFn(element),
);
};

export const getElementContainingPosition = (
elements: readonly ExcalidrawElement[],
x: number,
Expand Down
1 change: 1 addition & 0 deletions src/scene/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export {
getElementAtPosition,
getElementContainingPosition,
hasText,
getElementsAtPosition,
} from "./comparisons";
export { getZoomOrigin, getNormalizedZoom } from "./zoom";
Loading

0 comments on commit e7d186b

Please sign in to comment.