feat: allow scroll over constraints while mouse down
This commit is contained in:
parent
f7e8056abe
commit
35b43c14d8
@ -1495,6 +1495,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
|
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
|
||||||
|
console.log(this.state.cursorButton);
|
||||||
if (
|
if (
|
||||||
!this.state.showWelcomeScreen &&
|
!this.state.showWelcomeScreen &&
|
||||||
!this.scene.getElementsIncludingDeleted().length
|
!this.scene.getElementsIncludingDeleted().length
|
||||||
@ -7639,86 +7640,116 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
* @returns The modified next state with scrollX and scrollY constrained to the scroll constraints.
|
* @returns The modified next state with scrollX and scrollY constrained to the scroll constraints.
|
||||||
*/
|
*/
|
||||||
private constrainScroll = (prevState: AppState): ConstrainedScrollValues => {
|
private constrainScroll = (prevState: AppState): ConstrainedScrollValues => {
|
||||||
const { scrollX, scrollY, scrollConstraints, width, height, zoom } =
|
const {
|
||||||
this.state;
|
scrollX,
|
||||||
|
scrollY,
|
||||||
|
scrollConstraints,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
zoom,
|
||||||
|
cursorButton,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
// Skip if scroll constraints are not defined or if the zoom level or viewport dimensions have not changed.
|
// Set the overscroll allowance percentage
|
||||||
// Constrains and scene will update on change of viewport dimensions.
|
const OVERSCROLL_ALLOWANCE_PERCENTAGE = 0.1;
|
||||||
if (
|
|
||||||
!scrollConstraints ||
|
// Check if the state has changed since the last render
|
||||||
(this.state.zoom.value === prevState.zoom.value &&
|
const stateUnchanged =
|
||||||
this.state.scrollX === prevState.scrollX &&
|
zoom.value === prevState.zoom.value &&
|
||||||
this.state.scrollY === prevState.scrollY &&
|
scrollX === prevState.scrollX &&
|
||||||
this.state.width === prevState.width &&
|
scrollY === prevState.scrollY &&
|
||||||
this.state.height === prevState.height)
|
width === prevState.width &&
|
||||||
) {
|
height === prevState.height &&
|
||||||
|
cursorButton === prevState.cursorButton;
|
||||||
|
|
||||||
|
// If the state hasn't changed or the scroll constraints are not defined, return null
|
||||||
|
if (!scrollConstraints || stateUnchanged) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate maximum zoom for both X and Y axis based on width and height of viewport and scrollable area
|
// Calculate the maximum possible zoom based on the viewport and scrollable area sizes
|
||||||
const maxZoomX = width / scrollConstraints.width;
|
const scrollableWidth = scrollConstraints.width;
|
||||||
const maxZoomY = height / scrollConstraints.height;
|
const scrollableHeight = scrollConstraints.height;
|
||||||
|
const maxZoomX = width / scrollableWidth;
|
||||||
// The smallest zoom out of maxZoomX and maxZoomY is our zoom limit
|
const maxZoomY = height / scrollableHeight;
|
||||||
const zoomLimit = Math.min(maxZoomX, maxZoomY);
|
const zoomLimit = Math.min(maxZoomX, maxZoomY);
|
||||||
|
|
||||||
// Set default constrainedScrollX and constrainedScrollY values
|
// Default scroll and zoom values
|
||||||
let constrainedScrollX = scrollX;
|
let constrainedScrollX = scrollX;
|
||||||
let constrainedScrollY = scrollY;
|
let constrainedScrollY = scrollY;
|
||||||
let constrainedZoom = zoom;
|
const constrainedZoom = {
|
||||||
|
|
||||||
// Function to adjust scroll position for centered view depending on the zoom value
|
|
||||||
const adjustScrollForCenteredView = (zoomValue: number) => {
|
|
||||||
// If zoom value is less than or equal to maxZoomX, adjust scrollX to ensure the view is centered on the X axis
|
|
||||||
if (zoomValue <= maxZoomX) {
|
|
||||||
const centeredScrollX =
|
|
||||||
(scrollConstraints.width - width / zoomValue) / -2;
|
|
||||||
constrainedScrollX = scrollConstraints.x + centeredScrollX;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If zoom value is less than or equal to maxZoomY, adjust scrollY to ensure the view is centered on the Y axis
|
|
||||||
if (zoomValue <= maxZoomY) {
|
|
||||||
const centeredScrollY =
|
|
||||||
(scrollConstraints.height - height / zoomValue) / -2;
|
|
||||||
constrainedScrollY = scrollConstraints.y + centeredScrollY;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Constrain scrollX and scrollY within the scroll constraints
|
|
||||||
constrainedScrollX = Math.min(
|
|
||||||
scrollConstraints.x,
|
|
||||||
Math.max(
|
|
||||||
scrollX,
|
|
||||||
scrollConstraints.x - scrollConstraints.width + width / zoom.value,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
constrainedScrollY = Math.min(
|
|
||||||
scrollConstraints.y,
|
|
||||||
Math.max(
|
|
||||||
scrollY,
|
|
||||||
scrollConstraints.y - scrollConstraints.height + height / zoom.value,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Constrain zoom within the scroll constraints and adjust for centered view
|
|
||||||
constrainedZoom = {
|
|
||||||
value: getNormalizedZoom(Math.max(zoom.value, zoomLimit)),
|
value: getNormalizedZoom(Math.max(zoom.value, zoomLimit)),
|
||||||
};
|
};
|
||||||
|
|
||||||
adjustScrollForCenteredView(zoom.value);
|
// Calculate the overscroll allowance for each axis
|
||||||
|
const overscrollAllowanceX =
|
||||||
|
OVERSCROLL_ALLOWANCE_PERCENTAGE * scrollableWidth;
|
||||||
|
const overscrollAllowanceY =
|
||||||
|
OVERSCROLL_ALLOWANCE_PERCENTAGE * scrollableHeight;
|
||||||
|
|
||||||
// If any of the values have changed, set new state
|
// Define the maximum and minimum scroll for each axis based on the cursor button state
|
||||||
if (
|
const maxScrollX =
|
||||||
constrainedScrollX !== this.state.scrollX ||
|
cursorButton === "down"
|
||||||
constrainedScrollY !== this.state.scrollY ||
|
? scrollConstraints.x + overscrollAllowanceX
|
||||||
constrainedZoom.value !== this.state.zoom.value
|
: scrollConstraints.x;
|
||||||
) {
|
const minScrollX =
|
||||||
|
cursorButton === "down"
|
||||||
|
? scrollConstraints.x -
|
||||||
|
scrollableWidth +
|
||||||
|
width / zoom.value -
|
||||||
|
overscrollAllowanceX
|
||||||
|
: scrollConstraints.x - scrollableWidth + width / zoom.value;
|
||||||
|
|
||||||
|
const maxScrollY =
|
||||||
|
cursorButton === "down"
|
||||||
|
? scrollConstraints.y + overscrollAllowanceY
|
||||||
|
: scrollConstraints.y;
|
||||||
|
const minScrollY =
|
||||||
|
cursorButton === "down"
|
||||||
|
? scrollConstraints.y -
|
||||||
|
scrollableHeight +
|
||||||
|
height / zoom.value -
|
||||||
|
overscrollAllowanceY
|
||||||
|
: scrollConstraints.y - scrollableHeight + height / zoom.value;
|
||||||
|
|
||||||
|
// Constrain the scroll within the scroll constraints, with overscroll allowance if the cursor button is down
|
||||||
|
constrainedScrollX = Math.min(maxScrollX, Math.max(scrollX, minScrollX));
|
||||||
|
constrainedScrollY = Math.min(maxScrollY, Math.max(scrollY, minScrollY));
|
||||||
|
|
||||||
|
// Check if the zoom value requires adjustment for a centered view
|
||||||
|
const shouldAdjustForCenteredView =
|
||||||
|
zoom.value <= maxZoomX || zoom.value <= maxZoomY;
|
||||||
|
if (shouldAdjustForCenteredView) {
|
||||||
|
// Adjust the scroll position for a centered view based on the zoom value
|
||||||
|
const adjustScrollForCenteredView = (zoomValue: number) => {
|
||||||
|
if (zoomValue <= maxZoomX) {
|
||||||
|
const centeredScrollX = (scrollableWidth - width / zoomValue) / -2;
|
||||||
|
constrainedScrollX = scrollConstraints.x + centeredScrollX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zoomValue <= maxZoomY) {
|
||||||
|
const centeredScrollY = (scrollableHeight - height / zoomValue) / -2;
|
||||||
|
constrainedScrollY = scrollConstraints.y + centeredScrollY;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
adjustScrollForCenteredView(zoom.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the new state differs from the old state
|
||||||
|
const stateChanged =
|
||||||
|
constrainedScrollX !== scrollX ||
|
||||||
|
constrainedScrollY !== scrollY ||
|
||||||
|
constrainedZoom.value !== zoom.value;
|
||||||
|
|
||||||
|
// If the state has changed, update the state and return the new state
|
||||||
|
if (stateChanged) {
|
||||||
const constrainedState = {
|
const constrainedState = {
|
||||||
scrollX: constrainedScrollX,
|
scrollX: constrainedScrollX,
|
||||||
scrollY: constrainedScrollY,
|
scrollY: constrainedScrollY,
|
||||||
zoom: constrainedZoom,
|
zoom: constrainedZoom,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setState(constrainedState);
|
this.setState(constrainedState);
|
||||||
return constrainedState;
|
return constrainedState;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user