Kakao Map 여러 마커의 클릭이벤트

두두두·2022년 12월 5일
0

FrontEnd

목록 보기
3/3

목표

  1. 카카오맵을 활용하여 입력된 위도경도 좌표값들의 마커를 표시
  2. 마커를 클릭하면 인포창 표시, 인포창에는 도로명 주소와 장소의 이름 포함

참고사이트
지도 범위 재설정 하기
마커에 인포위도우 표시하기
여러개 마커에 인포윈도우 등록하기 2

좌표들의 마커 표시

좌표 배열과 장소의 이름 배열을 받아서 마커로 표시
받은 배열을 positions라는 변수에 하나씩 담는다
좌표는 kakaomap에서 사용하는 LatLng 객체로 변환하여 넣는다
장소의 이름은 content에 담는다
배열을 받으므로 해당 배열 길이만큼 for문 실행

let positions = [];

for(let i = 0; i< stay_name.length; i++) {
  positions.push({
    content: stay_name[i], 
    latlng: new kakao.maps.LatLng(lat[i], lng[i])
  });
}

LatLngBounds객체를 bounds로 생성하고 마커를 생성할 때 bounds.extend 함수를 이용하여 마커의 범위로 확장한다.
setBounds함수를 이용하여 모든 마커가 한 번에 보이도록 지도의 중심과 확대레벨을 설정한다.
인포에서 사용하기 위해 마커의 title은 장소의 이름으로 설정한다.(title: 마커에 마우스를 올려놓으면 title의 내용이 툴팁으로 표시)

let bounds = new kakao.maps.LatLngBounds();
for (let i = 0; i < positions.length; i ++) {
  let marker = new kakao.maps.Marker({
    map: map, 
    position: positions[i].latlng, 
    title : positions[i].content
  });
  bounds.extend(positions[i].latlng);
}
map.setBounds(bounds);

마커 클릭 인포 등록

function view_map(stay_name, lat, lng) {
	let mapContainer = document.getElementById('map_main'), // 지도를 표시할 div  
    mapOption = { 
        center: new kakao.maps.LatLng(33.450701, 126.570667), // 지도의 중심좌표
        level: 3 // 지도의 확대 레벨
    };

	let map = new kakao.maps.Map(mapContainer, mapOption); // 지도를 생성합니다
	
	setTimeout(function(){ map.relayout(); }, 100);
	let bounds = new kakao.maps.LatLngBounds();
	let selectedMarker = null;

	let positions = [];
	let infowindow;
	
	for(let i = 0; i< stay_name.length; i++) {
		positions.push({
			content: stay_name[i], 
	        latlng: new kakao.maps.LatLng(lat[i], lng[i])
		});
	}
	
	var geocoder = new kakao.maps.services.Geocoder();
	
	for (let i = 0; i < positions.length; i ++) {
	    let marker = new kakao.maps.Marker({
	        map: map, 
	        position: positions[i].latlng, 
	        title : positions[i].content
	    });
		bounds.extend(positions[i].latlng);
	    infowindow = new kakao.maps.InfoWindow({
	    	content: ""
	    });
	
	    
	    
	    kakao.maps.event.addListener(marker, 'click', function() {
	    	searchDetailAddrFromCoords(positions[i].latlng, function(result, status) {
		        if (status === kakao.maps.services.Status.OK) {
		            var detailAddr = !!result[0].road_address ? '<div>' + result[0].road_address.address_name + '</div>' : '';
		            
			        if (!selectedMarker || selectedMarker !== marker) {
			            !!selectedMarker && infowindow.close();
			        	
			            infowindow.open(map, marker);
			            
			            var content = document.createElement('div');
			    	    content.className="wrap"
			    	    content.style.cssText = 'background: white; border: 1px solid black';
			    	    
			    	    var info = document.createElement('div');
			    	    info.className="info";
			    	    
			    	    var title = document.createElement('div');
			    	    title.innerHTML =  marker.getTitle();
			    	    title.className="title";
			    	    
			    	    var closeBtn = document.createElement('button');
			    	    closeBtn.innerHTML = '닫기';
			    	    closeBtn.className = "close"
			    	    closeBtn.onclick = function () {
			    	    	infowindow.setMap(null);
			    	    };
			    	    
			    	    var info_body = document.createElement('div');
			    	    info_body.className = "info_body";
			    	    var ellipsis = document.createElement('div');
			    	    ellipsis.innerHTML = !!result[0].road_address ? result[0].road_address.address_name: '';
			    	    ellipsis.className = "ellipsis";
			    	    
			    	    info_body.appendChild(ellipsis);
			    	    title.appendChild(closeBtn);
			    	    info.appendChild(title);
			    	    info.appendChild(info_body);
			    	    content.appendChild(info);
			    	    
			    	    infowindow.setContent(content);
			    	    
			            //infowindow.setContent("<div>" + marker.getTitle() + "</div>");
			        }
			        selectedMarker = marker;
		        }
		   	})
		});
	}
	
	map.setBounds(bounds);
    function searchDetailAddrFromCoords(coords, callback) {
          geocoder.coord2Address(coords.getLng(), coords.getLat(), callback);
      }
}

setTimeout(function(){ map.relayout(); }, 100);
→ 맵 영역이 display:none에서 display:block로 변할 때 맵 영역이 잘려 출력되지 않도록 맵이 완전히 block으로 변한 뒤 맵을 relayout()하여 맵의 크기를 설정하는 것이다. 뒤의 시간은 코드마다 다르기 때문에 0,10 등 넣어보고 더 작은 수를 사용하길 바란다.

마커들에 동일한 클릭이벤트를 부여하기 때문에 생성하는 for문에서 클릭이벤트를 추가한다.

kakao.maps.InfoWindow객체를 담을 infowindow 변수를 선언한다. 마커의 title을 content로 담을 것이기 때문에 content는 빈 값으로 생성 후 나중에 셋팅한다.

생성한 마커에 클릭이벤트를 추가한다.
searchDetailAddrFromCoords 함수는 좌표를 주소값으로 반환해주는 함수이다
주소로 변환을 성공했다면 if문의 내용을 수행한다.
result[0].road_address는 변환한 도로명 주소값이다.

kakao.maps.event.addListener(marker, 'click', function() {
	   searchDetailAddrFromCoords(positions[i].latlng, function(result, status) {
		     if (status === kakao.maps.services.Status.OK) {
                var detailAddr = !!result[0].road_address ? '<div>' + result[0].road_address.address_name + '</div>' : '';

if (!selectedMarker || selectedMarker !== marker) 클릭한 마커가 없거나 지금 클릭한 마커가 이전에 클릭한 마커가 아니라면 실행
infowindow.open(map, marker);로 인포창을 맵의 마커에 표시한다.
infowindow.setContent(content); 함수를 사용하여 html 요소를 생성하여 infowindow의 content로 셋팅한다.
detailAddr 변수를 사용하려했지만 오히려 구조가 복잡해져 result[0].road_address.address_name 값만 사용

if (!selectedMarker || selectedMarker !== marker) {
  !!selectedMarker && infowindow.close();

  infowindow.open(map, marker);

  var content = document.createElement('div');
  content.className="wrap"
  content.style.cssText = 'background: white; border: 1px solid black';

  var info = document.createElement('div');
  info.className="info";

  var title = document.createElement('div');
  title.innerHTML =  marker.getTitle();
  title.className="title";

  var closeBtn = document.createElement('button');
  closeBtn.innerHTML = '닫기';
  closeBtn.className = "close"
  closeBtn.onclick = function () {
    infowindow.setMap(null);
  };

  var info_body = document.createElement('div');
  info_body.className = "info_body";
  var ellipsis = document.createElement('div');
  ellipsis.innerHTML = !!result[0].road_address ? result[0].road_address.address_name: '';
  ellipsis.className = "ellipsis";

  info_body.appendChild(ellipsis);
  title.appendChild(closeBtn);
  info.appendChild(title);
  info.appendChild(info_body);
  content.appendChild(info);

  infowindow.setContent(content);

  //infowindow.setContent("<div>" + marker.getTitle() + "</div>");
}
selectedMarker = marker;

0개의 댓글