언어·프레임워크/React.js

[React.js] 네이버 지도 API 마커 클러스터 튜터리얼 따라하기!

DandyNow 2024. 2. 21. 16:52
728x90
반응형

[그림 1] 마커 클러스터 적용 결과

 

1. 네이버 지도 API 설치

npm install react-naver-maps --save

 

2. App.js에 NavermapsProvider 적용

NavermapsProvider의 경우-이 글을 작성하는 시점에-공식 문서에는 NaverMapsProvider로 되어 있었고 따라서 로딩 에러가 발생했다. 따라서 NavermapsProvider라고 import 해야 한다.

// src/App.js
import { NavermapsProvider } from "react-naver-maps";
import NaverMapsMarkerCluster from "./components/NaverMapsMarkerCluster";

function App() {
  // ncpClientId에 네이버 지도 API 클라이언트 키를 넣으면 된다.
  // npx create-react-app으로 프로젝트를 생성했다면-별도의 의존성 설치 없이-프로젝트 최상위 폴더에 .env 파일을 생성하고 키를 기입하면 된다.
  // .env에는 REACT_APP_NAVER_KEY의 값으로 키를 기입하면 되는데, REACT_APP_라는 prefix에 유의 하자!
  const naverKey = process.env.REACT_APP_NAVER_KEY;

  return (
    <NavermapsProvider
      ncpClientId={naverKey} // 지도서비스 Client ID
      error={<p>error</p>}
      loading={<p>Maps Loading</p>}
    >
      <div style={{ display: "flex", width: "100dvw", height: "100dvh" }}>
        <NaverMapsMarkerCluster />
      </div>
    </NavermapsProvider>
  );
}

export default App;

 

3. 마커 클러스터 기능을 포함한 지도 컴포넌트 작성

// src/components/NaverMapsMarkerCluster.js

import {
  Container as MapDiv,
  NaverMap,
  useNavermaps,
  Overlay,
  useMap,
} from "react-naver-maps";
import { useState } from "react";
import { makeMarkerClustering } from "./marker-cluster";
import { accidentDeath } from "./data/accidentdeath.js";

function MarkerCluster() {
  const navermaps = useNavermaps();
  const map = useMap();

  // 아래 링크에서 marker-cluster.js를 다운로드한 후 이 컴포넌트와 동일 경로에 두고 import 하였다.
  // https://github.com/zeakd/react-naver-maps/blob/main/website/src/samples/marker-cluster.js
  const MarkerClustering = makeMarkerClustering(window.naver);

  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),
  };
  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: navermaps.Size(40, 40),
    anchor: 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: navermaps.Size(40, 40),
    anchor: 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: navermaps.Size(40, 40),
    anchor: 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: navermaps.Size(40, 40), // naver.maps를 navermaps로 수정
    anchor: navermaps.Point(20, 20), // (상동)
  };

  // 아래 링크에서 데이터가 든 js 파일 다운로드
  // https://github.com/navermaps/marker-tools.js/blob/master/marker-clustering/data/accidentdeath.js
  const data = accidentDeath.searchResult.accidentDeath;

  console.log(data);

  const [cluster] = useState(() => {
    const markers = [];

    for (var i = 0, ii = data.length; i < ii; i++) {
      var spot = data[i],
        latlng = new navermaps.LatLng(spot.grd_la, spot.grd_lo),
        marker = new navermaps.Marker({
          position: latlng,
          draggable: true,
        });

      markers.push(marker);
    }

    const cluster = new MarkerClustering({
      minClusterSize: 2,
      maxZoom: 8,
      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;
      },
    });

    return cluster;
  });

  return <Overlay element={cluster} />;
}

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

  return (
    <MapDiv
      style={{
        width: "100%",
        height: "100%",
      }}
    >
      <NaverMap
        zoom={6}
        center={new navermaps.LatLng(36.2253017, 127.6460516)}
        zoomControl={true}
        zoomControlOptions={{
          position: navermaps.Position.TOP_LEFT,
          style: navermaps.ZoomControlStyle.SMALL,
        }}
      >
        <MarkerCluster />
      </NaverMap>
    </MapDiv>
  );
}

export default NaverMapsMarkerCluster;

 

 

4. 위경도 데이터 추가

아래 코드는 위경도 데이터가 포함된 js 파일이다. navermaps 깃허브 링크를 통해 다운로드하면 된다.

// src/components/data/accidentdeath.js

// 다른 컴포넌트에서 import하기 위해 export 키워드 추가
export var accidentDeath = {
// (생략)
// 데이터가 너무 크면 렌더링 부담이 컸으므로 데이터를 일부 제거하고 테스트 해보는 것을 권한다.
}

😉 깃허브 링크 : https://github.com/navermaps/marker-tools.js/blob/master/marker-clustering/data/accidentdeath.js

 

📌 튜터리얼 진행 중 이슈

1) 'babel-parser', '.eslintrc' 관련  

[eslint] Failed to load parser 'babel-parser' declared in '.eslintrc': Cannot find module 'babel-parser'

위 와 같은 에러가 발생했고 아래와 같이 의존성 설치하여 해결했다.

npm install eslint @babel/core @babel/eslint-parser --save-dev
출처 : https://www.appsloveworld.com/reactjs/100/29/error-failed-to-load-parser-babel-eslint-parser-declared-in-eslintrc-js-c

 

2) 브라우저 렌더링 버벅거림

accidentdeath.js의 위경도 데이터가 너무 많아서 렌더링이 너무 오래 걸리거나 클릭, 스크롤 등 이벤트 발생 시 멈춰 버리기도 했다. 그래서 accidentdeath.js 코드를 약 5000줄 정도로 대폭 줄여 버렸다.

 

📌 공식 문서

아래 공식 문서와 공식 문서에 안내된 깃허브 자료를 활용하면 쉽게 따라 해 볼 수 있는데, marker-cluster.js와 위경도 데이터가 들어 있는 accidentdeath.js는 깃허브에서 찾으면 된다.

728x90
반응형