1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2024-11-02 03:25:53 +01:00

fix: object snapping not working (#8381)

This commit is contained in:
David Luzar 2024-08-15 18:48:25 +02:00 committed by GitHub
parent 3cfcc7b489
commit fb4bb29aa5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 46 deletions

@ -384,6 +384,7 @@ import {
getVisibleGaps, getVisibleGaps,
getReferenceSnapPoints, getReferenceSnapPoints,
SnapCache, SnapCache,
isGridModeEnabled,
} from "../snapping"; } from "../snapping";
import { actionWrapTextInContainer } from "../actions/actionBoundText"; import { actionWrapTextInContainer } from "../actions/actionBoundText";
import BraveMeasureTextError from "./BraveMeasureTextError"; import BraveMeasureTextError from "./BraveMeasureTextError";
@ -818,9 +819,7 @@ class App extends React.Component<AppProps, AppState> {
*/ */
public getEffectiveGridSize = () => { public getEffectiveGridSize = () => {
return ( return (
this.props.gridModeEnabled ?? this.state.gridModeEnabled isGridModeEnabled(this) ? this.state.gridSize : null
? this.state.gridSize
: null
) as NullableGridSize; ) as NullableGridSize;
}; };
@ -1696,9 +1695,7 @@ class App extends React.Component<AppProps, AppState> {
renderConfig={{ renderConfig={{
imageCache: this.imageCache, imageCache: this.imageCache,
isExporting: false, isExporting: false,
renderGrid: renderGrid: isGridModeEnabled(this),
this.props.gridModeEnabled ??
this.state.gridModeEnabled,
canvasBackgroundColor: canvasBackgroundColor:
this.state.viewBackgroundColor, this.state.viewBackgroundColor,
embedsValidationStatus: this.embedsValidationStatus, embedsValidationStatus: this.embedsValidationStatus,
@ -5452,7 +5449,7 @@ class App extends React.Component<AppProps, AppState> {
) { ) {
const { originOffset, snapLines } = getSnapLinesAtPointer( const { originOffset, snapLines } = getSnapLinesAtPointer(
this.scene.getNonDeletedElements(), this.scene.getNonDeletedElements(),
this.state, this,
{ {
x: scenePointerX, x: scenePointerX,
y: scenePointerY, y: scenePointerY,
@ -7499,7 +7496,7 @@ class App extends React.Component<AppProps, AppState> {
if ( if (
isSnappingEnabled({ isSnappingEnabled({
event, event,
appState: this.state, app: this,
selectedElements, selectedElements,
}) && }) &&
(recomputeAnyways || !SnapCache.getReferenceSnapPoints()) (recomputeAnyways || !SnapCache.getReferenceSnapPoints())
@ -7523,7 +7520,7 @@ class App extends React.Component<AppProps, AppState> {
if ( if (
isSnappingEnabled({ isSnappingEnabled({
event, event,
appState: this.state, app: this,
selectedElements, selectedElements,
}) && }) &&
(recomputeAnyways || !SnapCache.getVisibleGaps()) (recomputeAnyways || !SnapCache.getVisibleGaps())
@ -7811,7 +7808,7 @@ class App extends React.Component<AppProps, AppState> {
const { snapOffset, snapLines } = snapDraggedElements( const { snapOffset, snapLines } = snapDraggedElements(
originalElements, originalElements,
dragOffset, dragOffset,
this.state, this,
event, event,
this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElementsMap(),
); );
@ -9812,7 +9809,7 @@ class App extends React.Component<AppProps, AppState> {
const { snapOffset, snapLines } = snapNewElement( const { snapOffset, snapLines } = snapNewElement(
newElement, newElement,
this.state, this,
event, event,
{ {
x: x:
@ -9949,7 +9946,7 @@ class App extends React.Component<AppProps, AppState> {
const { snapOffset, snapLines } = snapResizingElements( const { snapOffset, snapLines } = snapResizingElements(
selectedElements, selectedElements,
getSelectedElements(originalElements, this.state), getSelectedElements(originalElements, this.state),
this.state, this,
event, event,
dragOffset, dragOffset,
transformHandleType, transformHandleType,

@ -12,6 +12,7 @@ import { isEraserActive } from "../appState";
import "./HintViewer.scss"; import "./HintViewer.scss";
import { isNodeInFlowchart } from "../element/flowchart"; import { isNodeInFlowchart } from "../element/flowchart";
import { isGridModeEnabled } from "../snapping";
interface HintViewerProps { interface HintViewerProps {
appState: UIAppState; appState: UIAppState;
@ -100,7 +101,7 @@ const getHints = ({
return t("hints.deepBoxSelect"); return t("hints.deepBoxSelect");
} }
if (appState.gridSize && appState.selectedElementsAreBeingDragged) { if (isGridModeEnabled(app) && appState.selectedElementsAreBeingDragged) {
return t("hints.disableSnapping"); return t("hints.disableSnapping");
} }

@ -28,6 +28,7 @@ import CanvasGrid from "./CanvasGrid";
import clsx from "clsx"; import clsx from "clsx";
import "./Stats.scss"; import "./Stats.scss";
import { isGridModeEnabled } from "../../snapping";
interface StatsProps { interface StatsProps {
app: AppClassProperties; app: AppClassProperties;
@ -44,8 +45,7 @@ export const Stats = (props: StatsProps) => {
selectedElementIds: appState.selectedElementIds, selectedElementIds: appState.selectedElementIds,
includeBoundTextElement: false, includeBoundTextElement: false,
}); });
const gridModeEnabled = const gridModeEnabled = isGridModeEnabled(props.app);
props.app.props.gridModeEnabled ?? appState.gridModeEnabled;
return ( return (
<StatsInner <StatsInner

@ -19,7 +19,12 @@ import {
getSelectedElements, getSelectedElements,
getVisibleAndNonSelectedElements, getVisibleAndNonSelectedElements,
} from "./scene/selection"; } from "./scene/selection";
import type { AppState, KeyboardModifiersObject, Point } from "./types"; import type {
AppClassProperties,
AppState,
KeyboardModifiersObject,
Point,
} from "./types";
const SNAP_DISTANCE = 8; const SNAP_DISTANCE = 8;
@ -139,21 +144,24 @@ export class SnapCache {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
export const isGridModeEnabled = (app: AppClassProperties): boolean =>
app.props.gridModeEnabled ?? app.state.gridModeEnabled;
export const isSnappingEnabled = ({ export const isSnappingEnabled = ({
event, event,
appState, app,
selectedElements, selectedElements,
}: { }: {
appState: AppState; app: AppClassProperties;
event: KeyboardModifiersObject; event: KeyboardModifiersObject;
selectedElements: NonDeletedExcalidrawElement[]; selectedElements: NonDeletedExcalidrawElement[];
}) => { }) => {
if (event) { if (event) {
return ( return (
(appState.objectsSnapModeEnabled && !event[KEYS.CTRL_OR_CMD]) || (app.state.objectsSnapModeEnabled && !event[KEYS.CTRL_OR_CMD]) ||
(!appState.objectsSnapModeEnabled && (!app.state.objectsSnapModeEnabled &&
event[KEYS.CTRL_OR_CMD] && event[KEYS.CTRL_OR_CMD] &&
appState.gridSize === null) !isGridModeEnabled(app))
); );
} }
@ -161,7 +169,7 @@ export const isSnappingEnabled = ({
if (selectedElements.length === 1 && selectedElements[0].type === "arrow") { if (selectedElements.length === 1 && selectedElements[0].type === "arrow") {
return false; return false;
} }
return appState.objectsSnapModeEnabled; return app.state.objectsSnapModeEnabled;
}; };
export const areRoughlyEqual = (a: number, b: number, precision = 0.01) => { export const areRoughlyEqual = (a: number, b: number, precision = 0.01) => {
@ -406,13 +414,13 @@ export const getVisibleGaps = (
const getGapSnaps = ( const getGapSnaps = (
selectedElements: ExcalidrawElement[], selectedElements: ExcalidrawElement[],
dragOffset: Vector2D, dragOffset: Vector2D,
appState: AppState, app: AppClassProperties,
event: KeyboardModifiersObject, event: KeyboardModifiersObject,
nearestSnapsX: Snaps, nearestSnapsX: Snaps,
nearestSnapsY: Snaps, nearestSnapsY: Snaps,
minOffset: Vector2D, minOffset: Vector2D,
) => { ) => {
if (!isSnappingEnabled({ appState, event, selectedElements })) { if (!isSnappingEnabled({ app, event, selectedElements })) {
return []; return [];
} }
@ -596,14 +604,14 @@ export const getReferenceSnapPoints = (
const getPointSnaps = ( const getPointSnaps = (
selectedElements: ExcalidrawElement[], selectedElements: ExcalidrawElement[],
selectionSnapPoints: Point[], selectionSnapPoints: Point[],
appState: AppState, app: AppClassProperties,
event: KeyboardModifiersObject, event: KeyboardModifiersObject,
nearestSnapsX: Snaps, nearestSnapsX: Snaps,
nearestSnapsY: Snaps, nearestSnapsY: Snaps,
minOffset: Vector2D, minOffset: Vector2D,
) => { ) => {
if ( if (
!isSnappingEnabled({ appState, event, selectedElements }) || !isSnappingEnabled({ app, event, selectedElements }) ||
(selectedElements.length === 0 && selectionSnapPoints.length === 0) (selectedElements.length === 0 && selectionSnapPoints.length === 0)
) { ) {
return []; return [];
@ -652,13 +660,14 @@ const getPointSnaps = (
export const snapDraggedElements = ( export const snapDraggedElements = (
elements: ExcalidrawElement[], elements: ExcalidrawElement[],
dragOffset: Vector2D, dragOffset: Vector2D,
appState: AppState, app: AppClassProperties,
event: KeyboardModifiersObject, event: KeyboardModifiersObject,
elementsMap: ElementsMap, elementsMap: ElementsMap,
) => { ) => {
const appState = app.state;
const selectedElements = getSelectedElements(elements, appState); const selectedElements = getSelectedElements(elements, appState);
if ( if (
!isSnappingEnabled({ appState, event, selectedElements }) || !isSnappingEnabled({ app, event, selectedElements }) ||
selectedElements.length === 0 selectedElements.length === 0
) { ) {
return { return {
@ -687,7 +696,7 @@ export const snapDraggedElements = (
getPointSnaps( getPointSnaps(
selectedElements, selectedElements,
selectionPoints, selectionPoints,
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -697,7 +706,7 @@ export const snapDraggedElements = (
getGapSnaps( getGapSnaps(
selectedElements, selectedElements,
dragOffset, dragOffset,
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -732,7 +741,7 @@ export const snapDraggedElements = (
getElementsCorners(selectedElements, elementsMap, { getElementsCorners(selectedElements, elementsMap, {
dragOffset: newDragOffset, dragOffset: newDragOffset,
}), }),
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -742,7 +751,7 @@ export const snapDraggedElements = (
getGapSnaps( getGapSnaps(
selectedElements, selectedElements,
newDragOffset, newDragOffset,
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -1075,13 +1084,13 @@ export const snapResizingElements = (
selectedElements: ExcalidrawElement[], selectedElements: ExcalidrawElement[],
// while using the original elements to appy dragOffset to calculate snaps // while using the original elements to appy dragOffset to calculate snaps
selectedOriginalElements: ExcalidrawElement[], selectedOriginalElements: ExcalidrawElement[],
appState: AppState, app: AppClassProperties,
event: KeyboardModifiersObject, event: KeyboardModifiersObject,
dragOffset: Vector2D, dragOffset: Vector2D,
transformHandle: MaybeTransformHandleType, transformHandle: MaybeTransformHandleType,
) => { ) => {
if ( if (
!isSnappingEnabled({ event, selectedElements, appState }) || !isSnappingEnabled({ event, selectedElements, app }) ||
selectedElements.length === 0 || selectedElements.length === 0 ||
(selectedElements.length === 1 && (selectedElements.length === 1 &&
!areRoughlyEqual(selectedElements[0].angle, 0)) !areRoughlyEqual(selectedElements[0].angle, 0))
@ -1147,7 +1156,7 @@ export const snapResizingElements = (
} }
} }
const snapDistance = getSnapDistance(appState.zoom.value); const snapDistance = getSnapDistance(app.state.zoom.value);
const minOffset = { const minOffset = {
x: snapDistance, x: snapDistance,
@ -1160,7 +1169,7 @@ export const snapResizingElements = (
getPointSnaps( getPointSnaps(
selectedOriginalElements, selectedOriginalElements,
selectionSnapPoints, selectionSnapPoints,
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -1193,7 +1202,7 @@ export const snapResizingElements = (
getPointSnaps( getPointSnaps(
selectedElements, selectedElements,
corners, corners,
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -1210,13 +1219,13 @@ export const snapResizingElements = (
export const snapNewElement = ( export const snapNewElement = (
newElement: ExcalidrawElement, newElement: ExcalidrawElement,
appState: AppState, app: AppClassProperties,
event: KeyboardModifiersObject, event: KeyboardModifiersObject,
origin: Vector2D, origin: Vector2D,
dragOffset: Vector2D, dragOffset: Vector2D,
elementsMap: ElementsMap, elementsMap: ElementsMap,
) => { ) => {
if (!isSnappingEnabled({ event, selectedElements: [newElement], appState })) { if (!isSnappingEnabled({ event, selectedElements: [newElement], app })) {
return { return {
snapOffset: { x: 0, y: 0 }, snapOffset: { x: 0, y: 0 },
snapLines: [], snapLines: [],
@ -1227,7 +1236,7 @@ export const snapNewElement = (
[origin.x + dragOffset.x, origin.y + dragOffset.y], [origin.x + dragOffset.x, origin.y + dragOffset.y],
]; ];
const snapDistance = getSnapDistance(appState.zoom.value); const snapDistance = getSnapDistance(app.state.zoom.value);
const minOffset = { const minOffset = {
x: snapDistance, x: snapDistance,
@ -1240,7 +1249,7 @@ export const snapNewElement = (
getPointSnaps( getPointSnaps(
[newElement], [newElement],
selectionSnapPoints, selectionSnapPoints,
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -1265,7 +1274,7 @@ export const snapNewElement = (
getPointSnaps( getPointSnaps(
[newElement], [newElement],
corners, corners,
appState, app,
event, event,
nearestSnapsX, nearestSnapsX,
nearestSnapsY, nearestSnapsY,
@ -1282,12 +1291,12 @@ export const snapNewElement = (
export const getSnapLinesAtPointer = ( export const getSnapLinesAtPointer = (
elements: readonly ExcalidrawElement[], elements: readonly ExcalidrawElement[],
appState: AppState, app: AppClassProperties,
pointer: Vector2D, pointer: Vector2D,
event: KeyboardModifiersObject, event: KeyboardModifiersObject,
elementsMap: ElementsMap, elementsMap: ElementsMap,
) => { ) => {
if (!isSnappingEnabled({ event, selectedElements: [], appState })) { if (!isSnappingEnabled({ event, selectedElements: [], app })) {
return { return {
originOffset: { x: 0, y: 0 }, originOffset: { x: 0, y: 0 },
snapLines: [], snapLines: [],
@ -1297,11 +1306,11 @@ export const getSnapLinesAtPointer = (
const referenceElements = getVisibleAndNonSelectedElements( const referenceElements = getVisibleAndNonSelectedElements(
elements, elements,
[], [],
appState, app.state,
elementsMap, elementsMap,
); );
const snapDistance = getSnapDistance(appState.zoom.value); const snapDistance = getSnapDistance(app.state.zoom.value);
const minOffset = { const minOffset = {
x: snapDistance, x: snapDistance,