feat: add zoom lock and viewportZoomFactor
This commit is contained in:
parent
e8e391e465
commit
9562e4309f
@ -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,
|
||||
|
@ -229,6 +229,10 @@ export type AppState = {
|
||||
width: number;
|
||||
height: number;
|
||||
isAnimating?: boolean;
|
||||
opts?: {
|
||||
viewportZoomFactor?: number;
|
||||
lockZoom?: boolean;
|
||||
};
|
||||
} | null;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user