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://js.api.mappable.world/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 '@mappable-world/mappable-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 mappable.ready;
          const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapMarker, MMapListener} = mappable;

          // Initialize the map
          map = new MMap(
              // 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 MMapDefaultSchemeLayer({}),
                  // Add a layer of geo objects to display the line
                  new MMapDefaultFeaturesLayer({})
              ]
          );

          const startAnimation = (markerProp: MarkerProps) => {
              const prevCoordinates = markerProp.coordinates;
              const diff: LngLat = [
                  markerProp.route.geometry.coordinates[0][0] - prevCoordinates[0],
                  markerProp.route.geometry.coordinates[0][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) {
                  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 MMapMarker(
                  {coordinates: markerProp.coordinates, disableRoundCoordinates: true},
                  markerElement
              );
              markers[markerProp.id].marker = marker;
              map.addChild(marker);
          });

          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 MMapListener({
                  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://js.api.mappable.world/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 '@mappable-world/mappable-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
      };

      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 @mappable-world/mappable-reactify
        const [mappableReact] = await Promise.all([
          mappable.import('@mappable-world/mappable-reactify'),
          mappable.ready
        ]);

        const reactify = mappableReact.reactify.bindTo(React, ReactDOM);
        const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapMarker, MMapListener} =
          reactify.module(mappable);
        const {useEffect, useState, useCallback, startTransition, useRef} = React;

        const MarkerComponent: TReact.FC<MarkerComponentProps> = ({marker, size, animationCb}) => {
          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 (
            <MMapMarker disableRoundCoordinates coordinates={coordinates}>
              <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>
            </MMapMarker>
          );
        };

        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) {
              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
            <MMap location={LOCATION} showScaleInCopyrights={true} ref={(x) => (map = x)}>
              {/* Add a map scheme layer */}
              <MMapDefaultSchemeLayer />
              {/* Add a layer of geo objects to display the line */}
              <MMapDefaultFeaturesLayer />

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

              <MMapListener onUpdate={onUpdate} />
            </MMap>
          );
        }

        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://js.api.mappable.world/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 '@mappable-world/mappable-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 [mappableVue] = await Promise.all([mappable.import('@mappable-world/mappable-vuefy'), mappable.ready]);
        const vuefy = mappableVue.vuefy.bindTo(Vue);
        const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapMarker, MMapListener} =
          vuefy.module(mappable);

        const MarkerComponent = Vue.defineComponent({
          components: {
            MMapMarker
          },
          props: {
            marker: {type: Object},
            animationCb: {type: Function},
            size: String
          },
          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,
              MarkerSize
            };
          },
          template: `
      <MMapMarker disableRoundCoordinates :coordinates="coordinates">
        <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>
      </MMapMarker>
    `
        });

        const App = Vue.createApp({
          components: {
            MMap,
            MMapDefaultSchemeLayer,
            MMapDefaultFeaturesLayer,
            MMapListener,
            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) {
                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: `
      <MMap
        :location="LOCATION"
        :ref="refMap"
        :showScaleInCopyrights="true"
      >
        <MMapDefaultSchemeLayer />
        <MMapDefaultFeaturesLayer />
        
        <template v-for="marker in markers" :key="marker.id">
          <MarkerComponent :marker="marker" :size="size" :animationCb="callback" />
        </template>

        <MMapListener :onUpdate="onUpdate" />
      </MMap>
    `
        });

        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 '@mappable-world/mappable-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;
  };
};

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 mappable.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: #46ab70;
  --left-medium-marker: 7px;
  --bottom-medium-marker: 7px;
  --left-big-marker: 8px;
  --bottom-big-marker: 8px;
}
import type {MMapLocationRequest} from '@mappable-world/mappable-types';
import {MarkerProps} from './common';

export const LOCATION: MMapLocationRequest = {
  center: [55.2811, 25.2239], // starting position [lng, lat]
  zoom: 13 // starting zoom
};

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

export const MARKERS: Array<MarkerProps> = [
  {
    angle: 0,
    coordinates: [55.248411, 25.211883],
    start: [55.248411, 25.211883],
    end: [55.318659, 25.285655],
    route: null,
    id: 1,
    text: 'M104',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.236095, 25.181797],
    start: [55.236095, 25.181797],
    end: [55.286697, 25.248211],
    route: null,
    id: 2,
    text: 'M106',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.329727, 25.253685],
    start: [55.329727, 25.253685],
    end: [55.269396, 25.225767],
    route: null,
    id: 3,
    text: 'M110',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.260341, 25.191205],
    start: [55.260341, 25.191205],
    end: [55.279214, 25.207077],
    route: null,
    id: 4,
    text: 'M111',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.262919, 25.185876],
    start: [55.262919, 25.185876],
    end: [55.247566, 25.149031],
    route: null,
    id: 5,
    text: 'M120',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.2959, 25.195],
    start: [55.2959, 25.195],
    end: [55.3042, 25.2543],
    route: null,
    id: 6,
    text: 'M121',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.3532, 25.2465],
    start: [55.3532, 25.2465],
    end: [55.3099, 25.1935],
    route: null,
    id: 7,
    text: 'M126',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.2529, 25.1952],
    start: [55.2529, 25.1952],
    end: [55.2844, 25.2463],
    route: null,
    id: 8,
    text: 'M126',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.2784, 25.2511],
    start: [55.2784, 25.2511],
    end: [55.3404, 25.2229],
    route: null,
    id: 9,
    text: 'M129',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.2734, 25.2265],
    start: [55.2734, 25.2265],
    end: [55.301, 25.2182],
    route: null,
    id: 10,
    text: 'M139',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  },
  {
    angle: 0,
    coordinates: [55.3132, 25.2079],
    start: [55.3132, 25.2079],
    end: [55.2894, 25.229],
    route: null,
    id: 11,
    text: 'M132',
    marker: {},
    icon: MARKER_ICONS,
    background: MARKER_BACKGROUNDS
  }
];