diff --git a/packages/excalidraw/components/Stats/Dimension.tsx b/packages/excalidraw/components/Stats/Dimension.tsx index a8868721b..66f39b20e 100644 --- a/packages/excalidraw/components/Stats/Dimension.tsx +++ b/packages/excalidraw/components/Stats/Dimension.tsx @@ -39,6 +39,7 @@ const handleDimensionChange: DragInputCallbackType< shouldKeepAspectRatio, shouldChangeByStepSize, nextValue, + ratio, property, originalAppState, instantChange, @@ -154,6 +155,12 @@ const handleDimensionChange: DragInputCallbackType< } if (nextValue !== undefined) { + if (ratio) { + ratio = property === "width" ? ratio : [ratio[1], ratio[0]]; + nextValue = (origElement[property] / ratio[0]) * ratio[1]; + property = property === "width" ? "height" : "width"; + } + const nextWidth = Math.max( property === "width" ? nextValue diff --git a/packages/excalidraw/components/Stats/DragInput.tsx b/packages/excalidraw/components/Stats/DragInput.tsx index 56138d810..8c4b55e23 100644 --- a/packages/excalidraw/components/Stats/DragInput.tsx +++ b/packages/excalidraw/components/Stats/DragInput.tsx @@ -33,6 +33,7 @@ export type DragInputCallbackType< shouldChangeByStepSize: boolean; scene: Scene; nextValue?: number; + ratio?: [number, number] | null; property: P; originalAppState: AppState; setInputValue: (value: number) => void; @@ -109,10 +110,21 @@ const StatsDragInput = < } stateRef.current.updatePending = false; + const ratioMatch = updatedValue + .trim() + .match(/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?)$/); + + let ratio: [number, number] | null = null; + if (ratioMatch) { + ratio = [Number(ratioMatch[1]), Number(ratioMatch[2])]; + } + const parsed = Number(updatedValue); if (isNaN(parsed)) { setInputValue(value.toString()); - return; + if (!ratio) { + return; + } } const rounded = Number(parsed.toFixed(2)); @@ -123,7 +135,11 @@ const StatsDragInput = < // 2. original was not "Mixed" and the difference between a new value and previous value is greater // than the smallest delta allowed, which is 0.01 // reason: idempotent to avoid unnecessary - if (isNaN(original) || Math.abs(rounded - original) >= SMALLEST_DELTA) { + if ( + isNaN(original) || + ratio || + Math.abs(rounded - original) >= SMALLEST_DELTA + ) { stateRef.current.lastUpdatedValue = updatedValue; dragInputCallback({ accumulatedChange: 0, @@ -134,6 +150,7 @@ const StatsDragInput = < shouldChangeByStepSize: false, scene, nextValue: rounded, + ratio, property, originalAppState: appState, setInputValue: (value) => setInputValue(String(value)), diff --git a/packages/excalidraw/components/Stats/MultiDimension.tsx b/packages/excalidraw/components/Stats/MultiDimension.tsx index 65f59ffe3..95570274e 100644 --- a/packages/excalidraw/components/Stats/MultiDimension.tsx +++ b/packages/excalidraw/components/Stats/MultiDimension.tsx @@ -151,6 +151,7 @@ const handleDimensionChange: DragInputCallbackType< originalAppState, shouldChangeByStepSize, nextValue, + ratio, scene, property, }) => { @@ -202,9 +203,22 @@ const handleDimensionChange: DragInputCallbackType< origElement && isPropertyEditable(latestElement, property) ) { + let _nextValue = nextValue; + let _property = property; + if (ratio) { + let _ratio = ratio; + if (ratio) { + _ratio = _property === "width" ? _ratio : [_ratio[1], _ratio[0]]; + _nextValue = (origElement[_property] / _ratio[0]) * _ratio[1]; + _property = _property === "width" ? "height" : "width"; + } + } + let nextWidth = - property === "width" ? Math.max(0, nextValue) : latestElement.width; - if (property === "width") { + _property === "width" + ? Math.max(0, _nextValue) + : latestElement.width; + if (_property === "width") { if (shouldChangeByStepSize) { nextWidth = getStepSizedValue(nextWidth, STEP_SIZE); } else { @@ -213,10 +227,10 @@ const handleDimensionChange: DragInputCallbackType< } let nextHeight = - property === "height" - ? Math.max(0, nextValue) + _property === "height" + ? Math.max(0, _nextValue) : latestElement.height; - if (property === "height") { + if (_property === "height") { if (shouldChangeByStepSize) { nextHeight = getStepSizedValue(nextHeight, STEP_SIZE); } else { @@ -234,7 +248,7 @@ const handleDimensionChange: DragInputCallbackType< origElement, originalElementsMap, scene, - property === "width" ? "e" : "s", + _property === "width" ? "e" : "s", { shouldInformMutation: false, },