mapbox-gl-js icon indicating copy to clipboard operation
mapbox-gl-js copied to clipboard

Icons disappear at certain zoom levels in Safari only, but are still clickable

Open stephenheron opened this issue 3 years ago • 7 comments

Hi,

I am having a very strange Safari issue. On zooming in and out some of our pins that are drawn using a symbol layer appear and disappear.

https://user-images.githubusercontent.com/142855/134563726-870a36c0-4849-4562-bd06-c1e653d3f6e1.mov

It is not shown in the video but when the pins are not visible they are still clickable. I have checked in both Chrome and Firefox and the problem does not happen.

I have tried v2.4, v2.3 and v.2.2 and the problem appears in all of them. I also checked out main and the problem is also present. Strangely I did find a single commit where the issue is not a problem, the video below shows that commit in action 457f808ad2ecdb90b2c2f5511734f1a2f0790740

https://user-images.githubusercontent.com/142855/134564184-afe86510-4b9f-4094-aad7-8a9c25797123.mov

I understand this is a very strange problem so if I can provide any more debugging assistance I will do my best.

Thanks, Stephen

stephenheron avatar Sep 23 '21 18:09 stephenheron

Hi @stephenheron it is an expected behavior for markers not render at certain zoom levels when using large geojson sources. You can check out the documentation here on different options when working with geojson sources. I also recommend trying to set 'icon-allow-overlap' to true in the symbol layer. Here is more documentation about the symbol layer if it helps as well. I will close this issue since it is not a bug report or feature request. If you need further assistance with this issue, please contact Mapbox Support. Thanks!

avpeery avatar Sep 23 '21 22:09 avpeery

It is not shown in the video but when the pins are not visible they are still clickable. I have checked in both Chrome and Firefox and the problem does not happen.

Hi @stephenheron, closely re-read the section emphasizing that these icons are still clickable and it is not occurring in Chrome and Firefox. Can you include a minimal reproduction of the code in jsbin or codepen? Thanks!

avpeery avatar Sep 23 '21 22:09 avpeery

Hi @avpeery

We had a look at replicating the issue in the jsbin and we discovered the source of the problems.

In our code we do something like this:

  //This is a workaround until this issue gets looked at: https://github.com/mapbox/mapbox-gl-js/issues/9018  
  map.addImage(imageId, {width: 0, height: 0, data: new Uint8Array()});
  map.loadImage(imageURL, (error, image) => {
    if (!error) {
      map.removeImage(imageId);
      map.addImage(imageId, image);
    }
  });
};

It effectively sets an empty image and then loads in a real image. This is so we don't need to preload all our pin images. This issue (https://github.com/mapbox/mapbox-gl-js/issues/9018) talks about the need to be able asynchronously load images but that feature is not available so we did the above as a work around.

However this seems to be the source of our "disappearing" pins. It seems like quickly removing/adding the images results in some of the pins keeping the old image and some the new image.

To more easily visualise the issue we changed the invisible pins to instead be a gradient.

You can see this behaviour on this jsbin: https://output.jsbin.com/yolusir/22/

This is the core of the issue on the jsbin below:

 const loadImage = () => {
      const imageId = "poi-accommodation"
      map.addImage(imageId, { width: 64, height: 64, data: getGradientImage() });
      map.loadImage("https://placekitten.com/g/90/111", (error, image) => {
        if (!error) {
          const runSetTimeout = false;
          map.removeImage(imageId);
          if (runSetTimeout) {
            setTimeout(() => {
              map.addImage(imageId, image);
            }, 1000)
          } else {
            map.addImage(imageId, image);
          }


        }
      });
    }

If we add a large setTimeout of 1s then it seems to be better however this is not a great user experience. You can see this behaviour here: https://jsbin.com/yolusir/25/

I hope this helps narrow down the problem! It does seem like a complicated one that is around add/removing of images. We did find this other issue: https://github.com/mapbox/mapbox-gl-js/issues/9004 which is sort of similar and talks about adding/removing of images.

Thanks, Stephen

stephenheron avatar Sep 24 '21 12:09 stephenheron

I also built a version of mapbox-gl with the commit that I found that works (https://github.com/mapbox/mapbox-gl-js/commit/457f808ad2ecdb90b2c2f5511734f1a2f0790740) and it seems totally fine: https://output.jsbin.com/yolusir/27/

stephenheron avatar Sep 24 '21 15:09 stephenheron

Thanks for your work investigating this @stephenheron! I'm looking into a fix for this, in the meantime a workaround is to replace the calls to map.removeImage() and map.addImage() with map.updateImage() followed by map.triggerRepaint().

Here's an updated jsbin with the workaround. Let me know if that helps!

SnailBones avatar Dec 14 '22 23:12 SnailBones

Another workaround that should be simpler for most use cases: load images on 'style.load' instead of 'styleimagemissing' events. ('load' events also work but may be slightly slower.)

Demo here.

SnailBones avatar Dec 15 '22 23:12 SnailBones

After further investigating this, I can confirm that this is the same as https://github.com/mapbox/mapbox-gl-js/issues/8335.

@stephenheron Can you confirm which (if either) of the above workarounds works for you?

If neither of the above work, there's a more general workaround shared in this comment.

Unfortunately, calls to addImage currently require a restart to tile parsing, so addImagecalled after loading an image will negatively affect map load time. I'm looking to move forward with asynchronous image loading (https://github.com/mapbox/mapbox-gl-js/issues/9018) to address the general problem, but please let us know if the workarounds are helpful in your use case!

SnailBones avatar Jan 04 '23 17:01 SnailBones