Search code examples
reactjsgoogle-mapsoverlappingmarkers

Overlapping markers spiderfier using "@react-google-maps/api


https://stackblitz.com/edit/react-kam469?file=Map.js

you can follow the above-given link.


Solution

  • enter image description here

    https://stackblitz.com/edit/react-kam469?file=Map.js

    you can follow this link by providing Google Map API key

    step1: install google map package for react ( npm i @react-google-maps/api ) 
    
    step2: install overlapping marker spiderfier ( npm i npm-overlapping-marker-spiderfier )
    

    Spiderfy.js component

    import React from "react";
    import { GoogleMap } from "@react-google-maps/api";
    
    class Spiderfy extends React.Component {
      constructor(props) {
        super(props);
        const oms = require(`npm-overlapping-marker-spiderfier/lib/oms.min`);
    
        this.oms = new oms.OverlappingMarkerSpiderfier(
          GoogleMap().MapContext._currentValue, // 1*
          {}
        );
    
        this.markerNodeMounted = this.markerNodeMounted.bind(this);
      }
    
      async markerNodeMounted(ref) {
        setTimeout(() => { //3*
          this.oms.addMarker(ref.marker); // 2*
          window.google.maps.event.addListener(ref.marker, "spider_click", e => {
            if (this.props.onSpiderClick) this.props.onSpiderClick(e);
          });
        }, 2000);
      }
    
      render() {
        return React.Children.map(this.props.children, child =>
          React.cloneElement(child, { ref: this.markerNodeMounted })
        );
      }
    }
    
    export default Spiderfy;
    
    
    // note 
    // 1*
    // if your are not able to get thecontext of google map then you can use MapContext._currentValue 
    // and import it instead of Google map i.e ( import { MapContext } from "@react-google-maps/api"; )
    
    // 2*
    // if you are not able to get the value with ref.marker then it can be ref.state.marker
    
    // 3* 
    // I am using setTimeout as a hack it could be more better but FYI if marker took time to load and you are have trouble with // // markers refs then you can use setTimeout !!! but its not an ideal solution but it works

    Map.js component

    import React from "react";
    import { GoogleMap, LoadScript } from "@react-google-maps/api";
    import Spiderfy from "./Spiderfy";
    import MapMarker from "./MapMarker";
    
    const containerStyle = {
      width: "100%",
      height: "400px"
    };
    
    const center = {
      lat: -34.2832517,
      lng: 142.6632107
    };
    
    let markerData = [
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -38.132245, lng: 144.2994245 }, title: "Geelong" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -38.132245, lng: 144.2994245 }, title: "Geelong" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -38.132245, lng: 144.2994245 }, title: "Geelong" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -37.9716929, lng: 144.772958 }, title: "Melbourne" },
      { position: { lat: -38.132245, lng: 144.2994245 }, title: "Geelong" },
    
    function Map() {
      const [map, setMap] = React.useState(null);
    
      const onUnmount = React.useCallback(function callback(map) {
        setMap(null);
      }, []);
    
      return (
        <LoadScript
          googleMapsApiKey="YOUR GOOGLE MAP API KEY"
          libraries={["visualization", "places"]}
        >
          <GoogleMap
            mapContainerStyle={containerStyle}
            center={center}
            zoom={5}
            onUnmount={onUnmount}
          >
              <Spiderfy>
                {markerData.map(data => (
                  <MapMarker position={data.position} title={data.title} />
                ))}
              </Spiderfy>
    
          </GoogleMap>
        </LoadScript>
      );
    }
    
    export default Map;

    MapMarker.js Component

    import React from "react";
    import { Marker } from "@react-google-maps/api";
    
    const MapMarker = React.forwardRef((props, ref) => { // Note below
      return <Marker position={props.position} title={props.title} ref={ref} />;
    });
    
    export default MapMarker;
    
    // Note if you are using class base component then you can forwardRef like 
    // export default React.forwardRef((props, ref) => <MapMarker innerRef={ref} {...props} />);

    index.js component

    import React, { Component } from "react";
    import { render } from "react-dom";
    import Map from "./Map";
    import "./style.css";
    
    const App = () => {
      return <Map />;
    };
    
    render(<App />, document.getElementById("root"));