fix jumping/flashing when zooming in or out too quickly

This commit is contained in:
Ryan Di 2025-05-09 13:00:56 +10:00
parent bc6cc83b1e
commit 84c396aec2
2 changed files with 42 additions and 19 deletions

View File

@ -531,6 +531,7 @@ import type { Action, ActionResult } from "../actions/types";
import {
constrainScrollState,
calculateConstrainedScrollCenter,
areCanvasViewsClose,
} from "../scene/scrollConstraints";
const AppContext = React.createContext<AppClassProperties>(null!);
@ -2975,9 +2976,6 @@ class App extends React.Component<AppProps, AppState> {
const newState = constrainScrollState(this.state, {
allowOverscroll: false,
});
scrollConstraintsAnimationTimeout = setTimeout(() => {
this.cancelInProgressAnimation?.();
const fromValues = {
scrollX: this.state.scrollX,
scrollY: this.state.scrollY,
@ -2989,6 +2987,16 @@ class App extends React.Component<AppProps, AppState> {
zoom: newState.zoom.value,
};
if (areCanvasViewsClose(fromValues, toValues)) {
return;
}
if (scrollConstraintsAnimationTimeout) {
clearTimeout(scrollConstraintsAnimationTimeout);
}
scrollConstraintsAnimationTimeout = setTimeout(() => {
this.cancelInProgressAnimation?.();
this.animateToConstrainedArea(fromValues, toValues);
}, 200);
}

View File

@ -1,5 +1,9 @@
import { isShallowEqual } from "@excalidraw/common";
import { AppState, ScrollConstraints } from "../types";
import {
AnimateTranslateCanvasValues,
AppState,
ScrollConstraints,
} from "../types";
import { getNormalizedZoom } from "./normalize";
/**
@ -18,14 +22,13 @@ import { getNormalizedZoom } from "./normalize";
*
* const { scrollX, scrollY, zoom } = this.calculateConstrainedScrollCenter(scrollConstraints, { scrollX, scrollY });
*/
type CanvasTranslate = Pick<AppState, "scrollX" | "scrollY" | "zoom">;
export const calculateConstrainedScrollCenter = (
state: AppState,
{ scrollX, scrollY }: Pick<AppState, "scrollX" | "scrollY">,
): {
scrollX: AppState["scrollX"];
scrollY: AppState["scrollY"];
zoom: AppState["zoom"];
} => {
): CanvasTranslate => {
const {
width,
height,
@ -352,7 +355,7 @@ const constrainScrollValues = ({
maxScrollY: number;
minScrollY: number;
constrainedZoom: AppState["zoom"];
}) => {
}): CanvasTranslate => {
const constrainedScrollX = Math.min(
maxScrollX,
Math.max(scrollX, minScrollX),
@ -389,7 +392,7 @@ const alignScrollConstraints = (
* Determines whether the current viewport is outside the constrained area defined in the AppState.
*
* @param state - The application state containing scroll, zoom, and constraint information.
* @returns True if the viewport is outside the constrained area; otherwise undefined.
* @returns True if the viewport is outside the constrained area, false otherwise.
*/
const isViewportOutsideOfConstrainedArea = (state: AppState) => {
if (!state.scrollConstraints) {
@ -521,3 +524,15 @@ export const constrainScrollState = (
...constrainedValues,
};
};
export const areCanvasViewsClose = (
from: AnimateTranslateCanvasValues,
to: AnimateTranslateCanvasValues,
): boolean => {
const threshold = 0.1; // Adjust based on your needs
return (
Math.abs(from.scrollX - to.scrollX) < threshold &&
Math.abs(from.scrollY - to.scrollY) < threshold &&
Math.abs(from.zoom - to.zoom) < threshold
);
};