Next.js 환경에서 네이버 맵을 이용하여 구현하고 있었는데,
마커들이 일정 이상 겹치면 합쳐서 보일 수 있게 클러스터링 기능 추가 요청사항을 받았다.
마커 클러스터링 기능을 프로젝트에 바로 구현하기 전, 먼저 문서를 따라 예시를 구현해보았다.
"next": "13.1.2",
"react": "18.2.0",
"react-naver-maps": "^0.1.2",
"typescript": "4.9.4",
react-naver-maps 라이브러리 문서에서
'마커 클러스터화하기' 문서를 참고하여 따라가 보았다.
MarkerClustering.js
을 로컬에 복사 붙여넣기const MarkerClustering = makeMarkerClustering(window.naver);
문서 예시를 보면 위와 같은 코드가 존재하는데, makeMarkerClustering
함수를 불러오기 위해 MarkerClustering.js
파일이 필요하다.
이 MarkerClustering.js
파일은 아래 링크에서 가져오면 된다.
MarkerClustering.js
문서에서 아래의 htmlMarker
들은 클러스터링 아이콘을 생성하는 부분이다.
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: navermaps.Size(40, 40),
anchor: navermaps.Point(20, 20),
}
...
나는 한 컴포넌트에서 마커를 생성해주는 것 까지 있으면 너무 복잡할 것 이라고 생각해서,
custom hook을 만들어 분리하였다.
navermaps
객체를 가지고 만들어주어야 해서 hook을 만들어서 분리하였다.
useGetClusterIcon
사용
const { htmlMarker1, htmlMarker2, htmlMarker3, htmlMarker4, htmlMarker5 } =
useGetClusterIcon(navermaps);
useGetClusterIcon
구현
const useGetClusterIcon = (navermaps: typeof naver.maps) => {
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: navermaps.Size(40, 40),
anchor: navermaps.Point(20, 20),
}
...
return { htmlMarker1, htmlMarker2, htmlMarker3, htmlMarker4, htmlMarker5 };
};
const markers = []
for (var i = 0, ii = data.length; i < ii; i++) {
var spot = data[i],
latlng = new naver.maps.LatLng(spot.grd_la, spot.grd_lo),
marker = new naver.maps.Marker({
position: latlng, // 마커의 위치
draggable: true, // 마커 이동 가능하게
})
markers.push(marker)
}
const cluster = new MarkerClustering({
minClusterSize: 2,
maxZoom: 8, // 조절하면 클러스터링이 되는 기준이 달라짐 (map zoom level)
map: map,
markers: markers, // 클러스터화 할 마커들
disableClickZoom: false,
gridSize: 120,
icons: [ // 클러스터 아이콘 세팅
htmlMarker1,
htmlMarker2,
htmlMarker3,
htmlMarker4,
htmlMarker5,
],
indexGenerator: [10, 100, 200, 500, 1000], // 클러스터링 기준 세팅
stylingFunction: function (clusterMarker, count) {
clusterMarker
.getElement()
.querySelector('div:first-child').innerText = count
},
})
클러스트 객체를 state로 관리하는 이유는, 클러스트 마커를 한번만 생성하기 위해서이다.
참고 링크
위에서 생성한 마커 리스트 markers
와 cluster
객체를 이용하여 cluster
state를 생성한다.
const [cluster] = useState(() => {
const markers = []
// ... 마커 생성
const cluster = new MarkerClustering({
...
})
return cluster
})
return <Overlay element={cluster} />
마커 클러스터링 기능을 구현하는데 필요한 파일을 다운받고,
실제로 프로젝트에서 실행해보았다.
예제에서는 마커를 생성하고, 클러스터링 하는 방법을 보여주었다.
예제를 프로젝트에 구현해보면서 예제가 마커 클러스터링을 어떻게 구현하고 있는지 알아 낼 수 있었다.
요구사항을 충족 하려면, 이미 생성되어 있는 커스텀 마커를 클러스터링 해야하기 때문에
이미 생성되어있는 마커를 props로 넘기고, 클러스터링 하는 법을 찾아보았다.
다음 글 =>