정리노트/팀프로젝트

[팀 프로젝트] 24.03.07. 노트

망고고래 2024. 3. 7. 17:58

카카오맵 API 가이드

https://apis.map.kakao.com 

 

 

마커를 띄울 주소를 동적으로 생성하면 'Uncaught TypeError: a.e is not a function'이 발생하는 문제

1)함수 하나 안에 다른 함수들을 다 넣어봄

실패

 

2)gpt 다시 돌려봄

카카오맵 API 코드 예시를 주고, JSON으로 좌표를 받아오는 코드를 준 뒤에 이 좌표값을 사용하고 싶다고 함

코드 예시보다 훨씬 간단한 코드를 줬는데 정상적으로 작동함(표시되어있는 마커가 다른 데이터를 새로 받아왔을 때도 초기화되지 않아서 다소 수정은 필요함)

왜 되지...?

function requestAddrArray(areaName, category){
    $.ajax({
        url: '/pet_hug/courses/getAddrArray',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({areaName: areaName, category: category}),
        success: function(data) {
            console.log("data : " + JSON.stringify(data));
            // 서버에서 응답이 올 경우 이곳에 코드를 작성합니다.
            console.log(data[0]);
            
            if(category == 'hotel'){
                console.log("응답성공");
                // 'hotelAddrs' 배열을 생성하고 주소를 지도에 표시
                var hotelAddrs = data[0].map(function(item){
                    return new kakao.maps.LatLng(item.lat, item.lng);
                });

                // 'hotelAddrs' 배열에 있는 주소 좌표를 지도에 표시
                for (var i = 0; i < hotelAddrs.length; i++) {
                    var marker = new kakao.maps.Marker({
                        position: hotelAddrs[i],
                        map: map // 'map'은 이미 생성된 지도 객체입니다
                    });
                }
            }
        },
        error: function(error) {
            // 에러가 발생한 경우 이곳에 코드를 작성합니다.
            // 'error' 변수에 에러 정보가 담겨 있습니다.
        }
    });
}

 

기존의 오류가 발생하던 코드

		/* 컨트롤러 연결 */
 		function requestAddrArray(areaName, category){
		    $.ajax({
		        url: '/pet_hug/courses/getAddrArray',
		        type: 'POST',
		        contentType: 'application/json',
		        data: JSON.stringify({areaName: areaName, category: category}),
		        success: function(data) {
		        	console.log("data : " + JSON.stringify(data));
		            // 서버에서 응답이 올 경우 이곳에 코드를 작성합니다.
		            console.log(data[0]);
		            
		            
					if(category == 'hotel'){
						console.log("응답성공");
						//hotelAddrs = JSON.parse("[" + data[0] + "]");
						//data[0].forEach(function(item){
							//hotelAddrs.push(item);
						//});
						hotelAddrs = data[0].map(function(item){
							return "new kakao.maps.LatLng(" + item.lat + ", " + item.lng + ")";
						});
						console.log('hotelAddrs[]: ' + hotelAddrs);
						createHotelMarkers();
						setHotelMarkers(map);
					}
		        },
		        error: function(error) {
		            // 에러가 발생한 경우 이곳에 코드를 작성합니다.
		            // 'error' 변수에 에러 정보가 담겨 있습니다.
		        }
		    });
		} 
	
		function createMarkerImage(src, size, options) {
			console.log("createMarkerImage() 실행")
		    var markerImage = new kakao.maps.MarkerImage(src, size, options);
		    return markerImage;            
		}
		// 좌표와 마커이미지를 받아 마커를 생성하여 리턴하는 함수입니다
		function createMarker(position, image) {
			console.log("createMarker() 실행")
		    var marker = new kakao.maps.Marker({
		        position: position,
		        image: image
		    });
		    
		    return marker;  
		}
		
		function createHotelMarkers() {
			console.log('createHotelMarkers() 실행')
			//마커
		    for (var i = 0; i < hotelAddrs.length; i++) {  
		        
		        var imageSize = new kakao.maps.Size(22, 26),
		            imageOptions = {  
		                spriteOrigin: new kakao.maps.Point(10, 0),    
		                spriteSize: new kakao.maps.Size(36, 98)  
		            };     
		        
		        // 마커이미지와 마커를 생성합니다
		        var markerImage = createMarkerImage(markerImageSrc, imageSize, imageOptions),    
		            marker = createMarker(hotelAddrs[i], markerImage);  
		        
		        // 생성된 마커를 커피숍 마커 배열에 추가합니다
		        hotelMarkers.push(marker);
		    }     
		}
		// 커피숍 마커들의 지도 표시 여부를 설정하는 함수입니다
		function setHotelMarkers(map) {
			console.log('setHotelMarkers() 실행')
		    for (var i = 0; i < hotelMarkers.length; i++) {  
		        hotelMarkers[i].setMap(map);
		    }        
		}

 

 

주소를 새로 받아와도 기존의 마커가 사라지지 않고 그대로 남아있는 문제가 발생했다. 코드를 다시 보니 hotelMarkers[]를 선언만 하고 마커를 배열에 넣어놓지 않았다. 그래서 관리가 안 됐었던 것 같다.

hotelMarkers[]에 마커를 넣는 코드를 추가했다.

		                // 'hotelAddrs' 배열에 있는 주소 좌표를 지도에 표시
		                for (var i = 0; i < hotelAddrs.length; i++) {
		                    var marker = new kakao.maps.Marker({
		                        position: hotelAddrs[i],
		                        map: map // 'map'은 이미 생성된 지도 객체입니다
		                    });
		                    hotelMarkers.push(marker);
		                }

 

 

 

추가할 기능

1. 마커 클릭하면 간단한 인포 표시 ←인포x 커스텀 오버레이로 변경(인포 윈도우는 커스텀이 안 됨)

- 정보를 표시하려면 배열만 받아오는 게 아니라 정보도 받아와야 함

- 상호, 사진, contentSeq(상세페이지 연결)

- 도메인, RowMapper, Repository-SQL문 수정 ♣

1)인포 표시 코드

var iwContent = '<div style="padding:5px;">Hello World!</div>', // 인포윈도우에 표출될 내용으로 HTML 문자열이나 document element가 가능합니다
    iwPosition = new kakao.maps.LatLng(33.450701, 126.570667), //인포윈도우 표시 위치입니다
    iwRemoveable = true; // removeable 속성을 ture 로 설정하면 인포윈도우를 닫을 수 있는 x버튼이 표시됩니다

// 인포윈도우를 생성하고 지도에 표시합니다
var infowindow = new kakao.maps.InfoWindow({
    map: map, // 인포윈도우가 표시될 지도
    position : iwPosition, 
    content : iwContent,
    removable : iwRemoveable
});
      
// 아래 코드는 인포윈도우를 지도에서 제거합니다
// infowindow.close();

 

2)클릭시 이벤트 발생

function addMarker(position) {

    // 마커를 생성하고 이미지는 기본 마커 이미지를 사용합니다
    var marker = new kakao.maps.Marker({
        map: map,
        position: position,
        image: normalImage
    });

    // 마커 객체에 마커아이디와 마커의 기본 이미지를 추가합니다
    marker.normalImage = normalImage;

    // 마커에 click 이벤트를 등록합니다
    kakao.maps.event.addListener(marker, 'click', function() {

        // 클릭된 마커가 없고, click 마커가 클릭된 마커가 아니면
        // 마커의 이미지를 클릭 이미지로 변경합니다
        if (!selectedMarker || selectedMarker !== marker) {

            // 클릭된 마커 객체가 null이 아니면
            // 클릭된 마커의 이미지를 기본 이미지로 변경하고
            !!selectedMarker && selectedMarker.setImage(selectedMarker.normalImage);

            // 현재 클릭된 마커의 이미지는 클릭 이미지로 변경합니다
            marker.setImage(clickImage);
        }

        // 클릭된 마커를 현재 클릭된 마커 객체로 설정합니다
        selectedMarker = marker;
    });
}

 

 

2. 인포에서 상세보기 클릭하면 상세페이지로 이동 ♣

 

 

3. 오버레이 열고 닫기 ♣

마커1의 오버레이가 펼쳐져있는 경우

- 마커1을 다시 클릭하면 오버레이 닫힘

- 마커2를 클릭하면 마커1의 오버레이가 닫히고 마커2의 오버레이가 열림

 

 

 

+코드 공부하기

자바스크립트는 gpt가 짜준 걸 이게 이거구나 이해만 하는 수준이라 공부를 따로 해야겠다.

		/* 카카오 지도 */
	    var mapContainer = document.getElementById('map'), // 지도를 표시할 div 
	    mapOption = {
	        center: new kakao.maps.LatLng(37.7091295,128.8324462), // 지도의 중심좌표
	        level: 8 // 지도의 확대 레벨
	    };  
	
		// 지도 생성    
		var map = new kakao.maps.Map(mapContainer, mapOption); 
	
		let hotelAddrs = [];
		let spotAddrs = [];
		let hotelMarkers = [];
		let spotMarkers = [];
		let cafeMarkers = [];
		let	expMarkers = []; 
		var markerImageSrc = 'https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/category.png';
		
		let hotelMarkerImageSrc = '/pet_hug/resources/images/map/hotelmarker.png';
		let spotMarkerImageSrc = '/pet_hug/resources/images/map/spotmarker.png';
		let cafeMarkerImageSrc = '/pet_hug/resources/images/map/cafemarker.png';
		let expMarkerImageSrc = '/pet_hug/resources/images/map/expmarker.png';
		
		let currentOverlay = null;
		let newOverlay = null;
		let previousMarker = null;
		
		
		/* 지도 이동, category/areaName 가져옴 */
		function selectChanged(){
			let areaName = document.getElementById("areaName").value;
			console.log("areaValue: ", areaName);
			let category = document.getElementById("category").value;
			console.log("categoryValue: ", category);
			
			if(areaName == '강릉시'){
				moveMap(37.7091295,128.8324462);	
			}else if(areaName == '고성군'){
				moveMap(38.3773762,128.3997526);
			}else if(areaName == '동해시'){
				moveMap(37.5067666,129.0555852);
			}else if(areaName == '삼척시'){
				moveMap(37.2773968,129.1220028);
			}else if(areaName == '속초시'){
				moveMap(38.17601,128.5194615);
			}else if(areaName == '양구군'){
				moveMap(38.178176,128.001272);
			}else if(areaName == '양양군'){
				moveMap(38.0045219,128.5950959);
			}else if(areaName == '영월군'){
				moveMap(37.2039413,128.500649);
			}else if(areaName == '원주시'){
				moveMap(37.3082307,127.9294889);
			}else if(areaName == '인제군'){
				moveMap(38.0688048,128.263324);
			}else if(areaName == '정선군'){
				moveMap(37.3786668,128.7390494);
			}else if(areaName == '철원군'){
				moveMap(38.2434576,127.4141162);
			}else if(areaName == '춘천시'){
				moveMap(37.8897796,127.7398952);
			}else if(areaName == '태백시'){
				moveMap(37.1722939,128.9800161);
			}else if(areaName == '평창군'){
				moveMap(37.556735,128.4826261);
			}else if(areaName == '홍천군'){
				moveMap(37.7450683,128.0742344);
			}else if(areaName == '화천군'){
				moveMap(38.1383179,127.6849292);
			}else if(areaName == '횡성군'){
				moveMap(37.5089632,128.0770982);
			}
			//기존 마커 제거
			removeMarkers();
			requestAddrArray(areaName, category);
		}
		
		function requestAddrArray(areaName, category){
		    $.ajax({
		        url: '/pet_hug/courses/getAddrArray',
		        type: 'POST',
		        contentType: 'application/json',
		        data: JSON.stringify({areaName: areaName, category: category}),
		        success: function(data) {
		            if(category === 'hotel'){
		                console.log("응답성공");
		                displayHotelMarkers(data);
		            }else if(category === 'spot'){
		            	console.log('관광지 응답 성공');
		            	displaySpotMarkers(data);
		            }else if(category === 'cafe'){
		            	console.log('식음료 응답 성공');
		            	displayCafeMarkers(data);
		            }else if(category === 'exp'){
		            	console.log('체험 응답 성공');
		            	displayExpMarkers(data);
		            }else if(category === 'all'){
		            	console.log('전체 응답 성공');
		            	displayHotelMarkers(data);
		            	displaySpotMarkers(data);
		            	displayCafeMarkers(data);
		            	displayExpMarkers(data);
		            }
		        },
		        error: function(error) {
		            // 에러가 발생한 경우 이곳에 코드를 작성합니다.
		            // 'error' 변수에 에러 정보가 담겨 있습니다.
		        }
		    });
		}
		
		function moveMap(latitude, longitude){
			let center = new kakao.maps.LatLng(latitude, longitude);
			map.setCenter(center);
		}
		
		function removeMarkers(){
		    for (var i = 0; i < hotelMarkers.length; i++) {
		        hotelMarkers[i].setMap(null);
		    }
		    for (var i = 0; i < spotMarkers.length; i++) {
		        spotMarkers[i].setMap(null);
		    }
		    for (var i = 0; i < cafeMarkers.length; i++) {
		        cafeMarkers[i].setMap(null);
		    }
		    for (var i = 0; i < expMarkers.length; i++) {
		        expMarkers[i].setMap(null);
		    }
		}
		
		
		function displayHotelMarkers(data){

			
			hotelAddrs = data[0].map(function(item){
				return new kakao.maps.LatLng(item.lat, item.lng);
			});
			
			var hotelInfo = data[0];
			
		    // 호텔 주소 배열에 있는 좌표를 지도에 표시
		    for (var i = 0; i < hotelAddrs.length; i++) {
		        var marker = new kakao.maps.Marker({
		            position: hotelAddrs[i],
		            image: new kakao.maps.MarkerImage(hotelMarkerImageSrc, new kakao.maps.Size(42, 42)),
		            map: map
		        });
		        hotelMarkers.push(marker);
		        
			 // 호텔 마커에 클릭 이벤트 리스너 추가
			    kakao.maps.event.addListener(marker, 'click', (function(marker, hotel) {
			        return function() {
			            // 이전에 클릭된 마커와 현재 클릭된 마커가 다른 경우에만 처리
			            if (previousMarker !== marker) {
			                // 이전에 클릭된 마커의 오버레이가 열려있으면 닫음
			                if (previousMarker && currentOverlay) {
			                    currentOverlay.setMap(null);
			                }
			                // 현재 클릭된 마커의 오버레이를 열고, 이전에 클릭된 마커를 저장
			                var overlayContent = '<div style="width: 200px; height: 220px; background-color: white">' +
			                    '<img src="' + hotel.p1 + '" style="width:100%"/>' +
			                    '<div style="padding: 5px;">' +
			                    '<div style="margin: 1px 0; height: 2rem; font-size: 1rem;">' +
			                    	'<p style="display: inline-block; width: 100%;">' + hotel.title + '</p><br>' +
			                    '</div>' +
			                    '<a href="/pet_hug/hotels/hotel?num=' + hotel.contentSeq + '" style="background-color: blue; color: white; border-radius: 4px; text-decoration: none; padding: 5px; display: block; width: 75px;">상세정보</a>' +
			                    '</div>' +
			                    '</div>';

			                var newOverlay = new kakao.maps.CustomOverlay({
			                    position: marker.getPosition(),
			                    content: overlayContent,
			                    xAnchor: 0.3,
			                    yAnchor: 1.2 // 마커보다 약간 위로 이동
			                });

			                newOverlay.setMap(map);
			                // 새로운 오버레이와 클릭된 마커를 저장
			                currentOverlay = newOverlay;
			                previousMarker = marker;
			            } else {
			                // 이전에 클릭된 마커와 현재 클릭된 마커가 같으면 오버레이를 닫음
			                if (currentOverlay) {
			                    currentOverlay.setMap(null);
			                    currentOverlay = null;
			                    previousMarker = null;
			                }
			            }
			        };
			    })(marker, hotelInfo[i]));
		    }
		}
		
		function displaySpotMarkers(data) {	    
		    // 관광명소 주소 배열 생성 및 마커 표시
		    spotAddrs = data[1].map(function(item){
		        return new kakao.maps.LatLng(item.lat, item.lng);
		    });

		    // 관광명소 주소 배열에 있는 좌표를 지도에 표시
		    for (var i = 0; i < spotAddrs.length; i++) {
		        var marker = new kakao.maps.Marker({
		            position: spotAddrs[i],
		            image: new kakao.maps.MarkerImage(spotMarkerImageSrc, new kakao.maps.Size(42, 42)),
		            map: map
		        });
		        spotMarkers.push(marker);
		    }
		}
		function displayCafeMarkers(data){
		    //주소 배열 생성 및 마커 표시
		    cafeAddrs = data[2].map(function(item){
		        return new kakao.maps.LatLng(item.lat, item.lng);
		    });

		    //주소 배열에 있는 좌표를 지도에 표시
		    for (var i = 0; i < spotAddrs.length; i++) {
		        var marker = new kakao.maps.Marker({
		            position: cafeAddrs[i],
		            image: new kakao.maps.MarkerImage(cafeMarkerImageSrc, new kakao.maps.Size(42, 42)),
		            map: map
		        });
		        cafeMarkers.push(marker);
		    }
		}
		function displayExpMarkers(data){
		    //주소 배열 생성 및 마커 표시
		    expAddrs = data[2].map(function(item){
		        return new kakao.maps.LatLng(item.lat, item.lng);
		    });

		    //주소 배열에 있는 좌표를 지도에 표시
		    for (var i = 0; i < expAddrs.length; i++) {
		        var marker = new kakao.maps.Marker({
		            position: expAddrs[i],
		            image: new kakao.maps.MarkerImage(expMarkerImageSrc, new kakao.maps.Size(42, 42)),
		            map: map
		        });
		        expMarkers.push(marker);
		    }
		}

 

 

내일 할일

해결하기...

 

moveMap() 사용해서 마커 클릭하면 지도 이동시키기