#15 중요 로직들 - 4 (feat. 카카오맵, 거리계산)

김대진·2023년 3월 21일
0

Sekkison Project

목록 보기
16/22
post-thumbnail

앞서서 약속 만들기 페이지를 만들어 보았으니 이제 약속정보를 표시하는 페이지를 만들어 보겠다.

우리 프로젝트의 약속정보 페이지는 다음 이미지와 같다.

물론 멤버가 아니라면 초대하기 버튼이 사라지고, 방장이 아니라면 폭파 버튼이 참가하기/나가기 버튼으로 대체된다.

멤버 부분을 보면 이름 우측에 거리가 표시된 것이 보일 텐데, 이 거리는 사용자의 실시간 위치와 DB에 저장된 약속장소의 위치 사이의 거리를 계산해서 약속시간 30분 전부터 보여주기 시작하고, 약속시간이 지나면 다시 비활성화된다.

약속 DB에는 약속장소의 좌표 X, Y가 저장되어 있고, 사이트에서는 50m 단위로 이동할 때마다 자신의 X, Y좌표를 유저 DB에 저장한다.
다음으로는 그 정보를 사용해서 좌표 사이 거리를 보여주면 될 것이다.

먼저는 유저의 위치정보를 받아올 필요가 있을 것이다. 유저의 위치정보를 받아오는 자바스크립트 코드는 다음과 같다.

javascript

//위치정보 받아오기
if (navigator.geolocation) {
   let before_record = null;
   const newId = navigator.geolocation.watchPosition(
      (position) => {
         let updateFlag = true;
         const now = new Date();
         const new_record = {
            err: 0,
            time: now.toLocaleTimeString(),
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
         };
         //시작
         if (before_record !== null) {
            const dist = getDistance(
               before_record.latitude,
               before_record.longitude,
               new_record.latitude,
               new_record.longitude,
            );
            //이동거리가 50m미만이면 안바뀜
            if(dist < 0.05) updateFlag = false;
         } 

         if(updateFlag) {
            setcoords(new_record);
            before_record = new_record;
         }
      },
      (err) => 
         { console.log(err.message); },
         { enableHighAccuracy: true, maximumAge: 10000, timeout: 5000 }
   );
}
//거리계산
function getDistance(lat1,lng1,lat2,lng2) {
   function deg2rad(deg) { return deg * (Math.PI/180)}

   var R = 6371; // Radius of the earth in km
   var dLat = deg2rad(lat2-lat1);  // deg2rad below
   var dLon = deg2rad(lng2-lng1);
   var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2);
   var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
   var d = R * c; // Distance in km
   return d;
}
//서버에 전송
function setcoords(record) {
   console.log(`X : ${record.latitude}`);
   console.log(`Y : ${record.longitude}`);

   $.ajax({
      url:`${path}/users/setPos/${localStorage.getItem("sks_id")}`,
      type:"PUT",
      data:{
         "x" : record.latitude,
         "y" : record.longitude
      },
      cache:false,
      success : function(data){
         if (data.success) console.log("위치 저장 완료");
         else console.log(data.msg);
      }
   });
}

위의 코드는 사용자의 움직임을 감지하다가 사용자가 50m 이상 움직였다면, 좌표를 갱신시켜 서버에 전송해 주는 코드이다.
실시간으로 감지를 할 수도 있지만, 실시간 감지는 비효율적일 것이라는 판단이었다. 이 코드를 모든 페이지에 들어가 있는 헤더의 js에 담아 실행시켰다.

다음은 약속정보 페이지에서 거리를 표시하는 로직이다.

javascript

endDist = appointdday;
startDist = new Date(Date.parse(appointdday)-1000*60*30);

javascript

function getDist(lat1,lng1,lat2,lng2) {
   if(new Date() < startDist) return "---"

   function deg2rad(deg) { return deg * (Math.PI/180)}

   let R = 6371;
   let dLat = deg2rad(lat2-lat1);
   let dLon = deg2rad(lng2-lng1);
   let a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2);
   let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
   let d = R * c * 1000;

   if (new Date() < endDist) {
      if (d >= 1000) return `${Math.round(d/100)/10}km`;
      else return `${Math.round(d)}m`;
   }
   else return "---";
}

getDist라는 함수는 위도값과 경도값 두 개 씩을 받아 사이의 거리를 계산하는 함수이다. 이 함수의 경우 약속시간 30분전부터만 거리를 보여주기 때문에 별도의 로직이 조금 더 들어갔지만, 만약 그저 거리만 표시하고 싶으면 다음 함수를 사용하기 바란다.

function getDist(lat1,lng1,lat2,lng2) {
   function deg2rad(deg) { return deg * (Math.PI/180)}

   let R = 6371;
   let dLat = deg2rad(lat2-lat1);
   let dLon = deg2rad(lng2-lng1);
   let a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2);
   let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
   let d = R * c * 1000;

   if (d >= 1000) return `${Math.round(d/100)/10}km`;
   else return `${Math.round(d)}m`;
}

이 방법을 사용하면, 사용자가 일정 거리를 움직일 때마다 감지해서 약속장소와의 거리를 표시할 수 있다.

참고로, 사용자의 위치를 받아오는 navigator.geolocation은 https에서만 동작하니 http에서 테스트해 보는 것은 권장되지 않는다.

profile
만재 개발자

0개의 댓글