diff --git a/src/core/bounds/bounds.utils.ts b/src/core/bounds/bounds.utils.ts index aa4e2b9a..d9c71aa5 100644 --- a/src/core/bounds/bounds.utils.ts +++ b/src/core/bounds/bounds.utils.ts @@ -159,6 +159,7 @@ export function getMouseBoundedPosition( paddingValueX: number, paddingValueY: number, wrapperComponent: HTMLDivElement | null, + maxBounds: BoundsType | null ): PositionType { const { minPositionX, minPositionY, maxPositionX, maxPositionY } = bounds; @@ -170,17 +171,22 @@ export function getMouseBoundedPosition( paddingY = paddingValueY; } + const minPositionXBound = limitToBounds && maxBounds?.minPositionX ? Math.max(minPositionX - paddingX, maxBounds?.minPositionX) : minPositionX - paddingX; + const maxPositionXBound = limitToBounds && maxBounds?.maxPositionX ? Math.max(maxPositionX + paddingX, maxBounds?.maxPositionX) : maxPositionX + paddingX; + const minPositionYBound = limitToBounds && maxBounds?.minPositionY ? Math.max(minPositionY - paddingY, maxBounds?.minPositionY) : minPositionY - paddingY; + const maxPositionYBound = limitToBounds && maxBounds?.maxPositionY ? Math.max(maxPositionY + paddingY, maxBounds?.maxPositionY) : maxPositionY + paddingY; + const x = boundLimiter( positionX, - minPositionX - paddingX, - maxPositionX + paddingX, + minPositionXBound, + maxPositionXBound, limitToBounds, ); const y = boundLimiter( positionY, - minPositionY - paddingY, - maxPositionY + paddingY, + minPositionYBound, + maxPositionYBound, limitToBounds, ); return { x, y }; diff --git a/src/core/handlers/handlers.utils.ts b/src/core/handlers/handlers.utils.ts index 0b9ec797..0ecc43e3 100644 --- a/src/core/handlers/handlers.utils.ts +++ b/src/core/handlers/handlers.utils.ts @@ -79,7 +79,7 @@ export function resetTransformations( animationType: keyof typeof animations, onResetTransformation?: () => void, ): void { - const { setup, wrapperComponent } = contextInstance; + const { setup, wrapperComponent, maxBounds } = contextInstance; const { limitToBounds } = setup; const initialTransformation = createState(contextInstance.props); const { scale, positionX, positionY } = contextInstance.transformState; @@ -99,6 +99,7 @@ export function resetTransformations( 0, 0, wrapperComponent, + maxBounds ); const newState = { @@ -145,7 +146,7 @@ export function calculateZoomToNode( customOffsetX = 0, customOffsetY = 0, ): { positionX: number; positionY: number; scale: number } { - const { wrapperComponent, contentComponent, transformState } = + const { wrapperComponent, contentComponent, transformState, maxBounds } = contextInstance; const { limitToBounds, minScale, maxScale } = contextInstance.setup; if (!wrapperComponent || !contentComponent) return transformState; @@ -193,6 +194,7 @@ export function calculateZoomToNode( 0, 0, wrapperComponent, + maxBounds ); return { positionX: x, positionY: y, scale: newScale }; diff --git a/src/core/instance.core.ts b/src/core/instance.core.ts index c7139651..c5dd5996 100644 --- a/src/core/instance.core.ts +++ b/src/core/instance.core.ts @@ -105,6 +105,14 @@ export class ZoomPanPinch { this.props = props; this.setup = createSetup(this.props); this.transformState = createState(this.props); + if (this.props.minPositionX || this.props.minPositionY || this.props.maxPositionX || this.props.maxPositionY) { + this.maxBounds = { + minPositionX: this.props.minPositionX ?? -Infinity, + minPositionY: this.props.minPositionY ?? -Infinity, + maxPositionX: this.props.maxPositionX ?? Infinity, + maxPositionY: this.props.maxPositionY ?? Infinity, + }; + } } mount = () => { @@ -119,6 +127,14 @@ export class ZoomPanPinch { this.props = newProps; handleCalculateBounds(this, this.transformState.scale); this.setup = createSetup(newProps); + if (newProps.minPositionX || newProps.minPositionY || newProps.maxPositionX || newProps.maxPositionY) { + this.maxBounds = { + minPositionX: newProps.minPositionX ?? -Infinity, + minPositionY: newProps.minPositionY ?? -Infinity, + maxPositionX: newProps.maxPositionX ?? Infinity, + maxPositionY: newProps.maxPositionY ?? Infinity, + }; + } }; initializeWindowEvents = (): void => { diff --git a/src/core/pan/panning.utils.ts b/src/core/pan/panning.utils.ts index d4871369..cceba9e2 100644 --- a/src/core/pan/panning.utils.ts +++ b/src/core/pan/panning.utils.ts @@ -145,6 +145,7 @@ export function handleNewPosition( paddingValueX: number, paddingValueY: number, ): void { + const { maxBounds } = contextInstance; const { limitToBounds } = contextInstance.setup; const { wrapperComponent, bounds } = contextInstance; const { scale, positionX, positionY } = contextInstance.transformState; @@ -165,6 +166,7 @@ export function handleNewPosition( paddingValueX, paddingValueY, wrapperComponent, + maxBounds ); contextInstance.setTransformState(scale, x, y); diff --git a/src/core/pinch/pinch.logic.ts b/src/core/pinch/pinch.logic.ts index 4b48c7b6..ef5cbcec 100644 --- a/src/core/pinch/pinch.logic.ts +++ b/src/core/pinch/pinch.logic.ts @@ -52,7 +52,7 @@ export const handlePinchZoom = ( contextInstance: ReactZoomPanPinchContext, event: TouchEvent, ): void => { - const { contentComponent, pinchStartDistance, wrapperComponent } = + const { contentComponent, pinchStartDistance, wrapperComponent, maxBounds } = contextInstance; const { scale } = contextInstance.transformState; const { limitToBounds, centerZoomedOut, zoomAnimation, alignmentAnimation } = @@ -111,6 +111,7 @@ export const handlePinchZoom = ( paddingValueX, paddingValueY, wrapperComponent, + maxBounds ); contextInstance.setTransformState(newScale, finalX, finalY); diff --git a/src/core/zoom/zoom.utils.ts b/src/core/zoom/zoom.utils.ts index ce5d7679..51aa814d 100644 --- a/src/core/zoom/zoom.utils.ts +++ b/src/core/zoom/zoom.utils.ts @@ -14,6 +14,7 @@ export function handleCalculateZoomPositions( limitToBounds: boolean, ): PositionType { const { scale, positionX, positionY } = contextInstance.transformState; + const { maxBounds } = contextInstance; const scaleDifference = newScale - scale; @@ -36,6 +37,7 @@ export function handleCalculateZoomPositions( 0, 0, null, + maxBounds ); return newPositions;