Panzoom: Pinch zoom moves image away from screen center

Created on 21 Sep 2020  ·  19Comments  ·  Source: timmywil/panzoom

Describe the bug

For some reason, when using my Panzoom app on mobile (any device), when trying to pinch zoom the image moves to the corner right when zooming in, and to the top left when zooming out, instead of zooming in place. Sometimes, when just starting the app, zoom out works properly before moving the image, and then the problem come back.

Zooming in and out with the scroll wheel works as it should, it's only pinch zoom that doesn't.

Your environment

  • Latest version (installed today)
  • Vivaldi browser, Kiwi browser, Chrome, Firefox, all latest versions.

Expected behavior

Zoomed image should stay centered where the user is zooming in/out.

Actual behavior

Zoomed image moves, and zooming in centers the bottom right of the image on the screen, while zooming out centers the top left.

Most helpful comment

Replace move function on panzoom.ts:426

function move(event: PointerEvent) {
if (
!isPanning ||
origX === undefined ||
origY === undefined ||
startClientX === undefined ||
startClientY === undefined
) {
return
}
addPointer(pointers, event)
const current = getMiddle(pointers)
if (pointers.length > 1) {
// Use the distance between the first 2 pointers
// to determine the current scale
// prevent zoom issue in mobile
if (startDistance === 0) {
startDistance = getDistance(pointers);
}
const diff = getDistance(pointers) - startDistance
const toScale = constrainScale((diff * options.step) / 80 + startScale).scale
zoomToPoint(toScale, current)
} else {
// added else condition to prevent mobile zoom focal point error
pan(
origX + (current.clientX - startClientX) / scale,
origY + (current.clientY - startClientY) / scale,
{
animate: false
}
);
}
}

All 19 comments

Thanks for opening an issue. I tried the demo on iOS and Android and could not reproduce. You listed desktop browsers, but pinch zooming is mainly for mobile (though some devices have both a mouse and a touch screen). It might be helpful to know which device you are using, even though I'd likely be unable to test on it.

There's not much I can do without being able to reproduce the problem. If you dig deeper and find that a code change in Panzoom fixes it (or that a different test case besides the demo reproduces the problem), please comment here and I'll consider a patch.

Hi mr Willison;

Thank you for your reply. I used both the desktop and mobile versions of
said browsers. I used a Redmi Note 8T and a Galaxy 8 to test this.

To see this problem, maybe you can take a look at the demo I'm developing?
Just type a name (nothing is stored, it's just a children's game) and click
on the "Exploració lliure" button; you'll be redirected to the Panzoomed
image. As you will see, mousewheel zoom works fine, but pinch zoom (and
actually panzoom.zoomIn() and panzoom.zoomOut() buttons too) moves the
image.

http://bake250.isdeveloping.com/objectiuexplora/solsticidelspirineus/

I'm really thankful for your help, and please excuse any inconvenience.

Best regards;

Jorge Sánchez Blanco

El lun., 21 sept. 2020 a las 19:45, Timmy Willison (<
[email protected]>) escribió:

Thanks for opening an issue. I tried the demo
https://timmywil.com/panzoom/demo on iOS and Android and could not
reproduce. You listed desktop browsers, but pinch zooming is mainly for
mobile (though some devices have both a mouse and a touch screen). It might
be helpful to know which device you are using, even though I'd likely be
unable to test on it.

There's not much I can do without being able to reproduce the problem. If
you dig deeper and find that a code change in Panzoom fixes it (or that a
different test case besides the demo reproduces the problem), please
comment here and I'll consider a patch.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/timmywil/panzoom/issues/512#issuecomment-696267620,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AOF4EAOK6YQVAHINOAQ3JZTSG6GMRANCNFSM4RUT4P7A
.

I am having the same issue. It looks like the focal point is not properly calculated and it is all the way at the bottom.

@jsblanco I see. Panzoom is relying on transform-origin: 50% 50%, which centers the animation on the center of the viewport rather than on the center of the image, which would be lower in this case. It moves the image because of the contain: outside setting to prevent the image from going too far down. I think this can be fixed by calling zoomToPoint or by using zoom with the focal option instead and finding the point in the viewport that is actually the center of the image. Does that make sense?

I could perhaps do something like this by default when contain: outside is set.

@rmatec Are you also using contain: outside?

I am not using the contain option. In my case, it looks like the focal point is at the bottom center. Pinching in or out is done relative to that point.

@rmatec I think there must be some option in play, as I don't see this behavior in the demos. Is there another option you are setting?

I am using the following to initialise Panzoom.

const panzoomConfig = { minScale: 1, maxScale: 2, step: 0.5, duration: 200 };

It works perfectly well on desktop but for some reason it doesn't on mobile.

Ok, your case sounds like it may be different. Could you reproduce in https://jsbin.com or https://codepen.io and make a new ticket? Here's a template that can be cloned https://jsbin.com/dibofogini/1/edit?html,js,output.

Will do. Thanks.

For some reason, while using the focal option, the image spawns near the
bottom right, and no further zooming can happen, neither in nor out.
Maybe I am doing something wrong? Do I have to pass any specific parameters
to panzoom.zoomIn() and .zoomOut() to indicate the focal point, or just
including it in the panzoom initial declaration should suffice?

For what it's worth, I've tried the following methods of getting the focal
point. I also tried putting raw numbers.

clientX: window.innerWidth /2,
clientY: window.innerHeight/2

clientX: document.documentElement.clientWidth/2,
clientY: document.documentElement.clientHeight/2

Removing contain: outside altogether just renders a black image.

El mar., 22 sept. 2020 a las 15:59, Timmy Willison (<
[email protected]>) escribió:

@jsblanco https://github.com/jsblanco I see. Panzoom is relying on transform-origin:
50% 50%, which centers the animation on the center of the viewport rather
than on the center of the image, which would be lower in this case. It
moves the image because of the contain: outside setting to prevent the
image from going too far down. I think this can be fixed by calling
zoomToPoint or by using zoom with the focal option instead and finding
the point in the viewport that is actually the center of the image. Does
that make sense?

I could perhaps do something like this by default when contain: outside
is set.

@rmatec https://github.com/rmatec Are you also using contain: outside?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/timmywil/panzoom/issues/512#issuecomment-696740708,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AOF4EANBQXE5TDJOZNTBN6LSHCUVXANCNFSM4RUT4P7A
.

@jsblanco Sorry, it's more complicated than that. The way to do it would be to find the center of the image and translate that to its point in the panzoom parent viewport. You'd then pass that as the focal option, and it should be calculated each time you call zoom. However, let me see if I can work up an example for you. That would fix zoomIn/zoomOut.

That said, this would not change the pinch zooming behavior. Arguably, that is doing the right thing as zooming on certain points bumps up against contain: outside. I'm not sure the fix there except perhaps to not allow the zoom if the image needs to move in order to keep it in the viewport properly.

Ok, your case sounds like it may be different. Could you reproduce in https://jsbin.com or https://codepen.io and make a new ticket? Here's a template that can be cloned https://jsbin.com/dibofogini/1/edit?html,js,output.

I've created https://github.com/timmywil/panzoom/issues/513 for my specific case. There is a link to JSBin that shows the issue.

I'm able to reproduce this issue if I leave "animate: true" on.
This issue doesn't appear at "animate: false" - I've cloned your template @timmywil to reproduce that issue:

https://jsbin.com/pemoveyeri/1/edit?

(I've implemented the wheel event listener to zoom directly - If you scroll fast enough, shifting position will happen.)

Okay, I moved my issue to #515 because while the issue is same, but it has with different configuration.

Hi;

Sorry for taking long to answer. I don't think it has to do with contain="outside"; I just removed it and it still exhibited the same behaviour, although not as intensely. The panzoom div and the image have a set size independent of that of the street, however; could that be part of the issue?

Thank you

@jsblanco The fix should be the same.

Hi, I was going to open a new issue about wheel zoom moving away from center but looked through this one and thought it is related enough. Following are my findings and workaround. Note that I have only tested in browsers on a MacBook using the trackpad.

I notice that for the focal point zooming demo, the center floats towards the upper left when zooming in Safari, Firefox. I get the same behaviour even in Chrome, but only when the web inspector is open.

So I started looking into it and my suspicion is that the mouse wheel event is triggering too often and things are not updating correctly due to the async nature of Panzoom. I thought if I try to throttle the frequency of the zooming it might help and sure enough it seems to "work". You can see it in action here: https://jsbin.com/joliduwulo/1/edit?html,js,output.

The caveat is that the zooming would appear less smooth. In this example I'm limiting it to one zoom max every 20ms but when I was testing with large SVGs, especially in Firefox, I needed to have that set to around 50ms for it to not lose the focal point.

@timmywil please let me know if you want me to open a new issue anyways. This seems like a hack but it solves the problem for me. If you think the solution is worth exploring I would love to help contribute.

+1 on the ability to center on the panzoom element rather than the viewport

Replace move function on panzoom.ts:426

function move(event: PointerEvent) {
if (
!isPanning ||
origX === undefined ||
origY === undefined ||
startClientX === undefined ||
startClientY === undefined
) {
return
}
addPointer(pointers, event)
const current = getMiddle(pointers)
if (pointers.length > 1) {
// Use the distance between the first 2 pointers
// to determine the current scale
// prevent zoom issue in mobile
if (startDistance === 0) {
startDistance = getDistance(pointers);
}
const diff = getDistance(pointers) - startDistance
const toScale = constrainScale((diff * options.step) / 80 + startScale).scale
zoomToPoint(toScale, current)
} else {
// added else condition to prevent mobile zoom focal point error
pan(
origX + (current.clientX - startClientX) / scale,
origY + (current.clientY - startClientY) / scale,
{
animate: false
}
);
}
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kylegoines picture kylegoines  ·  4Comments

YuriGor picture YuriGor  ·  12Comments

rpallares picture rpallares  ·  3Comments

adred picture adred  ·  21Comments

nich008 picture nich008  ·  14Comments