[Javascript/Geolocation] Web 실시간으로 수집한 위치 정보로 나침반 구현하기

2020. 5. 5. 20:27Frontend

반응형
해당 포스트는 https://courses.wesbos.com/account/access/5d760ba285f96c03c1e5725d/view/194128542 를 기반으로 작성되었습니다.

이번 예제는 Geolocation인터페이스를 사용해 웹에서 실시간 위치 정보 수집하기 입니다.

 


Geolocation.watchPosition() 사용하기

Geolocation.watchPosition()?

장치의 위치가 바뀔 때마다 자동으로 호출할 처리기 함수를 등록할 때 사용합니다. 선택적으로 오류 발생 시 사용할 콜백 함수도 지정할 수 있습니다.
  • 매개변수

    1. success : GeolocationPosition 객체를 입력 매개변수로 사용하는 콜백 함수
    2. error(option) : GeolocationPositionError 객체를 입력 매개변수로 사용하는 콜백 함수
    3. options(option) : 위치 감지 설정 옵션을 제공하는 PositionOptions 객체
  • 반환 값 : 등록한 처리기를 식별할 때 사용하는 정수 ID. ID를 Geolocation.clearWatch()에 전달해 등록을 해제할 수 있다.

* 자세한 설명은 MDN - Geolocation.watchPosition()에서 확인하실 수 있습니다.

GeolocationPosition 위치정보 수집

성공시 얻을 수 있는 GeolocationPosition 객체에선 어떤 위치 정보를 얻을 수 있을까?

GeolocationPosition 인터페이스?

주어진 시간에 장치가 위치한 지점을 나타냅니다. 지점은 Coordinates 객체로 표현하여, 지구를 나타내는 회전타원체 위의 2D 위치와 더불어 높이와 속도 정보를 담습니다.
  • Position.coords : 주어진 시간의 위치를 나타내는 Coordinates 객체
  • Position.timestamp : 위치를 기록한 시간을 나타내는 DOMTimeStamp

* 자세한 설명은 MDN - GeolocationPosition에서 확인하실 수 있습니다.

Coordinates 인터페이스

위치 및 고도 지구 장치뿐만 아니라, 이러한 특성이 계산되는 정확도를 나타낸다.

우리가 여기서 얻을 수 있는 정보는 다음과 같다.

  • latitude : 위도
  • longitude : 경도
  • altitude : 고도
  • accuracy : 위도, 경도 정확도
  • altitudeAccuracy : 고도 정확도
  • heading : 이동 방향
  • speed : 장치 속도

* 자세한 설명은 MDN - GeolocationCoordinates에서 확인하실 수 있습니다.


만들어 볼 예제

이러한 웹 사이트를 만드는 예제입니다.

실습 결과 확인은 스마트폰에서 npm 외부 링크로 접속해 확인하였습니다.

 

필요 기능을 분석해보자면,

  1. 사이트에 접속한 직후부터 동의하에 위치 정보를 수집합니다.
  2. 실시간 위치 정보를 바탕으로 나침반의 방향이 바뀌고 현재 속도가 표시됩니다.

예제 시작 코드

Wesbos께서 시작 코드를 제공해주시고 계십니다.

https://github.com/wesbos/JavaScript30/tree/master/21%20-%20Geolocation
여기서 index-START.html의 코드를 저희가 원하는 방향으로 수정해가면 됩니다.

코드 실행하고 싶으시면 해당 package.json도 같이 정의하시고
npm install -> npm start로 실행 후 index-START.html 눌러주세요.

script 코드

우리는 예제에 필요한 정보인 이동 방향, 장치 속도만 활용해 구현합니다.

나침반의 방향 설정은 rotate시켜 구현하였습니다.


id 추출 및 해제가 가능하다고 하여 에러 발생시 해제 까지 구현해보았습니다. (강의 영상엔 없음)

   let id = navigator.geolocation.watchPosition(data => {
      let {speed, heading} = data.coords;
      speedValue.textContent = speed.toString();
      arrow.style.transform = `rotate(${heading}deg)`;
    }, err => {
      console.log(err);
      alert('에러가 발생했습니다!');
      navigator.geolocation.clearWatch(id);
    });

전체 코드 (html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <meta name="viewport" content="width=device-width">
</head>
<body>
  <svg class="arrow" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve"><g><path fill="#ffffff" d="M32,1.824C15.361,1.824,1.825,15.361,1.825,32c0,16.639,13.537,30.176,30.175,30.176   S62.175,48.639,62.175,32C62.175,15.361,48.639,1.824,32,1.824z M29.715,3.988h1.12l2.333,3.807V3.988h1.069v5.701h-1.155   l-2.298-3.718v3.718h-1.069V3.988z M9.323,33.917H8.102l-1.136-4.262l-1.132,4.262H4.587l-1.361-5.701h1.178l0.859,3.916   l1.042-3.916h1.369l0.999,3.982l0.875-3.982h1.159L9.323,33.917z M33.995,59.828c-0.181,0.285-0.438,0.497-0.77,0.636   c-0.332,0.139-0.745,0.208-1.241,0.208c-0.721,0-1.274-0.167-1.661-0.5c-0.386-0.333-0.617-0.819-0.692-1.456l1.12-0.109   c0.067,0.376,0.204,0.652,0.41,0.828c0.206,0.176,0.484,0.264,0.834,0.264c0.371,0,0.65-0.078,0.838-0.235   c0.188-0.157,0.282-0.34,0.282-0.55c0-0.135-0.04-0.25-0.119-0.344c-0.079-0.095-0.217-0.177-0.414-0.247   c-0.135-0.047-0.442-0.13-0.922-0.249c-0.617-0.153-1.05-0.341-1.299-0.564c-0.35-0.314-0.525-0.696-0.525-1.147   c0-0.29,0.082-0.562,0.247-0.815c0.165-0.253,0.402-0.445,0.712-0.577c0.31-0.132,0.684-0.198,1.122-0.198   c0.716,0,1.254,0.157,1.616,0.471c0.362,0.314,0.552,0.733,0.57,1.256l-1.151,0.051c-0.049-0.293-0.155-0.504-0.317-0.632   c-0.162-0.128-0.405-0.193-0.729-0.193c-0.334,0-0.596,0.069-0.786,0.206c-0.122,0.088-0.183,0.206-0.183,0.354   c0,0.135,0.057,0.25,0.171,0.346c0.145,0.122,0.498,0.249,1.058,0.381c0.56,0.132,0.974,0.269,1.243,0.41   c0.268,0.141,0.478,0.334,0.63,0.58c0.152,0.245,0.227,0.548,0.227,0.908C34.267,59.237,34.176,59.543,33.995,59.828z M32,52.795   c-11.466,0-20.795-9.329-20.795-20.795c0-11.466,9.329-20.795,20.795-20.795S52.795,20.534,52.795,32   C52.795,43.466,43.466,52.795,32,52.795z M55.014,33.917v-5.701h4.227v0.965h-3.076v1.264h2.862v0.96h-2.862v1.552h3.185v0.961   H55.014z"/><g><path fill="#000000" d="M48.904,31.863c-4.074-1.358-8.148-2.717-12.226-4.066c-0.265-0.087-0.399-0.223-0.486-0.486    c-1.349-4.077-2.708-8.151-4.066-12.226c-0.029-0.087-0.074-0.169-0.132-0.3c-0.054,0.152-0.09,0.245-0.122,0.34    c-1.352,4.053-2.707,8.104-4.048,12.161c-0.096,0.292-0.246,0.428-0.532,0.522c-4.056,1.342-8.108,2.696-12.16,4.049    c-0.097,0.032-0.189,0.074-0.344,0.137c0.172,0.06,0.267,0.093,0.362,0.125c4.074,1.358,8.148,2.717,12.224,4.072    c0.204,0.068,0.337,0.158,0.412,0.386c1.243,3.757,2.498,7.511,3.75,11.265c0.144,0.432,0.291,0.862,0.463,1.373    c0.068-0.185,0.108-0.285,0.142-0.386c1.349-4.042,2.701-8.083,4.04-12.128c0.094-0.284,0.231-0.438,0.523-0.534    c4.056-1.341,8.108-2.696,12.161-4.048c0.099-0.033,0.195-0.076,0.347-0.137C49.067,31.925,48.987,31.891,48.904,31.863z     M37.475,32.038c-1.316,0.439-2.631,0.879-3.947,1.314c-0.095,0.031-0.139,0.081-0.17,0.173c-0.434,1.313-0.873,2.625-1.311,3.937    c-0.012,0.033-0.024,0.066-0.046,0.126c-0.056-0.166-0.104-0.306-0.15-0.446c-0.407-1.219-0.814-2.437-1.218-3.657    c-0.025-0.074-0.068-0.104-0.134-0.125c-1.323-0.44-2.646-0.881-3.968-1.322c-0.031-0.01-0.062-0.022-0.118-0.041    c0.05-0.02,0.081-0.034,0.112-0.045c1.315-0.439,2.631-0.879,3.947-1.314c0.093-0.03,0.142-0.075,0.173-0.17    c0.435-1.316,0.875-2.632,1.314-3.947c0.01-0.031,0.022-0.062,0.039-0.11c0.019,0.042,0.033,0.069,0.043,0.097    c0.441,1.323,0.882,2.645,1.321,3.969c0.028,0.085,0.072,0.129,0.158,0.158c1.324,0.438,2.646,0.879,3.969,1.32    c0.027,0.009,0.053,0.02,0.1,0.038C37.538,32.013,37.507,32.027,37.475,32.038z"/><path fill="#000000" d="M24.436,27.633c-1.069-2.137-2.119-4.237-3.216-6.43c2.189,1.094,4.292,2.145,6.433,3.216    c-0.359,0.713-0.706,1.404-1.057,2.091c-0.023,0.045-0.078,0.082-0.127,0.106C25.807,26.949,25.143,27.28,24.436,27.633z"/><path fill="#000000" d="M39.573,27.632c-0.696-0.348-1.351-0.673-2.002-1.005c-0.076-0.038-0.155-0.104-0.193-0.177    c-0.338-0.661-0.666-1.326-1.019-2.033c2.121-1.061,4.228-2.115,6.43-3.217C41.69,23.399,40.635,25.509,39.573,27.632z"/><path fill="#000000" d="M24.436,36.339c0.712,0.357,1.394,0.698,2.074,1.043c0.046,0.024,0.088,0.073,0.113,0.121    c0.339,0.671,0.674,1.345,1.028,2.051c-2.126,1.063-4.232,2.117-6.43,3.216C22.317,40.577,23.37,38.472,24.436,36.339z"/><path fill="#000000" d="M36.358,39.555c0.354-0.707,0.688-1.38,1.028-2.05c0.028-0.056,0.084-0.111,0.14-0.139    c0.67-0.339,1.343-0.674,2.047-1.026c1.066,2.131,2.118,4.235,3.215,6.43C40.601,41.676,38.503,40.628,36.358,39.555z"/></g></g></svg>


  <h1 class="speed">
    <span class="speed-value">0</span>
    <span class="units">KM/H</span>
  </h1>

  <style>
    html {
      font-size: 100px;
    }

    body {
      margin: 0;
      font-family: sans-serif;
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      background:
        radial-gradient(black 15%, transparent 16%) 0 0,
        radial-gradient(black 15%, transparent 16%) 8px 8px,
        radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 0 1px,
        radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 8px 9px;
      background-color: #282828;
      background-size: 16px 16px;
      background-attachment: fixed;
    }

    .arrow {
      width: 250px;
      overflow: hidden;
      transition: all 0.2s;
      transform: rotate(0deg);
      display: inline-block;
    }

    h1 {
      color: white;
      font-weight: 100;
      font-size: 60px;
      display: flex;
      align-items: center;
    }

    .units {
      font-size: 15px;
    }
    /*Compass: https://thenounproject.com/search/?q=compass&i=592352*/
  </style>
  <script>
    const arrow = document.querySelector('.arrow');
    const speedValue = document.querySelector('.speed-value');

    let id = navigator.geolocation.watchPosition(data => {
      let {speed, heading} = data.coords;
      speedValue.textContent = speed.toString();
      arrow.style.transform = `rotate(${heading}deg)`;
    }, err => {
      console.log(err);
      alert('에러가 발생했습니다!');
      navigator.geolocation.clearWatch(id);
    });
  </script>
</body>
</html>

 

 

 

 

 

 

반응형