react-map-gl icon indicating copy to clipboard operation
react-map-gl copied to clipboard

[Feat] Add onStyleImageMissing callback for Map

Open joshkautz opened this issue 2 years ago • 4 comments

Target Use Case

Mapbox throws a warning when you try to load an image that hasn't been added.

Image [...] could not be loaded. Please make sure you have added the image with map.addImage() or a "sprite" property in your style. You can provide missing images by listening for the "styleimagemissing" map event.

They have a new map event, styleimagemissing, that I think should be exposed by this React Wrapper. Unless this is already an event type that's supported with another callback handler that I've been overlooking.

Proposal

The usage might look something like this. I'm happy to help contribute in this feature if it's something that folks think would be good to add. I'll wait to hear back from a maintainer first though 😄

<Map
   {...initialViewState}
   mapboxAccessToken={MAPBOX_TOKEN}
   projection={'globe'}
   style={{ position: 'absolute', top: '0', bottom: '0', left: '0', right: '0' }}

   onStyleImageMissing={evt => {
      evt.target.loadImage(
         "./icons/mapbox-marker-icon-20px-red.png",
         (error, image) => {
            if (error)
               throw error;
            evt.target.addImage(mapImages.Default, image);
         }
      );
   }}
/>

joshkautz avatar Dec 16 '22 18:12 joshkautz

Do you need to manipulate any React state in this callback? You can always add an event listener using a ref to the map.

Pessimistress avatar Dec 16 '22 21:12 Pessimistress

Yes, I can create an event listener for this specific event like this:

[...]

const mapRef = useRef();
const map = mapRef.current;

useEffect(() => {
   if (map) {
      map.on('styleimagemissing', () => {
         if (!map.hasImage(id)) {
            map.loadImage(
               "./icons/mapbox-marker-icon-20px-red.png",
               (error, image) => {
                  if (error) throw error;
                  if (!map.hasImage(id))
                     map.addImage(id, image);
               }
            );
         }
      });
   }
  }, [map]);

[...]

I guess what I'm trying to better understand is if this would be a desirable callback to add to react-map-gl. If it is not, could you try to explain to me why not? I don't have a strong opinion on the matter; I'm really new to MapBox (and react-map-gl, for that matter), so I'm just trying to better understand. Thank you in advance.

joshkautz avatar Dec 16 '22 22:12 joshkautz

I don't have a strong opinion against this. Asking the question because there are dozens of other mapbox events that we don't have a React callback prop for. Should we add all of them? Is there any performance implication if we attach a listener to every event?

One possible argument for not having this prop is that, you do not need to manipulate any React state in the listener. You are technically "leaving" the React system.

Pessimistress avatar Dec 28 '22 18:12 Pessimistress

Hey, thanks for this threat, which helped me to build my own useMissingImage hook.

I thought I would share it as inspiration for others:

  • useMissingImage.ts: https://github.com/FixMyBerlin/atlas-app/blob/develop/src/components/MapInterface/Map/utils/useMissingImage.ts
  • My docs on the topic an the file I use to map imageIds to actual images (same folder) https://github.com/FixMyBerlin/atlas-app/blob/develop/src/components/MapInterface/mapData/topicsMapData/mapboxStyleImages/README.md

tordans avatar Mar 09 '23 19:03 tordans