pixi-viewport
pixi-viewport copied to clipboard
Restrict Panning and Zooming
Hi Is there any way to restrict the panning to not make the canvas outside the view?
Basically, what I want is:
- Not able to Zoom out.
- Restrict Panning if the user tries to move the pixi canvas outside the view such that there is no empty space shown ever.
- Resetting the zooming and panning to the original position.
Also, when I render a very large image, the initial coordinates are changed automatically. Is there any way that that does not happen?
For restricting the panning, bounce
seems to be working but it is only bouncing back if pushed towards right or bottom. The top and left side of the canvas is not restricted.
ensureVisible
and fit
can be used to reset the zooming and panning to the original position.
ensureVisible
ensures panning is in the visible area. fit(false, width, height)
ensures that zooming is as per width and height specified. So, I think it is pretty easy to reset the zooming and panning to original position.
For restricting the panning,
bounce
seems to be working but it is only bouncing back if pushed towards right or bottom. The top and left side of the canvas is not restricted.
To ensure the view doesn't go out from the top and left, I wrote the following code:
viewport.on("drag-end", function(){
if(this.getVisibleBounds().x > 0 || this.getVisibleBounds().x > 0){
this.ensureVisible(0,0);
}
});
Is this correct way of doing this?
This is the final code that I wrote to get closest to what I want:
let viewport = new Viewport.Viewport({
screenWidth: width,
screenHeight: height,
worldWidth: width*2,
worldHeight: height*2,
interaction: context.app.renderer.plugins.interaction,
stopPropagation: true
});
viewport.drag().pinch().wheel().decelerate().bounce()
.on("drag-end", function(){
if(this.getVisibleBounds().x > 0 || this.getVisibleBounds().y > 0){
this.ensureVisible(0,0);
}
})
.on("zoomed", function(){
if(this.lastViewport.scaleX < 1 || this.lastViewport.scaleY < 1){
let self = this;
this.ensureVisible(0,0);
setTimeout(() => {
self.fit(false, width, height);
}, 100);
}
});
Is this fine?
Did you try .viewport.clamp()? That's designed to stop the viewport from panning beyond the boundaries (or whatever area you set).
How does the clampZoom() minWidth and minHeight properties work? When I'm using renderer sizes 800x600, world size 10000x10000, clamp() properties: left: -10000, right: 10000, top: -10000, bottom: 10000.
And if i use clampZoom() maxWidth: 1600 maxHeight: 1200, i can zoom out twice the viewport size. But if i use minWidth: 400 and minHeight: 300 with my maxWidth and maxHeight properties, the whole renderer is empty somehow.
Man, I need to update the docs. I keep forgetting how clampZoom works.
The minWidth/Height settings are how small the world can get (as it would appear on the screen) before clamping. The maxWidth/maxHeight is how larger the world can scale (as it would appear on the screen) before clamping.
For example, if you have a world size of 1000 x 1000 and a screen size of 100 x 100, if you set minWidth/Height = 100 then the world will not be able to zoom smaller than the screen size (ie, zooming out so it appears smaller than the screen). Similarly, if you set maxWidth/Height = 100 the world will not be able to zoom larger than the screen size (ie, zooming in so it appears larger than the screen).
Your renderer is likely empty because there is a conflict in the settings between the clamp and the clampZoom.
Also struggle with this a little, but I'm probably not understanding how to use it.
With clamp, it would ideal to keep the world within view - as in, when the world is panned outside the left edge, the clamp would constrain to the right edge of the world.
Like, if clamp direction was "all", it would assure the world couldn't be pushed off the screen at any zoom level from any direction.
Often struggle with the origin / pivot point - centering, and zoom level percentages in regards to clamp and fitting the world.
By default, clamp({ direction: all })
will clamp so the world can't leave the viewport.
If you want to allow the world to leave but never completely disappear, you'd have to reset the boundaries: clamp({ direction: all, left: -worldWidth * 0.1, right: worldWidth * 1.9, top: -worldHeight * 0.1, bottom: worldHeight * 1.9 })
. If my math is correct, that would allow the world to always have at least 10% of the world visible.
I added options.minScale/maxScale to clampZoom() to hopefully make that plugin easier to use.
viewport.clampZoom({ minScale: .5, maxScale: 3 }) Indeed, this works for me. Thanks.
In there a way to automatically fit the content?
viewport.fit()
will fit the contents. If you want to use it with clampZoom, use the code from the fit() (or fitWidth/fitHeight) to get the correct amounts.
For me, it is difficult to think in terms of width/height fit. It is more natural to think the visualization in terms of scale — perhaps because my navigation is zoom-based. Thanks!