이번 프로젝트 주제로 부동산관련 웹서비스를 만들기로 결정을 하면서, 지도 구현이 필요하였고 그 부분을 내가 맡게 되었다. 네이버맵과 카카오맵 중 어떤것으로 할 까 고민하다 조금도 레퍼런스가 많은 카카오맵으로 선택을 하게되었다.
먼저 https://apis.map.kakao.com 에 들어가서 API키를 발급받았다.
이 부분이 생각보다 수훨히 진행되지 않았다. next.js를 처음 사용하면서 next.js 문법을 사용하고 싶었는데, script를 불러오기전에 kakao 코드들이 실행이되면서 에러가 계속 났다. 그리하여 다른 블로그를 찾아보고 아래 코드와 같이 useEffect
와 useState
를 사용하여 로드를 해주었다.
const [mapLoaded, setMapLoaded] = useState<boolean>(false);
useEffect(() => {
const $script = document.createElement("script");
$script.async = true;
$script.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_CLIENT_ID}&autoload=false&libraries=services,clusterer,drawing`;
$script.addEventListener("load", () => setMapLoaded(true));
document.head.appendChild($script);
}, []);
useEffect(() => {
if (!mapLoaded) return;
kakao.maps.load(() => {
const container = document.getElementById("map") as HTMLElement;
const options = {
center: new kakao.maps.LatLng(37.555078, 126.970702),
level: 8,
};
kakaoMap.current = new kakao.maps.Map(container, options);
const zoomControl = new kakao.maps.ZoomControl();
kakaoMap.current.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);
kakao.maps.event.addListener(kakaoMap.current, "idle", setCoodinate);
setLoadMap(true);
});
}, [mapLoaded]);
첫번째 useEffect
에서 script를 불러온 다음 setMapLoadaed
를 true처리를 해주었고 mapLoad
가 true가 되면 두 번째 useEffect
에서 map을 불러오는 함수를 실행시킨다.
또한 지도의 좌표가 바뀔때마다 그 위치의 매물 정보를 불러오기 위해 kakao.maps.event.addListener(kakaoMap.current, "idle", setCoodinate)
로 setCoordinate
함수를 실행시켰다.
10.17.22
pages 폴더안에 _document 파일을 만들고 여기서 script를 import 하면 간편히 해결 가능하다.
https://apis.map.kakao.com/web/sample/addClustererClickEvent/ 설명을 참고하며 구현을 하였습니다.
지도위에 부동산 매물 갯수를 보여줘야하므로 클러스터를 구현하였다.
처음에는 cluster
변수를 createmakres
함수안에 넣어줬었는데, 이렇게 되버리니 createmakers 함수가 실행이 될 때 마다 클러스터가 중복으로 새롭게 생성되는 현상이 발생되었다. 그런 이유 때문에 useRef
를 사용하여 cluster
변수를 최상단에서 만들어주었다.
갯수마다 클러스터의 스타일을 다르게 해주기위해 calculator
와 styles
코드를 구현하였다.
const cluster = useRef<kakao.maps.MarkerClusterer>();
const createmakers = (sale: House[]) => {
const markers = sale.map(
(item) =>
new kakao.maps.Marker({
position: new kakao.maps.LatLng(item.latitude, item.longitude),
}),
);
if (cluster.current !== undefined && cluster !== undefined) {
cluster.current.setMinClusterSize(1);
cluster.current.clear();
cluster.current.addMarkers(markers);
}
};
useEffect(() => {
if (!loadMap) return;
cluster.current = new kakao.maps.MarkerClusterer({
map: kakaoMap.current,
averageCenter: true,
calculator: [10, 30, 100, 1000],
styles: [
{
background: "rgba(255, 80, 80, .8)",
width: "3rem",
height: "3rem",
color: "#fff",
borderRadius: "3rem",
textAlign: "center",
lineHeight: "3.3rem",
fontSize: "1.5rem",
},
{
background: "rgba(255, 80, 80, .8)",
width: "3.5rem",
height: "3.5rem",
color: "#fff",
borderRadius: "3rem",
textAlign: "center",
lineHeight: "4.1rem",
fontSize: "2rem",
},
{
background: "rgba(255, 80, 80, .8)",
width: "5rem",
height: "5rem",
color: "#fff",
borderRadius: "3rem",
textAlign: "center",
lineHeight: "5rem",
fontSize: "2rem",
},
{
background: "rgba(255, 80, 80, .8)",
width: "6rem",
height: "6rem",
color: "#fff",
borderRadius: "3rem",
textAlign: "center",
lineHeight: "6rem",
fontSize: "2rem",
},
],
});
getSaleList();
}, [loadMap]);
타입스크립트를 사용했기 때문에 처음에 type error가 났었다. 다른곳에서는 global interface를 선언하여 사용을 하는것을 봤는데, 처음에 그렇게 했다가 찾아보니 감사하게도 카카오맵 타입정의를 만드신분이 계셨다.
https://github.com/JaeSeoKim/kakao.maps.d.ts 여기서 설치를 한뒤 내가 필요한 부분만 조금 변경을 하여 사용하였다.