場景
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>