JSFiddle - React, Tailwind, and code Playground

by wintyo

HTML

<div id="map"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>

CSS

html,body{
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}
#map{
  height: 100%;
  width: 100%;
}

JavaScript

const BASE_LAT = 35.6809591;
const BASE_LNG = 139.7673068;

const locations = _.times(50000).map(() => {
  return {
    lat: BASE_LAT + (0.1 * Math.random() - 0.05),
    lng: BASE_LNG + (0.1 * Math.random() - 0.05),
  };
});

function initMap() {
  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 15,
    center: { lat: BASE_LAT, lng: BASE_LNG },
    gestureHandling: 'greedy',
    disableDefaultUI: true,
    clickableIcons: false,
  });
  
  const markers = locations.map((location) => {
    const marker = new google.maps.Marker({
      position: location,
    })
    return marker;
  });
  
  const clusterer = new markerClusterer.MarkerClusterer({ map });
  
  const updateCluster = _.debounce(() => {
    const bounds = map.getBounds();
    // ざっくりやる場合
    clusterer.clearMarkers();
    const visibleMarkers = markers.filter((marker) => {
      return marker.getVisible() && bounds.contains(marker.getPosition());
    });
    clusterer.addMarkers(visibleMarkers);  
    
    /*
    // 丁寧にやる場合
    // 必要なマーカーだけ取り除いたり追加してもチラつきが発生するのでざっくりやって良さそう
    const remainMarkers = markers.filter((marker) => clusterer.markers.indexOf(marker) === -1);
    const [inBoundsMarkers, outBoundsMarkers] = _.partition(clusterer.markers, (marker) => {
      return marker.getVisible() && bounds.contains(marker.getPosition());
    });
    console.log('outBoundsMarkers:', outBoundsMarkers.length);
    clusterer.removeMarkers(outBoundsMarkers);
    
    const additionalMarkers = remainMarkers.filter((marker) => {
      return marker.getVisible() && bounds.contains(marker.getPosition());
    });
    console.log('additional Markers:', additionalMarkers.length);
    clusterer.addMarkers(additionalMarkers);
    */
  }, 100);
  
  map.addListener('dragend', updateCluster);
  map.addListener('zoom_changed', updateCluster);
  updateCluster();
}

initMap();