Openlayers中使用Overlay實現點擊要素彈窗並且彈窗隨之移動


場景

Vue+Openlayer使用overlay實現彈窗彈出顯示與關閉:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/121268946

實現彈窗的效果可以參考上面。

要實現的效果是點擊某個元素彈窗顯示,並且彈窗隨着元素的移動而移動。

實現元素移動的效果可以參考如下:

Openlayers中使用Image的rotation實現車輛定位導航帶轉角(判斷車輛圖片旋轉角度):

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/118635362

結合以上兩個的效果

 

 

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi
關注公眾號
霸道的程序猿
獲取編程相關電子書、教程推送與免費下載。

實現

1、實現彈窗的代碼基本同上,不同的是添加了一個布爾變量,控制是否顯示彈窗

        var isShowDialog = false;
        let _that = this;
        map.on('singleclick', function (evt) {
            let coordinate = evt.coordinate
            // 點擊尺 (這里是尺(米),並不是經緯度);
            var feature = map.forEachFeatureAtPixel(evt.pixel, (feature) => {
                return feature;
            });
            if (feature) { //捕捉到要素
                content.innerHTML = `
                    <p>公眾號:</p>
                    <p>霸道的程序猿</p>`;
                _that.overlay.setPosition(coordinate); //把 overlay 顯示到指定的 x,y坐標
                isShowDialog = true;
            } else {
                console.log("沒有元素");
            }
        });

布爾變量的默認值為false,在地圖的點擊事件中,捕獲到元素之后,將其設置為true。

2、然后定時器一直監測

            setTimeout(() => {
                if (isShowDialog) {
                    this.overlay.setPosition([Number(item.x), Number(item.y)]);
                }
            }, 0);

當布爾變量為true時,將overlay彈窗顯示在當前坐標位置上。

這里的item.x是通過定時器模擬獲取的后台坐標數據。

3、在彈窗的關閉事件中再將布爾變量設置為false

        //彈窗關閉事件
        closer.onclick = function () {
            _that.overlay.setPosition(undefined);
            closer.blur();
            isShowDialog = false;
            return false;
        };

4、完整示例代碼

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

<head>
    <meta charset="UTF-8">
    <title>OpenLayers example</title>
    <link rel="stylesheet" href="lib/ol65/ol.css" type="text/css">
    <style>
        html,
        body,
        #map {
            padding: 0;
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }

        .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: 12px;
            left: -50px;
        }

        .popup-content {
            width: 400px;
        }

        .ol-popup-closer {
            text-decoration: none;
            position: absolute;
            top: 2px;
            right: 8px;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <div id="popup" class="ol-popup">
        <a href="#" id="popup-closer" class="ol-popup-closer">X</a>
        <div id="popup-content" class="popup-content"></div>
    </div>
    <script type="text/javascript" src="lib/ol65/ol.js"></script>
    <script type="text/javascript">
        //打點數據源
        var wrnameData = [{
                x: '-11561016.25956459',
                y: '5542204.803284118',
                wrname: '公眾號'
            },
            {
                x: '-11562479.441174088',
                y: '5540478.999423137',
                wrname: '霸道的程序猿'
            }
        ];

        //定位數據源
        var positionData = [{
                x: '-11560139.941628069',
                y: '5538515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11560039.941628069',
                y: '5537515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11559039.941628069',
                y: '5536515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11558039.941628069',
                y: '5535515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11557039.941628069',
                y: '5534515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11556039.941628069',
                y: '5533515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11555039.941628069',
                y: '5532515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11554039.941628069',
                y: '5531515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11553039.941628069',
                y: '5530515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11552039.941628069',
                y: '5529515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11551039.941628069',
                y: '5528515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11550039.941628069',
                y: '5527515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11549039.941628069',
                y: '5526515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11548039.941628069',
                y: '5525515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11547039.941628069',
                y: '5524515.7834814',
                carNumber: '霸道的程序猿'
            },
            {
                x: '-11546039.941628069',
                y: '5523515.7834814',
                carNumber: '霸道的程序猿'
            }

        ];

        // 打點圖標的圖層
        var pointLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: []
            })
        })

        var source = new ol.source.XYZ({
            tileUrlFunction: function (xyz, obj1, obj2) {
                if (!xyz)
                    return "";
                var z = xyz[0];
                var x = Math.abs(xyz[1]);
                var y = Math.abs(xyz[2]);
                var xyz_convert = self.convert_(z, x, y);
                x = xyz_convert[0];
                y = xyz_convert[1];
                z = xyz_convert[2];
                var shift = z / 2;
                var half = 2 << shift;
                var digits = 1;
                if (half > 10)
                    digits = parseInt(Math.log(half) / Math.log(10)) + 1;
                var halfx = parseInt(x / half);
                var halfy = parseInt(y / half);
                x = parseInt(x);
                y = parseInt(y) - 1;
                var url = "./images/EPSG_900913" + "_" + self.padLeft_(2, z) + "/" + self.padLeft_(digits,
                        halfx) + "_" + self.padLeft_(digits, halfy) + "/" + self.padLeft_(2 * digits, x) +
                    "_" + self.padLeft_(2 * digits, y) + "." + 'png';
                return url;
            }
        });

        //projections投影坐標系轉換相關的操作
        var projection = new ol.proj.Projection({
            code: 'EPSG:900913',
            units: 'm',
            axisOrientation: 'neu'
        });

        //Layers 圖層管理類,用來管理圖層信息。主要包括Tile,Image,Vector,VectorTile等圖層。
        var layer = new ol.layer.Tile({
            source: source
        });

        //線的數據源
        var drwaSource = new ol.source.Vector({
            wrapX: false
        })

        //線的圖層
        var lineVector = new ol.layer.Vector({
            source: self.drwaSource
        });


        //定位圖層的Source
        var positonSource = new ol.source.Vector({
            features: []
        });

        // 定位圖層
        var positionLayer = new ol.layer.Vector({
            source: positonSource
        });

        //View 視圖管理器,主要用來管理地圖視圖,分辨率或旋轉,中心、投影、分辨率、縮放級別等。
        var view = new ol.View({
            //中心點
            center: [-11549894, 5533433],
            //縮放等級
            zoom: 11,
            //投影坐標系
            projection: projection,
            //邊界
            extent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]
        });

        //Map Openlayers的核心組件,包含圖層、交互事件、UI控制元素等。
        var map = new ol.Map({
            layers: [layer, pointLayer, lineVector, positionLayer],
            target: 'map',
            view: view
        });

        //單擊獲取地圖坐標
        map.on('singleclick', (evt) => {
            console.log(evt.coordinate);
        });

        //xy行列轉換
        function convert_(zoomLevel, x, y) {
            var extent = Math.pow(2, zoomLevel);
            if (x < 0 || x > extent - 1) {
                console.log("The X coordinate is not sane: " + x);
                return;
            }
            if (y < 0 || y > extent - 1) {
                console.log("The Y coordinate is not sane: " + y);
                return;
            }
            // openlayers 6.0版本
            var gridLoc = [x, extent - y, zoomLevel];

            // openlayers 4.5版本
            // var gridLoc = [x, extent - y + 1, zoomLevel];
            return gridLoc;
        }

        //字符截取
        function padLeft_(num, val) {
            return (new Array(num).join('0') + val).slice(-num);
        }

        //調用畫線方法
        this.drawLine();

        /**
         * 畫線
         * */
        function drawLine() {
            let self = this
            //設置起點與終點
            let pointData = [
                [-11561569.727802912, 5540797.727555227],
                [-11563653.520735113, 5540037.346516268]
            ]
            //下邊來添加一線feature
            var feature = new ol.Feature({
                type: 'lineStyle',
                geometry: new ol.geom.LineString(
                    pointData // 線的坐標
                )
            })
            //設置線的樣式
            let lineStyle = new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: 'red',
                    width: 4
                })
            })
            // 添加線的樣式
            feature.setStyle(lineStyle)
            // 添加線的fature
            self.drwaSource.addFeature(feature)
        }

        //清除線的方法
        function clearLine() {
            this.drwaSource.clear();
        }
        // 獲取到彈框的節點DOM
        var container = document.getElementById("popup");
        var content = document.getElementById("popup-content");
        var closer = document.getElementById("popup-closer");
        //彈窗關閉事件
        closer.onclick = function () {
            _that.overlay.setPosition(undefined);
            closer.blur();
            isShowDialog = false;
            return false;
        };
        // 創建一個彈窗 Overlay 對象
        var overlay = new ol.Overlay({
            element: container, //綁定 Overlay 對象和 DOM 對象的
            autoPan: true, // 定義彈出窗口在邊緣點擊時候可能不完整 設置自動平移效果
            autoPanAnimation: {
                duration: 250 //自動平移效果的動畫時間 9毫秒
            }
        });
        map.addOverlay(overlay);
        //控制是否顯示彈窗
        var isShowDialog = false;
        let _that = this;
        map.on('singleclick', function (evt) {
            let coordinate = evt.coordinate
            // 點擊尺 (這里是尺(米),並不是經緯度);
            var feature = map.forEachFeatureAtPixel(evt.pixel, (feature) => {
                return feature;
            });
            if (feature) { //捕捉到要素
                content.innerHTML = `
                    <p>公眾號:</p>
                    <p>霸道的程序猿</p>`;
                _that.overlay.setPosition(coordinate); //把 overlay 顯示到指定的 x,y坐標
                isShowDialog = true;
            } else {
                console.log("沒有元素");
            }
        });

        //調用打點方法
        this.drawPoint();
        /**
         * 圖標文字打點
         * */
        function drawPoint() {
            this.wrnameData.forEach((item, index) => {
                var feature = new ol.Feature({
                    geometry: new ol.geom.Point([Number(item.x), Number(item.y)])
                })
                let style = new ol.style.Style({
                    image: new ol.style.Icon({
                        scale: 0.8,
                        src: './icon/house.png',
                        anchor: [0.48, 0.52]
                    }),
                    text: new ol.style.Text({
                        font: 'normal 12px 黑體',
                        // // 對其方式
                        textAlign: 'center',
                        // 基准線
                        textBaseline: 'middle',
                        offsetY: -35,
                        offsetX: 0,
                        backgroundFill: new ol.style.Stroke({
                            color: 'rgba(0,0,255,0.7)',
                        }),
                        // 文本填充樣式
                        fill: new ol.style.Fill({
                            color: 'rgba(236,218,20,1)'
                        }),
                        padding: [5, 5, 5, 5],
                        text: `${item.wrname}`,
                    })
                })
                feature.setStyle(style);
                this.pointLayer.getSource().addFeature(feature);
            });
        }

        //定時器循環模擬定位效果
        var index = 0;
        setInterval(() => {
            //坐標數據到頭了 就重新開始
            if (index > this.positionData.length - 2) {
                index = 0;
            }

            //定義角度
            var rotation = 0;
            //如果是最后一個點
            if (index == this.positionData.length - 1) {
                rotation = setAngle(this.positionData[index], this.positionData[index]);
            } else {
                rotation = setAngle(this.positionData[index], this.positionData[index + 1]);
            }

            //根據索引獲取數據
            var item = this.positionData[index];
            //清除上次的
            if (this.positonSource) {
                this.positonSource.clear();
            }
            var feature = new ol.Feature({
                geometry: new ol.geom.Point([Number(item.x), Number(item.y)])
            });

            var style = new ol.style.Style({
                image: new ol.style.Icon({
                    scale: 0.8,
                    src: './icon/car.png',
                    anchor: [0.48, 0.52],
                    //設置旋轉角度
                    rotation: -rotation,
                }),
                text: new ol.style.Text({
                    font: 'normal 12px 黑體',
                    // // 對其方式
                    textAlign: 'center',
                    // 基准線
                    textBaseline: 'middle',
                    offsetY: -35,
                    offsetX: 0,
                    backgroundFill: new ol.style.Stroke({
                        color: 'rgba(0,0,255,0.7)',
                    }),
                    // 文本填充樣式
                    fill: new ol.style.Fill({
                        color: 'rgba(236,218,20,1)'
                    }),
                    padding: [5, 5, 5, 5],
                    text: `${item.carNumber}`,
                })
            });

            //設置樣式
            feature.setStyle(style);
            //添加feture
            this.positonSource.addFeature(feature)
            setTimeout(() => {
                if (isShowDialog) {
                    this.overlay.setPosition([Number(item.x), Number(item.y)]);
                }
            }, 0);
            //移到下個點
            index++;
        }, 1000);

        // 點位轉角
        function setAngle(first, second) {
            var dx = second.x - first.x
            var dy = second.y - first.y
            var rotation = Math.atan2(dy, dx)
            return rotation
        }
    </script>

 

</body>

</html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM