react-google-maps icon indicating copy to clipboard operation
react-google-maps copied to clipboard

[Bug] when zooming fast back and forth the map gets to a state that is stuck

Open ronlv10 opened this issue 1 year ago • 27 comments

Description

When using a phone and zooming fast back and forth (out in out) with a map with advanced markers + clustering, sometimes the map gets to a state that it's stuck (and "going crazy")

after it happens a user can't do anything on the map and sometimes it's stuck in a way that reloads the tab doesn't work.

See:

https://github.com/user-attachments/assets/d85c4741-13a3-4fef-908e-c5f353e2cf72

P.S It also happened in my implementation of clustering on a map with an app that I have built.

Steps to Reproduce

not an easy one. I used the clustering demo : https://visgl.github.io/react-google-maps/examples/custom-marker-clustering

you should use your phone and zoom in and out aggressively

Environment

  • Library version: 1.3.0
  • Google maps version: weekly
  • Browser and Version: chrome
  • OS: android

Logs

there is an warning when it happens: 

Cannot remove a WebglOverlay that has not been set to a map

ronlv10 avatar Oct 05 '24 07:10 ronlv10

the error is the same as https://github.com/visgl/react-google-maps/issues/419 but in this bug it says that there is no impact on the app. Here the bug is critical.

ronlv10 avatar Oct 05 '24 07:10 ronlv10

hey, @usefulthink any comment? This bug impacts our app severely

ronlv10 avatar Nov 06 '24 11:11 ronlv10

As far as I know, the issue in #419 has been resolved upstream in the maps API itself. Are you still seeing that warning-message?

usefulthink avatar Nov 06 '24 18:11 usefulthink

And you're saying it is severely affecting your app, can you elaborate on that a bit? I was under the impression that the original issue only happens occasionally when aggressively zooming around the screen, which isn't something I'd expect users to do.

usefulthink avatar Nov 06 '24 18:11 usefulthink

And you're saying it is severely affecting your app, can you elaborate on that a bit? I was under the impression that the original issue only happens occasionally when aggressively zooming around the screen, which isn't something I'd expect users to do.

It happened to me multiple times while doing usability session with users. It doesn't happen only when zooming aggressively but it was my way to reproduce it faster. Here are two videos that I made now, zooming slowly back and forth until it happens: one from the demo clustering and one from my app. (please note it happens only with mobile zoom (two fingers)

Demo:

https://github.com/user-attachments/assets/fe47c598-1404-45b5-a1ad-b5beff922bcc

My app:

https://github.com/user-attachments/assets/8b34b524-1f9f-4fda-b816-4db389423684

As far as I know, the issue in #419 has been resolved upstream in the maps API itself. Are you still seeing that warning-message?

After upgrade the package version I didn't see the warning, I did saw now this error:

InvalidValueError: setCenter: not a LatLng or LatLngLiteral with finite coordinates: in property lng: -Infinity is not an accepted value

PS After reproducing it millions of times, I suspect that it happens when the user zooms out and keeps the fingers on the screen (and probably touching the markers)

ronlv10 avatar Nov 10 '24 11:11 ronlv10

Thanks a lot. That's an error-message I haven't yet seen, and a very helpful one at that. Let me see if I can figure out how it's even possible that lat/lng are Infinity. I'll also try to reproduce it myself.

usefulthink avatar Nov 10 '24 14:11 usefulthink

great, thanks a lot!

If you're struggling to reproduce let me know. I would be happy to jump on a call, I got to reproduce it through a few zooming.

ronlv10 avatar Nov 10 '24 17:11 ronlv10

Hey @usefulthink , Have you able to reproduce it on your side ?

ronlv10 avatar Nov 17 '24 10:11 ronlv10

Hey I'm also running into this issue. I have about 3000 markers that we're using clustering with. When we zoom in and out on chrome on iPhone the map resets to a zoom of 0. I turned on isFractionalZoomEnabled and it helped to prevent the issue from happening as often, but now when it happens the entire map crashes with no logs.

Same way to reproduce, just zooming in and out slowly on the markers. I'm able to have the same thing happen on the example here: https://visgl.github.io/react-google-maps/examples/custom-marker-clustering by opening it on iOS safari and zooming in and out a few times.

@ronlv10 were you able to resolve this? @usefulthink did you ever look at this again? this is a critical issue for our maps application

dnishiyama avatar Apr 03 '25 03:04 dnishiyama

I have the feeling there are different issues at play here.

If I recall correctly, the initial problem appears to have had something to do with the browser handling the pinch-zoom instead of the map, which could happen if you pinch-zoom any other elements of the page. I blamed that on our website not being built with mobile users in mind, but didn't have the time to investigate further.

What has been reported later doesn't seem to be related to that, though. I should be able to spend a bit of time on that next week.

usefulthink avatar Apr 03 '25 09:04 usefulthink

Thanks for the quick response here, @usefulthink. To help out I made a minimal reproduction repo: https://github.com/dnishiyama/visgl-react-app-bug

And it is deployed here: https://visgl-react-app-bug.vercel.app/

And here is a video of my zooming and unzooming. You'll notice that it kicks me out to a 0 zoom a couple times (@ 11 seconds and @ 14 seconds and @27 seconds). This is somewhat rare on iOS (5 times in a minute of zooming), but for android the users are reporting that it is happening more frequently.

https://github.com/user-attachments/assets/f1de77cf-80bb-4027-b7b5-cbafb784f5fe

dnishiyama avatar Apr 03 '25 14:04 dnishiyama

Also, I see what you're saying that this might be a separate issue. Let me know if you'd like me to create a separate issue

dnishiyama avatar Apr 03 '25 18:04 dnishiyama

Very cool, thanks a lot! Did you see that only in iOS Safari (I'm assuming a current version(?)), or are other browsers affected as well?

usefulthink avatar Apr 03 '25 18:04 usefulthink

No problem! I've seen it on Safari from iOS 18.3.2 and Chrome 134.0.6998.99. Let me know if I can provide anything else

dnishiyama avatar Apr 03 '25 19:04 dnishiyama

I just confirmed that it is happening on android on this version as well:

Image

Any chance you've gotten a chance to look at this @usefulthink? Appreciate any help you can provide 🙏

dnishiyama avatar Apr 11 '25 16:04 dnishiyama

I already spent some time with it, and it seems somewhat reproducible with lots of stuff going on on the map. However, I haven't yet found a good way to get to the root-cause of the issue or a reduced example that still reproduces the problem.

usefulthink avatar Apr 11 '25 16:04 usefulthink

@usefulthink thanks for looking at it. By reduced example do you mean less markers? Or do you mean on a different repository? I'm able to reproduce on the example here: https://visgl.github.io/react-google-maps/examples/custom-marker-clustering. That one seems to be very basic. Thanks for any help

dnishiyama avatar Apr 21 '25 00:04 dnishiyama

Hey @usefulthink, I am also experiencing the map crashing our app when users zoom in and out on the map "quickly". Like @dnishiyama , I've also had users report that it kicks out to a 0 zoom a couple times.

Debouncing the onZoomChanged event on <Map/> helped this, but it still happens intermittently. Its happening on web (Chrome 136.0.7103.114) though for me, not just mobile browsers. I am also using the @googlemaps/markerclusterer package. Let me know if any more info would help.

Do you any updates? Thanks in advance.

rivaridley avatar May 23 '25 18:05 rivaridley

Yes this is still a pain for our users. It seems that it is trying to set a negative or NaN zoom. Is there some place in the package where we can get in front of that zoom update? I've tried to patch the base package, but can't seem to get in front of the erroneous zoom setting. Would really appreciate any help you can provide on this @usefulthink.

dnishiyama avatar May 23 '25 19:05 dnishiyama

Is there anyway to intercept the zoom updates? I think if we could just sanitize them we could fix (at least bandaid) the problem

dnishiyama avatar May 25 '25 02:05 dnishiyama

The camera-logic of the Map-component works like this:

  1. when the user interacts with the map, it will emit bounds_change events
  2. react-google-maps receives those events and updates an internal copy of all camera parameters (center/zoom/heading/tilt) from the values currently in the map instance, and triggers a re-render of the Map component
  3. during rendering, the controlled props are checked against the internal copy of the parameters. If there is a discrepancy, we force the camera to update.

This is to allow the application to actually be in control of the camera parameters and to be able to override user-actions within the map without needlessly interfering with every update (In practice, this only partially works, since moveCamera will also abort implicit animations that are essential to the map UX. The Map component needs some more fine-tuning in this area).

This is the code for handling the bound-change events: https://github.com/visgl/react-google-maps/blob/1008a391d8f65626b0e34fce20bb4edb3eeccccd/src/components/map/use-tracked-camera-state-ref.ts#L13-L35

And this is where the values from the camera-props are written back to the Google map if they’re different from what is expected (as per the last observed bounds_changed event):

https://github.com/visgl/react-google-maps/blob/1008a391d8f65626b0e34fce20bb4edb3eeccccd/src/components/map/use-map-camera-params.ts#L36-L70

For the marker-clustering example, there's an additional listener for the bounds_change event that independently uses the map's bounds and zoom to compute the clusters that need to be shown.

https://github.com/visgl/react-google-maps/blob/b9760e98e1fd8f635b68ac7279d4280661db3fcf/examples/custom-marker-clustering/src/hooks/use-map-viewport.ts#L18-L38

usefulthink avatar May 27 '25 08:05 usefulthink

Hey! Long time, happy to see I am not the only one who ran into this bug 🙂

I recently took the time to dive into this again. First, I tried to understand whether the root cause comes from react-google-maps or from the Google Maps JS API. To check that, I cloned the custom-marker-clustering example locally and commented out all the calls to map.moveCamera, map.setOptions, map.setCenter, etc. Removing these calls did not help - the issue still reproduced quickly.

So I created a plain HTML + Google Maps JS example with 5k markers and clusters (thanks to AI). It was very difficult to reproduce, but after many zoom-ins and zoom-outs I managed to reproduce the bug! That proves the root cause is within the underlying Google Maps JS. here is the html code - you will need to update the map id and api key

Notes:

  1. It seems like the zoom level becomes negative and is then clamped to zero.
  2. My gut feeling is that it's mix of JS cpu intensive computation of clusters, that catch the main thread, and calculation of "acceleration" zoom (based on timestamp or something) + touching the markers (which probably impact the coordination of the zoom calculation) that makes the zoom out to be huge - I don't really understand why and google maps JS is minified and obfuscated.
  3. I do not think it is the browser handling the pinch-zoom instead of the map, as suggested in this comment

@usefulthink let me know if it makes sense to raise this directly with the Google Maps team. I assume you have experience with doing that.

However, I noticed in the plain HTML example: the clustering and rendering of markers happen only after zooming is complete (after releasing the fingers from the screen). In contrast, in the custom-marker-clustering example, it happens during the zoom gesture itself and I think it's the reason that it reudces the probability of facing this issue

I was curious about this difference and found that Google the way implemented js-markerclusterer is listen to the idle event instead of bounds_changed. This is more of a product decision, but it significantly reduces the chance of triggering the issue.

I created PR #806 to make this behavior the default in the example, so users copying from it get the safer approach by default.

ronlv10 avatar Jul 28 '25 16:07 ronlv10

@ronlv10 thanks a lot for investigating and your summary. A combination of blocking the main thread and time-sensitive computations like acceleration could indeed explain this behavior.

If that is the case, the maps API team would very likely want to know this, and it should be relatively simple to fix. I can see if I can write this up in an issue report.

usefulthink avatar Jul 28 '25 20:07 usefulthink

@usefulthink Cool! Thank you for doing this.

I created a repo that reproduces it using the vanilla Google Maps JS - I added a patch-package to markerclusterer that will run every bounds_changed instead of idle - and it increases the likelihood of the reproduction (see video below)

Repo: https://github.com/ronlv10/reproduce-maps-issue Video:

https://github.com/user-attachments/assets/ac565308-cb4b-41b2-bd8d-a56e7a74d6de

Thanks!

ronlv10 avatar Jul 28 '25 22:07 ronlv10

Hey @usefulthink, Any updates on this? Have you had a chance to submit the issue to Google?

ronlv10 avatar Aug 08 '25 07:08 ronlv10

Hello! The version 1.5.5 has this problem too. Any updates of the problem?

siregic avatar Sep 25 '25 17:09 siregic

@vis.gl+react-google-maps+1.5.3.patch.zip

Hello, everyone! In the attachment you can find some temporarily fix (patch of 1.5.3 version). It fixes “bounce to min-zoom” during fast pinch-zoom with markers (see #563).

siregic avatar Sep 26 '25 06:09 siregic