Skip to content

Commit 4b4efa1

Browse files
sheikhshaheerimranSheikh Shaheer
authored andcommitted
fix(bounds): support optional maxBounds for stricter position constraints
Allows users to define max bounds for pan/zoom behavior. This improves control over movement limits when the default limitToBounds is not sufficient. Previously, min and max positions for X and Y were not used to constrain the image bounds.
1 parent a0dac69 commit 4b4efa1

File tree

6 files changed

+36
-7
lines changed

6 files changed

+36
-7
lines changed

src/core/bounds/bounds.utils.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ export function getMouseBoundedPosition(
159159
paddingValueX: number,
160160
paddingValueY: number,
161161
wrapperComponent: HTMLDivElement | null,
162+
maxBounds: BoundsType | null
162163
): PositionType {
163164
const { minPositionX, minPositionY, maxPositionX, maxPositionY } = bounds;
164165

@@ -170,17 +171,22 @@ export function getMouseBoundedPosition(
170171
paddingY = paddingValueY;
171172
}
172173

174+
const minPositionXBound = limitToBounds && maxBounds?.minPositionX ? Math.max(minPositionX - paddingX, maxBounds?.minPositionX) : minPositionX - paddingX;
175+
const maxPositionXBound = limitToBounds && maxBounds?.maxPositionX ? Math.max(maxPositionX + paddingX, maxBounds?.maxPositionX) : maxPositionX + paddingX;
176+
const minPositionYBound = limitToBounds && maxBounds?.minPositionY ? Math.max(minPositionY - paddingY, maxBounds?.minPositionY) : minPositionY - paddingY;
177+
const maxPositionYBound = limitToBounds && maxBounds?.maxPositionY ? Math.max(maxPositionY + paddingY, maxBounds?.maxPositionY) : maxPositionY + paddingY;
178+
173179
const x = boundLimiter(
174180
positionX,
175-
minPositionX - paddingX,
176-
maxPositionX + paddingX,
181+
minPositionXBound,
182+
maxPositionXBound,
177183
limitToBounds,
178184
);
179185

180186
const y = boundLimiter(
181187
positionY,
182-
minPositionY - paddingY,
183-
maxPositionY + paddingY,
188+
minPositionYBound,
189+
maxPositionYBound,
184190
limitToBounds,
185191
);
186192
return { x, y };

src/core/handlers/handlers.utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export function resetTransformations(
7979
animationType: keyof typeof animations,
8080
onResetTransformation?: () => void,
8181
): void {
82-
const { setup, wrapperComponent } = contextInstance;
82+
const { setup, wrapperComponent, maxBounds } = contextInstance;
8383
const { limitToBounds } = setup;
8484
const initialTransformation = createState(contextInstance.props);
8585
const { scale, positionX, positionY } = contextInstance.transformState;
@@ -99,6 +99,7 @@ export function resetTransformations(
9999
0,
100100
0,
101101
wrapperComponent,
102+
maxBounds
102103
);
103104

104105
const newState = {
@@ -145,7 +146,7 @@ export function calculateZoomToNode(
145146
customOffsetX = 0,
146147
customOffsetY = 0,
147148
): { positionX: number; positionY: number; scale: number } {
148-
const { wrapperComponent, contentComponent, transformState } =
149+
const { wrapperComponent, contentComponent, transformState, maxBounds } =
149150
contextInstance;
150151
const { limitToBounds, minScale, maxScale } = contextInstance.setup;
151152
if (!wrapperComponent || !contentComponent) return transformState;
@@ -193,6 +194,7 @@ export function calculateZoomToNode(
193194
0,
194195
0,
195196
wrapperComponent,
197+
maxBounds
196198
);
197199

198200
return { positionX: x, positionY: y, scale: newScale };

src/core/instance.core.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ export class ZoomPanPinch {
105105
this.props = props;
106106
this.setup = createSetup(this.props);
107107
this.transformState = createState(this.props);
108+
if (this.props.minPositionX || this.props.minPositionY || this.props.maxPositionX || this.props.maxPositionY) {
109+
this.maxBounds = {
110+
minPositionX: this.props.minPositionX ?? -Infinity,
111+
minPositionY: this.props.minPositionY ?? -Infinity,
112+
maxPositionX: this.props.maxPositionX ?? Infinity,
113+
maxPositionY: this.props.maxPositionY ?? Infinity,
114+
};
115+
}
108116
}
109117

110118
mount = () => {
@@ -119,6 +127,14 @@ export class ZoomPanPinch {
119127
this.props = newProps;
120128
handleCalculateBounds(this, this.transformState.scale);
121129
this.setup = createSetup(newProps);
130+
if (newProps.minPositionX || newProps.minPositionY || newProps.maxPositionX || newProps.maxPositionY) {
131+
this.maxBounds = {
132+
minPositionX: newProps.minPositionX ?? -Infinity,
133+
minPositionY: newProps.minPositionY ?? -Infinity,
134+
maxPositionX: newProps.maxPositionX ?? Infinity,
135+
maxPositionY: newProps.maxPositionY ?? Infinity,
136+
};
137+
}
122138
};
123139

124140
initializeWindowEvents = (): void => {

src/core/pan/panning.utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ export function handleNewPosition(
145145
paddingValueX: number,
146146
paddingValueY: number,
147147
): void {
148+
const { maxBounds } = contextInstance;
148149
const { limitToBounds } = contextInstance.setup;
149150
const { wrapperComponent, bounds } = contextInstance;
150151
const { scale, positionX, positionY } = contextInstance.transformState;
@@ -165,6 +166,7 @@ export function handleNewPosition(
165166
paddingValueX,
166167
paddingValueY,
167168
wrapperComponent,
169+
maxBounds
168170
);
169171

170172
contextInstance.setTransformState(scale, x, y);

src/core/pinch/pinch.logic.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const handlePinchZoom = (
5252
contextInstance: ReactZoomPanPinchContext,
5353
event: TouchEvent,
5454
): void => {
55-
const { contentComponent, pinchStartDistance, wrapperComponent } =
55+
const { contentComponent, pinchStartDistance, wrapperComponent, maxBounds } =
5656
contextInstance;
5757
const { scale } = contextInstance.transformState;
5858
const { limitToBounds, centerZoomedOut, zoomAnimation, alignmentAnimation } =
@@ -111,6 +111,7 @@ export const handlePinchZoom = (
111111
paddingValueX,
112112
paddingValueY,
113113
wrapperComponent,
114+
maxBounds
114115
);
115116

116117
contextInstance.setTransformState(newScale, finalX, finalY);

src/core/zoom/zoom.utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export function handleCalculateZoomPositions(
1414
limitToBounds: boolean,
1515
): PositionType {
1616
const { scale, positionX, positionY } = contextInstance.transformState;
17+
const { maxBounds } = contextInstance;
1718

1819
const scaleDifference = newScale - scale;
1920

@@ -36,6 +37,7 @@ export function handleCalculateZoomPositions(
3637
0,
3738
0,
3839
null,
40+
maxBounds
3941
);
4042

4143
return newPositions;

0 commit comments

Comments
 (0)