[FAQ] 지도/로컬 API 문의 전 꼭 읽어 주세요.
https://devtalk.kakao.com/t/faq-api/125610
안녕하세요 담당자님
저는 현재 Next.js에서 카카오맵을 사용하고 있습니다.
현재 프로젝트에서 Marker대신 CustomOverlay를 사용하여 해당 위치에 있는 장소의 정보(이름, 인원 수)를 제공하고 있습니다.
그리고 클러스터 안에 있는 CustomOverlay들의 인원 수 합을 계산하여 클러스터에 삽입하려고 합니다. (하단 예시 이미지 참조)
이전에는 Marker의 title에 값을 주어 ‘clustered’ 이벤트가 발생했을 때 getMarkers() 메소드의 getTitle() 을 사용하여 리턴값을 innerHTML로 삽입시켰습니다.
그런데 CustomOverlay로 변경하면서 title값을 사용할 수 없게 되어서 위 이미지와 같이 클러스터에 기본값으로 설정한 0명으로 표기되고 있습니다.
아래는 현재 제 코드입니다.
CustomOverlay
const [customMarkers, setCustomMarkers] = useState<kakao.maps.CustomOverlay[]>([]);
setCustomMarkers(csMarker => [...csMarker, new kakao.maps.CustomOverlay({
content: `
<div style="display: flex; flex-direction: column; align-items: center; width: max-content; height: 52px;">
<div style="position: relative; display: flex; justify-content: center; align-items: center; padding: 8px; gap: 8px; height: 44px; background-color: var(--gray50); border-radius: 8px; box-shadow: 1px 4px 8px 2px rgba(51, 51, 51, 0.12), 2px 3px 16px 1px rgba(221, 221, 221, 0.08), 2px 3px 6px 3px rgba(230, 230, 230, 0.16);">
<img src="/images/${distanceSort[i].groupType === "기업" ? "icon_company.png" : "icon_university.png"}" alt=${distanceSort[i].groupType === "기업" ? "기업 아이콘 이미지" : "학교 아이콘 이미지"} style="width: 24px; height: 24px; border-radius: 50%;">
<div>
<p class="c1" style="width: fit-content; color: var(--gray900);">${distanceSort[i].name}</p>
<p class="c2" style="width: fit-content; color: var(--gray700);">${formatNumber(distanceSort[i].people)}명</p>
</div>
<div style="position: absolute; width: 12px; height: 10px; left: 50%; bottom: -8px; background-color: var(--gray50); transform: rotate(45deg) translateX(-50%);"></div>
</div>
</div>
`,
position: new kakao.maps.LatLng(distanceSort[i].lat, distanceSort[i].lng),
yAnchor: 1
})]);
Cluster
setCluster(new kakao.maps.MarkerClusterer({
map,
markers: customMarkers,
averageCenter: true,
gridSize: 120,
minLevel: 2,
clickable: false,
hoverable: false,
texts: function (count: number): string {
if (defaultTM128.mapx !== 285639 && defaultTM128.mapy !== 540107) {
return `
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; border-radius: 50%; background-color: var(--gray0); width: 100%; height: 100%;">
<div style="width: 88px; font-size: 16px; font-weight: 600; color: var(--gray800); text-align: center;">0명</div>
<div style="width: 88px; font-size: 14px; color: var(--gray500); text-align: center;">단체 ${count}개</div>
</div>
`;
} else {
return `
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; border-radius: 50%; background-color: var(--gray0); width: 100%; height: 100%;">
<div style="width: 88px; font-size: 16px; font-weight: 600; color: var(--gray800); text-align: center;">???명</div>
<div style="width: 88px; font-size: 14px; color: var(--gray500); text-align: center;">단체 ???개</div>
</div>
`;
}
},
styles: [
{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '120px',
height: '120px',
background: "radial-gradient(101.47% 101.47% at 27.21% 6.25%, rgba(13, 255, 255, 0.7) 0%, rgba(177, 10, 255, 0.28) 100%)",
boxShadow: "1px 4px 8px 2px rgba(51, 51, 51, 0.12), 2px 3px 16px 1px rgba(221, 221, 221, 0.08), 2px 3px 6px 3px rgba(230, 230, 230, 0.16)",
borderRadius: '50%',
padding: "14px",
textAlign: 'center'
}
]
}))
Cluster Event
const [cluster, setCluster] = useState<kakao.maps.MarkerClusterer>();
useEffect(() => {
if (cluster) {
kakao.maps.event.addListener(cluster, "clustered", function (clusters: kakao.maps.Cluster[]) {
try {
for (let i = 0; i < clusters.length; i++) {
const cls = clusters[i];
const overlay = cls.getClusterMarker().getContent();
const getMarker = cls.getMarkers();
// 현재 동작하지 않음 getTItle에러
const total = getMarker.reduce((prev, curr) => prev + Number(curr.getTitle().split(": ")[1].replace("명", "")), 0)
if (typeof overlay !== "string") {
overlay.firstElementChild!.firstElementChild!.innerHTML = `${total}명`
}
}
} catch (error) {
console.error(error);
}
});
};
}, [cluster, defaultTM128]);
이에 대해서 두 가지의 질문이 있습니다.
-
현재 getMarkers()를 했을 때 CustomOverlay를 사용 중이니 당연히 getTitle()을 하면 오류가 발생합니다. CustomOverlay에서는 특정 값을 호출할 수 있는 방법이 아예 없는 건가요?
-
해당 문제를 해결하기 위해 다른 방법을 생각하다가 Marker와 CustomOverlay를 동시에 사용하고 Marker의 opacity를 낮추어 Marker가 존재는 하되 화면에 보이지 않게 하려고 했습니다. 그런데 문제는 동시에 적용이 안되는 것입니다. CustomOverlay가 클러스터링 되지 않아 모든 장소의 정보가 나타나게 됩니다. Marker와 CustomOverlay를 동시에 cluster에서 사용할 수 있는 방법이 있나요?