Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make viewer stay inside SVG boundaries? #143

Open
enekesabel opened this issue Apr 11, 2019 · 5 comments
Open

Make viewer stay inside SVG boundaries? #143

enekesabel opened this issue Apr 11, 2019 · 5 comments
Labels

Comments

@enekesabel
Copy link

enekesabel commented Apr 11, 2019

Hi,

Is it possible to restrict the viewer going outside the boundaries of the SVG element? I'd like to achieve a map-like behavior where you can navigate only inside the svg map. I thought preventPanOutside will do exactly that, but it lets the user drag the map till the corners of the viewer.

Could somebody point me in the right direction?

Thanks,
Abel

@krnlde
Copy link
Contributor

krnlde commented Nov 20, 2019

Without having any context how this lib actually does it: the preventPanOutside calculation seems to use the opposite corners. The calculation could be "corrected" to match your request if the left corner adds the SVGs width, the right corner substracts the width, top adds the height and bottom substracts it - but it's probably easier to just exchange sides (left<-> right, top <->bottom). I'm not sure how @chrvadala calculates the boundaries but you/he could use the corresponding values provided by .getBoundingClientRect() / .getBBox() with the applied .getScreenCTM().inverse() / .getCTM().inverse() to do that.

@wolasss
Copy link
Contributor

wolasss commented Dec 7, 2019

I agree and I also need this feature, if I find some time I might implement it and create a PR

@davidsharp
Copy link

It's a bit of a hack, but you catch pan events with onPan and limit the values to within the SVG and passing your new doctored values to setState. In the values object, e refers to x-axis translation, and f refers to y-axis translation. It's worth noting that the translations describes the movement of the SVG, so by panning an SVG up (scrolling down the 'page'), f goes from 0 into negative digits.

I'm using it here to disable left/right pan (I've got the SVG width set to fill the viewer), then by working out the scaling factor, I can get the height of the scaled SVG (and then I take away the viewer height as the number basically refers to the top of the viewer window):

onPan={value=>{
	//calculate scaled SVG height minus a single viewer height
	const scaledMaxHeight = (value.SVGHeight/(value.SVGWidth/value.viewerWidth))-value.viewerHeight
	this.setState({value:{
		...value,
		// prevents panning left/right
		e:0,
		// limit up/down panning to within the SVG
		f: value.f>0?0
			:value.f<0-scaledMaxHeight?0-scaledMaxHeight
			:value.f
		}})
}}

@WouterrV
Copy link

I started building this feature: https://codesandbox.io/s/react-svg-pan-zoom-testing-wm6ssl (and abandoned it, because it's not really a must-have for our app)

But intercepting the value in onPan gets quite janky because the UI gets adjusted after the fact. What would probably work very fluidly is using a custom setValue function that corrects out-of-bounds values.

@etienne-85
Copy link

etienne-85 commented Jul 12, 2023

I'm also looking forward to that feat. As it might be a must have for our app, may have a look if no one else has implemented it and if not requiring to much time to implement .
Will let you know if I have a working POC

EDIT: Think I've got basic implementation by listening to value changes and restricting depending on image displayed size
This is still of an hack for now with some values tweaked on the fly but to give an idea, relevant piece of code I used:

    // image displayed size (after zoom scale applied)
    const onScreenWidth = SVGWidth * widthScale;
    const onScreenHeight = SVGHeight * heightScale;
    // compute max offsets
    const maxWidthOffset = viewerWidth - onScreenWidth + 5;
    const maxHeightOffset = viewerHeight - onScreenHeight + 5;
    // adjusting current pan values to match offset boundaries
    widthOffset = Math.min(0, Math.max(widthOffset, maxWidthOffset));
    heightOffset = Math.min(0, Math.max(heightOffset, maxHeightOffset));

Link to working POC which may be updated later on:
https://l4p4qq.csb.app/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants