Заказ в пути

Положение курьера обновляется вдоль дорожного маршрута. Карта и остальные слои остаются на месте.

  1. Запустите пример и следите за синей меткой.
  2. Можно перемещать карту: обновление координат не сбрасывает камеру.
import * as sdk from "@umap-llc/map-react";

// HTML: <div id="map" style="height:480px;position:relative"></div>
const map = sdk.createMap({
  container: "map",
  style: "YOUR_STYLE_URL",
  accessToken: "YOUR_ACCESS_TOKEN",
  center: [71.423, 51.128],
  zoom: 14,
});

async function setupExample(map, sdk, report = console.log) {
  const response = await fetch(
    "https://developer.umap.kz/examples/data/trip.geojson",
  );
  if (!response.ok) throw new Error("Не удалось загрузить поездку");
  const trip = await response.json();
  const path = trip.features[0].geometry.coordinates;
  await map.addSource("trip", { type: "geojson", data: trip });
  map.addLayer({
    id: "trip-line",
    type: "line",
    source: "trip",
    "rendering-order": "overlay",
    paint: {
      "line-color": "#1769e0",
      "line-width": 4,
      "line-opacity": 0.65,
    },
  });
  await map.addSource("courier", {
    type: "geojson",
    data: { type: "FeatureCollection", features: [] },
  });
  map.addLayer({
    id: "courier-halo",
    type: "circle",
    source: "courier",
    "rendering-order": "overlay",
    paint: { "circle-radius": 12, "circle-color": "#fff" },
  });
  map.addLayer({
    id: "courier-dot",
    type: "circle",
    source: "courier",
    "rendering-order": "overlay",
    paint: { "circle-radius": 8, "circle-color": "#1769e0" },
  });
  map.fitBounds(
    [
      [71.399, 51.122],
      [71.438, 51.14],
    ],
    { padding: 65, maxZoom: 14.5 },
  );
  const distances = [0];
  for (let i = 1; i < path.length; i++)
    distances.push(
      distances[i - 1] +
        Math.hypot(
          (path[i][0] - path[i - 1][0]) * 0.63,
          path[i][1] - path[i - 1][1],
        ),
    );
  const start = performance.now();
  let frame = 0;
  const update = () => {
    const progress = Math.min(1, (performance.now() - start) / 45000);
    const d = progress * distances[distances.length - 1];
    let i = 0;
    while (i < path.length - 2 && distances[i + 1] < d) i++;
    const t = Math.min(
      1,
      (d - distances[i]) / (distances[i + 1] - distances[i] || 1),
    );
    const p = [
      path[i][0] + (path[i + 1][0] - path[i][0]) * t,
      path[i][1] + (path[i + 1][1] - path[i][1]) * t,
    ];
    map.setData("courier", {
      type: "FeatureCollection",
      features: [
        {
          type: "Feature",
          properties: {},
          geometry: { type: "Point", coordinates: p },
        },
      ],
    });
    if (progress < 1) frame = requestAnimationFrame(update);
    else report("Курьер прибыл");
  };
  report("Курьер в пути · заказ №1042");
  update();
  return () => cancelAnimationFrame(frame);
}

map.once("load", async () => {
  const cleanup = await setupExample(map, sdk);
  if (cleanup) map.once("remove", cleanup);
});
Как запустить у себя

В JavaScript укажите Style URL и ключ своей карты. Код запускайте в проекте со сборщиком. Во Flutter сохраните пример в lib/main.dart и передайте UMAP_STYLE_URL и UMAP_ACCESS_TOKEN через --dart-define.

Примеры со своими данными загружают подготовленные GeoJSON и изображения. Замените их файлами вашего приложения. Для Flutter-примеров с загрузкой файлов добавьте зависимость: flutter pub add http.

Установка и первая карта →Скачать Flutter-пример