From c0bd9027cbe43edf1aff09691f7a5758bd805ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arno=C5=A1t=20Pleskot?= Date: Sun, 9 Jul 2023 21:04:34 +0200 Subject: [PATCH] feat: animate the scroll to constrained area --- src/components/App.tsx | 54 ++++++++++++++++++++++++++++++++++++++---- src/types.ts | 1 + 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 9983a95911..aa9590fc8b 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -7657,6 +7657,10 @@ class App extends React.Component { // Set the overscroll allowance percentage const OVERSCROLL_ALLOWANCE_PERCENTAGE = 0.2; + if (!scrollConstraints || scrollConstraints.isAnimating) { + return null; + } + // Check if the state has changed since the last render const stateUnchanged = zoom.value === prevState.zoom.value && @@ -7671,11 +7675,11 @@ class App extends React.Component { return null; } - // Calculate the maximum possible zoom based on the viewport and scrollable area sizes + // Calculate the zoom level on which will constrained area fit the viewport for each axis const scrollableWidth = scrollConstraints.width; const scrollableHeight = scrollConstraints.height; - const maxZoomX = width / scrollableWidth; - const maxZoomY = height / scrollableHeight; + const zoomLevelX = width / scrollableWidth; + const zoomLevelY = height / scrollableHeight; // Default scroll and zoom values let constrainedScrollX = scrollX; @@ -7689,7 +7693,7 @@ class App extends React.Component { // When we are zoomed out enough to contain constrained area in the viewport we will center the view const shouldAdjustForCenteredView = - zoom.value <= maxZoomX || zoom.value <= maxZoomY; + zoom.value <= zoomLevelX || zoom.value <= zoomLevelY; // When viewport is smaller than the scrollable area, user can pan freely within the constrained area, // otherwilse the viewport is centered to the center of the scrollable area @@ -7767,6 +7771,48 @@ class App extends React.Component { constrainedScrollX !== scrollX || constrainedScrollY !== scrollY; if (isStateChanged) { + // Animate the scroll position when the cursor button is not down and scroll position is outside of the scroll constraints + if ( + (scrollX < scrollConstraints.x || + scrollX + width > scrollConstraints.x + scrollConstraints.width || + scrollY < scrollConstraints.y || + scrollY + height > scrollConstraints.y + scrollConstraints.height) && + cursorButton !== "down" && + !scrollConstraints.isAnimating + ) { + this.setState({ + scrollConstraints: { ...scrollConstraints, isAnimating: true }, + }); + + easeToValuesRAF({ + fromValues: { scrollX, scrollY }, + toValues: { + scrollX: constrainedScrollX, + scrollY: constrainedScrollY, + }, + onStep: ({ scrollX, scrollY }) => { + console.log("onStep"); + this.setState({ + scrollX, + scrollY, + }); + }, + onStart: () => { + this.setState({ + scrollConstraints: { ...scrollConstraints, isAnimating: true }, + }); + }, + onEnd: () => { + this.setState({ + scrollConstraints: { ...scrollConstraints, isAnimating: false }, + }); + }, + }); + + console.log("isAnimating"); + return null; + } + const constrainedState = { scrollX: constrainedScrollX, scrollY: constrainedScrollY, diff --git a/src/types.ts b/src/types.ts index 25f42872bc..f048db85b2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -228,6 +228,7 @@ export type AppState = { y: number; width: number; height: number; + isAnimating?: boolean; } | null; };