우선 시작에 앞서 kakaomap api를 사용하는데에 리액트에 적용하기 위해서 스크립트 보다는 리액트에서 사용하기 좋게 만들어진 이 react-kako-maps-sdk를 사용하기로 했다. https://react-kakao-maps-sdk.jaeseokim.dev/
우선 마커를 찍어줄 때 어떻게 진행했냐면 keywordSearch()
를 통해서 신병교육대와 훈련소를 찾고 catergorySearch()
를 통해 "FD6"이라는 코드로 음식점을 다 가져왔다.
const getPlacesPositionForMarkers = (data) => {
let temp = [];
for (let i = 0; i < data.length; i++) {
temp.push(data[i]);
}
let addedReviewsAndBookMarks = temp.map((e) => {
return { ...e, reviews: [], bookmark: 0 };
});
setRestaurants(addedReviewsAndBookMarks);
setMarkers(temp);
};
const searchRestaurants = (bounds) => {
places.categorySearch('FD6', getPlacesPositionForMarkers, {
bounds: bounds,
useMapBounds: true
});
};
const keywordSearch = () => {
if (!map) return;
places.keywordSearch(campSearchWordConverter(paramId), (data, status, _pagination) => {
if (status === window.kakao.maps.services.Status.OK) {
const bounds = new window.kakao.maps.LatLngBounds();
let markers = [];
for (var i = 0; i < data.length; i++) {
markers.push({
position: {
lat: data[i].y,
lng: data[i].x
},
content: data[i].place_name
});
bounds.extend(new window.kakao.maps.LatLng(data[i].y, data[i].x));
}
// 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
map.setBounds(bounds);
map.setLevel(5);
searchRestaurants(map.getBounds());
}
});
};
이렇게 마크를 markers라는 배열에 담아주고 나서
return(
<Map
center={{
lat: 37.566826,
lng: 126.9786567
}}
style={{
width: '100%',
height: '100%'
}}
level={5}
onCreate={setMap}
>
{markers.map((marker) => {
return (
<EventMarkerContainer
key={marker.id}
position={{ lat: marker.y, lng: marker.x }}
content={marker.place_name}
/>
);
})}
</Map>
)
EventMarkerContainer에다가 position과 오버레이에 넣어줄 컨텐츠를 넣어준다.
따로 제공되는 컴포넌트는 아니고 MapMarker를 묶어둔 컴포넌트이다.
const EventMarkerContainer = ({ position, content }) => {
const map = useMap();
const [isVisible, setIsVisible] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const handleMarkerInfo = (marker) => {
map.panTo(marker.getPosition());
setIsOpen(true);
};
return (
<>
<MapMarker
position={position}
clickable={true}
onClick={(marker) => handleMarkerInfo(marker)}
image={{ src: '/assets/markerLine2.png', size: { width: 60, height: 60 } }}
// onMouseOver={() => setIsVisible(true)}
// onMouseOut={() => setIsVisible(false)}
/>
{(isVisible || isOpen) && (
<CustomOverlayMap position={{ lat: String(Number(position.lat) + 0.0002), lng: position.lng }}>
<div className="flex flex-col bg-white">
<button onClick={() => setIsOpen(false)}>닫기</button>
<div>{content}</div>
</div>
</CustomOverlayMap>
)}
</>
);
};
export default EventMarkerContainer;
맨 처음에는 인포윈도우로 표시하려 했는데 스타일링이 잘 안되는 것 같았다. width나 height가 설정이 안되는 느낌이라 커스텀 오버레이를 만들기로 했다.
인포윈도우로 사용하기 위해서는 원래 MapMarker의 children으로 넣어주는 거였는데 오버레이는 그럴 필요가 없었다.
return (
<MapMarker
position={position}
clickable={true}
onClick={(marker) => handleMarkerInfo(marker)}
image={{ src: '/assets/markerLine2.png', size: { width: 60, height: 60}}}>
{content}
</MapMarker>
요렇게 넣어주면 content가 인포윈도우로 자연스럽게 나가는데 커스텀 오버레이는 그냥 마커의 밖에서 선언을 하고 open여부를 결정해주면 된다. 닫기도 가능해야하기 때문에 state로 관리해서 열고 닫아주면 끝!
내일은 오버레이 css좀 건드려봐야겠다
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ^^7