feat: add zoom lock and viewportZoomFactor

This commit is contained in:
Arnošt Pleskot 2023-07-10 18:10:22 +02:00
parent e8e391e465
commit 9562e4309f
No known key found for this signature in database
2 changed files with 43 additions and 21 deletions

View File

@ -223,6 +223,7 @@ import {
FrameNameBoundsCache,
SidebarName,
SidebarTabName,
NormalizedZoomValue,
} from "../types";
import {
debounce,
@ -7650,20 +7651,17 @@ class App extends React.Component<AppProps, AppState> {
scrollConstraints,
width,
height,
zoom,
zoom: currentZoom,
cursorButton,
} = this.state;
// 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 &&
currentZoom.value === prevState.zoom.value &&
scrollX === prevState.scrollX &&
scrollY === prevState.scrollY &&
width === prevState.width &&
@ -7671,10 +7669,17 @@ class App extends React.Component<AppProps, AppState> {
cursorButton === prevState.cursorButton;
// If the state hasn't changed and scrollConstraints didn't just get defined, return null
if (!scrollConstraints || (stateUnchanged && prevState.scrollConstraints)) {
if (stateUnchanged && prevState.scrollConstraints) {
return null;
}
// Set the overscroll allowance percentage
const OVERSCROLL_ALLOWANCE_PERCENTAGE = 0.2;
const lockZoom = scrollConstraints.opts?.lockZoom ?? false;
const viewportZoomFactor = scrollConstraints.opts?.viewportZoomFactor
? Math.min(1, Math.max(scrollConstraints.opts.viewportZoomFactor, 0.1))
: 0.9;
/**
* Calculate the zoom levels on which will constrained area fits the viewport for each axis
* @returns The zoom levels for the X and Y axes.
@ -7684,20 +7689,21 @@ class App extends React.Component<AppProps, AppState> {
const scrollableHeight = scrollConstraints.height;
const zoomLevelX = width / scrollableWidth;
const zoomLevelY = height / scrollableHeight;
return { zoomLevelX, zoomLevelY };
const maxZoomLevel = lockZoom
? Math.min(zoomLevelX, zoomLevelY) * viewportZoomFactor
: null;
return { zoomLevelX, zoomLevelY, maxZoomLevel };
};
/**
* Calculates the center position of the constrained scroll area.
* @returns The X and Y coordinates of the center position.
*/
const calculateConstrainedScrollCenter = () => {
const calculateConstrainedScrollCenter = (zoom: number) => {
const constrainedScrollCenterX =
scrollConstraints.x +
(scrollConstraints.width - width / zoom.value) / -2;
scrollConstraints.x + (scrollConstraints.width - width / zoom) / -2;
const constrainedScrollCenterY =
scrollConstraints.y +
(scrollConstraints.height - height / zoom.value) / -2;
scrollConstraints.y + (scrollConstraints.height - height / zoom) / -2;
return { constrainedScrollCenterX, constrainedScrollCenterY };
};
@ -7728,6 +7734,7 @@ class App extends React.Component<AppProps, AppState> {
overscrollAllowanceY: number,
constrainedScrollCenterX: number,
constrainedScrollCenterY: number,
zoom: number,
) => {
let maxScrollX;
let minScrollX;
@ -7744,13 +7751,13 @@ class App extends React.Component<AppProps, AppState> {
minScrollX =
scrollConstraints.x -
scrollConstraints.width +
width / zoom.value -
width / zoom -
overscrollAllowanceX;
maxScrollY = scrollConstraints.y + overscrollAllowanceY;
minScrollY =
scrollConstraints.y -
scrollConstraints.height +
height / zoom.value -
height / zoom -
overscrollAllowanceY;
} else if (cursorButton !== "down" && shouldAdjustForCenteredView) {
maxScrollX = constrainedScrollCenterX;
@ -7760,10 +7767,10 @@ class App extends React.Component<AppProps, AppState> {
} else {
maxScrollX = scrollConstraints.x;
minScrollX =
scrollConstraints.x - scrollConstraints.width + width / zoom.value;
scrollConstraints.x - scrollConstraints.width + width / zoom;
maxScrollY = scrollConstraints.y;
minScrollY =
scrollConstraints.y - scrollConstraints.height + height / zoom.value;
scrollConstraints.y - scrollConstraints.height + height / zoom;
}
return { maxScrollX, minScrollX, maxScrollY, minScrollY };
@ -7816,7 +7823,7 @@ class App extends React.Component<AppProps, AppState> {
scrollY + height >
scrollConstraints.y + scrollConstraints.height) &&
cursorButton !== "down" &&
zoom.value === prevState.zoom.value
currentZoom.value === prevState.zoom.value
) {
this.setState({
scrollConstraints: { ...scrollConstraints, isAnimating: true },
@ -7849,7 +7856,14 @@ class App extends React.Component<AppProps, AppState> {
const constrainedState = {
scrollX: constrainedScrollX,
scrollY: constrainedScrollY,
zoom,
zoom: {
value: maxZoomLevel
? (Math.max(
currentZoom.value,
maxZoomLevel,
) as NormalizedZoomValue)
: currentZoom.value,
},
};
this.setState(constrainedState);
@ -7860,13 +7874,16 @@ class App extends React.Component<AppProps, AppState> {
};
// Compute the constrained scroll values.
const { zoomLevelX, zoomLevelY } = calculateZoomLevel();
const { zoomLevelX, zoomLevelY, maxZoomLevel } = calculateZoomLevel();
const zoom = maxZoomLevel
? Math.max(maxZoomLevel, currentZoom.value)
: currentZoom.value;
const { constrainedScrollCenterX, constrainedScrollCenterY } =
calculateConstrainedScrollCenter();
calculateConstrainedScrollCenter(zoom);
const { overscrollAllowanceX, overscrollAllowanceY } =
calculateOverscrollAllowance();
const shouldAdjustForCenteredView =
zoom.value <= zoomLevelX || zoom.value <= zoomLevelY;
zoom <= zoomLevelX || zoom <= zoomLevelY;
const { maxScrollX, minScrollX, maxScrollY, minScrollY } =
calculateMinMaxScrollValues(
shouldAdjustForCenteredView,
@ -7874,6 +7891,7 @@ class App extends React.Component<AppProps, AppState> {
overscrollAllowanceY,
constrainedScrollCenterX,
constrainedScrollCenterY,
zoom,
);
const { constrainedScrollX, constrainedScrollY } = constrainScrollValues(
maxScrollX,

View File

@ -229,6 +229,10 @@ export type AppState = {
width: number;
height: number;
isAnimating?: boolean;
opts?: {
viewportZoomFactor?: number;
lockZoom?: boolean;
};
} | null;
};