마커 클러스터링

대량 마커를 클러스터링하여 지도에 표시하는 예제입니다. react-naver-maps 컴포넌트 대신 imperative API를 직접 사용하는 escape hatch 패턴을 보여줍니다.

네이버 공식 예제 - 마커 클러스터링

코드 보기
import { useEffect, useRef } from 'react';
import {
  NavermapsProvider,
  Container as MapDiv,
  NaverMap,
  useMap,
  useNavermaps,
} from 'react-naver-maps';
import { makeMarkerClustering } from '../samples/marker-cluster';
import { accidentDeath } from '../samples/accident-death';

function ClusterMap() {
  const navermaps = useNavermaps();
  const map = useMap();
  const clusterRef = useRef<any>(null);

  useEffect(() => {
    const MarkerClustering = makeMarkerClustering(window.naver);
    const data = accidentDeath.searchResult.accidentDeath;
    const markers = data.map((d: any) => {
      return new navermaps.Marker({
        position: new navermaps.LatLng(
          parseFloat(d.grd_la),
          parseFloat(d.grd_lo),
        ),
      });
    });

    const htmlMarker1 = {
      content:
        '<div style="cursor:pointer;width:40px;height:40px;line-height:42px;font-size:10px;color:white;text-align:center;font-weight:bold;background:url(https://navermaps.github.io/maps.js.ncp/docs/img/cluster-marker-1.png);background-size:contain;"></div>',
      size: new navermaps.Size(40, 40),
      anchor: new navermaps.Point(20, 20),
    };
    const htmlMarker2 = {
      content:
        '<div style="cursor:pointer;width:40px;height:40px;line-height:42px;font-size:10px;color:white;text-align:center;font-weight:bold;background:url(https://navermaps.github.io/maps.js.ncp/docs/img/cluster-marker-2.png);background-size:contain;"></div>',
      size: new navermaps.Size(40, 40),
      anchor: new navermaps.Point(20, 20),
    };
    const htmlMarker3 = {
      content:
        '<div style="cursor:pointer;width:40px;height:40px;line-height:42px;font-size:10px;color:white;text-align:center;font-weight:bold;background:url(https://navermaps.github.io/maps.js.ncp/docs/img/cluster-marker-3.png);background-size:contain;"></div>',
      size: new navermaps.Size(40, 40),
      anchor: new navermaps.Point(20, 20),
    };
    const htmlMarker4 = {
      content:
        '<div style="cursor:pointer;width:40px;height:40px;line-height:42px;font-size:10px;color:white;text-align:center;font-weight:bold;background:url(https://navermaps.github.io/maps.js.ncp/docs/img/cluster-marker-4.png);background-size:contain;"></div>',
      size: new navermaps.Size(40, 40),
      anchor: new navermaps.Point(20, 20),
    };
    const htmlMarker5 = {
      content:
        '<div style="cursor:pointer;width:40px;height:40px;line-height:42px;font-size:10px;color:white;text-align:center;font-weight:bold;background:url(https://navermaps.github.io/maps.js.ncp/docs/img/cluster-marker-5.png);background-size:contain;"></div>',
      size: new navermaps.Size(40, 40),
      anchor: new navermaps.Point(20, 20),
    };

    clusterRef.current = new MarkerClustering({
      minClusterSize: 2,
      maxZoom: 13,
      map: map,
      markers: markers,
      disableClickZoom: false,
      gridSize: 120,
      icons: [htmlMarker1, htmlMarker2, htmlMarker3, htmlMarker4, htmlMarker5],
      indexGenerator: [10, 100, 200, 500, 1000],
      stylingFunction: (clusterMarker: any, count: number) => {
        clusterMarker.getElement().querySelector('div').textContent =
          count.toString();
      },
    });

    return () => {
      if (clusterRef.current) {
        clusterRef.current.setMap(null);
      }
    };
  }, [map, navermaps]);

  return null;
}

function ClusterMapContent() {
  const navermaps = useNavermaps();

  return (
    <NaverMap
      defaultCenter={new navermaps.LatLng(36.2253017, 127.6460516)}
      defaultZoom={6}
    >
      <ClusterMap />
    </NaverMap>
  );
}

function ClusterMapContainer() {
  return (
    <MapDiv style={{ width: '100%', height: '600px' }}>
      <ClusterMapContent />
    </MapDiv>
  );
}

export default function MarkerClusterExample() {
  return (
    <NavermapsProvider ncpKeyId="aluya4ff04">
      <ClusterMapContainer />
    </NavermapsProvider>
  );
}

설명

useMap() 훅으로 map 인스턴스를 가져와 useEffect 내에서 네이버맵의 MarkerClustering 유틸리티를 직접 생성합니다. 컴포넌트로 감싸지 않는 imperative 사용은 서드파티 유틸이나 고급 사용 시에 활용할 수 있습니다.