Анимированная карта путешествий с 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 одновременных путешествий.
Вы можете найти рабочий сайт в этом стекблице.