최초 작성일: 2022.07.30
이 기능을 만들게 된 계기
재직중인 회사에서 운영중인 서비스(오늘수거) 특성상 매일 수거 건들을 수집해서 기사분들께 배정해드리는 기능이 존재합니다.
기존에는 마커를 선택하거나 주소를 선택해서 배정을 했는데, 하나씩 클릭을 해서 배정을 진행했어야 했기 때문에 배정을 하는데에 편의가 좋지 않았습니다.
따라서 PM님께서 지도에서 드래그로 여러 마커를 한번에 선택할 수 있게 해줬으면 좋겠다고 업데이트 요청이 들어와 작업을 하게 되었습니다. 그때 PM님께서 참고 자료로 주셨던 한 레퍼런스가 매우 많이 도움이 되었습니다.
하지만 레퍼런스는 바닐라 JS로 되어있기 때문에 Google Maps API 문서를 보고 React Typescript에 맞게 수정하는 과정이 필요했습니다.
저에게는 이 기능을 만드는 게 쉽지만은 않았어서 이 기능이 필요할 누군가를 위해 포스팅을 해봅니다.
사용한 라이브러리
@googlemaps/react-wrapper
@types/google.maps
$ npm i @googlemaps/react-wrapper
$ npm i -D @types/google.maps
Github
https://github.com/xodms1701/select-marker-with-drag
이 프로젝트에서 핵심적으로 구현한 것은 Shift를 누르고 드래그를 하면 주소가 선택되는 기능! 입니다. 물론 마커를 클릭했을 때에도 선택 및 선택 취소가 가능합니다.
테스트해보고 싶으시다면 clone 받으시고 다음과 같이 .env파일을 생성하시면 됩니다.
REACT_APP_GOOGLE_MAP_API_KEY=google에서 발급받은 api key
설명
...
React.useEffect(() => {
if (marker) {
["click"].forEach((eventName) =>
google.maps.event.clearListeners(marker, eventName)
);
if (options.onClick) {
marker.addListener("click", options.onClick);
}
}
}, [marker, options.onClick]);
...
google.maps.MarkerOptions에는 onClick 함수가 없습니다. 대신 addListener로 클릭이나 등등 다른 이벤트를 할당할 수 있습니다.
useEffect 안에서 dependency가 있는 state가 변경될 때 할당된 이벤트가 있다면 해제하고 다시 할당합니다. 이렇게 하지 않는다면 변경된 state가 이벤트에 동기화 되지 않습니다.
google.maps.Map에도 마찬가지입니다.
...
map.addListener("mouseup", (e: google.maps.MapMouseEvent) => {
if (mouseIsDown && shiftPressed) {
mouseIsDown = 0;
if (gribBoundingBox !== null) {
const array = React.Children.toArray(children);
for (let item of array) {
let val = item as React.ReactElement;
let position: google.maps.LatLngLiteral = val.props.position;
if (gribBoundingBox.getBounds()?.contains(position)) {
const key = Number(val.key?.toString().replace(".$", ""));
const idx = selectionModel.indexOf(key);
if (idx > -1) {
selectionModel.splice(idx, 1);
} else {
selectionModel.push(key);
}
}
}
setSelectionModel([...selectionModel]);
gribBoundingBox?.setMap(null);
}
gribBoundingBox = null;
}
map.setOptions({
draggable: true,
});
});
...
제 생각에는 이 코드가 제일 핵심적이라고 생각합니다.
for of 구문을 보면, 드래그를 해서 영역을 설정했을 때 중복으로 선택된 주소는 선택 취소를 할 것인지, 혹은 그냥 중복이 된 주소와 새로 선택된 주소 모두 선택할지 등의 로직을 짤 수 있습니다. 지금 구성한 로직은 중복 선택되면 선택 취소를 하는 로직입니다.
마무리
더 궁금하신게 있다면... github issue나 제 트위터 DM으로 연락 부탁드립니다.
참고 자료
https://developers.google.com/maps/documentation/javascript/react-map
https://stackoverflow.com/a/23163930/10861368
'개발' 카테고리의 다른 글
[k8s] EFK 스택 구성하기 with helm charts (0) | 2023.09.27 |
---|---|
[NestJS] 슬랙 알람 데코레이터 리팩토링 (0) | 2023.05.12 |
Naming Convention (0) | 2023.05.12 |
REST API Convention (0) | 2023.05.12 |