OpenLayers地图标注及弹窗实现

1. 引言

地图标注是在地图中进行文字或图标的标注,从而显示对应的信息

本文基于OpenLayers实现地图上图文的标注与弹窗显示

OpenLayers官网:OpenLayers - Welcome

OpenLayers的GitHub站点:openlayers/openlayers: OpenLayers (github.com)

OpenLayers API文档:OpenLayers v6.15.1 API - Index

2. 图文标注实现

本文实现图文标注的实质就是添加点时设置点要素(Point)的Style

设置图片标注就是在Style中添加Image

设置文字标注就是在Style中添加Text

以下是实现图文标注的核心代码:

const feature = new ol.Feature({
    geometry: new ol.geom.Point(evt.coordinate)
});
feature.setStyle(new ol.style.Style({
    text: new ol.style.Text({
        text: evt.coordinate[0].toFixed(4) + ',' + evt.coordinate[1].toFixed(4),
        offsetY: 30,
        font: '12px Calibri,sans-serif',
        fill: new ol.style.Fill({
            color: '#000'
        }),
        stroke: new ol.style.Stroke({
            color: '#fff',
            width: 3
        })
    }),
    image: new ol.style.Icon({
        src: './images/blueIcon.png',
        scale: 0.5,
        anchor: [0.5, 0.5],
        rotateWithView: true,
        rotation: 0,
        opacity: 0.5,
        color: '#0000ff'

    })
}));
vectorSource.addFeature(feature);

完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css" type="text/css">
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
    <style>
        html,
        body,
        #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
        }

        #button {
            position: absolute;
            top: 80px;
            left: 10px;
            z-index: 100;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <div id="button">
        <button onclick="active()">激活</button>
        <button onclick="deactive()">反激活</button>
    </div>
    <script>
        function active() {
            map.on('click', onClick);
        }

        function deactive() {
            map.un('click', onClick);
        }
    </script>
    <script>
        const map = new ol.Map({
            target: 'map',
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                })
            ],
            view: new ol.View({
                center: [128, 31.5],
                zoom: 5,
                projection: 'EPSG:4326'
            })
        });

        const vectorSource = new ol.source.Vector({
            features: []
        });
        const vectorLayer = new ol.layer.Vector({
            source: vectorSource,
            style: new ol.style.Style({

            })
        });
        map.addLayer(vectorLayer);

        function onClick(evt) {
            console.log(evt.coordinate);
            const feature = new ol.Feature({
                geometry: new ol.geom.Point(evt.coordinate)
            });
            feature.setStyle(new ol.style.Style({
                text: new ol.style.Text({
                    text: evt.coordinate[0].toFixed(4) + ',' + evt.coordinate[1].toFixed(4),
                    offsetY: 30,
                    font: '12px Calibri,sans-serif',
                    fill: new ol.style.Fill({
                        color: '#000'
                    }),
                    stroke: new ol.style.Stroke({
                        color: '#f00',
                        width: 3
                    })
                }),
                image: new ol.style.Icon({
                    src: './images/blueIcon.png',
                    scale: 0.5,
                    anchor: [0.5, 0.5],
                    rotateWithView: true,
                    rotation: 0,
                    opacity: 0.5,
                    color: '#0000ff'

                })
            }));
            vectorSource.addFeature(feature);
        }
    </script>
</body>

</html>

实现效果如下:

image-20220720232504438

3. Popup弹窗

当我们点击某个要素时,希望在这个要素附近显示其具体信息,这个时候往往使用Popup弹出框实现

本文的Popup弹出框的实现实质就是在OpenLayers中创建一个Overlay,其实现流程为:

  • 创建DOM元素(通常为div及包含的子元素)
  • 创建Overlay并将DOM元素挂载
  • 监听地图点击事件
  • 点击地图中的要素时读取要素信息并向地图(Map)中添加Overlay

具体实现流程如下:

创建DOM元素

<div id="popup" class="ol-popup">
    <a href="#" id="popup-closer" class="ol-popup-closer"></a>
    <div id="popup-content"></div>
</div>

创建Overlay并将DOM元素挂载

const popup = new ol.Overlay({
    element: document.getElementById('popup')
});

监听事件,读取要素信息并向地图中添加Overlay

map.on('click', popupFunc)
function popupFunc(evt) {
    var feature = map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
        return feature
    })
    if (feature) {
        console.log(evt.coordinate);
        const content = feature.getGeometry().getCoordinates();
        popup.setPosition(content);
        map.addOverlay(popup);
        document.getElementById('popup-content').innerHTML = `
            <p>lng: ${content[0].toFixed(4)}</p>
            <p>lat: ${content[1].toFixed(4)}</p>
            `;
        document.querySelector('#popup-closer').addEventListener('click', function () {
            map.removeOverlay(popup);
        });
    }
}

完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css" type="text/css">
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
    <style>
        html,
        body,
        #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
        }
        #button {
            position: absolute;
            top: 80px;
            left: 10px;
            z-index: 100;
        }

        .ol-popup {
            position: absolute;
            background-color: white;
            -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
            filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
            padding: 15px;
            border-radius: 10px;
            border: 1px solid #cccccc;
            bottom: 10px;
            left: -50px;
        }

        .ol-popup:after,
        .ol-popup:before {
            top: 100%;
            border: solid transparent;
            content: ' ';
            height: 0;
            width: 0;
            position: absolute;
            pointer-events: none;
        }

        .ol-popup:after {
            border-top-color: white;
            border-width: 10px;
            left: 48px;
            margin-left: -10px;
        }

        .ol-popup:before {
            border-top-color: #cccccc;
            border-width: 11px;
            left: 48px;
            margin-left: -11px;
        }

        .ol-popup-closer {
            text-decoration: none;
            position: absolute;
            top: 2px;
            right: 8px;
        }

        .ol-popup-closer:after {
            content: '✖';
        }

        #popup-content {
            font-size: 14px;
            font-family: '微软雅黑';
        }

        #popup-content .markerInfo {
            font-weight: bold;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <div id="popup" class="ol-popup">
        <a href="#" id="popup-closer" class="ol-popup-closer"></a>
        <div id="popup-content"></div>
    </div>
    <div id="button">
        <button onclick="active()">激活</button>
        <button onclick="deactive()">反激活</button>
    </div>

    <script>
        function active() {
            map.addInteraction(draw);
            map.un('click', popupFunc);
        }

        function deactive() {
            map.removeInteraction(draw);
            map.on('click', popupFunc)
        }
    </script>
    <script>
        const map = new ol.Map({
            target: 'map',
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                })
            ],
            view: new ol.View({
                center: [100.2382, 30.0207],
                zoom: 12,
                projection: 'EPSG:4326'
            })
        });
        const popup = new ol.Overlay({
            element: document.getElementById('popup')
        });
        const source = new ol.source.Vector({
            features: []
        });
        const vector = new ol.layer.Vector({
            source: source
        });
        map.addLayer(vector);

        const draw = new ol.interaction.Draw({
            source: source,
            type: 'Point'
        })

        function popupFunc(evt) {
            var feature = map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
                return feature
            })
            if (feature) {
                console.log(evt.coordinate);
                const content = feature.getGeometry().getCoordinates();
                popup.setPosition(content);
                map.addOverlay(popup);
                document.getElementById('popup-content').innerHTML = `
            <p>lng: ${content[0].toFixed(4)}</p>
            <p>lat: ${content[1].toFixed(4)}</p>
            `;
                document.querySelector('#popup-closer').addEventListener('click', function () {
                    map.removeOverlay(popup);
                });
            }
        }

        draw.on('drawend', function (evt) {
            const feature = evt.feature;
            const coordinates = feature.getGeometry().getCoordinates();
            console.log(coordinates);
            feature.setStyle(new ol.style.Style({
                image: new ol.style.Icon({
                    src: './images/blueIcon.png'
                }),
                text: new ol.style.Text({
                    text: coordinates[0].toFixed(4) + ',' + coordinates[1].toFixed(4),
                    offsetY: 30,
                    fill: new ol.style.Fill({
                        color: '#f00'
                    })
                })
            }))
        });

    </script>
</body>

</html>

最后的结果如下图:

image-20220720234415670

4. 参考资料

[1]OpenLayers v6.15.1 API - Index

posted @ 2022-07-20 23:49  当时明月在曾照彩云归  阅读(3109)  评论(0编辑  收藏  举报