Add a button to show all content, if the zoom allows it. (#1406)

* add zoom center action button

* enhance zoom calculation and scroll to center

* add zoom out and center button

* filter deleted elements

* improve complexity

* add key shortcut

* calculate zoom value

* don't render zoomCenter action

* offset from top to account for shape menu

* change shortcut & add to shortcut dialog

* decrease offset

* revert offset

* change hotkey & description

* rename to zoomToFit

* change shortcut label & position

Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Steven Nguyen 2020-04-18 15:50:30 +02:00 committed by GitHub
parent ff0ecb5e33
commit 2bfb0c20c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 3 deletions

View File

@ -4,13 +4,14 @@ import { getDefaultAppState } from "../appState";
import { trash, zoomIn, zoomOut, resetZoom } from "../components/icons"; import { trash, zoomIn, zoomOut, resetZoom } from "../components/icons";
import { ToolButton } from "../components/ToolButton"; import { ToolButton } from "../components/ToolButton";
import { t } from "../i18n"; import { t } from "../i18n";
import { getNormalizedZoom } from "../scene"; import { getNormalizedZoom, calculateScrollCenter } from "../scene";
import { KEYS } from "../keys"; import { KEYS } from "../keys";
import { getShortcutKey } from "../utils"; import { getShortcutKey } from "../utils";
import useIsMobile from "../is-mobile"; import useIsMobile from "../is-mobile";
import { register } from "./register"; import { register } from "./register";
import { newElementWith } from "../element/mutateElement"; import { newElementWith } from "../element/mutateElement";
import { AppState } from "../types"; import { AppState, FlooredNumber } from "../types";
import { getCommonBounds } from "../element";
export const actionChangeViewBackgroundColor = register({ export const actionChangeViewBackgroundColor = register({
name: "changeViewBackgroundColor", name: "changeViewBackgroundColor",
@ -73,6 +74,7 @@ const ZOOM_STEP = 0.1;
const KEY_CODES = { const KEY_CODES = {
MINUS: "Minus", MINUS: "Minus",
EQUAL: "Equal", EQUAL: "Equal",
ONE: "Digit1",
ZERO: "Digit0", ZERO: "Digit0",
NUM_SUBTRACT: "NumpadSubtract", NUM_SUBTRACT: "NumpadSubtract",
NUM_ADD: "NumpadAdd", NUM_ADD: "NumpadAdd",
@ -159,3 +161,64 @@ export const actionResetZoom = register({
(event.code === KEY_CODES.ZERO || event.code === KEY_CODES.NUM_ZERO) && (event.code === KEY_CODES.ZERO || event.code === KEY_CODES.NUM_ZERO) &&
(event[KEYS.CTRL_OR_CMD] || event.shiftKey), (event[KEYS.CTRL_OR_CMD] || event.shiftKey),
}); });
const calculateZoom = (
commonBounds: number[],
currentZoom: number,
{
scrollX,
scrollY,
}: {
scrollX: FlooredNumber;
scrollY: FlooredNumber;
},
): number => {
const { innerWidth, innerHeight } = window;
const [x, y] = commonBounds;
const zoomX = -innerWidth / (2 * scrollX + 2 * x - innerWidth);
const zoomY = -innerHeight / (2 * scrollY + 2 * y - innerHeight);
const margin = 0.01;
let newZoom;
if (zoomX < zoomY) {
newZoom = zoomX - margin;
} else if (zoomY <= zoomX) {
newZoom = zoomY - margin;
} else {
newZoom = currentZoom;
}
if (newZoom <= 0.1) {
return 0.1;
}
if (newZoom >= 1) {
return 1;
}
return newZoom;
};
export const actionZoomToFit = register({
name: "zoomToFit",
perform: (elements, appState) => {
const nonDeletedElements = elements.filter((element) => !element.isDeleted);
const scrollCenter = calculateScrollCenter(nonDeletedElements);
const commonBounds = getCommonBounds(nonDeletedElements);
const zoom = calculateZoom(commonBounds, appState.zoom, scrollCenter);
return {
appState: {
...appState,
scrollX: scrollCenter.scrollX,
scrollY: scrollCenter.scrollY,
zoom,
},
commitToHistory: false,
};
},
keyTest: (event) =>
event.code === KEY_CODES.ONE &&
event.shiftKey &&
!event.altKey &&
!event[KEYS.CTRL_OR_CMD],
});

View File

@ -25,6 +25,7 @@ export {
actionZoomIn, actionZoomIn,
actionZoomOut, actionZoomOut,
actionResetZoom, actionResetZoom,
actionZoomToFit,
} from "./actionCanvas"; } from "./actionCanvas";
export { actionFinalize } from "./actionFinalize"; export { actionFinalize } from "./actionFinalize";

View File

@ -48,6 +48,7 @@ export type ActionName =
| "zoomIn" | "zoomIn"
| "zoomOut" | "zoomOut"
| "resetZoom" | "resetZoom"
| "zoomToFit"
| "changeFontFamily" | "changeFontFamily"
| "changeTextAlign" | "changeTextAlign"
| "toggleFullScreen" | "toggleFullScreen"

View File

@ -228,6 +228,10 @@ export const ShortcutsDialog = ({ onClose }: { onClose?: () => void }) => {
label={t("buttons.resetZoom")} label={t("buttons.resetZoom")}
shortcuts={[getShortcutKey("CtrlOrCmd+0")]} shortcuts={[getShortcutKey("CtrlOrCmd+0")]}
/> />
<Shortcut
label={t("shortcutsDialog.zoomToFit")}
shortcuts={["Shift+1"]}
/>
<Shortcut <Shortcut
label={t("buttons.toggleFullScreen")} label={t("buttons.toggleFullScreen")}
shortcuts={["F"]} shortcuts={["F"]}

View File

@ -150,7 +150,8 @@
"howto": "Follow our guides", "howto": "Follow our guides",
"github": "Found an issue? Submit", "github": "Found an issue? Submit",
"textNewLine": "Add new line (text)", "textNewLine": "Add new line (text)",
"textFinish": "Finish editing (text)" "textFinish": "Finish editing (text)",
"zoomToFit": "Zoom to fit all elements"
}, },
"encrypted": { "encrypted": {
"tooltip": "Your drawings are end-to-end encrypted so Excalidraw's servers will never see them.\nClick the icon to learn more..." "tooltip": "Your drawings are end-to-end encrypted so Excalidraw's servers will never see them.\nClick the icon to learn more..."