mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: Add zoom to fit for selected elements (#2522)
This commit is contained in:
parent
59cff0f219
commit
5abe9b93e8
6 changed files with 65 additions and 31 deletions
|
@ -4,12 +4,14 @@ import { getDefaultAppState } from "../appState";
|
|||
import { trash, zoomIn, zoomOut, resetZoom } from "../components/icons";
|
||||
import { ToolButton } from "../components/ToolButton";
|
||||
import { t } from "../i18n";
|
||||
import { getNormalizedZoom } from "../scene";
|
||||
import { getNormalizedZoom, getSelectedElements } from "../scene";
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import { CODES, KEYS } from "../keys";
|
||||
import { getShortcutKey } from "../utils";
|
||||
import useIsMobile from "../is-mobile";
|
||||
import { register } from "./register";
|
||||
import { newElementWith } from "../element/mutateElement";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState, NormalizedZoomValue } from "../types";
|
||||
import { getCommonBounds } from "../element";
|
||||
import { getNewZoom } from "../scene/zoom";
|
||||
|
@ -204,38 +206,60 @@ const zoomValueToFitBoundsOnViewport = (
|
|||
return clampedZoomValueToFitElements as NormalizedZoomValue;
|
||||
};
|
||||
|
||||
const zoomToFitElements = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: Readonly<AppState>,
|
||||
zoomToSelection: boolean,
|
||||
) => {
|
||||
const nonDeletedElements = getNonDeletedElements(elements);
|
||||
const selectedElements = getSelectedElements(nonDeletedElements, appState);
|
||||
|
||||
const commonBounds =
|
||||
zoomToSelection && selectedElements.length > 0
|
||||
? getCommonBounds(selectedElements)
|
||||
: getCommonBounds(nonDeletedElements);
|
||||
|
||||
const zoomValue = zoomValueToFitBoundsOnViewport(commonBounds, {
|
||||
width: appState.width,
|
||||
height: appState.height,
|
||||
});
|
||||
const newZoom = getNewZoom(zoomValue, appState.zoom);
|
||||
const action = zoomToSelection ? "selection" : "fit";
|
||||
|
||||
const [x1, y1, x2, y2] = commonBounds;
|
||||
const centerX = (x1 + x2) / 2;
|
||||
const centerY = (y1 + y2) / 2;
|
||||
trackEvent(EVENT_ACTION, "zoom", action, newZoom.value * 100);
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
...centerScrollOn({
|
||||
scenePoint: { x: centerX, y: centerY },
|
||||
viewportDimensions: {
|
||||
width: appState.width,
|
||||
height: appState.height,
|
||||
},
|
||||
zoom: newZoom,
|
||||
}),
|
||||
zoom: newZoom,
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
};
|
||||
|
||||
export const actionZoomToSelected = register({
|
||||
name: "zoomToSelection",
|
||||
perform: (elements, appState) => zoomToFitElements(elements, appState, true),
|
||||
keyTest: (event) =>
|
||||
event.code === CODES.TWO &&
|
||||
event.shiftKey &&
|
||||
!event.altKey &&
|
||||
!event[KEYS.CTRL_OR_CMD],
|
||||
});
|
||||
|
||||
export const actionZoomToFit = register({
|
||||
name: "zoomToFit",
|
||||
perform: (elements, appState) => {
|
||||
const nonDeletedElements = elements.filter((element) => !element.isDeleted);
|
||||
const commonBounds = getCommonBounds(nonDeletedElements);
|
||||
|
||||
const zoomValue = zoomValueToFitBoundsOnViewport(commonBounds, {
|
||||
width: appState.width,
|
||||
height: appState.height,
|
||||
});
|
||||
const newZoom = getNewZoom(zoomValue, appState.zoom);
|
||||
|
||||
const [x1, y1, x2, y2] = commonBounds;
|
||||
const centerX = (x1 + x2) / 2;
|
||||
const centerY = (y1 + y2) / 2;
|
||||
trackEvent(EVENT_ACTION, "zoom", "fit", newZoom.value * 100);
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
...centerScrollOn({
|
||||
scenePoint: { x: centerX, y: centerY },
|
||||
viewportDimensions: {
|
||||
width: appState.width,
|
||||
height: appState.height,
|
||||
},
|
||||
zoom: newZoom,
|
||||
}),
|
||||
zoom: newZoom,
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
},
|
||||
perform: (elements, appState) => zoomToFitElements(elements, appState, false),
|
||||
keyTest: (event) =>
|
||||
event.code === CODES.ONE &&
|
||||
event.shiftKey &&
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue