다음 토이프로젝트의 개발 기록이다.
Kakao 지도 API, react-kakao-maps-sdk를 사용하였다.
화면 위에 네이버나 카카오 지도를 렌더링하고 싶었다. 고맙게도 네이버, 카카오에서 자기네들의 지도를 활용할 수 있게 API를 제공해주고 있었다.
DOM에 직접 접근해서 세팅하는 방법과 SDK를 사용해서 간단하게 세팅하는 방법 두 가지가 존재하는데, 각각 어떻게 세팅하면 되는지 간단하게 서술하고자 한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Kakao 지도 시작하기</title>
</head>
<body>
<div id="map" style="width:500px;height:400px;"></div>
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY를 넣으시면 됩니다."></script>
<script>
var container = document.getElementById('map');
var options = {
center: new kakao.maps.LatLng(33.450701, 126.570667),
level: 3
};
var map = new kakao.maps.Map(container, options);
</script>
</body>
</html>
Tutorial | react-kakao-maps-sdk docs
import { useKakaoLoader as useKakaoLoaderOrigin } from "react-kakao-maps-sdk";
export default function useKakaoLoader() {
useKakaoLoaderOrigin({
appkey: import.meta.env.VITE_KAKAO_APP_KEY as string,
libraries: ["clusterer", "drawing", "services"],
});
}
import { Map } from "react-kakao-maps-sdk";
import useKakaoLoader from "@src/useKakaoLoader";
const KaKaoMap = () => {
useKakaoLoader();
return (
<Map
center={{ lat: 33.5563, lng: 126.79581 }}
style={{ width: "800px", height: "600px" }}
level={3}
/>
);
};
export default KaKaoMap;
react sdk를 세팅한 환경에서 진행했다.
검색어로 검색 & 마커 띄우기 & 마커 정보 기반으로 DIV 만들어서 상호작용을 해보는 예제이다.
다음 사진과 같은 결과를 렌더링하게 된다.
import { useState, useRef, useEffect } from "react";
import { Map, MapMarker } from "react-kakao-maps-sdk";
import useKakaoLoader from "@src/useKakaoLoader";
import { getKakaoLocal } from "@src/API";
import Form from "react-bootstrap/Form";
import styled from "styled-components";
interface MarkerType {
position: {
lat: number;
lng: number;
};
content: string;
}
const KaKaoMap = () => {
useKakaoLoader();
const [map, setMap] = useState<kakao.maps.Map | null>(null);
const [info, setInfo]: any = useState();
const [markers, setMarkers] = useState<MarkerType[]>([]);
const [mapLevel, setMapLevel] = useState<number>(3);
const mapRef = useRef<kakao.maps.Map>(null);
const [address, setAddress] = useState<string>("");
const handleInput = (e: any) => {
if (e.key === "Enter") e.preventDefault();
setAddress(e.target.value);
};
const insertAddress = () => {
searchPlaces(address);
setAddress("");
};
const getInfo = () => {
const map = mapRef.current;
if (!map) return;
const center = map.getCenter();
console.log("map info ", center);
};
const overMarkerPos = (marker: MarkerType) => {
if (!map) return;
// 맵 레벨 제어
const position = marker.position;
map.setLevel(2);
setMapLevel(map.getLevel());
map.panTo(new kakao.maps.LatLng(position.lat, position.lng));
// region_2depth_name 를 기준으로 검색
// 스페이스 바 사이의 공백 제거 필요
};
const onClickMarker = async (marker: MarkerType) => {
if (!map) return;
const position = marker.position;
const result = await getKakaoLocal.getKakaoSearchCoord(
position.lng,
position.lat
);
};
const searchPlaces = (keyword: string) => {
if (!map) return;
const ps = new kakao.maps.services.Places();
ps.keywordSearch(
keyword,
(data, status, _pagination) => {
if (status === kakao.maps.services.Status.OK) {
// 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해
// LatLngBounds 객체에 좌표를 추가합니다
const bounds = new kakao.maps.LatLngBounds();
const markers: MarkerType[] = [];
console.log("data ", data);
for (let i = 0; i < data.length; i++) {
// @ts-ignore
markers.push({
position: {
lat: Number(data[i].y),
lng: Number(data[i].x),
},
content: data[i].place_name,
});
// @ts-ignore
bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
}
setMarkers([...markers]);
// 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
map.setBounds(bounds);
console.log("마커 : ", markers);
} else {
console.log("검색 결과가 없습니다.");
}
},
{ page: 5 }
);
};
return (
<>
<Form>
<Form.Control
size="lg"
type="text"
placeholder="주소 입력"
value={address}
onChange={handleInput}
onKeyDown={handleInput} // Handle key down event
/>
</Form>
<button onClick={insertAddress}>확인</button>
<Map
center={{
lat: 37.566826,
lng: 126.9786567,
}}
style={{ width: "800px", height: "600px" }}
level={mapLevel}
ref={mapRef}
onCreate={setMap}
>
{markers.map((marker: MarkerType) => (
<MapMarker position={marker.position} onClick={() => setInfo(marker)}>
{info && info.content === marker.content && (
<div>{marker.content}</div>
)}
</MapMarker>
))}
</Map>
{markers.length > 0 && (
<MarkersContainer>
{markers.map((marker: MarkerType, index: number) => (
<div
key={index}
onMouseOver={() => overMarkerPos(marker)}
onClick={() => onClickMarker(marker)}
>
{marker.content}
</div>
))}
</MarkersContainer>
)}
<button id="getInfoBtn" onClick={getInfo}>
맵정보 가져오기
</button>
</>
);
};
export default KaKaoMap;
const MarkersContainer = styled.div`
display: flex;
flex-direction: column;
div {
cursor: pointer;
padding: 5px;
border: 1px solid black;
}
`;