본문 바로가기
API사용

[Mapbox] 길찾기 API 기본 사용법 예시

by 미눅스[멘토] 2025. 4. 17.
728x90

 

 

https://docs.mapbox.com/help/tutorials/getting-started-directions-api/?step=0

 

Getting started with the Mapbox Directions API | Help

Add routing capabilities to your application with the Mapbox Directions API.

docs.mapbox.com

 위 URL로 접속하면 길찾기 예시를 확인할 수 있다.

*월 10만건에 대해 무료로 제공한다.

접속해서 설명서대로 단계를 한개씩 밟아보자.

 

설명하기 너무 길어 VsCode로 복붙 후 눈으로 확인하자

설명은 주석으로 달아놓았다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8" />
  <title>Mapbox Directions API - 경로 찾기 예제</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
    #instructions {
      position: absolute;
      margin: 20px;
      width: 25%;
      top: 0;
      bottom: 20%;
      padding: 20px;
      background-color: #fff;
      overflow-y: scroll;
      font-family: sans-serif;
    }
  </style>
</head>

<body>
  <!-- 지도 표시할 영역 -->
  <div id="map"></div>

  <!-- 경로 안내 표시할 영역 -->
  <div id="instructions"></div>

  <script>
    // Mapbox 액세스 토큰 설정
    mapboxgl.accessToken = ' minwooToken' ;

    // 지도 객체 생성
    const map = new mapboxgl.Map({
      container: 'map', // 지도를 표시할 div ID
      style: 'mapbox://styles/mapbox/streets-v12', // 지도 스타일
      center: [126.735901, 37.348980], // 초기 중심 좌표 (경도, 위도)
      zoom: 12 // 초기 확대 레벨
    });

    // 출발 지점 좌표 (고정)
    const start = [126.735901, 37.348980];

    /**
     * 도착 지점을 받아 경로를 요청하고 지도에 표시하는 함수
     * @param {Array} end 도착 지점 좌표 [lng, lat]
     */
    async function getRoute(end) {
      // Directions API를 호출하여 경로 데이터 가져오기
      const query = await fetch(
        `https://api.mapbox.com/directions/v5/mapbox/cycling/${start[0]},${start[1]};${end[0]},${end[1]}?steps=true&geometries=geojson&language=ko&access_token=${mapboxgl.accessToken}`
      );

      const json = await query.json();
      const data = json.routes[0]; // 첫 번째 경로 정보 가져오기
      const route = data.geometry; // 경로의 GeoJSON 데이터

      // GeoJSON 형식으로 경로 데이터 생성
      const geojson = {
        'type': 'Feature',
        'properties': {},
        'geometry': route
      };

      // 만약 기존에 'route' 소스가 있으면 데이터 업데이트
      if (map.getSource('route')) {
        map.getSource('route').setData(geojson);
      }
      // 없으면 새로 'route' 레이어 추가
      else {
        map.addLayer({
          id: 'route',
          type: 'line',
          source: {
            type: 'geojson',
            data: geojson
          },
          layout: {
            'line-join': 'round', // 선을 부드럽게 연결
            'line-cap': 'round'   // 선 끝을 둥글게
          },
          paint: {
            'line-color': '#3887be', // 선 색상
            'line-width': 5,          // 선 굵기
            'line-opacity': 0.75      // 선 투명도
          }
        });
      }

      // 경로 안내(instructions) 영역 업데이트
      const instructions = document.getElementById('instructions');
      const steps = data.legs[0].steps; // 단계별 안내 정보

      let tripInstructions = '';
      for (const step of steps) {
        tripInstructions += `<li>${step.maneuver.instruction}</li>`; // 각각 안내 문구 추가
      }

      // 경로 안내 HTML 작성
      instructions.innerHTML = `
        <p id="prompt">📍 지도를 클릭하면 다른 도착지까지 경로를 찾을 수 있습니다.</p>
        <p><strong>예상 소요 시간: ${Math.floor(data.duration / 60)}분 🚴</strong></p>
        <ol>${tripInstructions}</ol>
      `;
    }

    // 지도 로드 완료 시
    map.on('load', () => {
      // 기본 도착 지점 설정
      const defaultEnd = [126.740000, 37.355000];

      // 출발 지점을 지도에 원(circle)으로 표시
      map.addLayer({
        'id': 'origin-circle',
        'type': 'circle',
        'source': {
          'type': 'geojson',
          'data': {
            'type': 'FeatureCollection',
            'features': [
              {
                'type': 'Feature',
                'properties': {},
                'geometry': {
                  'type': 'Point',
                  'coordinates': start
                }
              }
            ]
          }
        },
        'paint': {
          'circle-radius': 10, // 원 크기
          'circle-color': '#4ce05b' // 원 색상 (초록색)
        }
      });

      // 도착 지점을 지도에 원(circle)으로 표시
      map.addLayer({
        'id': 'destination-circle',
        'type': 'circle',
        'source': {
          'type': 'geojson',
          'data': {
            'type': 'FeatureCollection',
            'features': [
              {
                'type': 'Feature',
                'properties': {},
                'geometry': {
                  'type': 'Point',
                  'coordinates': defaultEnd
                }
              }
            ]
          }
        },
        'paint': {
          'circle-radius': 10, // 원 크기
          'circle-color': '#f30' // 원 색상 (빨간색)
        }
      });

      // 기본 경로 요청 및 표시
      getRoute(defaultEnd);
    });

    // 지도 클릭 시 이벤트 처리
    map.on('click', (event) => {
      // 클릭한 좌표 가져오기
      const coords = Object.keys(event.lngLat).map(
        (key) => event.lngLat[key]
      );

      // 클릭한 위치를 도착지로 설정
      const end = {
        'type': 'FeatureCollection',
        'features': [
          {
            'type': 'Feature',
            'properties': {},
            'geometry': {
              'type': 'Point',
              'coordinates': coords
            }
          }
        ]
      };

      // 도착지 데이터 업데이트
      map.getSource('destination-circle').setData(end);

      // 새 경로 요청
      getRoute(coords);
    });
  </script>
</body>
</html>

 

 

 

 

이렇게 시작점, 도착점의 길과 예상 소요시간 및 순서까지 잘 나오는것을 확인

 

 

 


 

 

자전거 애니메이션 추가버전

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8" />
  <title>Mapbox Directions API - 경로 찾기 예제</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
    #instructions {
      position: absolute;
      margin: 20px;
      width: 25%;
      top: 0;
      bottom: 20%;
      padding: 20px;
      background-color: #fff;
      overflow-y: scroll;
      font-family: sans-serif;
    }
  </style>
</head>

<body>
  <div id="map"></div>
  <div id="instructions"></div>

  <script>
    mapboxgl.accessToken = 'minwooToken';

    const map = new mapboxgl.Map({
      container: 'map',
      style: 'mapbox://styles/mapbox/streets-v12',
      center: [126.735901, 37.348980],
      zoom: 12
    });

    const start = [126.735901, 37.348980];
    let marker;
    let animationFrameId;

    //두 좌표 사이를 선형 보간(interpolate)
    function interpolate(p1, p2, t) {
      const lng = p1[0] + (p2[0] - p1[0]) * t;
      const lat = p1[1] + (p2[1] - p1[1]) * t;
      return [lng, lat];
    }

    //경로 따라 자전거 아이콘 부드럽게 애니메이션
    function animateRoute(coordinates) {
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
      }
      if (marker) {
        marker.remove();
      }

      const bikeIcon = document.createElement('div');
      bikeIcon.innerHTML = '🚴';
      bikeIcon.style.fontSize = '24px';
      bikeIcon.style.transform = 'translate(-50%, -50%)';

      marker = new mapboxgl.Marker(bikeIcon)
        .setLngLat(coordinates[0])
        .addTo(map);

      let progress = 0;
      const speed = 0.01; // ★ 속도 설정 (0.001 ~ 0.003 추천)

      function moveMarker() {
        const n = coordinates.length;
        const currentIndex = Math.floor(progress);
        const nextIndex = currentIndex + 1;

        if (nextIndex >= n) return; // 경로 끝 도달

        const t = progress - currentIndex;
        const currentCoord = coordinates[currentIndex];
        const nextCoord = coordinates[nextIndex];

        const interpolatedCoord = interpolate(currentCoord, nextCoord, t);
        marker.setLngLat(interpolatedCoord);

        progress += speed;
        animationFrameId = requestAnimationFrame(moveMarker);
      }

      moveMarker();
    }

    //도착 지점을 받아 경로를 요청하고 지도에 표시하는 함수
    async function getRoute(end) {
      const query = await fetch(
        `https://api.mapbox.com/directions/v5/mapbox/cycling/${start[0]},${start[1]};${end[0]},${end[1]}?steps=true&geometries=geojson&language=ko&access_token=${mapboxgl.accessToken}`
      );

      const json = await query.json();
      const data = json.routes[0];
      const route = data.geometry;

      const geojson = {
        'type': 'Feature',
        'properties': {},
        'geometry': route
      };

      if (map.getSource('route')) {
        map.getSource('route').setData(geojson);
      } else {
        map.addLayer({
          id: 'route',
          type: 'line',
          source: {
            type: 'geojson',
            data: geojson
          },
          layout: {
            'line-join': 'round',
            'line-cap': 'round'
          },
          paint: {
            'line-color': '#3887be',
            'line-width': 5,
            'line-opacity': 0.75
          }
        });
      }

      const instructions = document.getElementById('instructions');
      const steps = data.legs[0].steps;

      let tripInstructions = '';
      for (const step of steps) {
        tripInstructions += `<li>${step.maneuver.instruction}</li>`;
      }

      instructions.innerHTML = `
        <p id="prompt">📍지도를 클릭하면 다른 도착지까지 경로를 찾을 수 있습니다.</p>
        <p><strong>예상 소요 시간: ${Math.floor(data.duration / 60)}분 🚴</strong></p>
        <ol>${tripInstructions}</ol>
      `;

      //경로 따라 부드러운 자전거 애니메이션 시작
      animateRoute(route.coordinates);
    }

    map.on('load', () => {
      const defaultEnd = [126.740000, 37.355000];

      map.addLayer({
        'id': 'origin-circle',
        'type': 'circle',
        'source': {
          'type': 'geojson',
          'data': {
            'type': 'FeatureCollection',
            'features': [
              {
                'type': 'Feature',
                'properties': {},
                'geometry': {
                  'type': 'Point',
                  'coordinates': start
                }
              }
            ]
          }
        },
        'paint': {
          'circle-radius': 10,
          'circle-color': '#4ce05b'
        }
      });

      map.addLayer({
        'id': 'destination-circle',
        'type': 'circle',
        'source': {
          'type': 'geojson',
          'data': {
            'type': 'FeatureCollection',
            'features': [
              {
                'type': 'Feature',
                'properties': {},
                'geometry': {
                  'type': 'Point',
                  'coordinates': defaultEnd
                }
              }
            ]
          }
        },
        'paint': {
          'circle-radius': 10,
          'circle-color': '#f30'
        }
      });

      getRoute(defaultEnd);
    });

    map.on('click', (event) => {
      const coords = Object.keys(event.lngLat).map(
        (key) => event.lngLat[key]
      );

      const end = {
        'type': 'FeatureCollection',
        'features': [
          {
            'type': 'Feature',
            'properties': {},
            'geometry': {
              'type': 'Point',
              'coordinates': coords
            }
          }
        ]
      };

      map.getSource('destination-circle').setData(end);
      getRoute(coords);
    });
  </script>
</body>
</html>