Skip to content

Построить маршрут между двумя точками

Совет

Не забудьте задать router в servicesApikeys в настройках при инициализации vue-yandex-maps, в противном случае метод работать не будет.

Создать ключ API Матрицы Расстояний и Построения маршрута можно в Кабинете разработчика.

html
<yandex-map
  v-model="map"
  :settings="{
    location,
    theme,
    showScaleInCopyrights: true,
  }"
  :width="width"
  :height="height"
>
  <yandex-map-default-scheme-layer />
  <yandex-map-default-features-layer />
  <yandex-map-controls :settings="{ position: 'bottom left' }">
    <yandex-map-control>
      <div class="info">
        Перетаскивайте маркеры, чтобы изменить маршрут
      </div>
    </yandex-map-control>
  </yandex-map-controls>

  <yandex-map-default-marker
    :settings="{
      coordinates: pointACoordinates,
      title: 'Точка A',
      subtitle: pointASubtitle,
      draggable: true,
      onDragMove: onDragMovePointAHandler,
      onDragEnd: onDragEndHandler,
    }"
  />
  <yandex-map-default-marker
    :settings="{
      coordinates: pointBCoordinates,
      title: 'Точка Б',
      subtitle: pointBSubtitle,
      draggable: true,
      onDragMove: onDragMovePointBHandler,
      onDragEnd: onDragEndHandler,
    }"
  />

  <yandex-map-feature
    v-if="route"
    :settings="{
      ...route,
      style: lineStyle,
    }"
  />
</yandex-map>
ts
import {
  YandexMap,
  YandexMapDefaultSchemeLayer,
  YandexMapControls,
  YandexMapControl,
  YandexMapDefaultFeaturesLayer,
  YandexMapDefaultMarker,
  YandexMapFeature,
  getLocationFromBounds,
  VueYandexMaps,
} from 'vue-yandex-maps';
import type { YMapLocationRequest } from '@yandex/ymaps3-types/imperative/YMap';
import type {
  DrawingStyle, LngLat, RouteFeature, YMap, YMapMarkerEventHandler,
} from '@yandex/ymaps3-types';
import {
  ref, shallowRef, watch,
} from 'vue';

const location = ref<YMapLocationRequest>({
  center: [37.623082, 55.75254], // starting position [lng, lat]
  zoom: 9, // starting zoom
});

const map = shallowRef<YMap | null>(null);

// The initial coordinates of the starting and ending points of the route
const INITIAL_ROUTE_POINTS: LngLat[] = [
  [37.620028, 55.741556],
  [38.130492, 56.31112],
];

// An object containing the route line style
const lineStyle: DrawingStyle = {
  fillRule: 'nonzero',
  fill: '#333',
  fillOpacity: 0.9,
  stroke: [
    {
      width: 6,
      color: '#007afce6',
    },
    {
      width: 10,
      color: '#fff',
    },
  ],
};

// Converting [Lng, Lat] coordinates to string format
function getPointStr(point: LngLat) {
  return point.map((c) => c!.toFixed(4))
    .join('; ');
}

const pointASubtitle = ref(getPointStr(INITIAL_ROUTE_POINTS[0]));
const pointBSubtitle = ref(getPointStr(INITIAL_ROUTE_POINTS[1]));
const pointACoordinates = ref(INITIAL_ROUTE_POINTS[0]);
const pointBCoordinates = ref(INITIAL_ROUTE_POINTS[1]);
const route = ref<RouteFeature | null>(null);

// The function for fetching a route between two points
async function fetchRoute(startCoordinates: LngLat, endCoordinates: LngLat) {
  // Request a route from the Router API with the specified parameters.
  const routes = await ymaps3.route({
    points: [startCoordinates, endCoordinates], // Start and end points of the route LngLat[]
    type: 'driving', // Type of the route
    bounds: true, // Flag indicating whether to include route boundaries in the response
  });

  // Check if a route was found
  if (!routes[0]) return;

  // Convert the received route to a RouteFeature object.
  const firstRoute = routes[0].toRoute();

  // Check if a route has coordinates
  if (firstRoute.geometry.coordinates.length === 0) return;

  return firstRoute;
}

const routeHandler = async (newRoute?: RouteFeature) => {
  // If the route is not found, then we alert a message and clear the route line
  if (!newRoute) {
    alert('Route not found');
    route.value = null;
    return;
  }

  route.value = newRoute;
  if (newRoute.properties.bounds) {
    const newLocation = await getLocationFromBounds({
      bounds: newRoute.properties.bounds,
      map: map.value!,
    });

    // Чтобы маршрут всегда помещался на экран
    location.value = {
      center: newLocation.center,
      zoom: Math.floor(newLocation.zoom) - 1,
      duration: 300,
    };
  }
};

watch(VueYandexMaps.loadStatus, async (status) => {
  if (status !== 'loaded') return;

  const fetchedRoute = await fetchRoute(pointACoordinates.value, pointBCoordinates.value);
  await routeHandler(fetchedRoute);
}, {
  immediate: true,
});

// The handler functions for updating the coordinates and subtitle of the marker when dragging
const onDragMovePointAHandler: YMapMarkerEventHandler = (coordinates: LngLat) => {
  pointASubtitle.value = getPointStr(coordinates);
  pointACoordinates.value = coordinates;
};
const onDragMovePointBHandler: YMapMarkerEventHandler = (coordinates: LngLat) => {
  pointBSubtitle.value = getPointStr(coordinates);
  pointBCoordinates.value = coordinates;
};

// The handler function for updating route data after dragging the marker
const onDragEndHandler: YMapMarkerEventHandler = () => {
  fetchRoute(pointACoordinates.value, pointBCoordinates.value)
    .then(routeHandler);
};
css
<style scoped>
.info {
  padding: 10px;
  font-size: 14px;
}
</style>

Сделано с ♥ под лицензией MIT.