티스토리 뷰

1️⃣ kakao map api와 DB 연동

travelRetrieve.jsp

✅ 지도만 나오는 버전
//서버에서 가져온 위치 정보를 JavaScript 변수에 할당
//var locations = ${locations};

// 서버에서 위도와 경도 정보를 비동기적으로 가져오는 함수
function getLocationsFromServer() {
    // AJAX 또는 Fetch를 사용하여 서버에서 위치 정보를 가져온다.
    // 서버에서 가져온 데이터는 JSON 형식.
    fetch('/app/loginCheck/travelDel?travelID='+travelID) // API 엔드포인트
        .then(response => response.json())
        .then(data => {
        	 console.log(data); // 데이터 확인을 위한 로그 출력
            // 가져온 데이터를 처리.
            displayLocationsOnMap(data);
        })
        .catch(error => {
            console.error('Error fetching location data:', error);
        });
}

//가져온 위치 정보를 지도에 표시하는 함수
function displayLocationsOnMap(locations) {
    var map = new kakao.maps.Map(document.getElementById('map'), {
        center: new kakao.maps.LatLng(37.566826, 126.9786567), // 지도의 중심 좌표 설정
        level: 3 // 지도의 확대 레벨 설정
    });

    // 가져온 위치 정보를 반복하면서 마커를 생성하고 지도에 표시합니다.
    locations.forEach(location => {
        var markerPosition = new kakao.maps.LatLng(location.latitude, location.longitude);

        // 마커를 생성하고 지도에 추가
        var marker = new kakao.maps.Marker({
            position: markerPosition
        });
        marker.setMap(map);
    });
}

// 페이지 로드 시 위치 정보를 가져와서 지도에 표시
getLocationsFromServer();​

 

 

 

 

서버로부터 받아온 계획(plan) 데이터를 사용하여 웹 페이지에 동적으로 일정 버튼을 생성하고, 각 버튼을 클릭할 때 해당 날짜의 일정 목록을 동적으로 생성하고 지도에 마커를 추가하는 기능을 구현했다.

    <script>
    
    var markers = [];  // 마커 배열
    
    $(function(){
  
  var obj = {};
     <c:forEach items="${planList}" var="plan" varStatus="status">
     
         if(!obj["${plan.day_num}"]){
             obj["${plan.day_num}"] = [];  //day_num에 해당하는 키 없을 시, 새로운 배열 생성하여 obj 객체에 담음
         }
         obj["${plan.day_num}"].push({   //day_num을 키로 하고 해당 날짜에 대한 일정 목록을 값으로 가짐
             item: "${plan.item}",
             item_add: "${plan.item_add}",
             time: "${plan.time}",
             time: "${plan.time}",
             mapx: "${plan.mapx}",
             mapy: "${plan.mapy}",
             idx: "${plan.idx}"
         })
     </c:forEach>

     var days = '';  //days 초기화. 일정 버튼 저장할 HTML 문자열 가짐.
     
     Object.keys(obj).forEach(function(e){  //obj객체의 키를 반복하면서 day_num에 대한 버튼 생성
     	 //TODO: html 수정  
         days += '<button class="btn btn-primary plan-days" data-day='+e+'>DAY '+e+'</button>';
     });

     $('#test-days tbody').html(days);  //test-days 테이블의 tbody에 일정 버튼 추가
     
   	//plan-days 버튼 클릭 이벤트
   	// 버튼 클릭시 해당 날짜의 일정 항목이 test-plan-item에 동적으로 생성됨
     $(".plan-days").on("click", function(){  
     	var day = $(this).data("day");
     	var planList = obj[day];
     	
     	$("#test-plan-item").empty();
     	
     	planList.forEach(function(plan){	
 		    
     		// TODO html 수정
 		    var html = ' <a href="#" class="list-group-item list-group-item-action py-3 lh-sm" aria-current="true">';
 		    html+='<div class="d-flex w-100 align-items-center justify-content-between">';
 		    html+=' <p> <strong class="mb-1">'+plan.item+'</strong> </p>';
 		    html+='<small class="text-body-secondary">'+plan.time+'</small>';
 		    html+='</div>';
 		    html+='<div class="col-10 mb-1 small">'+plan.item_add+'</div>';
 		    html+='</a>';
 	
     		$("#test-plan-item").append(html);  //html을 추가하여 세부 일정에 표시
     		
     		// 테스트
     		console.log(plan.item);
     		console.log(plan.mapx);
     		console.log(plan.mapy);
     		
     		// 해당 day에 속하는 모든 일정 항목의 위치 정보를 모아두고 전달
     		  var dayPlans = [];
     		  planList.forEach(function(plan) {
     		    dayPlans.push({ mapx: plan.mapx, mapy: plan.mapy });
     		  });
     		  
     		 // 마커 추가 함수 호출
     	    addMarkers(dayPlans);
     	});
     	
     })
    
 function addMarkers(dayPlans) {
    	 dayPlans.forEach(function(plan) {
        var mapx = plan.mapx;
        var mapy = plan.mapy;
        
       // 카카오맵 API 초기화
       kakao.maps.load(function() {
         var container = document.getElementById('map');
         var options = {
           center: new kakao.maps.LatLng(mapy, mapx),
           level: 3 // 지도 확대 수준 조정 (1-9 사이의 값)
         };

         var map = new kakao.maps.Map(container, options);

         // 마커 생성
         var markerPosition = new kakao.maps.LatLng(mapy, mapx);
         var marker = new kakao.maps.Marker({
           position: markerPosition
         });

         // 마커 지도에 표시
         marker.setMap(map);
         markers.push(marker);
         
         console.log(markers)
       });
      });
     }

    });

 

  1. 일정 데이터 객체(obj) 생성:
    • obj 객체는 planList에 대한 데이터를 날짜(day_num)를 기준으로 구조화한 것이다.
    • 각 날짜별로 배열이 생성되고, 해당 배열에는 날짜에 속하는 일정들이 객체 형태로 담겨 있다.
  2. 일정 버튼 생성:
    • Object.keys(obj).forEach를 사용하여 날짜별로 버튼을 생성하고, 이를 #test-days 테이블의 tbody에 추가한다.
  3. 일정 버튼 클릭 이벤트:
    • .plan-days 클래스를 가진 버튼이 클릭되면 해당 날짜의 일정 목록을 동적으로 생성하고, 지도에 마커를 추가하는 이벤트 핸들러가 실행된다.
  4. 일정 목록 동적 생성:
    • $(".plan-days").on("click", function(){...}에서 해당 날짜의 일정 목록을 동적으로 생성하고, 이를 #test-plan-item 영역에 추가한다.
  5. 마커 추가 함수(addMarkers):
    • addMarkers 함수는 각 일정의 위치 정보를 받아와 지도에 마커를 추가하는 역할을 한다.
    • 카카오맵 API를 사용하여 해당 위치로 지도를 생성하고, 마커를 해당 위치에 추가한다.
  6. 마커 배열(markers):
    • markers 배열은 생성된 마커를 저장하는 역할이다. 

 


 

 

🧨 일정 당 모든 세부 내역의 마커가 한번에 보이지않고, 최종적으로 하나의 마커만 보이는 이슈 발생

원인)

여러 개의 마커가 추가되어도 마지막 마커만 보이는 문제는 JavaScript의 비동기 작동과 클로저(Closure) 문제 때문에 발생할 수 있다. kakao.maps.load 메서드가 비동기적으로 실행되고, 마커 생성 루프에서 클로저 문제로 인해 마지막 마커만 나타날 수 있다.

 

해결)

클로저 문제를 해결하고, 각 마커에 대한 올바른 위치 정보를 보존해야 한다.

결론적으로 markers 배열을 전역 변수로 놓고, 그럼으로써 각 함수를 간단히 함으로써 해결했다.

<script>
    var markers = []; // 마커 배열 (전역 변수)
    
    $(function(){
    	 var obj = {};  // day버튼
    	    <c:forEach items="${planList}" var="plan" varStatus="status">
    	        if(!obj["${plan.day_num}"]){
    	            obj["${plan.day_num}"] = [];  //day_num에 해당하는 키 없을 시, 새로운 배열 생성하여 obj 객체에 담음
    	        }
    	        obj["${plan.day_num}"].push({   //day_num을 키로 하고 해당 날짜에 대한 일정 목록을 값으로 가짐
    	            item: "${plan.item}",
    	            item_add: "${plan.item_add}",
    	            time: "${plan.time}",
    	            time: "${plan.time}",
    	            mapx: "${plan.mapx}",
    	            mapy: "${plan.mapy}",
    	            idx: "${plan.idx}"
    	        })
    	    </c:forEach>

    	    var days = '';  //days 초기화. 일정 버튼 저장할 HTML 문자열 가짐.
    	    
    	    Object.keys(obj).forEach(function(e){  //obj객체의 키를 반복하면서 day_num에 대한 버튼 생성
    	    	 //TODO: html 수정  
    	        days += '<button class="btn btn-primary plan-days" data-day='+e+'>DAY '+e+'</button>';
    	    });

    	    $('#test-days tbody').html(days);  //test-days 테이블의 tbody에 일정 버튼 추가
    	    
    	    	// 마커 초기화
	 	    	clearMarkers(); 
    	    
    	  	//-----------plan-days 버튼 클릭 이벤트 시작------------
    	  	// 버튼 클릭시 해당 날짜의 일정 항목이 test-plan-item에 동적으로 생성됨
    	    $(".plan-days").on("click", function(){  
    	    	var day = $(this).data("day");
    	    	var planList = obj[day];
    	    	
    	    	$("#test-plan-item").empty();
    	    	
    	    	// 선택한 day에 속하는 세부일정의 위치 정보 저장
    	    	 var dayPlans = [];
    	    	    planList.forEach(function(plan) {
    	    	      dayPlans.push({ mapx: plan.mapx, mapy: plan.mapy });
    	    	    
    	    		// TODO html 수정
    			    var html = ' <a href="#" class="list-group-item list-group-item-action py-3 lh-sm" aria-current="true">';
    			    html+='<div class="d-flex w-100 align-items-center justify-content-between">';
    			    html+=' <p> <strong class="mb-1">'+plan.item+'</strong> </p>';
    			    html+='<small class="text-body-secondary">'+plan.time+'</small>';
    			    html+='</div>';
    			    html+='<div class="col-10 mb-1 small">'+plan.item_add+'</div>';
    			    html+='</a>';
    		
    	    		$("#test-plan-item").append(html);  //html을 추가하여 세부 일정에 표시
    	    	
    	    		// 테스트 코드
//     	    		console.log(plan.item);
//   	    		console.log(plan.mapx);
//    	    		console.log(plan.mapy); 
    	    	});
    	    
    	    		// 마커 추가
    	    		addMarkers(dayPlans);
    	    		
    	    });
    	    
    	    //-----------plan-days 버튼 클릭 이벤트 끝------------
    	    
    	    
    	    // 초기화 함수
    	    function clearMarkers() {
    	        markers.forEach(function(marker) {
    	            marker.setMap(null);
    	        });
    	        markers = [];
    	    }
    	    	
    	    	
    	    });  
    	  //---------------------------------- function() 끝 ----------------------------------
    	   
    	    // 마커 추가 함수
    	    function addMarkers(dayPlans) {

    	          // Kakao Map
    	          kakao.maps.load(function() {
    	            var container = document.getElementById('map');
    	            var options = {
    	              center: new kakao.maps.LatLng(dayPlans[0].mapy, dayPlans[0].mapx),  //첫 번째 마커 위치를 기준으로 중심 위치 설정
    	              level: 3
    	            };

    	            var map = new kakao.maps.Map(container, options);

	    	        // 마커 생성하고 추가
	    	        dayPlans.forEach(function(plan) {
		    	        var mapx = plan.mapx;
		    	        var mapy = plan.mapy;
	    	          
	    	            // 마커 생성
	    	            var markerPosition = new kakao.maps.LatLng(mapy, mapx);
	    	            var marker = new kakao.maps.Marker({
	    	                position: markerPosition
	    	            });
	
	    	            // 지도에 마커 출력
	    	            marker.setMap(map);
	    	            markers.push(marker);
	    	            
	    	            // 테스트 코드
	    	            console.log(markers);
	    	          });
	    	      });
    	      }

	</script>​

 

 

⭐ markers 배열을 전역 변수로 선언하는 이유?
마커 객체에 대한 참조를 유지하고, 다른 함수 또는 이벤트 처리에서 해당 마커를 쉽게 조작하고 접근하기 위함이다. 전역 변수로 선언하면 어디서든 해당 변수에 접근할 수 있으므로 여러 함수에서 마커 배열에 마커를 추가하거나 마커를 삭제하고, 필요한 경우 모든 마커를 초기화할 수 있다. 즉 유지보수가 더 쉬워진다.

⭐  markers 배열을 지역 변수로 선언한다면?
각 함수가 별개의 배열을 가지므로 일관성이 떨어지고 코드가 복잡해진다.

 

 

 


 

 

2️⃣ 버튼 활성화 추가

사용자가 어느 DAY 버튼을 눌렀는지 알 수 있게 버튼 활성화를 이용하여 표시하도록 했다.

 

 

 

그리고 페이지가 로드되면 사용자가 아무것도 클릭하지 않아도 자동으로 DAY1이 활성화되어 첫 화면에 보여지도록 하는 코드 추가

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함