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:
parent
3cfcc7b489
commit
fb4bb29aa5
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user