mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: split gridSize
from enabled state & support custom gridStep
(#8364)
This commit is contained in:
parent
4320a3cf41
commit
3cfcc7b489
31 changed files with 737 additions and 278 deletions
|
@ -60,7 +60,6 @@ import {
|
|||
ENV,
|
||||
EVENT,
|
||||
FRAME_STYLE,
|
||||
GRID_SIZE,
|
||||
IMAGE_MIME_TYPES,
|
||||
IMAGE_RENDER_TIMEOUT,
|
||||
isBrave,
|
||||
|
@ -258,6 +257,7 @@ import type {
|
|||
UnsubscribeCallback,
|
||||
EmbedsValidationStatus,
|
||||
ElementsPendingErasure,
|
||||
NullableGridSize,
|
||||
} from "../types";
|
||||
import {
|
||||
debounce,
|
||||
|
@ -661,7 +661,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
objectsSnapModeEnabled,
|
||||
gridSize: gridModeEnabled ? GRID_SIZE : null,
|
||||
gridModeEnabled: gridModeEnabled ?? defaultAppState.gridModeEnabled,
|
||||
name,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
|
@ -812,6 +812,18 @@ class App extends React.Component<AppProps, AppState> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns gridSize taking into account `gridModeEnabled`.
|
||||
* If disabled, returns null.
|
||||
*/
|
||||
public getEffectiveGridSize = () => {
|
||||
return (
|
||||
this.props.gridModeEnabled ?? this.state.gridModeEnabled
|
||||
? this.state.gridSize
|
||||
: null
|
||||
) as NullableGridSize;
|
||||
};
|
||||
|
||||
private getHTMLIFrameElement(
|
||||
element: ExcalidrawIframeLikeElement,
|
||||
): HTMLIFrameElement | undefined {
|
||||
|
@ -1684,7 +1696,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||
renderConfig={{
|
||||
imageCache: this.imageCache,
|
||||
isExporting: false,
|
||||
renderGrid: true,
|
||||
renderGrid:
|
||||
this.props.gridModeEnabled ??
|
||||
this.state.gridModeEnabled,
|
||||
canvasBackgroundColor:
|
||||
this.state.viewBackgroundColor,
|
||||
embedsValidationStatus: this.embedsValidationStatus,
|
||||
|
@ -2171,7 +2185,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||
if (actionResult.appState || editingElement || this.state.contextMenu) {
|
||||
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
||||
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
||||
let gridSize = actionResult?.appState?.gridSize || null;
|
||||
const theme =
|
||||
actionResult?.appState?.theme || this.props.theme || THEME.LIGHT;
|
||||
const name = actionResult?.appState?.name ?? this.state.name;
|
||||
|
@ -2185,10 +2198,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||
zenModeEnabled = this.props.zenModeEnabled;
|
||||
}
|
||||
|
||||
if (typeof this.props.gridModeEnabled !== "undefined") {
|
||||
gridSize = this.props.gridModeEnabled ? GRID_SIZE : null;
|
||||
}
|
||||
|
||||
editingElement = actionResult.appState?.editingElement || null;
|
||||
|
||||
// make sure editingElement points to latest element reference
|
||||
|
@ -2220,7 +2229,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||
editingElement,
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridSize,
|
||||
theme,
|
||||
name,
|
||||
errorMessage,
|
||||
|
@ -2777,12 +2785,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.setState({ theme: this.props.theme });
|
||||
}
|
||||
|
||||
if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {
|
||||
this.setState({
|
||||
gridSize: this.props.gridModeEnabled ? GRID_SIZE : null,
|
||||
});
|
||||
}
|
||||
|
||||
this.excalidrawContainerRef.current?.classList.toggle(
|
||||
"theme--dark",
|
||||
this.state.theme === THEME.DARK,
|
||||
|
@ -3185,7 +3187,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const dx = x - elementsCenterX;
|
||||
const dy = y - elementsCenterY;
|
||||
|
||||
const [gridX, gridY] = getGridPoint(dx, dy, this.state.gridSize);
|
||||
const [gridX, gridY] = getGridPoint(dx, dy, this.getEffectiveGridSize());
|
||||
|
||||
const newElements = duplicateElements(
|
||||
elements.map((element) => {
|
||||
|
@ -3570,7 +3572,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
* Zooms on canvas viewport center
|
||||
*/
|
||||
zoomCanvas = (
|
||||
/** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */
|
||||
/**
|
||||
* Decimal fraction, auto-clamped between MIN_ZOOM and MAX_ZOOM.
|
||||
* 1 = 100% zoom, 2 = 200% zoom, 0.5 = 50% zoom
|
||||
*/
|
||||
value: number,
|
||||
) => {
|
||||
this.setState({
|
||||
|
@ -4148,10 +4153,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
? elbowArrow.startBinding || elbowArrow.endBinding
|
||||
? 0
|
||||
: ELEMENT_TRANSLATE_AMOUNT
|
||||
: (this.state.gridSize &&
|
||||
: (this.getEffectiveGridSize() &&
|
||||
(event.shiftKey
|
||||
? ELEMENT_TRANSLATE_AMOUNT
|
||||
: this.state.gridSize)) ||
|
||||
: this.getEffectiveGridSize())) ||
|
||||
(event.shiftKey
|
||||
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
||||
: ELEMENT_TRANSLATE_AMOUNT);
|
||||
|
@ -5496,7 +5501,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
event,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
this.state,
|
||||
this,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
|
||||
|
@ -5586,7 +5591,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
scenePointerY,
|
||||
event[KEYS.CTRL_OR_CMD] || isElbowArrow(multiElement)
|
||||
? null
|
||||
: this.state.gridSize,
|
||||
: this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const [lastCommittedX, lastCommittedY] =
|
||||
|
@ -6553,7 +6558,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
origin.y,
|
||||
event[KEYS.CTRL_OR_CMD] || isElbowArrowOnly
|
||||
? null
|
||||
: this.state.gridSize,
|
||||
: this.getEffectiveGridSize(),
|
||||
),
|
||||
),
|
||||
scrollbars: isOverScrollBars(
|
||||
|
@ -6730,7 +6735,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.state.editingLinearElement || this.state.selectedLinearElement;
|
||||
const ret = LinearElementEditor.handlePointerDown(
|
||||
event,
|
||||
this.state,
|
||||
this,
|
||||
this.store,
|
||||
pointerDownState.origin,
|
||||
linearElementEditor,
|
||||
|
@ -7093,7 +7098,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
sceneY,
|
||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||
? null
|
||||
: this.state.gridSize,
|
||||
: this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const element = newIframeElement({
|
||||
|
@ -7133,7 +7138,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
sceneY,
|
||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||
? null
|
||||
: this.state.gridSize,
|
||||
: this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const embedLink = getEmbedLink(link);
|
||||
|
@ -7186,7 +7191,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
sceneY,
|
||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||
? null
|
||||
: this.state.gridSize,
|
||||
: this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const topLayerFrame = addToFrameUnderCursor
|
||||
|
@ -7283,7 +7288,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const [gridX, gridY] = getGridPoint(
|
||||
pointerDownState.origin.x,
|
||||
pointerDownState.origin.y,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
||||
|
@ -7404,7 +7409,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
pointerDownState.origin.y,
|
||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||
? null
|
||||
: this.state.gridSize,
|
||||
: this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
||||
|
@ -7462,7 +7467,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
pointerDownState.origin.y,
|
||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||
? null
|
||||
: this.state.gridSize,
|
||||
: this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const constructorOpts = {
|
||||
|
@ -7598,7 +7603,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const [gridX, gridY] = getGridPoint(
|
||||
pointerCoords.x,
|
||||
pointerCoords.y,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
// for arrows/lines, don't start dragging until a given threshold
|
||||
|
@ -7645,7 +7650,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const ret = LinearElementEditor.addMidpoint(
|
||||
this.state.selectedLinearElement,
|
||||
pointerCoords,
|
||||
this.state,
|
||||
this,
|
||||
!event[KEYS.CTRL_OR_CMD],
|
||||
elementsMap,
|
||||
);
|
||||
|
@ -7688,7 +7693,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
|
||||
const didDrag = LinearElementEditor.handlePointDragging(
|
||||
event,
|
||||
this.state,
|
||||
this,
|
||||
pointerCoords.x,
|
||||
pointerCoords.y,
|
||||
(element, pointsSceneCoords) => {
|
||||
|
@ -7822,7 +7827,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
dragOffset,
|
||||
this.scene,
|
||||
snapOffset,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
this.setState({
|
||||
|
@ -9794,7 +9799,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
let [gridX, gridY] = getGridPoint(
|
||||
pointerCoords.x,
|
||||
pointerCoords.y,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const image =
|
||||
|
@ -9898,7 +9903,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
let [resizeX, resizeY] = getGridPoint(
|
||||
pointerCoords.x - pointerDownState.resize.offset.x,
|
||||
pointerCoords.y - pointerDownState.resize.offset.y,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const frameElementsOffsetsMap = new Map<
|
||||
|
@ -9929,7 +9934,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const [gridX, gridY] = getGridPoint(
|
||||
pointerCoords.x,
|
||||
pointerCoords.y,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||
);
|
||||
|
||||
const dragOffset = {
|
||||
|
|
|
@ -360,7 +360,7 @@ const LayerUI = ({
|
|||
)}
|
||||
{shouldShowStats && (
|
||||
<Stats
|
||||
scene={app.scene}
|
||||
app={app}
|
||||
onClose={() => {
|
||||
actionManager.executeAction(actionToggleStats);
|
||||
}}
|
||||
|
|
67
packages/excalidraw/components/Stats/CanvasGrid.tsx
Normal file
67
packages/excalidraw/components/Stats/CanvasGrid.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
import StatsDragInput from "./DragInput";
|
||||
import type Scene from "../../scene/Scene";
|
||||
import type { AppState } from "../../types";
|
||||
import { getStepSizedValue } from "./utils";
|
||||
import { getNormalizedGridStep } from "../../scene";
|
||||
|
||||
interface PositionProps {
|
||||
property: "gridStep";
|
||||
scene: Scene;
|
||||
appState: AppState;
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
}
|
||||
|
||||
const STEP_SIZE = 5;
|
||||
|
||||
const CanvasGrid = ({
|
||||
property,
|
||||
scene,
|
||||
appState,
|
||||
setAppState,
|
||||
}: PositionProps) => {
|
||||
return (
|
||||
<StatsDragInput
|
||||
label="Grid step"
|
||||
sensitivity={8}
|
||||
elements={[]}
|
||||
dragInputCallback={({
|
||||
nextValue,
|
||||
instantChange,
|
||||
shouldChangeByStepSize,
|
||||
setInputValue,
|
||||
}) => {
|
||||
setAppState((state) => {
|
||||
let nextGridStep;
|
||||
|
||||
if (nextValue) {
|
||||
nextGridStep = nextValue;
|
||||
} else if (instantChange) {
|
||||
nextGridStep = shouldChangeByStepSize
|
||||
? getStepSizedValue(
|
||||
state.gridStep + STEP_SIZE * Math.sign(instantChange),
|
||||
STEP_SIZE,
|
||||
)
|
||||
: state.gridStep + instantChange;
|
||||
}
|
||||
|
||||
if (!nextGridStep) {
|
||||
setInputValue(state.gridStep);
|
||||
return null;
|
||||
}
|
||||
|
||||
nextGridStep = getNormalizedGridStep(nextGridStep);
|
||||
setInputValue(nextGridStep);
|
||||
return {
|
||||
gridStep: nextGridStep,
|
||||
};
|
||||
});
|
||||
}}
|
||||
scene={scene}
|
||||
value={appState.gridStep}
|
||||
property={property}
|
||||
appState={appState}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CanvasGrid;
|
|
@ -18,7 +18,8 @@
|
|||
flex-shrink: 0;
|
||||
border: 1px solid var(--default-border-color);
|
||||
border-right: 0;
|
||||
width: 2rem;
|
||||
padding: 0 0.5rem 0 0.75rem;
|
||||
min-width: 1rem;
|
||||
height: 2rem;
|
||||
box-sizing: border-box;
|
||||
color: var(--popup-text-color);
|
||||
|
|
|
@ -29,6 +29,7 @@ export type DragInputCallbackType<
|
|||
nextValue?: number;
|
||||
property: P;
|
||||
originalAppState: AppState;
|
||||
setInputValue: (value: number) => void;
|
||||
}) => void;
|
||||
|
||||
interface StatsDragInputProps<
|
||||
|
@ -45,6 +46,8 @@ interface StatsDragInputProps<
|
|||
property: T;
|
||||
scene: Scene;
|
||||
appState: AppState;
|
||||
/** how many px you need to drag to get 1 unit change */
|
||||
sensitivity?: number;
|
||||
}
|
||||
|
||||
const StatsDragInput = <
|
||||
|
@ -61,6 +64,7 @@ const StatsDragInput = <
|
|||
property,
|
||||
scene,
|
||||
appState,
|
||||
sensitivity = 1,
|
||||
}: StatsDragInputProps<T, E>) => {
|
||||
const app = useApp();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
@ -126,6 +130,7 @@ const StatsDragInput = <
|
|||
nextValue: rounded,
|
||||
property,
|
||||
originalAppState: appState,
|
||||
setInputValue: (value) => setInputValue(String(value)),
|
||||
});
|
||||
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
|
||||
}
|
||||
|
@ -172,6 +177,8 @@ const StatsDragInput = <
|
|||
ref={labelRef}
|
||||
onPointerDown={(event) => {
|
||||
if (inputRef.current && editable) {
|
||||
document.body.classList.add("excalidraw-cursor-resize");
|
||||
|
||||
let startValue = Number(inputRef.current.value);
|
||||
if (isNaN(startValue)) {
|
||||
startValue = 0;
|
||||
|
@ -196,35 +203,43 @@ const StatsDragInput = <
|
|||
|
||||
const originalAppState: AppState = cloneJSON(appState);
|
||||
|
||||
let accumulatedChange: number | null = null;
|
||||
|
||||
document.body.classList.add("excalidraw-cursor-resize");
|
||||
let accumulatedChange = 0;
|
||||
let stepChange = 0;
|
||||
|
||||
const onPointerMove = (event: PointerEvent) => {
|
||||
if (!accumulatedChange) {
|
||||
accumulatedChange = 0;
|
||||
}
|
||||
|
||||
if (
|
||||
lastPointer &&
|
||||
originalElementsMap !== null &&
|
||||
originalElements !== null &&
|
||||
accumulatedChange !== null
|
||||
originalElements !== null
|
||||
) {
|
||||
const instantChange = event.clientX - lastPointer.x;
|
||||
accumulatedChange += instantChange;
|
||||
|
||||
dragInputCallback({
|
||||
accumulatedChange,
|
||||
instantChange,
|
||||
originalElements,
|
||||
originalElementsMap,
|
||||
shouldKeepAspectRatio: shouldKeepAspectRatio!!,
|
||||
shouldChangeByStepSize: event.shiftKey,
|
||||
property,
|
||||
scene,
|
||||
originalAppState,
|
||||
});
|
||||
if (instantChange !== 0) {
|
||||
stepChange += instantChange;
|
||||
|
||||
if (Math.abs(stepChange) >= sensitivity) {
|
||||
stepChange =
|
||||
Math.sign(stepChange) *
|
||||
Math.floor(Math.abs(stepChange) / sensitivity);
|
||||
|
||||
accumulatedChange += stepChange;
|
||||
|
||||
dragInputCallback({
|
||||
accumulatedChange,
|
||||
instantChange: stepChange,
|
||||
originalElements,
|
||||
originalElementsMap,
|
||||
shouldKeepAspectRatio: shouldKeepAspectRatio!!,
|
||||
shouldChangeByStepSize: event.shiftKey,
|
||||
property,
|
||||
scene,
|
||||
originalAppState,
|
||||
setInputValue: (value) => setInputValue(String(value)),
|
||||
});
|
||||
|
||||
stepChange = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastPointer = {
|
||||
|
@ -246,7 +261,8 @@ const StatsDragInput = <
|
|||
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
|
||||
|
||||
lastPointer = null;
|
||||
accumulatedChange = null;
|
||||
accumulatedChange = 0;
|
||||
stepChange = 0;
|
||||
originalElements = null;
|
||||
originalElementsMap = null;
|
||||
|
||||
|
|
|
@ -2,7 +2,11 @@ import { useEffect, useMemo, useState, memo } from "react";
|
|||
import { getCommonBounds } from "../../element/bounds";
|
||||
import type { NonDeletedExcalidrawElement } from "../../element/types";
|
||||
import { t } from "../../i18n";
|
||||
import type { AppState, ExcalidrawProps } from "../../types";
|
||||
import type {
|
||||
AppClassProperties,
|
||||
AppState,
|
||||
ExcalidrawProps,
|
||||
} from "../../types";
|
||||
import { CloseIcon } from "../icons";
|
||||
import { Island } from "../Island";
|
||||
import { throttle } from "lodash";
|
||||
|
@ -16,17 +20,17 @@ import MultiFontSize from "./MultiFontSize";
|
|||
import Position from "./Position";
|
||||
import MultiPosition from "./MultiPosition";
|
||||
import Collapsible from "./Collapsible";
|
||||
import type Scene from "../../scene/Scene";
|
||||
import { useExcalidrawAppState, useExcalidrawSetAppState } from "../App";
|
||||
import { getAtomicUnits } from "./utils";
|
||||
import { STATS_PANELS } from "../../constants";
|
||||
import { isElbowArrow } from "../../element/typeChecks";
|
||||
import CanvasGrid from "./CanvasGrid";
|
||||
import clsx from "clsx";
|
||||
|
||||
import "./Stats.scss";
|
||||
|
||||
interface StatsProps {
|
||||
scene: Scene;
|
||||
app: AppClassProperties;
|
||||
onClose: () => void;
|
||||
renderCustomStats: ExcalidrawProps["renderCustomStats"];
|
||||
}
|
||||
|
@ -35,11 +39,13 @@ const STATS_TIMEOUT = 50;
|
|||
|
||||
export const Stats = (props: StatsProps) => {
|
||||
const appState = useExcalidrawAppState();
|
||||
const sceneNonce = props.scene.getSceneNonce() || 1;
|
||||
const selectedElements = props.scene.getSelectedElements({
|
||||
const sceneNonce = props.app.scene.getSceneNonce() || 1;
|
||||
const selectedElements = props.app.scene.getSelectedElements({
|
||||
selectedElementIds: appState.selectedElementIds,
|
||||
includeBoundTextElement: false,
|
||||
});
|
||||
const gridModeEnabled =
|
||||
props.app.props.gridModeEnabled ?? appState.gridModeEnabled;
|
||||
|
||||
return (
|
||||
<StatsInner
|
||||
|
@ -47,6 +53,7 @@ export const Stats = (props: StatsProps) => {
|
|||
appState={appState}
|
||||
sceneNonce={sceneNonce}
|
||||
selectedElements={selectedElements}
|
||||
gridModeEnabled={gridModeEnabled}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -97,17 +104,20 @@ Stats.StatsRows = StatsRows;
|
|||
|
||||
export const StatsInner = memo(
|
||||
({
|
||||
scene,
|
||||
app,
|
||||
onClose,
|
||||
renderCustomStats,
|
||||
selectedElements,
|
||||
appState,
|
||||
sceneNonce,
|
||||
gridModeEnabled,
|
||||
}: StatsProps & {
|
||||
sceneNonce: number;
|
||||
selectedElements: readonly NonDeletedExcalidrawElement[];
|
||||
appState: AppState;
|
||||
gridModeEnabled: boolean;
|
||||
}) => {
|
||||
const scene = app.scene;
|
||||
const elements = scene.getNonDeletedElements();
|
||||
const elementsMap = scene.getNonDeletedElementsMap();
|
||||
const setAppState = useExcalidrawSetAppState();
|
||||
|
@ -189,6 +199,19 @@ export const StatsInner = memo(
|
|||
<div>{t("stats.height")}</div>
|
||||
<div>{sceneDimension.height}</div>
|
||||
</StatsRow>
|
||||
{gridModeEnabled && (
|
||||
<>
|
||||
<StatsRow heading>Canvas</StatsRow>
|
||||
<StatsRow>
|
||||
<CanvasGrid
|
||||
property="gridStep"
|
||||
scene={scene}
|
||||
appState={appState}
|
||||
setAppState={setAppState}
|
||||
/>
|
||||
</StatsRow>
|
||||
</>
|
||||
)}
|
||||
</StatsRows>
|
||||
|
||||
{renderCustomStats?.(elements, appState)}
|
||||
|
@ -362,7 +385,9 @@ export const StatsInner = memo(
|
|||
return (
|
||||
prev.sceneNonce === next.sceneNonce &&
|
||||
prev.selectedElements === next.selectedElements &&
|
||||
prev.appState.stats.panels === next.appState.stats.panels
|
||||
prev.appState.stats.panels === next.appState.stats.panels &&
|
||||
prev.gridModeEnabled === next.gridModeEnabled &&
|
||||
prev.appState.gridStep === next.appState.gridStep
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -41,7 +41,8 @@ export type StatsInputProperty =
|
|||
| "width"
|
||||
| "height"
|
||||
| "angle"
|
||||
| "fontSize";
|
||||
| "fontSize"
|
||||
| "gridStep";
|
||||
|
||||
export const SMALLEST_DELTA = 0.01;
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ const getRelevantAppStateProps = (
|
|||
exportScale: appState.exportScale,
|
||||
selectedElementsAreBeingDragged: appState.selectedElementsAreBeingDragged,
|
||||
gridSize: appState.gridSize,
|
||||
gridStep: appState.gridStep,
|
||||
frameRendering: appState.frameRendering,
|
||||
selectedElementIds: appState.selectedElementIds,
|
||||
frameToHighlight: appState.frameToHighlight,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue