-
Notifications
You must be signed in to change notification settings - Fork 4
[페이지별] 교통 정보
minjee edited this page Sep 23, 2023
·
30 revisions
카카오 맵 API를 불러옵니다.
useEffect(() => {
if (window.kakao && window.kakao.maps) {
const container = document.getElementById('mapContainer');
const options = {
center: new window.kakao.maps.LatLng(33.5068, 126.4929),
level: 5,
};
const map = new window.kakao.maps.Map(container, options);
}
}, []);
useEffect 훅을 사용하여 컴포넌트가 마운트될 때 카카오 맵을 초기화하고 렌더링합니다.
- 초기 중심 좌표로 위도 33.5068, 경도 126.4929(제주 공항)를 설정하여 사용자가 페이지에 처음 접속했을 때 제주 공항이 보이도록 했습니다.
mapRef.current = map;
map.addOverlayMapTypeId(window.kakao.maps.MapTypeId.TRAFFIC);
const zoomControl = new window.kakao.maps.ZoomControl();
map.addControl(zoomControl, window.kakao.maps.ControlPosition.RIGHT);
useEffect 안에 추가되어 교통 정보를 표시하고, 사용자가 지도의 확대/축소를 조절할 수 있는 컨트롤을 제공합니다.
- map.addOverlayMapTypeId(...): 지도 위에 교통 정보(예: 도로 상황)를 표시하는 데 사용됩니다.
- const zoomControl ...: 이 두 줄의 코드는 화면 오른쪽에 위치한 확대/축소 컨트롤을 생성하고, 그것을 지도에 추가합니다.
검색어를 입력하면 결과를 출력하고 Input을 초기화합니다.
function searchPlaces() {
if (!window.kakao || !window.kakao.maps || !mapRef.current) return;
const places = new window.kakao.maps.services.Places();
places.keywordSearch(keyword, function (result, status) {
removeMarkers();
let tempMarkers = [];
if (status === window.kakao.maps.services.Status.OK) {
for (let i = 0; i < result.length; i++) {
let markerInfo = displayMarker(result[i]);
tempMarkers.push(markerInfo);
}
setMarkers(tempMarkers);
mapRef.current.setLevel(8);
}
});
setKeyword('');
사용자가 입력한 키워드를 바탕으로 장소를 검색하고, 그 결과를 처리합니다.
- window.kakao.maps.services.Places()를 이용하여 Places 객체를 생성합니다. 그리고 해당 객체의 keywordSearch 메서드를 호출하여 키워드에 대한 검색을 수행합니다.
- 검색 결과는 콜백 함수 내부에서 처리되며, 여기서 기존 마커들을 제거하고 새로운 마커들을 생성하여 지도 위에 표시하고 줌 레벨을 조정합니다.
- setKeyword('')에서 입력 필드를 초기화하여 다음 검색 준비를 합니다.
<div className="absolute top-5 left-5 flex gap-2 z-10">
<input
type="text"
value={keyword}
className="w-[25vw] px-5 py-3 border-[3px] border-white rounded-lg"
placeholder="장소 검색"
onChange={(e) => setKeyword(e.target.value)}
onKeyPress={handleKeyPress}
/>
<button
className="w-[5vw] bg-blue text-white border-0 rounded-lg"
onClick={searchPlaces}
>
검색
</button>
</div>
버튼에 onClick을 사용해 searchPlaces 함수를 적용했습니다.
function handleKeyPress(event) {
if (event.key === 'Enter') {
searchPlaces();
}
}
Input에 적용시켜 검색어를 입력 후 엔터키로도 검색이 가능하도록 했습니다.
지도에 마커를 생성하고 마커 클릭 시 이동합니다.
function displayMarker(place) {
const marker = new window.kakao.maps.Marker({
position: new window.kakao.maps.LatLng(place.y, place.x),
map: mapRef.current,
});
const infowindow = new window.kakao.maps.InfoWindow({ zIndex: 1 });
window.kakao.maps.event.addListener(marker, 'mouseover', function () {
infowindow.setContent(
'<div className="p-1 text-sm">' + place.place_name + '</div>'
);
infowindow.open(mapRef.current, marker);
});
return marker;
}
주어진 장소 정보(place)를 바탕으로 지도 위에 마커를 생성하고 표시합니다. 각 마커는 해당 장소의 이름을 보여주는 정보창과 연결되어 있습니다. 마커를 클릭 시 infowindow를 표시해 줍니다.
window.kakao.maps.event.addListener(marker, 'click', function () {
mapRef.current.setCenter(marker.getPosition());
mapRef.current.setLevel(1);
});
각 마커에 'click' 이벤트 리스너를 추가하여, 클릭 시 해당 위치로 지도 중심을 이동하고 줌 레벨을 변경합니다. 마커를 클릭 시 마커 위치를 중심으로 이동하고 5 레벨에서 1 레벨로 확대해 위치를 조금 더 자세히 보여 줍니다.
function removeMarkers() {
for (let i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
setMarkers([]);
}
현재 지도 위에 표시된 모든 마커들을 제거합니다. 새로운 검색이 실행될 때마다 이 함수를 호출하여 지도를 초기화합니다.
import { useEffect, useRef, useState } from 'react';
export default function GetKakaoMap() {
const mapRef = useRef(null);
const [keyword, setKeyword] = useState('');
const [markers, setMarkers] = useState([]);
// 카카오 맵 생성하기
useEffect(() => {
if (window.kakao && window.kakao.maps) {
const container = document.getElementById('mapContainer');
const options = {
center: new window.kakao.maps.LatLng(33.5068, 126.4929),
level: 5,
};
const map = new window.kakao.maps.Map(container, options);
mapRef.current = map;
map.addOverlayMapTypeId(window.kakao.maps.MapTypeId.TRAFFIC);
const zoomControl = new window.kakao.maps.ZoomControl();
map.addControl(zoomControl, window.kakao.maps.ControlPosition.RIGHT);
}
}, []);
function searchPlaces() {
if (!window.kakao || !window.kakao.maps || !mapRef.current) return;
const places = new window.kakao.maps.services.Places();
places.keywordSearch(keyword, function (result, status) {
removeMarkers();
let tempMarkers = [];
if (status === window.kakao.maps.services.Status.OK) {
for (let i = 0; i < result.length; i++) {
let markerInfo = displayMarker(result[i]);
tempMarkers.push(markerInfo);
}
setMarkers(tempMarkers);
mapRef.current.setLevel(8);
}
});
setKeyword('');
function displayMarker(place) {
const marker = new window.kakao.maps.Marker({
position: new window.kakao.maps.LatLng(place.y, place.x),
map: mapRef.current,
});
const infowindow = new window.kakao.maps.InfoWindow({ zIndex: 1 });
window.kakao.maps.event.addListener(marker, 'mouseover', function () {
infowindow.setContent(
'<div className="p-1 text-sm">' + place.place_name + '</div>'
);
infowindow.open(mapRef.current, marker);
});
window.kakao.maps.event.addListener(marker, 'click', function () {
mapRef.current.setCenter(marker.getPosition());
mapRef.current.setLevel(1);
});
window.kakao.maps.event.addListener(marker, 'mouseout', function () {
infowindow.close();
});
return marker;
}
function removeMarkers() {
for (let i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
setMarkers([]);
}
}
function handleKeyPress(event) {
if (event.key === 'Enter') {
searchPlaces();
}
}
return (
<div className="relative border-4 border-blue w-[80%] h-[60vw]">
<div id="mapContainer" className="w-full h-full relative">
<div id="map" className="w-full h-full" />
</div>
<div className="absolute top-5 left-5 flex gap-2 z-[9]">
<input
type="text"
value={keyword}
className="w-[25vw] px-5 py-3 border-[3px] border-white rounded-lg"
placeholder="장소 검색"
onChange={(e) => setKeyword(e.target.value)}
onKeyPress={handleKeyPress}
/>
<button
className="w-[5vw] bg-blue text-white border-0 rounded-lg"
onClick={searchPlaces}
>
검색
</button>
</div>
</div>
);
}