Tmap 혹은 Naver 맵에서 화면에 따라 마커를 실시간으로 감추기 (강려크한 대용량 마커 처리)
요즘 차량관제와 관련된 백오피스를 개발하면서 지도와 열심히 씨름중임.
매일 수십개의 스팟과 함께 지도에는 언제나 수백개의 차량을 표현하는 마커가 떠 있어야 하는 미션이 주어짐.
이렇게 대용량 마커를 Static map 에 출력하는 방법은
위 이미지처럼 무식하게(?) marker를 때려박거나 클러스터러를 활용하는 방법이 있다.
개발하는 관점에서는 당연히 클러스터러가 편하고 쉽고 섹시한 방법처럼 생각할지 모르겠지만,
지도에서 어떤 객체를 바로 검색하거나 찾아야되는 요구사항에서는 마커를 때려박는 경우도 있다.
네이버맵이든, 티맵, 카카오맵등 대부분의 맵의 JS작동방식이 비슷해서인지 몰라도
동일하게 300개이상의 대량 마커가 지도에 한꺼번에 출력되면 엄청난 렉이 동반된다.
웃긴건 업체들마다 API로 제공하는 Namespace조차도 90%정도 비슷함.. ㅎㅎ
겨우 300개 밖에 안띄웠는데 i9 맥북이 갑자기 이륙과 동시에 엄청난 렉이 걸린다.
(개발자도 함께 이륙이 마렵다.)
Naver 맵에서 지도이동에 따른 마커의 활성화처리
네이버맵의 경우 그나마 좀 친절하다.
https://navermaps.github.io/maps.js.ncp/docs/tutorial-marker-viewport.example.html 를 통해서 대량마커처리에 대한 예제를 제공해준다. 아래는 예제와 다르게 300개의 마커를 출력하여 테스트해볼 수 있는 소스코드이다. (클라이언트 ID는 변경필요)
<script type='text/javascript' src='https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=클라이언트아이디' ></script>
<div id='map' style='width:100%;height:100%;'></div>
<script type='text/javascript'>
'use strict'; //엄격한 스크립트모드
var init_lat = 37.51490471; //위도
var init_lon = 126.98274432; //경도
var map = []; //지도객체
var markers = []; //마커객체
//마커 업데이트함수
var markerUpdate = function(){
var mapBounds = map.getBounds();
var marker, position;
for(var i=0; i<markers.length; i++){
marker = markers[i]
position = marker.getPosition();
if(mapBounds.hasLatLng(position)){
markers[i].setMap(map); //지도에 마커보이게
}else{
markers[i].setMap(null); //지도에 마커가리기
}
}
};
//마커 삽입함수
var addMarkers = function(){
for(var i=0; i<300; i++){
var lat = Math.random() / 10;
var lon = Math.random() / 10;
var marker = new naver.maps.Marker({
position: new naver.maps.LatLng(init_lat + lat, init_lon + lon),
title: 'mylatlon'
});
markers.push(marker);
markerUpdate();
}
};
window.onload = function(){
//맵로드
map = new naver.maps.Map('map', {
center: new naver.maps.LatLng(init_lat, init_lon),
zoom: 14
});
//줌을 땡기면 마커업데이트
naver.maps.Event.addListener(map, 'zoom_changed', function() {
markerUpdate();
});
//드래그를 하면 마커업데이트
naver.maps.Event.addListener(map, 'dragend', function() {
markerUpdate();
});
//마커불러오기
addMarkers();
};
</script>
Tmap 맵에서 지도이동에 따른 마커의 활성화처리
티맵은 개발 문서가 네이버보다 조금은(?) 더 편하게 되어있지만, 대량마커에 대한 처리예시가 없다.
무엇보다, 이벤트핸들러가 네이버보다 굉장히 불친절하기 때문에 네이버는 dragend를 제공하지만, 티맵은 drag만 제공함.
(아래소스코드에서 앱키는 변경필요)
<script type='text/javascript' src='https://apis.openapi.sk.com/tmap/jsv2?version=1&appKey=앱키변경필요' charset='utf-8'></script>
<div id='map' style='width:100%;height:100%;'></div>
<script type='text/javascript'>
'use strict'; //엄격한 스크립트모드
var init_lat = 37.51490471; //위도
var init_lon = 126.98274432; //경도
var map = []; //지도객체
var markers = []; //마커객체
//마커 업데이트함수
var markerUpdate = function(){
var mapBounds = map.getBounds();
var marker, position;
for(var i=0; i<markers.length; i++){
marker = markers[i]
position = marker.getPosition();
if(mapBounds.contains(position)){
markers[i].setMap(map); //지도에 마커보이게
}else{
markers[i].setMap(null); //지도에 마커가리기
}
}
};
//마커 삽입함수
var addMarkers = function(){
for(var i=0; i<300; i++){
var lat = Math.random() / 10;
var lon = Math.random() / 10;
var marker = new Tmapv2.Marker({
position: new Tmapv2.LatLng(init_lat + lat, init_lon + lon),
title: 'mylatlon'
});
markers.push(marker);
markerUpdate();
}
};
window.onload = function(){
//맵로드
map = new Tmapv2.Map('map', {
center: new Tmapv2.LatLng(init_lat, init_lon),
zoom: 14,
httpsMode: true //사용환경이 https일때는 true설정필요
});
//줌을 땡기면 마커업데이트
map.addListener('zoom_changed', function() {
markerUpdate();
});
//지도 이동하면 마커업데이트 (PC용)
map.addListener('center_changed', function() {
markerUpdate();
});
//드래그를 하면 마커업데이트 (모바일용)
map.addListener('drag', function() {
markerUpdate();
},{once:true});
//마커불러오기
addMarkers();
};
</script>
결론 및 성능테스트
대용량마커에서는 무조건 마커제어가 필요하다.
개인적으로 DOM상에 마커객체들이 깜빡이는게 싫다면, SK Tmap을 추천하고
그냥 간단한 웹서비스를 원한다면 NAVER map을 추천함.
NAVER map | SK Tmap | |
드래그시 마커방식 | Dragend (드래그가 끝날때 1회) | Drag (드래그하는 도중 계속 수행) |
줌 인/아웃시 마커방식 | 마커가 사라졌다가 다시 출력 | 마커 계속 출력 가능 |
특징 | 우리에게 익숙한 지도, 300개 이상 마커 현실적 불가능 | 1000개 이상 마커도 서비스가능, 지도가 번잡하다 |
Map 호출 객체명 | naver.maps.Map | Tmapv2.Map |
Marker 호출 객체명 | naver.maps.Marker | Tmapv2.Marker |
좌표계 호출 객체명 | naver.maps.LatLng | Tmapv2.LatLng |
bound확인 return함수명 | hasLatLng() | contains() |
정리하면서 느낀건데 호출되는 객체가 굉장히 유사하다..... ㅎㅎ
이번엔 1000개의 마커를 띄워서 비교해보았다.
2가지 Map API를 활용하여 테스트를 해보니
생각외로, Tmap 이 대용량 마커처리에 최적화되어 있는것을 확인할 수 있다.
NAVER map | SK Tmap | |
1000개 마커 Load속도 | 34150ms | 725ms |
1000개 마커를 하나의 지도에 띄울일은 없겠지?
무엇보다, 마커를 띄운상태에서 줌인/줌아웃을 하는 동안 다음과 같은 이슈가 있었다.
서비스에 맵을 도입할때 참고하면 좋을듯 하다.
NAVER map | KAKAO map | SK Tmap | |
줌인/줌아웃 하는 동안 | 일시적으로 마커 안보임 | 일시적으로 마커 안보임 | 마커가 계속 보임 |
NAVER map 마커 샘플 : https://navermaps.github.io/maps.js.ncp/docs/tutorial-1-marker-simple.example.html
KAKAO map 마커 샘플 : https://apis.map.kakao.com/web/sample/multipleMarkerImage/
SK Tmap 마커 샘플 : https://tmapapi.sktelecom.com/main.html#webv2/sample/webSample15
KAKAO map의 경우 카카오에서 직접운영하는 map.kakao.com 에서는 제공되는 API와 동일하게 줌인/줌아웃을 하는 동안 마커가 일시적으로 사라지는 방식이 동일하지만,
NAVER map의 경우 네이버에서 직접운영하는 map.naver.com 에서는 제공되는 API와 다르게 줌인/줌아웃을 하는 동안 마커가 일시적으로 사라지지는 않았다. 아마 구현하는 방식의 차이가 존재하는 듯하다.