[팀 프로젝트] 24.03.07. 노트
카카오맵 API 가이드
마커를 띄울 주소를 동적으로 생성하면 '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() 사용해서 마커 클릭하면 지도 이동시키기