jawj / OverlappingMarkerSpiderfier-Leaflet

Deals with overlapping markers in the Leaflet maps API, Google Earth-style
253 stars 68 forks source link

[Not an issue] Info for React integration #55

Open jabidof opened 1 year ago

jabidof commented 1 year ago

For any interested react-leaflet users, you can integrate this lib following way:

declare global {
  interface Window {
    OverlappingMarkerSpiderfier: any;
  }
}

interface ISpiderify {
  onClick?: (marker: L.Marker<any>) => void;
  onSpiderfy?: (markers: Marker<any>[]) => void;
  onUnspiderfy?: (markers: L.Marker<any>[]) => void;
  children?: React.ReactNode;
}
export const Spiderify = (props: ISpiderify) => {
  const map = useMap();

  const oms: any = useMemo(() => {
    const _oms =new window.OverlappingMarkerSpiderfier(map, {
      keepSpiderfied: false,
      nearbyDistance: 20, // This is the pixel radius within which a marker is considered to be overlapping a clicked marker. D=20
      circleSpiralSwitchover: Infinity, // This is the lowest number of markers that will be fanned out into a spiral instead of a circle. Set this to 0 to always get spirals, or Infinity for all circles.
      legWeight: 1.5, // This determines the thickness of the lines joining spiderfied markers to their original locations.
    });
    _oms.addListener("spiderfy", (markers: Marker[]) => {
      markers.forEach((m) => m.closePopup()); //force to close popup
      if (props.onSpiderfy) props.onSpiderfy(markers);
    });
    _oms.addListener("unspiderfy", (markers: Marker[]) => {
      if (props.onUnspiderfy) props.onUnspiderfy(markers);
    });
    _oms.addListener("click", (marker: Marker) => {
      if (props.onClick) props.onClick(marker);
    });
    return _oms;
  }, [map, props]);

  const childrenWithProps = React.Children.map(props.children, (child) => {
    // Checking isValidElement is the safe way and avoids a
    // typescript error too.
    if (React.isValidElement(child)) {
      // @ts-ignore
      return React.cloneElement(child, { oms });
    }
    return child;
  });
  return <LayerGroup>{childrenWithProps}</LayerGroup>;
};

Then in your MapContainer:

<Spiderify
  onClick={(m) => {
    console.log("click", m);
  }}
>
      {... all your <Marker /> ...}
</Spiderify>

Probably it can be improved...

Samettkaya commented 10 months ago

Hello, I tried this example and it didn't work for me. how can I do it

Thomas-Martin-1998 commented 9 months ago

Anyone got something that works? I just spent all day trying to get this to work with React-Leaflet, the documentation/examples are all out of date. This is the best I've seen yet, but it doesn't work, and I have no errors to help me debug why.

RISHIKESHk07 commented 4 months ago

@Thomas-Martin-1998 any luck on solving this problem ?