DevGang
Авторизоваться

Анимированная карта путешествий с Leaflet

В этом уроке мы узнаем, как анимировать маркер с помощью Leaflet, без использования сторонних библиотек или плагинов Leaflet.

Leaflet - самая известная библиотека карт с открытым исходным кодом, имеющая множество плагинов. Два из них используются для анимации маркера на карте:

К сожалению, они больше не поддерживаются и имеют множество проблем в работе с последними версиями Leaflet и современными Javascript-фреймворками.

Тем не менее, они не являются необходимыми для анимации наших собственных маркеров или треков. Здесь вы узнаете, как отобразить текущее местоположение на карте. Приступим к работе с маркерами.

Инициализация проекта

Давайте создадим консоль Leaflet в нашем файле index.html:

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
  </head>

  <body>
    <div id="leaflet-container" style="width: 70vw; height: 70vh; margin: 50px auto"></div>
  </body>
  <script src="script.js"></script>
</html>

Затем инициализируйте Leaflet в нашем файле script.js:

const leafletMap = L.map(document.getElementById("leaflet-container")).setView([0, 0], 1);

Вот наш набор данных: массив случайных координат с временными метками, сгенерированный с помощью цикла:

const dataset = [{
  lng: -100,
  lat: -80,
  timestamp: new Date().getTime()
}];
let timestamp = 1710067901850;

for (let i = 1; i < 300; i++) {
  dataset.push({
    lng: dataset[i - 1].lng + Math.random(),
    lat: dataset[i - 1].lat + Math.random(),
    timestamp: dataset[i - 1].timestamp + 500
  });
};

Наконец, мы создадим маркер из исходной позиции и добавим его на карту:

let marker = L.marker(dataset[0], { icon: new L.Icon({ iconUrl: '/marker.svg', iconSize: [20, 20], iconAnchor: [10, 20] }) });
marker.addTo(leafletMap);

Анимация маркера

Теперь создадим функцию start(), которая будет использовать интервал для ежесекундного тиканья часов.

Функция tick будет перемещать положение маркера в течение периода между первой и последней меткой времени:

let tick = dataset[0].timestamp;
const endTime = dataset[dataset.length - 1].timestamp;
let interval;
function start() {
  interval = setInterval(() => {
    if (tick > endTime) {
      // End of animation: leave tracks and markers where they are but stop intervals
      stop();
    } else {
      // Create or update the marker
      moveMarker();

      // Update tick including speed
      tick += 500;
    }
  }, 100);
}

Функция stop() удаляет интервал, перемещает маркер обратно в начало координат и сбрасывает отметку:

function stop() {
  clearInterval(interval);
  tick = dataset[0].timestamp;
  marker.setLatLng(dataset[0]);
}

Давайте создадим нашу функцию moveMarker(): сначала она циклически просматривает наш набор данных, чтобы найти временную метку, наиболее близкую к нашей метке. Затем она перемещает маркер, обновляя свойство latlng координат маркера:

function moveMarker() {
  // Look for the timestamp just before tick
  let closestPointIndex = -1;
  for (let i = 0; i < dataset.length && closestPointIndex < 0; i += 1) {
    const timestamp = dataset[i].timestamp;
    if (timestamp > tick) {
      closestPointIndex = i === 0 ? 0 : i - 1;
    }
  }
  marker.setLatLng(dataset[closestPointIndex]);
}

Рисунок пути

Давайте улучшим нашу анимацию, нарисовав также и дорожку. Сначала мы создадим линию сразу после нашего маркера:

let path = L.polyline(dataset[0]);
path.addTo(leafletMap);

И обновите координаты так же, как мы делали это для маркера:

  marker.setLatLng(dataset[closestPointIndex]);
  path.setLatLngs(dataset.slice(0, closestPointIndex + 1));

Результат:

Добавление элементов управления воспроизведением

У нас уже есть функции start() и stop().

Теперь добавим несколько функций управления, например pause(): она проста, так как аналогична stop(), но не сбрасывает метку:

function pause() {
  clearInterval(interval);
}

Таким образом, функция start() продолжит воспроизведение с того места, где оно было приостановлено.

Мы можем добавить наши кнопки воспроизведения, которые привязаны к соответствующим функциям:

Здесь приведен HTML-код:

  <style>
    button {
      background-color: slateblue;
      border: 1px solid skyblue;
      color: lightblue;
      font-size: 1.25em;
      padding: 10px 20px;
      width: 70px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    button:hover {
      background-color: darkslateblue;
      color: white;
    }
  </style>

  <body>
    <section style="display: flex; width: 200px; margin: auto">
      <button
        onclick="start()"
        style="border-radius: 10px 0 0 10px; font-size: 1.5em"
      >
        ▶
      </button>
      <button
        onclick="pause()"
        style="border-radius: 0"
      >
        ❚❚
      </button>
      <button
        onclick="stop()"
        style="border-radius: 0 10px 10px 0; font-size: 2em; padding-top: 2px"
      >
        ■
      </button>   
    </section>

Заключение

В этой статье мы создали анимированную карту путешествий с помощью Leaflet.

Это решение действительно простое и не требует сторонних плагинов.

Кроме того, оно масштабируемо, так как в тестере было проверено 20 одновременных путешествий.

Вы можете найти рабочий сайт в этом стекблице.

Источник:

#JavaScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу