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

Open on CodeSandbox

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
    <script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
    <!-- To make the map appear, you must add your apikey -->
    <script src="https://api-maps.yandex.ru/v3/?apikey=<YOUR_APIKEY>&lang=en_US" type="text/javascript"></script>

    <script
      data-plugins="transform-modules-umd"
      data-presets="typescript"
      type="text/babel"
      src="./common.ts"
    ></script>
    <script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
      import type {LngLat, RouteFeature} from '@yandex/ymaps3-types';
      import {LOCATION, INITIAL_ROUTE_POINTS, getPointStr, fetchRoute, lineStyle, InfoMessage} from './common';

      window.map = null;

      main();
      async function main() {
        // Waiting for all api elements to be loaded
        await ymaps3.ready;
        const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapFeature, YMapControls, YMapControlButton} =
          ymaps3;
        const {YMapDefaultMarker} = await ymaps3.import('@yandex/ymaps3-markers@0.0.1');

        // Initialize the map
        map = new YMap(
          // Pass the link to the HTMLElement of the container
          document.getElementById('app'),
          // Pass the map initialization parameters
          {location: LOCATION, showScaleInCopyrights: true, margin: [100, 100, 100, 100]},
          [
            // Add a map scheme layer
            new YMapDefaultSchemeLayer({}),
            // Add a layer of geo objects to display markers and line
            new YMapDefaultFeaturesLayer({})
          ]
        );

        // Create and add route start and end markers to the map.
        const pointA = new YMapDefaultMarker({
          coordinates: INITIAL_ROUTE_POINTS[0],
          draggable: true,
          title: 'Point A',
          subtitle: getPointStr(INITIAL_ROUTE_POINTS[0]),
          onDragMove: onDragMovePointAHandler,
          onDragEnd: onDragEndHandler
        });
        const pointB = new YMapDefaultMarker({
          coordinates: INITIAL_ROUTE_POINTS[1],
          draggable: true,
          title: 'Point B',
          subtitle: getPointStr(INITIAL_ROUTE_POINTS[1]),
          onDragMove: onDragMovePointBHandler,
          onDragEnd: onDragEndHandler
        });
        map.addChild(pointA).addChild(pointB);

        // Create and add a route line to the map
        const routeLine = new YMapFeature({geometry: {type: 'LineString', coordinates: []}, style: lineStyle});
        map.addChild(routeLine);

        // Get and process data about the initial route
        fetchRoute(pointA.coordinates, pointB.coordinates).then(routeHandler);

        /* Create and add a shared container for controls to the map.
    Using YMapControls you can change the position of the control */
        const topRightControls = new YMapControls({position: 'top right'});
        map.addChild(topRightControls);
        // Add a custom information message control to the map
        topRightControls.addChild(new InfoMessage({text: 'Drag any marker to rebuild the route.'}));

        const topLeftControls = new YMapControls({position: 'top left'}, [
          new YMapControlButton({
            text: 'Driving',
            onClick: () => fetchRoute(pointA.coordinates, pointB.coordinates, 'driving').then(routeHandler)
          }),
          new YMapControlButton({
            text: 'Truck',
            onClick: () => fetchRoute(pointA.coordinates, pointB.coordinates, 'truck').then(routeHandler)
          }),
          new YMapControlButton({
            text: 'Walking',
            onClick: () => fetchRoute(pointA.coordinates, pointB.coordinates, 'walking').then(routeHandler)
          }),
          new YMapControlButton({
            text: 'Transit',
            onClick: () => fetchRoute(pointA.coordinates, pointB.coordinates, 'transit').then(routeHandler)
          })
        ]);
        map.addChild(topLeftControls);

        // The handler functions for updating the coordinates and subtitle of the marker when dragging
        function onDragMovePointAHandler(coordinates: LngLat) {
          pointA.update({coordinates, subtitle: getPointStr(coordinates)});
        }
        function onDragMovePointBHandler(coordinates: LngLat) {
          pointB.update({coordinates, subtitle: getPointStr(coordinates)});
        }

        // The handler function for updating route data after dragging the marker
        function onDragEndHandler() {
          fetchRoute(pointA.coordinates, pointB.coordinates).then(routeHandler);
        }

        /* A handler function that updates the route line 
    and shifts the map to the new route boundaries, if they are available. */
        function routeHandler(newRoute: RouteFeature) {
          // If the route is not found, then we alert a message and clear the route line
          if (!newRoute) {
            alert('Route not found');
            routeLine.update({geometry: {type: 'LineString', coordinates: []}});
            return;
          }

          routeLine.update({...newRoute});
          if (newRoute.properties.bounds) {
            map.setLocation({bounds: newRoute.properties.bounds, duration: 300});
          }
        }
      }
    </script>

    <!-- prettier-ignore -->
    <style> html, body, #app { width: 100%; height: 100%; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .toolbar { position: absolute; z-index: 1000; top: 0; left: 0; display: flex; align-items: center; padding: 16px; } .toolbar a { padding: 16px; }  </style>
    <link rel="stylesheet" href="./common.css" />
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
    <script crossorigin src="https://cdn.jsdelivr.net/npm/react@17/umd/react.production.min.js"></script>
    <script crossorigin src="https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.production.min.js"></script>
    <script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
    <!-- To make the map appear, you must add your apikey -->
    <script src="https://api-maps.yandex.ru/v3/?apikey=<YOUR_APIKEY>&lang=en_US" type="text/javascript"></script>

    <script
      data-plugins="transform-modules-umd"
      data-presets="react, typescript"
      type="text/babel"
      src="./common.ts"
    ></script>
    <script data-plugins="transform-modules-umd" data-presets="react, typescript" type="text/babel">
      import type {LngLat, RouteFeature} from '@yandex/ymaps3-types';
      import {LOCATION, INITIAL_ROUTE_POINTS, getPointStr, fetchRoute, lineStyle, InfoMessage} from './common';

      window.map = null;

      main();
      async function main() {
        // For each object in the JS API, there is a React counterpart
        // To use the React version of the API, include the module @yandex/ymaps3-reactify
        const [ymaps3React] = await Promise.all([ymaps3.import('@yandex/ymaps3-reactify'), ymaps3.ready]);
        const reactify = ymaps3React.reactify.bindTo(React, ReactDOM);
        const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapFeature, YMapControls, YMapControlButton} =
          reactify.module(ymaps3);

        // Import the package to add a default marker
        const {YMapDefaultMarker} = reactify.module(await ymaps3.import('@yandex/ymaps3-markers@0.0.1'));

        // Using ymaps3-rectify, we turn a custom InfoMessage into a React component
        const {InfoMessage: InfoMessageR} = reactify.module({InfoMessage});

        const {useState, useCallback, useEffect} = React;

        function App() {
          const [location, setLocation] = useState(LOCATION);
          const [pointASubtitle, setPointASubtitle] = useState(getPointStr(INITIAL_ROUTE_POINTS[0]));
          const [pointBSubtitle, setPointBSubtitle] = useState(getPointStr(INITIAL_ROUTE_POINTS[0]));
          const [pointACoordinates, setPointACoordinates] = useState(INITIAL_ROUTE_POINTS[0]);
          const [pointBCoordinates, setPointBCoordinates] = useState(INITIAL_ROUTE_POINTS[1]);
          const [route, setRoute] = useState < RouteFeature > null;

          // Get and process route data during the first rendering
          useEffect(() => {
            fetchRoute(pointACoordinates, pointBCoordinates).then(routeHandler);
          }, []);

          // The handler functions for updating the coordinates and subtitle of the marker when dragging
          const onDragMovePointAHandler = useCallback((coordinates: LngLat) => {
            setPointASubtitle(getPointStr(coordinates));
            setPointACoordinates(coordinates);
          }, []);
          const onDragMovePointBHandler = useCallback((coordinates: LngLat) => {
            setPointBSubtitle(getPointStr(coordinates));
            setPointBCoordinates(coordinates);
          }, []);

          // The handler function for updating route data after dragging the marker
          const onDragEndHandler = useCallback(() => {
            fetchRoute(pointACoordinates, pointBCoordinates).then(routeHandler);
          }, [pointACoordinates, pointBCoordinates]);

          const buildDrivingRoute = useCallback(
            () => fetchRoute(pointACoordinates, pointBCoordinates, 'driving').then(routeHandler),
            []
          );
          const buildTruckRoute = useCallback(
            () => fetchRoute(pointACoordinates, pointBCoordinates, 'truck').then(routeHandler),
            []
          );
          const buildWalkingRoute = useCallback(
            () => fetchRoute(pointACoordinates, pointBCoordinates, 'walking').then(routeHandler),
            []
          );
          const buildTransitRoute = useCallback(
            () => fetchRoute(pointACoordinates, pointBCoordinates, 'transit').then(routeHandler),
            []
          );

          /* A handler function that updates the route line 
        and shifts the map to the new route boundaries, if they are available. */
          const routeHandler = useCallback((newRoute: RouteFeature) => {
            // If the route is not found, then we alert a message and clear the route line
            if (!newRoute) {
              alert('Route not found');
              setRoute(null);
              return;
            }

            setRoute(newRoute);
            if (newRoute.properties.bounds) {
              setLocation({bounds: newRoute.properties.bounds, duration: 300});
            }
          }, []);
          return (
            // Initialize the map and pass initialization parameters
            <YMap
              location={location}
              showScaleInCopyrights={true}
              margin={[100, 100, 100, 100]}
              ref={(x) => (map = x)}
            >
              {/* Add a map scheme layer */}
              <YMapDefaultSchemeLayer />
              {/* Add a layer of geo objects to display markers and line */}
              <YMapDefaultFeaturesLayer />

              {/* Add route start and end markers to the map */}
              <YMapDefaultMarker
                coordinates={pointACoordinates}
                title="Point A"
                subtitle={pointASubtitle}
                draggable
                onDragMove={onDragMovePointAHandler}
                onDragEnd={onDragEndHandler}
              />
              <YMapDefaultMarker
                coordinates={pointBCoordinates}
                title="Point B"
                subtitle={pointBSubtitle}
                draggable
                onDragMove={onDragMovePointBHandler}
                onDragEnd={onDragEndHandler}
              />

              {/* Add the route line to the map when it becomes available */}
              {route && <YMapFeature {...route} style={lineStyle} />}

              {/* Add a shared container for controls to the map.
                Using YMapControls you can change the position of the control */}
              <YMapControls position="top right">
                {/* Add a custom information message control to the map */}
                <InfoMessageR text="Drag any marker to rebuild the route." />
              </YMapControls>
              <YMapControls position="top left">
                <YMapControlButton text="Driving" onClick={buildDrivingRoute} />
                <YMapControlButton text="Truck" onClick={buildTruckRoute} />
                <YMapControlButton text="Walking" onClick={buildWalkingRoute} />
                <YMapControlButton text="Transit" onClick={buildTransitRoute} />
              </YMapControls>
            </YMap>
          );
        }

        ReactDOM.render(
          <React.StrictMode>
            <App />
          </React.StrictMode>,
          document.getElementById('app')
        );
      }
    </script>

    <!-- prettier-ignore -->
    <style> html, body, #app { width: 100%; height: 100%; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .toolbar { position: absolute; z-index: 1000; top: 0; left: 0; display: flex; align-items: center; padding: 16px; } .toolbar a { padding: 16px; }  </style>
    <link rel="stylesheet" href="./common.css" />
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
    <script crossorigin src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
    <script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>

    <script src="https://api-maps.yandex.ru/v3/?apikey=<YOUR_APIKEY>&lang=en_US" type="text/javascript"></script>

    <script
      data-plugins="transform-modules-umd"
      data-presets="typescript"
      type="text/babel"
      src="./common.ts"
    ></script>
    <script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
      import type {LngLat, RouteFeature} from '@yandex/ymaps3-types';
      import {LOCATION, INITIAL_ROUTE_POINTS, getPointStr, fetchRoute, lineStyle, InfoMessage} from './common';

      window.map = null;

      async function main() {
        // For each object in the JS API, there is a Vue counterpart
        // To use the Vue version of the API, include the module @yandex/ymaps3-vuefy
        const [ymaps3Vue] = await Promise.all([ymaps3.import('@yandex/ymaps3-vuefy'), ymaps3.ready]);
        const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
        const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapFeature, YMapControls, YMapControlButton} =
          vuefy.module(ymaps3);

        // Import the package to add a default marker
        const {YMapDefaultMarker} = vuefy.module(await ymaps3.import('@yandex/ymaps3-markers@0.0.1'));

        // Using ymaps3-vuefy, we turn a custom InfoMessage into a Vue component
        const {InfoMessage: InfoMessageV} = vuefy.module({InfoMessage});

        const {createApp, onMounted, ref} = Vue;

        const app = createApp({
          components: {
            YMap,
            YMapDefaultSchemeLayer,
            YMapDefaultFeaturesLayer,
            YMapFeature,
            YMapControls,
            YMapControlButton,
            YMapDefaultMarker,
            InfoMessageV
          },
          setup() {
            const refMap = (ref) => {
              window.map = ref?.entity;
            };

            const location = ref(LOCATION);
            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;

            // Get and process route data during the first rendering
            onMounted(() => {
              fetchRoute(pointACoordinates.value, pointBCoordinates.value).then(routeHandler);
            });

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

            // The handler function for updating route data after dragging the marker
            const onDragEndHandler = () => {
              fetchRoute(pointACoordinates.value, pointBCoordinates.value).then(routeHandler);
            };

            const buildDrivingRoute = () =>
              fetchRoute(pointACoordinates.value, pointBCoordinates.value, 'driving').then(routeHandler);
            const buildTruckRoute = () =>
              fetchRoute(pointACoordinates.value, pointBCoordinates.value, 'truck').then(routeHandler);
            const buildWalkingRoute = () =>
              fetchRoute(pointACoordinates.value, pointBCoordinates.value, 'walking').then(routeHandler);
            const buildTransitRoute = () =>
              fetchRoute(pointACoordinates.value, pointBCoordinates.value, 'transit').then(routeHandler);

            /* A handler function that updates the route line 
            and shifts the map to the new route boundaries, if they are available. */
            const routeHandler = (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) {
                location.value = {bounds: newRoute.properties.bounds, duration: 300};
              }
            };

            return {
              refMap,
              location,
              pointACoordinates,
              pointBCoordinates,
              pointASubtitle,
              pointBSubtitle,
              route,
              lineStyle,
              onDragMovePointAHandler,
              onDragMovePointBHandler,
              onDragEndHandler,
              buildDrivingRoute,
              buildTruckRoute,
              buildWalkingRoute,
              buildTransitRoute
            };
          },
          template: `
            <!--Initialize the map and pass initialization parameters-->
            <YMap :location="location" :showScaleInCopyrights="true" :margin="[100, 100, 100, 100]" :ref="refMap">
                <!--Add a map scheme layer-->
                <YMapDefaultSchemeLayer />
                <!--Add a layer of geo objects to display markers and line-->
                <YMapDefaultFeaturesLayer />

                <!--Add route start and end markers to the map-->
                <YMapDefaultMarker 
                    :coordinates="pointACoordinates" 
                    title="Point A" 
                    :subtitle="pointASubtitle" 
                    :draggable="true" 
                    :onDragMove="onDragMovePointAHandler"
                    :onDragEnd="onDragEndHandler" 
                />
                <YMapDefaultMarker 
                    :coordinates="pointBCoordinates" 
                    title="Point B" 
                    :subtitle="pointBSubtitle" 
                    :draggable="true"
                    :onDragMove="onDragMovePointBHandler"
                    :onDragEnd="onDragEndHandler"  
                />
                
                <!--Add the route line to the map when it becomes available-->
                <YMapFeature v-if="route" v-bind="route" :style="lineStyle" />

                <!--Add a shared container for controls to the map. Using YMapControls you can change the position of the control-->
                <YMapControls position="top right">
                <!--Add a custom information message control to the map-->
                    <InfoMessageV text="Drag any marker to rebuild the route." />
                </YMapControls>
                <YMapControls position="top left">
                    <YMapControlButton text="Driving" :onClick="buildDrivingRoute"/>
                    <YMapControlButton text="Truck" :onClick="buildTruckRoute"/>
                    <YMapControlButton text="Walking" :onClick="buildWalkingRoute"/>
                    <YMapControlButton text="Transit" :onClick="buildTransitRoute"/>
                </YMapControls>
            </YMap>`
        });
        app.mount('#app');
      }
      main();
    </script>

    <!-- prettier-ignore -->
    <style> html, body, #app { width: 100%; height: 100%; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .toolbar { position: absolute; z-index: 1000; top: 0; left: 0; display: flex; align-items: center; padding: 16px; } .toolbar a { padding: 16px; }  </style>
    <link rel="stylesheet" href="./common.css" />
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
.infoWindow {
  width: 250px;
  padding: 15px;
  padding-left: 50px;

  position: relative;

  border-radius: 15px;
  background-color: rgba(255, 255, 255, 0.9);
  font-size: 16px;
}

.infoIcon {
  width: 30px;
  height: 30px;

  position: absolute;
  top: 50%;
  left: 10px;
  transform: translateY(-50%);
}
import type {YMapLocationRequest, LngLat, DrawingStyle, RouteOptions, TruckParameters} from '@yandex/ymaps3-types';

// Wait for the api to load to access the map configuration
ymaps3.ready.then(() => {
  // Copy your api key for routes from the developer's dashboard and paste it here
  ymaps3.getDefaultConfig().setApikeys({router: 'YOUR_APIKEY'});
});

export const LOCATION: YMapLocationRequest = {
  center: [37.623082, 55.75254], // starting position [lng, lat]
  zoom: 9 // starting zoom
};

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

// An object containing the route line style
export 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
export function getPointStr(point: LngLat) {
  return point.map((c) => c.toFixed(4)).join('; ');
}

// The function for fetching a route between two points
export async function fetchRoute(
  startCoordinates: LngLat,
  endCoordinates: LngLat,
  type: RouteOptions['type'] = 'driving'
) {
  let truck: TruckParameters;
  if (type === 'truck') {
    // set truck with trailer by default
    truck = {
      weight: 40,
      maxWeight: 40,
      axleWeight: 10,
      payload: 20,
      height: 4,
      width: 2.5,
      length: 16,
      ecoClass: 4,
      hasTrailer: true
    };
  }
  // 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, // Type of the route
    bounds: true, // Flag indicating whether to include route boundaries in the response
    truck
  });

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

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

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

  return route;
}

// Create a custom information message control
export let InfoMessage = null;

interface InfoMessageProps {
  text: string;
}

// Wait for the api to load to access the entity system (YMapComplexEntity)
ymaps3.ready.then(() => {
  class InfoMessageClass extends ymaps3.YMapComplexEntity<InfoMessageProps> {
    private _element!: HTMLDivElement;
    private _detachDom!: () => void;

    // Method for create a DOM control element
    _createElement(props: InfoMessageProps) {
      // Create a root element
      const infoWindow = document.createElement('div');
      infoWindow.className = 'infoWindow';
      infoWindow.textContent = props.text;

      // Create an icon element
      const infoIcon = document.createElement('img');
      infoIcon.src = '../info-icon.svg';
      infoIcon.className = 'infoIcon';
      infoWindow.appendChild(infoIcon);

      return infoWindow;
    }

    // Method for attaching the control to the map
    _onAttach() {
      this._element = this._createElement(this._props);
      this._detachDom = ymaps3.useDomContext(this, this._element, this._element);
    }

    // Method for detaching control from the map
    _onDetach() {
      this._detachDom();
      this._detachDom = undefined;
      this._element = undefined;
    }
  }

  InfoMessage = InfoMessageClass;
});