mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: use single function for animating canvas translation
This commit is contained in:
parent
edf54d1543
commit
ddb08ce732
2 changed files with 91 additions and 82 deletions
|
@ -228,6 +228,7 @@ import {
|
||||||
SidebarName,
|
SidebarName,
|
||||||
SidebarTabName,
|
SidebarTabName,
|
||||||
ScrollConstraints,
|
ScrollConstraints,
|
||||||
|
AnimateTranslateCanvasValues,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import {
|
import {
|
||||||
debounce,
|
debounce,
|
||||||
|
@ -2627,28 +2628,18 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const origScrollY = this.state.scrollY;
|
const origScrollY = this.state.scrollY;
|
||||||
const origZoom = this.state.zoom.value;
|
const origZoom = this.state.zoom.value;
|
||||||
|
|
||||||
const cancel = easeToValuesRAF({
|
const fromValues = {
|
||||||
fromValues: {
|
scrollX: this.state.scrollX,
|
||||||
scrollX: origScrollX,
|
scrollY: this.state.scrollY,
|
||||||
scrollY: origScrollY,
|
zoom: this.state.zoom.value,
|
||||||
zoom: origZoom,
|
};
|
||||||
},
|
|
||||||
toValues: { scrollX, scrollY, zoom: zoom.value },
|
const toValues = { scrollX, scrollY, zoom: zoom.value };
|
||||||
interpolateValue: (from, to, progress, key) => {
|
|
||||||
// for zoom, use different easing
|
this.animateTranslateCanvas({
|
||||||
if (key === "zoom") {
|
fromValues,
|
||||||
return from * Math.pow(to / from, easeOut(progress));
|
toValues,
|
||||||
}
|
duration: opts?.duration ?? 500,
|
||||||
// handle using default
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
onStep: ({ scrollX, scrollY, zoom }) => {
|
|
||||||
this.setState({
|
|
||||||
scrollX,
|
|
||||||
scrollY,
|
|
||||||
zoom: { value: zoom },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onStart: () => {
|
onStart: () => {
|
||||||
this.setState({ shouldCacheIgnoreZoom: true });
|
this.setState({ shouldCacheIgnoreZoom: true });
|
||||||
},
|
},
|
||||||
|
@ -2658,13 +2649,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
onCancel: () => {
|
onCancel: () => {
|
||||||
this.setState({ shouldCacheIgnoreZoom: false });
|
this.setState({ shouldCacheIgnoreZoom: false });
|
||||||
},
|
},
|
||||||
duration: opts?.duration ?? 500,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.cancelInProgresAnimation = () => {
|
|
||||||
cancel();
|
|
||||||
this.cancelInProgresAnimation = null;
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
this.setState({ scrollX, scrollY, zoom });
|
this.setState({ scrollX, scrollY, zoom });
|
||||||
}
|
}
|
||||||
|
@ -2707,74 +2692,92 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
this.setState(state, () => {
|
this.setState(state, () => {
|
||||||
if (shouldAnimate && animateTo) {
|
if (shouldAnimate && animateTo) {
|
||||||
scrollConstraintsAnimationTimeout = setTimeout(() => {
|
scrollConstraintsAnimationTimeout = setTimeout(() => {
|
||||||
const cancel = easeToValuesRAF({
|
const fromValues = {
|
||||||
fromValues: {
|
scrollX: newState.scrollX,
|
||||||
scrollX: newState.scrollX,
|
scrollY: newState.scrollY,
|
||||||
scrollY: newState.scrollY,
|
zoom: newState.zoom.value,
|
||||||
zoom: newState.zoom.value,
|
};
|
||||||
},
|
const toValues = {
|
||||||
toValues: {
|
scrollX: animateTo.scrollX,
|
||||||
scrollX: animateTo.scrollX,
|
scrollY: animateTo.scrollY,
|
||||||
scrollY: animateTo.scrollY,
|
zoom: animateTo.zoom.value,
|
||||||
zoom: animateTo.zoom.value,
|
};
|
||||||
},
|
const cleanUp = () => {
|
||||||
interpolateValue: (from, to, progress, key) => {
|
this.setState((inAnimationState) => ({
|
||||||
// for zoom, use different easing
|
shouldCacheIgnoreZoom: false,
|
||||||
if (key === "zoom") {
|
scrollConstraints: {
|
||||||
return from * Math.pow(to / from, easeOut(progress));
|
...inAnimationState.scrollConstraints!,
|
||||||
}
|
isAnimating: false,
|
||||||
// handle using default
|
},
|
||||||
return undefined;
|
}));
|
||||||
},
|
};
|
||||||
onStep: ({ scrollX, scrollY, zoom }) => {
|
|
||||||
this.setState({
|
this.animateTranslateCanvas({
|
||||||
scrollX,
|
fromValues,
|
||||||
scrollY,
|
toValues,
|
||||||
zoom: { value: getNormalizedZoom(zoom) },
|
duration: 200,
|
||||||
});
|
|
||||||
},
|
|
||||||
onStart: () => {
|
onStart: () => {
|
||||||
this.setState((inAnimationState) => ({
|
this.setState((inAnimationState) => ({
|
||||||
shouldCacheIgnoreZoom: true,
|
shouldCacheIgnoreZoom: true,
|
||||||
scrollConstraints: {
|
scrollConstraints: {
|
||||||
...inAnimationState.scrollConstraints!, // existance scrollConstraints is checked in test for shouldAnimate
|
...inAnimationState.scrollConstraints!,
|
||||||
isAnimating: true,
|
isAnimating: true,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
cancelRender();
|
|
||||||
},
|
},
|
||||||
onEnd: () => {
|
onEnd: cleanUp,
|
||||||
this.setState((inAnimationState) => ({
|
onCancel: cleanUp,
|
||||||
shouldCacheIgnoreZoom: false,
|
|
||||||
scrollConstraints: {
|
|
||||||
...inAnimationState.scrollConstraints!,
|
|
||||||
isAnimating: false,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
onCancel: () => {
|
|
||||||
this.setState((inAnimationState) => {
|
|
||||||
return {
|
|
||||||
shouldCacheIgnoreZoom: false,
|
|
||||||
scrollConstraints: {
|
|
||||||
...inAnimationState.scrollConstraints!,
|
|
||||||
isAnimating: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
duration: 200,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.cancelInProgresAnimation = () => {
|
|
||||||
cancel();
|
|
||||||
this.cancelInProgresAnimation = null;
|
|
||||||
};
|
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
animateTranslateCanvas = ({
|
||||||
|
fromValues,
|
||||||
|
toValues,
|
||||||
|
duration,
|
||||||
|
onStart,
|
||||||
|
onEnd,
|
||||||
|
onCancel,
|
||||||
|
}: {
|
||||||
|
fromValues: AnimateTranslateCanvasValues;
|
||||||
|
toValues: AnimateTranslateCanvasValues;
|
||||||
|
duration: number;
|
||||||
|
onStart: () => void;
|
||||||
|
onEnd: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}) => {
|
||||||
|
const cancel = easeToValuesRAF({
|
||||||
|
fromValues,
|
||||||
|
toValues,
|
||||||
|
interpolateValue: (from, to, progress, key) => {
|
||||||
|
// for zoom, use different easing
|
||||||
|
if (key === "zoom") {
|
||||||
|
return from * Math.pow(to / from, easeOut(progress));
|
||||||
|
}
|
||||||
|
// handle using default
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
onStep: ({ scrollX, scrollY, zoom }) => {
|
||||||
|
this.setState({
|
||||||
|
scrollX,
|
||||||
|
scrollY,
|
||||||
|
zoom: { value: zoom },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onStart,
|
||||||
|
onEnd,
|
||||||
|
onCancel,
|
||||||
|
duration,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cancelInProgresAnimation = () => {
|
||||||
|
cancel();
|
||||||
|
this.cancelInProgresAnimation = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
setToast = (
|
setToast = (
|
||||||
toast: {
|
toast: {
|
||||||
message: string;
|
message: string;
|
||||||
|
|
|
@ -665,3 +665,9 @@ export type ScrollConstraints = {
|
||||||
viewportZoomFactor?: number;
|
viewportZoomFactor?: number;
|
||||||
lockZoom?: boolean;
|
lockZoom?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AnimateTranslateCanvasValues = {
|
||||||
|
scrollX: AppState["scrollX"];
|
||||||
|
scrollY: AppState["scrollY"];
|
||||||
|
zoom: AppState["zoom"]["value"];
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue