Live markers

Open in 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="../variables.ts"
    ></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, MapEventUpdateHandler, RouteFeature} from '@yandex/ymaps3-types';
      import {LOCATION, MARKERS} from '../variables';
      import {
          ZOOMS,
          ANIMATION_DURATION,
          angleFromCoordinate,
          animate,
          fetchRoute,
          MarkerSize,
          type MarkerProps
      } from './common';

      window.map = null;

      main();

      async function main() {
          let markers = MARKERS.reduce<{[key: number]: MarkerProps}>((previousValue, currentValue) => {
              previousValue[currentValue.id] = currentValue;
              return previousValue;
          }, {});
          let size = MarkerSize.big;

          // Waiting for all api elements to be loaded
          await ymaps3.ready;
          const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapMarker, YMapListener} = ymaps3;

          // 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},
              [
                  // Add a map scheme layer
                  new YMapDefaultSchemeLayer({}),
                  // Add a layer of geo objects to display the line
                  new YMapDefaultFeaturesLayer({})
              ]
          );

          const previousCoordinates = new Map();

          const startAnimation = (markerProp: MarkerProps) => {
              if (!previousCoordinates.has(markerProp.marker)) {
                  previousCoordinates.set(markerProp.marker, [...markerProp.coordinates]);
              }

              const prevCoordinates = previousCoordinates.get(markerProp.marker);

              const diff: LngLat = [
                  markerProp.coordinates[0] - prevCoordinates[0],
                  markerProp.coordinates[1] - prevCoordinates[1]
              ];

              if (Math.abs(diff[0]) + Math.abs(diff[1]) < 1e-6) {
                  setNextCoordinates(markerProp);
                  return;
              }
              animate((progress) => {
                  markerProp.marker.update({
                      coordinates: [prevCoordinates[0] + diff[0] * progress, prevCoordinates[1] + diff[1] * progress]
                  });
                  if (progress === 1) {
                      setNextCoordinates(markerProp);
                  }
              }, ANIMATION_DURATION);
          };

          const setNextCoordinates = (markerProp: MarkerProps) => {
              if (markerProp.route && markerProp.route.geometry.coordinates.length > 1) {
                  const coordinates = markerProp.route.geometry.coordinates.shift();
                  const angle = angleFromCoordinate(coordinates, markerProp.route.geometry.coordinates[0]);
                  markerProp.coordinates = coordinates;

                  const markerElement = document.getElementById(String(markerProp.id));
                  (markerElement.firstElementChild as HTMLElement).style.transform = `rotate(${angle}deg)`;
                  markerProp.angle = angle;

                  startAnimation(markerProp);
              }
          };

          /* 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, id: number) => {
              if (markers[id]) {
                  markers[id].route = newRoute;
              }
              setNextCoordinates(markers[id]);
          };

          Object.values(markers).forEach((marker) => {
              fetchRoute(marker.start, marker.end).then((route) => routeHandler(route, marker.id));
          });

          // Create markers with a custom icon and add them to the map
          Object.values(markers).forEach((markerProp) => {
              const markerElement = document.createElement('div');
              markerElement.id = String(markerProp.id);
              markerElement.classList.add('marker_container', MarkerSize.big);

              const markerElementImg = document.createElement('img');
              markerElementImg.src = markerProp.background[MarkerSize.big];
              markerElementImg.alt = 'marker';
              markerElementImg.classList.add('marker', MarkerSize.big);
              markerElement.appendChild(markerElementImg);

              const markerElementIconImg = document.createElement('img');
              markerElementIconImg.src = markerProp.icon[MarkerSize.big];
              markerElementIconImg.alt = 'icon';
              markerElementIconImg.classList.add('marker_icon', MarkerSize.big);
              markerElement.appendChild(markerElementIconImg);

              const markerElementText = document.createElement('span');
              markerElementText.innerText = markerProp.text;
              markerElementText.classList.add('marker_text', MarkerSize.big);
              markerElement.appendChild(markerElementText);

              const marker = new YMapMarker(
                  {coordinates: markerProp.coordinates, disableRoundCoordinates: true, zIndex: markerProp.id},
                  markerElement
              );
              markers[markerProp.id].marker = marker;
              map.addChild(marker);
              startAnimation(markerProp)
          });

          const updateHandler: MapEventUpdateHandler = (o) => {
              let newSize;
              if (o.location.zoom <= ZOOMS.small) {
                  newSize = MarkerSize.small;
              } else if (o.location.zoom <= ZOOMS.big && o.location.zoom >= ZOOMS.small) {
                  newSize = MarkerSize.medium;
              } else if (o.location.zoom >= ZOOMS.big) {
                  newSize = MarkerSize.big;
              }
              if (newSize !== size) {
                  Object.values(markers).forEach((markerProp) => {
                      const markerElement = document.getElementById(String(markerProp.id));
                      markerElement.classList.replace(size, newSize);

                      (markerElement.firstElementChild as HTMLImageElement).src = markerProp.background[newSize];
                      (markerElement.firstElementChild as HTMLImageElement).classList.replace(size, newSize);

                      markerElement.children[1].classList.replace(size, newSize);
                      (markerElement.children[1] as HTMLImageElement).src = markerProp.icon[newSize];

                      (markerElement.lastElementChild as HTMLSpanElement).innerText = markerProp.text;
                      (markerElement.lastElementChild as HTMLSpanElement).classList.replace(size, newSize);
                  });
                  size = newSize;
              }
          };

          /* Add a listener to the map and pass the handlers functions for the events you want to process
        These are just some of the events, you can see them all in the documentation */
          map.addChild(
              new YMapListener({
                  onUpdate: updateHandler
              })
          );
      }
    </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" />
    <link rel="stylesheet" href="../variables.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@18/umd/react.production.min.js"></script>
    <script crossorigin src="https://cdn.jsdelivr.net/npm/react-dom@18/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="typescript"
      type="text/babel"
      src="../variables.ts"
    ></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="react, typescript" type="text/babel">
      import type TReact from 'react';
      import type {LngLat, MapEventUpdateHandler, RouteFeature} from '@yandex/ymaps3-types';
      import {LOCATION, MARKERS} from '../variables';
      import {
        ANIMATION_DURATION,
        ZOOMS,
        angleFromCoordinate,
        animate,
        fetchRoute,
        MarkerSize,
        type MarkerProps
      } from './common';

      window.map = null;

      main();

      type MarkerComponentProps = {
        marker: MarkerProps,
        size: MarkerSize,
        animationCb: (marker: MarkerProps) => void,
        zIndex: number
      };

      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, YMapMarker, YMapListener} =
          reactify.module(ymaps3);
        const {useEffect, useState, useCallback, startTransition, useRef} = React;

        const MarkerComponent: TReact.FC<MarkerComponentProps> = ({marker, size, animationCb, zIndex}) => {
          const [coordinates, setCoordinates] = useState < LngLat > (() => marker.coordinates);
          const prevCoordinatesRef = useRef < LngLat > marker.coordinates;

          useEffect(() => {
            const prevCoordinates = prevCoordinatesRef.current;
            const diff: LngLat = [
              marker.coordinates[0] - prevCoordinates[0],
              marker.coordinates[1] - prevCoordinates[1]
            ];
            prevCoordinatesRef.current = marker.coordinates;

            if (Math.abs(diff[0]) + Math.abs(diff[1]) < 1e-6) {
              animationCb(marker);
              return;
            }

            animate((progress) => {
              startTransition(() => {
                setCoordinates([prevCoordinates[0] + diff[0] * progress, prevCoordinates[1] + diff[1] * progress]);
              });
              if (progress === 1) {
                animationCb(marker);
              }
            }, ANIMATION_DURATION);
          }, [marker.coordinates]);

          return (
            <YMapMarker disableRoundCoordinates coordinates={coordinates} zIndex={zIndex}>
              <div className={`marker_container ${size}`}>
                <img
                  src={marker.background[size]}
                  alt="marker"
                  style={{transform: `rotate(${marker.angle}deg)`}}
                  className={`marker ${size}`}
                />
                {size !== MarkerSize.small && (
                  <img src={marker.icon[size]} alt="icon" className={`marker_icon ${size}`} />
                )}
                {size === MarkerSize.big && <span className="marker_text">{marker.text}</span>}
              </div>
            </YMapMarker>
          );
        };

        function App() {
          const [size, setSize] = useState < MarkerSize > MarkerSize.big;
          const [markers, setMarkers] = useState < Array < MarkerProps >> MARKERS;

          const onUpdate: MapEventUpdateHandler = useCallback((o) => {
            if (o.location.zoom <= ZOOMS.small) {
              setSize(MarkerSize.small);
            } else if (o.location.zoom <= ZOOMS.big && o.location.zoom >= ZOOMS.small) {
              setSize(MarkerSize.medium);
            } else if (o.location.zoom >= ZOOMS.big) {
              setSize(MarkerSize.big);
            }
          }, []);

          // Get and process route data during the first rendering
          useEffect(() => {
            markers.forEach((marker) => {
              fetchRoute(marker.start, marker.end).then((route) => routeHandler(route, marker.id));
            });
          }, []);

          /* 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, id: number) => {
            setMarkers((state) =>
              state.map((item) => {
                if (item.id === id) {
                  item.route = newRoute;
                }
                return item;
              })
            );
            const marker = markers.find((item) => item.id === id);
            setNextCoordinates(marker);
          };

          const setNextCoordinates = (markerProp: MarkerProps) => {
            if (markerProp.route && markerProp.route.geometry.coordinates.length > 1) {
              const coordinates = markerProp.route.geometry.coordinates.shift();
              const angle = angleFromCoordinate(coordinates, markerProp.route.geometry.coordinates[0]);
              setMarkers((state) =>
                state.map((item) => {
                  if (item.id === markerProp.id) {
                    return {
                      ...item,
                      coordinates,
                      angle
                    };
                  }
                  return item;
                })
              );
            }
          };

          return (
            // Initialize the map and pass initialization parameters
            <YMap location={LOCATION} showScaleInCopyrights={true} ref={(x) => (map = x)}>
              {/* Add a map scheme layer */}
              <YMapDefaultSchemeLayer />
              {/* Add a layer of geo objects to display the line */}
              <YMapDefaultFeaturesLayer />

              {markers.map((marker) => (
                <MarkerComponent
                  key={marker.id}
                  zIndex={marker.id}
                  marker={marker}
                  size={size}
                  animationCb={() => setNextCoordinates(marker)}
                />
              ))}

              <YMapListener onUpdate={onUpdate} />
            </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" />
    <link rel="stylesheet" href="../variables.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>
    <!-- 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="../variables.ts"
    ></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 {MapEventUpdateHandler, RouteFeature} from '@yandex/ymaps3-types';
      import {MARKERS, LOCATION} from '../variables';
      import {
        ANIMATION_DURATION,
        ZOOMS,
        angleFromCoordinate,
        animate,
        fetchRoute,
        MarkerSize,
        type MarkerProps
      } from './common';

      window.map = null;

      async function main() {
        const [ymaps3Vue] = await Promise.all([ymaps3.import('@yandex/ymaps3-vuefy'), ymaps3.ready]);
        const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
        const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapMarker, YMapListener} =
          vuefy.module(ymaps3);

        const MarkerComponent = Vue.defineComponent({
          components: {
            YMapMarker
          },
          props: {
            marker: {type: Object},
            animationCb: {type: Function},
            size: String,
            zIndex: Number
          },
          setup(props) {
            const coordinates = Vue.ref(props.marker.coordinates.slice());
            const prevCoordinatesRef = Vue.ref(props.marker.coordinates.slice());
            const angle = Vue.ref(props.marker.angle);

            Vue.watch(
              () => props.marker.coordinates,
              (newCoordinates) => {
                const prevCoordinates = prevCoordinatesRef.value;
                const diff = [newCoordinates[0] - prevCoordinates[0], newCoordinates[1] - prevCoordinates[1]];
                prevCoordinatesRef.value = newCoordinates;

                if (Math.abs(diff[0]) + Math.abs(diff[1]) < 1e-6) {
                  props.animationCb(props.marker);
                  return;
                }

                animate((progress) => {
                  coordinates.value = [
                    prevCoordinates[0] + diff[0] * progress,
                    prevCoordinates[1] + diff[1] * progress
                  ];
                  if (progress === 1) {
                    props.animationCb(props.marker);
                  }
                }, ANIMATION_DURATION);
              }
            );

            Vue.watch(
              () => props.marker.angle,
              (angleProp) => {
                angle.value = angleProp;
              }
            );

            Vue.onMounted(() => {
              prevCoordinatesRef.value = props.marker.coordinates.slice();
            });

            return {
              background: props.marker.background,
              icon: props.marker.icon,
              text: props.marker.text,
              angle,
              coordinates,
              zIndex: props.marker.id,
              MarkerSize
            };
          },
          template: `
      <YMapMarker disableRoundCoordinates :coordinates="coordinates" :zIndex="zIndex">
        <div :class="['marker_container', size]">
          <img
            :src="background[size]"
            alt="marker"
            :class="['marker', size]"
            :style="{ transform: 'rotate(' + angle + 'deg)' }"
          />
          <img
            v-if="size !== MarkerSize.small"
            :src="icon[size]"
            alt="icon"
            :class="['marker_icon', size]"
          />
          <span v-if="size === MarkerSize.big" class="marker_text">{{ text }}</span>
        </div>
      </YMapMarker>
    `
        });

        const App = Vue.createApp({
          components: {
            YMap,
            YMapDefaultSchemeLayer,
            YMapDefaultFeaturesLayer,
            YMapListener,
            MarkerComponent
          },
          setup() {
            let markers = Vue.ref(MARKERS);
            const size = Vue.ref(MarkerSize.big);

            const refMap = (ref) => {
              window.map = ref?.entity;
            };

            const onUpdate: MapEventUpdateHandler = (o) => {
              if (o.location.zoom <= ZOOMS.small) {
                size.value = MarkerSize.small;
              } else if (o.location.zoom <= ZOOMS.big && o.location.zoom >= ZOOMS.small) {
                size.value = MarkerSize.medium;
              } else if (o.location.zoom >= ZOOMS.big) {
                size.value = MarkerSize.big;
              }
            };

            const setNextCoordinates = (markerProp: MarkerProps) => {
              if (markerProp.route && markerProp.route.geometry.coordinates.length > 1) {
                const coordinates = markerProp.route.geometry.coordinates.shift();
                const angle = angleFromCoordinate(coordinates, markerProp.route.geometry.coordinates[0]);
                markers.value = markers.value.map((marker) => {
                  if (marker.id === markerProp.id) {
                    return {
                      ...marker,
                      coordinates,
                      angle
                    };
                  }
                  return marker;
                });
              }
            };
            /* 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, id: number) => {
              markers.value = markers.value.map((marker) => {
                if (marker.id === id) {
                  return {
                    ...marker,
                    route: newRoute
                  };
                }
                return marker;
              });
              const marker = markers.value.find((marker) => marker.id === id);
              setNextCoordinates(marker);
            };

            Vue.onMounted(() => {
              markers.value.forEach((marker) => {
                fetchRoute(marker.start, marker.end).then((route) => routeHandler(route, marker.id));
              });
            });

            const callback = (marker: MarkerProps) => {
              setNextCoordinates(marker);
            };

            return {
              refMap,
              LOCATION,
              markers,
              onUpdate,
              size,
              callback
            };
          },
          template: `
      <YMap
        :location="LOCATION"
        :ref="refMap"
        :showScaleInCopyrights="true"
      >
        <YMapDefaultSchemeLayer />
        <YMapDefaultFeaturesLayer />

        <template v-for="marker in markers" :key="marker.id">
          <MarkerComponent :marker="marker" :size="size" :animationCb="callback" />
        </template>

        <YMapListener :onUpdate="onUpdate" />
      </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" />
    <link rel="stylesheet" href="../variables.css" />
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
.marker_container {
  position: absolute;
  transform: translate(-50%, -50%);
}

.marker_container.big {
  width: 38px;
  height: 38px;
}

.marker_container.medium {
  width: 28px;
  height: 28px;
}

.marker_text {
  position: absolute;
  background: white;
  left: 18px;
  bottom: 9px;
  z-index: -1;
  border-radius: 8px;
  padding: 4px 4px 4px 16px;
  font-size: 14px;
  line-height: 16px;
  color: var(--color-text);
  font-weight: 500;
}

.marker.big {
  transform-origin: 50% 57%;
  width: 38px;
  height: 38px;
}
.marker.medium {
  transform-origin: 50% 55%;
  width: 28px;
  height: 28px;
}

.marker_text.big {
  display: inline-block;
}

.marker_text.medium {
  display: none;
}

.marker_text.small {
  display: none;
}

.marker_icon.big {
  position: absolute;
  left: 11px;
  bottom: 9px;
}

.marker_icon.small {
  display: none;
}

.marker_icon.medium {
  position: absolute;
  left: var(--left-medium-marker);
  bottom: var(--bottom-medium-marker);
}
// The function for fetching a route between two points
import {LngLat, RouteFeature} from '@yandex/ymaps3-types';

export enum MarkerSize {
  small = 'small',
  big = 'big',
  medium = 'medium'
}

export type MarkerProps = {
  angle: number;
  start: LngLat;
  end: LngLat;
  route: RouteFeature;
  coordinates: LngLat;
  id: number;
  text: string;
  marker: any;
  icon: {
    [key in MarkerSize]: string;
  };
  background: {
    [key in MarkerSize]: string;
  };
};

// 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 ZOOMS = {
  small: 12,
  big: 13
};

export const ANIMATION_DURATION = 4000;

export function animate(cb: (progress: number) => void, duration: number) {
  const startTime = Date.now();
  function tick() {
    const progress = (Date.now() - startTime) / duration;
    if (progress >= 1) {
      cb(1);
      return;
    }

    cb(progress);
    requestAnimationFrame(tick);
  }

  requestAnimationFrame(tick);
}

export 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 route = routes[0].toRoute();

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

  return route;
}

export function angleFromCoordinate(lngLat1: LngLat, lngLat2: LngLat) {
  const toRadians = (degrees: number) => degrees * (Math.PI / 180);
  const toDegrees = (radians: number) => radians * (180 / Math.PI);

  const dLon = toRadians(lngLat2[0] - lngLat1[0]);

  const y = Math.sin(dLon) * Math.cos(toRadians(lngLat2[1]));
  const x =
    Math.cos(toRadians(lngLat1[1])) * Math.sin(toRadians(lngLat2[1])) -
    Math.sin(toRadians(lngLat1[1])) * Math.cos(toRadians(lngLat2[1])) * Math.cos(dLon);

  let brng = Math.atan2(y, x);

  brng = toDegrees(brng);
  brng = (brng + 360) % 360;

  return brng;
}
:root {
  --color-text: #3cb200;
  --left-medium-marker: 8px;
  --bottom-medium-marker: 7px;
  --left-big-marker: 8px;
  --bottom-big-marker: 8px;
}
import type {YMapLocationRequest} from '@yandex/ymaps3-types';
import {MarkerProps} from './common';

export const LOCATION: YMapLocationRequest = {
  center: [37.629, 55.7521], // starting position [lng, lat]
  zoom: 13 // starting zoom
};

const MARKER_ICONS = {
  small: '../ymaps-bus-medium.svg',
  medium: '../ymaps-bus-medium.svg',
  big: '../ymaps-bus-big.svg'
};
const MARKER_BACKGROUNDS = {
  small: '../ymaps-marker-small.svg',
  medium: '../ymaps-marker-medium.svg',
  big: '../ymaps-marker-big.svg'
};

export const MARKERS: Array<MarkerProps> = [
  {
    angle: 0,
    coordinates: [37.620028, 55.741556],
    start: [37.620028, 55.741556],
    end: [38.130492, 56.31112],
    route: null,
    id: 1,
    text: 'M104',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.5698, 55.7297],
    start: [37.5698, 55.7297],
    end: [37.6691, 55.7263],
    route: null,
    id: 2,
    text: 'M106',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.5871, 55.7822],
    start: [37.5871, 55.7822],
    end: [37.6814, 55.7585],
    route: null,
    id: 3,
    text: 'M110',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.5898, 55.7705],
    start: [37.5898, 55.7705],
    end: [37.6808, 55.7524],
    route: null,
    id: 4,
    text: 'M111',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.6483, 55.7547],
    start: [37.6483, 55.7547],
    end: [37.6322, 55.729],
    route: null,
    id: 5,
    text: 'M120',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.5822, 55.7476],
    start: [37.58222, 55.7476],
    end: [37.63105, 55.7665],
    route: null,
    id: 6,
    text: 'M121',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.6423, 55.7421],
    start: [37.6423, 55.74219],
    end: [37.6084, 55.7393],
    route: null,
    id: 7,
    text: 'M122',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.5975, 55.7576],
    start: [37.5975, 55.7576],
    end: [37.6459, 55.761],
    route: null,
    id: 8,
    text: 'M123',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.5828, 55.7478],
    start: [37.5828, 55.7478],
    end: [37.6274, 55.7737],
    route: null,
    id: 9,
    text: 'M124',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.6088, 55.7496],
    start: [37.6088, 55.7496],
    end: [37.6383, 55.7649],
    route: null,
    id: 10,
    text: 'M125',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [37.6715, 55.7364],
    start: [37.6715, 55.7364],
    end: [37.64402, 55.7482],
    route: null,
    id: 11,
    text: 'M126',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  }
];