Создание линии

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 {DomEventHandlerObject, DomEvent} from '@yandex/ymaps3-types';
      import {LOCATION, INITIAL_LINE_COORDINATES, 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,
          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({})
          ]
        );

        // State with line coordinates
        const lineCoordinates = INITIAL_LINE_COORDINATES;

        // Create a line object, set its coordinates and styles, and add it to the map
        const line = new YMapFeature({
          geometry: {
            type: 'LineString',
            coordinates: lineCoordinates
          },
          style: {stroke: [{color: '#007afce6', width: 4}]}
        });
        map.addChild(line);

        // Create a map listener, create an onClick event for it, and add it to the map
        const listener = new YMapListener({
          onClick: onClickListenerHandler
        });
        map.addChild(listener);

        /* The onClick event handler function for the map listener. 
    When this event is activated, the coordinates of the current point are added 
    to the array of coordinates of the line */
        function onClickListenerHandler(object: DomEventHandlerObject, event: DomEvent) {
          lineCoordinates.push(event.coordinates);
          line.update({
            geometry: {
              type: 'LineString',
              coordinates: lineCoordinates
            }
          });

          bottomControls.addChild(clearLineBtn);
        }

        /* Create and add a shared container for controls to the map.
    Using YMapControls you can change the position of the control */
        const bottomControls = new YMapControls({position: 'bottom'});
        map.addChild(bottomControls);

        // Create and add a line removal button to the map
        let clearLineBtn = new YMapControlButton({
          text: 'Delete the line',
          color: '#fff',
          background: '#007afce6',
          onClick: onClickBtnHandler
        });
        bottomControls.addChild(clearLineBtn);

        /* The onClick event handler function for the button. 
    When this event is activated, the array of line coordinates is cleared */
        function onClickBtnHandler() {
          lineCoordinates.length = 0;
          line.update({
            geometry: {
              type: 'LineString',
              coordinates: lineCoordinates
            }
          });

          bottomControls.removeChild(clearLineBtn);
        }

        /* 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: 'To add a new point to the line, just click on the desired location on the map.'})
        );
      }
    </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 {DomEventHandlerObject, DomEvent} from '@yandex/ymaps3-types';
      import {LOCATION, INITIAL_LINE_COORDINATES, 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,
          YMapListener
        } = reactify.module(ymaps3);

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

        const {useState, useCallback} = React;

        function App() {
          // The state with line coordinates
          const [lineCoordinates, setLineCoordinates] = useState(INITIAL_LINE_COORDINATES);
          // The state of the line's existence
          const [isLineExist, setIsLineExist] = useState(true);

          /* The onClick event handler function for the map listener.
        When this event is activated, the coordinates of the current point are added
        to the array of coordinates of the line */
          const onClickListenerHandler = useCallback((object: DomEventHandlerObject, event: DomEvent) => {
            setLineCoordinates((prevLineCoordinates) => [...prevLineCoordinates, event.coordinates]);
            setIsLineExist(true);
          }, []);

          /* The onClick event handler function for the button.
        When this event is activated, the array of line coordinates is cleared */
          const onClickBtnHandler = useCallback(() => {
            setLineCoordinates([]);
            setIsLineExist(false);
          }, []);

          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 />

              {/* Add a line object to the map, set its coordinates and styles */}
              <YMapFeature
                geometry={{
                  type: 'LineString',
                  coordinates: lineCoordinates
                }}
                style={{stroke: [{color: '#007afce6', width: 4}]}}
              />

              {/* Add a map listener to the map, create an onClick event for it */}
              <YMapListener onClick={onClickListenerHandler} />

              {/* Create or delete a line removal button using conditional rendering */}
              {isLineExist && (
                <YMapControls position="bottom">
                  <YMapControlButton
                    text="Delete the line"
                    color="#fff"
                    background="#007afce6"
                    onClick={onClickBtnHandler}
                  />
                </YMapControls>
              )}

              {/* 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="To add a new point to the line, just click on the desired location on the map." />
              </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>
    <!-- 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 {LOCATION, INITIAL_LINE_COORDINATES, InfoMessage} 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,
          YMapFeature,
          YMapControls,
          YMapControlButton,
          YMapListener
        } = vuefy.module(ymaps3);

        const {InfoMessage: InfoMessageV} = vuefy.module({InfoMessage});

        const App = Vue.createApp({
          components: {
            YMap,
            YMapDefaultSchemeLayer,
            YMapDefaultFeaturesLayer,
            YMapFeature,
            YMapControls,
            YMapControlButton,
            YMapListener,
            InfoMessageV
          },
          setup() {
            const lineCoordinates = Vue.ref(INITIAL_LINE_COORDINATES);
            const isLineExist = Vue.ref(true);

            const onClickListenerHandler = (object, event) => {
              lineCoordinates.value.push(event.coordinates);
              isLineExist.value = true;
            };

            const onClickBtnHandler = () => {
              lineCoordinates.value = [];
              isLineExist.value = false;
            };

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

            return {
              refMap,
              lineCoordinates,
              isLineExist,
              onClickListenerHandler,
              onClickBtnHandler,
              LOCATION
            };
          },
          template: `
      <YMap
        :location="LOCATION"
        :ref="refMap"
        :showScaleInCopyrights="true"
      >
        <YMapDefaultSchemeLayer />
        <YMapDefaultFeaturesLayer />
        
        <YMapFeature
          v-if="lineCoordinates.length > 0"
          :geometry="{
            type: 'LineString',
            coordinates: lineCoordinates
          }"
          :style="{ stroke: [{ color: '#007afce6', width: 4 }] }"
        />
        
        <YMapControls position="bottom" v-if="isLineExist">
          <YMapControlButton
            text="Delete the line"
            color="#fff"
            background="#007afce6"
            @click="onClickBtnHandler"
          />
        </YMapControls>

        <YMapListener @click="onClickListenerHandler" />

        <YMapControls position="top right">
          <InfoMessageV text="To add a new point to the line, just click on the desired location on the map." />
        </YMapControls>
      </YMap>
    `
        });

        App.mount('#app');
      }

      main();
    </script>

    <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} from '@yandex/ymaps3-types';

export const LOCATION: YMapLocationRequest = {
  center: [87.0764, 28.3], // starting position [lng, lat]
  zoom: 10.7 // starting zoom
};

// The array of coordinates following the course of the Arun River.
export const INITIAL_LINE_COORDINATES: LngLat[] = [
  [86.86385144616358, 28.116408418627383],
  [86.81839686158105, 28.207288455680004],
  [86.81808226511791, 28.22806172843069],
  [86.82031538666244, 28.233797292491484],
  [86.81472565766904, 28.256087324925446],
  [86.80790342291837, 28.269123341443187],
  [86.80645477029938, 28.27525587569196],
  [86.80802334159438, 28.284579144705692],
  [86.82236456486294, 28.30302488453657],
  [86.8404130550352, 28.31244898081271],
  [86.85774203315137, 28.316018431353587],
  [86.92003905590767, 28.307458931889137],
  [86.94147211211823, 28.327385436365866],
  [86.96047236560229, 28.379870569048947],
  [86.97633868599863, 28.40045387913822],
  [87.0230092257106, 28.417227886422154],
  [87.04041289769795, 28.412869410130657],
  [87.0563226922615, 28.40335937826793],
  [87.06789936697723, 28.401067131394555],
  [87.09546140544649, 28.404831704446202],
  [87.10278140482315, 28.406548833235735],
  [87.11846040699565, 28.404679235671836],
  [87.14572366998014, 28.393186941012182],
  [87.14746557763569, 28.38842302269884],
  [87.16574223424259, 28.377389828495165],
  [87.1776900441308, 28.35942815283268],
  [87.18471126802267, 28.354736898303855],
  [87.1938239203079, 28.353547532886758],
  [87.20726881712218, 28.349384647915294],
  [87.22295453007217, 28.349252490136283],
  [87.23375742296602, 28.344200427946454],
  [87.28088925568717, 28.333825025190656],
  [87.29585938546269, 28.32476224099636],
  [87.30990183324649, 28.32800081295931],
  [87.3192385671453, 28.328199089636495],
  [87.35075938078766, 28.31874748571409],
  [87.36449721762801, 28.310366119340454],
  [87.38660660350038, 28.290797705213187],
  [87.38757762382585, 28.286235626685304],
  [87.38571027704609, 28.279425199952268],
  [87.372340074103, 28.27763986965878],
  [87.35753996538894, 28.254855225339856]
];

// 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;
});