Создание интерактивной карты с перетаскиваемой точкой и обновляемыми координатами с помощью OpenLayers

В этой статье мы расскажем, как создать интерактивную карту с помощью библиотеки OpenLayers, на которой будет перетаскиваемая точка. При перетаскивании точки будут обновляться ее координаты. Кроме того, при клике на карту точка будет перемещаться в место клика, и соответственно будут обновляться координаты.

Для начала, подключим необходимые файлы OpenLayers к нашей HTML-странице:

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>интерактивная карта OpenLayers</title>
    <script src="ol.js"></script>
    <link rel="stylesheet" href="ol.css">
    <style>
        #map {
            width: 100%;
            height: 400px;
        }
    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <p id="coordinates"></p>
</body>
</html>

или онлайн:

<script src="https://cdn.jsdelivr.net/npm/ol@v10.2.0/dist/ol.js"></script> 
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v10.2.0/ol.css">

Затем создадим точку и слой векторов:

const marker = new ol.Feature({
    geometry: new ol.geom.Point(ol.proj.fromLonLat([37.6173, 55.7558])) // Москва
});

const vectorSource = new ol.source.Vector({
    features: [marker]
});

const vectorLayer = new ol.layer.Vector({
    source: vectorSource
});

Создадим карту и добавим на нее слой векторов:

const map = new ol.Map({
    target: 'map',
    layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM()
        }),
        vectorLayer
    ],
    view: new ol.View({
        center: ol.proj.fromLonLat([37.6173, 55.7558]),
        zoom: 10
    })
});

Добавим функцию для обновления координат точки:

const updateCoordinates = () => {
    const coordinates = ol.proj.toLonLat(marker.getGeometry().getCoordinates());
    document.getElementById('coordinates').innerText = `Координаты: ${coordinates[0].toFixed(5)}, ${coordinates[1].toFixed(5)}`;
};

Установим стиль точки, чтобы она выглядела как стандартный маркер на Google Maps:

const iconStyle = new ol.style.Style({
    image: new ol.style.Icon({
        anchor: [0.5, 1],
        anchorXUnits: 'fraction',
        anchorYUnits: 'fraction',
        src: 'https://maps.gstatic.com/mapfiles/api-3/images/spotlight-poi.png'
    })
});

marker.setStyle(iconStyle);

Добавим интерактивность перетаскивания точки:

const dragInteraction = new ol.interaction.Translate({
    features: vectorSource.getFeaturesCollection()
});
dragInteraction.on('translateend', updateCoordinates);
map.addInteraction(dragInteraction);

И наконец, добавим функционал перемещения точки при клике на карту:

map.on('singleclick', function(event) {
    const clickedCoordinates = event.coordinate;
    marker.getGeometry().setCoordinates(clickedCoordinates);
    updateCoordinates();
});

Теперь у нас есть интерактивная карта с перетаскиваемой точкой и обновляемыми координатами. При перетаскивании точки координаты обновляются при отпускании левой кнопки мыши, а при клике на карту точка перемещается в место клика, и соответственно обновляются координаты.

Вот готовая html страница со скриптом:

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>интерактивная карта OpenLayers</title>
    <script src="ol.js"></script>
    <link rel="stylesheet" href="ol.css">
    <style>
        #map {
            width: 100%;
            height: 400px;
        }
    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <p id="coordinates"></p>

	<script>
        const marker = new ol.Feature({
            geometry: new ol.geom.Point(ol.proj.fromLonLat([37.6173, 55.7558])) // Москва
        });

        const vectorSource = new ol.source.Vector({
            features: [marker]
        });

        const vectorLayer = new ol.layer.Vector({
            source: vectorSource
        });

        const map = new ol.Map({
            target: 'map',
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                }),
                vectorLayer
            ],
            view: new ol.View({
                center: ol.proj.fromLonLat([37.6173, 55.7558]),
                zoom: 10
            })
        });

        const updateCoordinates = () => {
            const coordinates = ol.proj.toLonLat(marker.getGeometry().getCoordinates());
            document.getElementById('coordinates').innerText = `Координаты: ${coordinates[0].toFixed(5)}, ${coordinates[1].toFixed(5)}`;
        };

        const iconStyle = new ol.style.Style({
            image: new ol.style.Icon({
                anchor: [0.5, 1],
                anchorXUnits: 'fraction',
                anchorYUnits: 'fraction',
                src: 'https://maps.gstatic.com/mapfiles/api-3/images/spotlight-poi.png'
            })
        });

        marker.setStyle(iconStyle);

        const dragInteraction = new ol.interaction.Translate({
            features: vectorSource.getFeaturesCollection()
        });
        dragInteraction.on('translateend', updateCoordinates);
        map.addInteraction(dragInteraction);

        map.on('singleclick', function (event) {
            const clickedCoordinates = event.coordinate;
            marker.getGeometry().setCoordinates(clickedCoordinates);
            updateCoordinates();
        });

        updateCoordinates();
    </script>
    
</body>
</html>