feat: use single function for animating canvas translation

This commit is contained in:
Arnošt Pleskot 2023-09-13 16:18:47 +02:00
parent edf54d1543
commit ddb08ce732
No known key found for this signature in database
2 changed files with 91 additions and 82 deletions

View file

@ -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;

View file

@ -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"];
};