[NextJS] Naver Map Clustering
2023. 11. 30. 13:43ㆍNextJS
준비물 : 네이버 맵 사용을 위한 클라이언트 ID
풀코드는 아래와 같음.
import React, { useEffect, useRef } from 'react'
import { NaverMaps, ClusteringMapProps } from '../types/naverMaps'
import authConfig from 'src/configs/auth'
// shopList (상점 목록)과 onShopSelect (상점 선택시 호출할 함수) 두 개의 prop을 받음
const NaverMapMarketClustering = ({ shopList, onShopSelect }: ClusteringMapProps) => {
// useRef를 사용하여 지도를 표시할 DOM 요소의 참조(mapRef)를 생성
const mapRef = useRef(null)
// 동적으로 외부 스크립트를 로드하는 loadScript 함수를 정의
// 스크립트 URL(src)과 로드 완료시 호출할 콜백 함수(callback)를 매개변수로 받음
const loadScript = (src: any, callback: any) => {
// 이미 로드된 스크립트인지 확인하여 중복 로드를 방지
if (document.querySelector(`script[src="${src}"]`)) {
callback()
return
}
const script = document.createElement('script')
script.src = src
script.async = true
script.onload = () => {
if (callback) callback()
}
script.onerror = () => {
console.error(`Script load error for ${src}`)
}
document.head.appendChild(script)
}
// 스크립트 로드가 완료되면 지도를 초기화하고 상점 마커를 추가
const initializeMapAndMarkers = async (navermaps: NaverMaps) => {
let map: any
// 네이버 지도 인스턴스를 생성하고, shopList를 이용하여 각 상점 위치에 마커를 추가
if (mapRef.current) {
map = new navermaps.Map(mapRef.current, {
center: new navermaps.LatLng(36, 128),
zoom: 7,
mapTypeControl: false,
mapDataControl: false,
logoControl: false,
scaleControl: false,
zoomControl: true,
zoomControlOptions: {
position: navermaps.Position.TOP_RIGHT,
style: navermaps.ZoomControlStyle.SMALL
}
})
}
if (shopList) {
const markers = shopList.map((shop: any) => {
const position = new navermaps.LatLng(shop.si_branch_latiitude, shop.si_branch_longitude)
const imageUrl = `${authConfig.imageEndpoint}${shop.si_company_image_logo}`
const marker = new navermaps.Marker({
position,
map,
title: shop.si_shop_name,
icon: {
content: `<img src="${imageUrl}" alt="${shop.si_shop_name}" style="width: 40px; height: 40px; object-fit: contain;">`,
size: new navermaps.Size(40, 40),
anchor: new navermaps.Point(20, 20)
}
})
// 마커 클릭 이벤트에 displayShopInfo 함수를 연결하여 상점 정보를 표시
navermaps.Event.addListener(marker, 'click', () => {
displayShopInfo(shop)
})
return marker
})
function displayShopInfo(shop: any) {
onShopSelect({
shopName: shop.si_company_name,
shopAddress: shop.si_company_address_1 + ' ' + shop.si_company_address_2,
image: shop.si_company_image_main_1
})
}
var 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(${authConfig.frontEndpoint}/images/image/cluster-marker-1.png);background-size:contain;"></div>`,
size: new navermaps.Size(40, 40),
anchor: new navermaps.Point(20, 20)
},
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(${authConfig.frontEndpoint}/images/image/cluster-marker-2.png);background-size:contain;"></div>`,
size: new navermaps.Size(40, 40),
anchor: new navermaps.Point(20, 20)
},
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(${authConfig.frontEndpoint}/images/image/cluster-marker-1.png);background-size:contain;"></div>`,
size: new navermaps.Size(40, 40),
anchor: new navermaps.Point(20, 20)
},
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(${authConfig.frontEndpoint}/images/image/cluster-marker-2.png);background-size:contain;"></div>`,
size: new navermaps.Size(40, 40),
anchor: new navermaps.Point(20, 20)
},
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(${authConfig.frontEndpoint}/images/image/cluster-marker-1.png);background-size:contain;"></div>`,
size: new navermaps.Size(40, 40),
anchor: new navermaps.Point(20, 20)
}
// @ts-ignore
// Cannot find name 'MarkerClustering'. Did you mean 'markerClustering'? 에러 회피
const markerClustering = 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: (clusterMarker: any, count: number) => {
clusterMarker.getElement().querySelector('div:first-child').textContent = count
}
})
}
}
// 컴포넌트가 마운트될 때 네이버 지도 API 스크립트와 마커 클러스터링 스크립트를 로드
useEffect(() => {
loadScript(
`https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${authConfig.naverMapCliendId}&submodules=geocoder,panorama`,
() => {
if (window.naver && window.naver.maps) {
loadScript('/scripts/MarkerClustering.js', () => {
initializeMapAndMarkers(window.naver.maps)
})
}
}
)
}, [shopList])
return <div ref={mapRef} style={{ width: '100%', height: '400px', marginBottom: 15 }} />
}
export default NaverMapMarketClustering
참조 문서 : https://navermaps.github.io/maps.js.ncp/docs/tutorial-marker-cluster.example.html
github : https://github.com/navermaps/marker-tools.js/tree/master/marker-clustering
'NextJS' 카테고리의 다른 글
[NextJS] Google map 사용 (1) | 2023.11.09 |
---|---|
[NextJS] dynamic (0) | 2023.08.03 |
[NextJS] 빌드 디렉토리 구조 (0) | 2023.08.01 |
[NextJS] getInitialProps 사용법 (0) | 2022.08.30 |