Vue中动态添加弹窗

  1 <template>
  2   <div>
  3     <div ref="emap" id="map"></div>
  4     <div id="popup" class="ol-popup">
  5       <a href="#" id="popup-closer" class="ol-popup-closer"></a>
  6       <div id="popup-content"></div>
  7     </div>
  8   </div>
  9 </template>
 10 
 11 <script>
 12 import "ol/ol.css";
 13 import Map from "ol/Map";
 14 import Stamen from "ol/source/Stamen";
 15 import VectorSource from "ol/source/Vector";
 16 import View from "ol/View";
 17 import {
 18   Heatmap as HeatmapLayer,
 19   Tile as TileLayer,
 20   Vector as LayerVec
 21 } from "ol/layer";
 22 import GeoJSON from "ol/format/GeoJSON";
 23 
 24 import olsourceOSM from "ol/source/OSM";
 25 import { get as getProjection, transform, fromLonLat } from "ol/proj";
 26 
 27 import { Vector as SourceVec, Cluster, XYZ } from "ol/source";
 28 import { Feature, Overlay } from "ol";
 29 import { Point } from "ol/geom";
 30 import { Style, Icon, Stroke, Fill, Text, Circle } from "ol/style";
 31 
 32 export default {
 33   name: "heatmap",
 34   data() {
 35     return {
 36       maps: null,
 37       center: [113.0521, 34.6006],
 38       heatData: {
 39         type: "FeatureCollection",
 40         features: [
 41           { type: "Point", coordinates: [104.4, 31.19], count: 100 },
 42           { type: "Point", coordinates: [113.3, 30.6], count: 19 },
 43           { type: "Point", coordinates: [123.3, 30.6], count: 419 },
 44           { type: "Point", coordinates: [105.3, 30.6], count: 319 },
 45           { type: "Point", coordinates: [106.3, 30.6], count: 719 },
 46           { type: "Point", coordinates: [109.3, 31.6], count: 519 },
 47           { type: "Point", coordinates: [109.3, 30.6], count: 319 },
 48           { type: "Point", coordinates: [108.3, 32.6], count: 139 },
 49           { type: "Point", coordinates: [118.3, 31.6], count: 129 },
 50           { type: "Point", coordinates: [108.3, 33.6], count: 190 },
 51           { type: "Point", coordinates: [108.3, 32.6], count: 189 },
 52           { type: "Point", coordinates: [100.3, 30.6], count: 1 },
 53           { type: "Point", coordinates: [109.3, 30.6], count: 119 },
 54           { type: "Point", coordinates: [108.3, 31.6], count: 200 },
 55           { type: "Point", coordinates: [118.3, 30.6], count: 300 }
 56         ]
 57       },
 58       view: null,
 59       points: [
 60         {
 61           address: "五指山测试工地",
 62           cameraId: "T204",
 63           lat: "18.77520",
 64           lon: "109.5170"
 65         },
 66         {
 67           address: "椰树第三工业城测试工地",
 68           cameraId: "T206",
 69           lat: "19.9332",
 70           lon: "110.1424"
 71         },
 72         {
 73           address: "海南热带野生动物园测试工地",
 74           cameraId: "T214",
 75           lat: "19.7688",
 76           lon: "110.2477"
 77         },
 78         {
 79           address: "白石岭测试工地",
 80           cameraId: "T213",
 81           lat: "19.1607",
 82           lon: "110.3775"
 83         },
 84         {
 85           address: "海南大学测试工地",
 86           cameraId: "T212",
 87           lat: "20.06089",
 88           lon: "110.32645"
 89         }
 90       ]
 91     };
 92   },
 93   methods: {
 94     initMap() {
 95       let _this = this;
 96       let projection = getProjection("EPSG:4326");
 97       // 热力图层
 98       let vector = new HeatmapLayer({
 99         source: new VectorSource({
100           features: new GeoJSON().readFeatures(_this.heatData, {
101             dataProjection: "EPSG:4326",
102             featureProjection: "EPSG:3857"
103           })
104         }),
105         blur: 20,
106         radius: 10
107       });
108 
109       // 底图1
110       let tile = new TileLayer({
111         source: new olsourceOSM()
112       });
113 
114       // 地图中心
115       let view = new View({
116         center: transform(_this.center, "EPSG:4326", "EPSG:3857"),
117         zoom: 5,
118         minZoom: 5, //设置缩放的最大和最小级别
119         maxZoom: 13
120       });
121 
122       // 实例化底图
123       _this.maps = new Map({
124         layers: [tile, vector],
125         target: "map",
126         view
127       });
128 
129       // 一、将点进行转换
130       var new_cicy_data = [];
131       for (let i = 0; i < _this.points.length; i++) {
132         new_cicy_data[i] = _this.points[i];
133         _this.points[i].ol = [];
134         _this.points[i].ol[0] = parseFloat(_this.points[i].lon);
135         _this.points[i].ol[1] = parseFloat(_this.points[i].lat);
136         _this.points[i].key = i;
137       }
138 
139       var createLabelStyle = function(feature) {
140         return new Style({
141           image: new Icon({
142             scale: 1,
143             //透明度
144             opacity: 1,
145             //图标的url
146             src: "/static/img/normal_green.png"
147           })
148         });
149       };
150       //二、标点渲染
151       for (let i = 0; i < new_cicy_data.length; i++) {
152         show_dian(new_cicy_data[i]);
153       }
154       function show_dian(info) {
155         //实例化Vector要素,通过矢量图层添加到地图容器中
156         let iconFeature = new Feature({
157           //坐标点
158           geometry: new Point(fromLonLat(info.ol)),
159           //名称属性
160           name: info.cameraId,
161           //address: info.address,
162           key: info.key
163         });
164         iconFeature.setStyle(createLabelStyle(iconFeature));
165         //矢量标注的数据源
166         let vectorSource = new VectorSource({
167           features: [iconFeature]
168         });
169         //矢量标注图层
170         let vectorLayer = new LayerVec({
171           source: vectorSource
172         });
173         _this.maps.addLayer(vectorLayer);
174       }
175       /*********************显示弹出层**************************/
176       /**
177        * 实现popup的html元素
178        */
179       var container = document.getElementById("popup");
180       var content = document.getElementById("popup-content");
181       var closer = document.getElementById("popup-closer");
182 
183       /**
184        * 在地图容器中创建一个Overlay
185        */
186       let overlay = new Overlay({
187         element: container,
188         autoPan: true
189       });
190       /**
191        * 添加关闭按钮的单击事件(隐藏弹窗)
192        *
193        */
194       closer.onclick = function() {
195         //未定义popup位置
196         overlay.setPosition(undefined);
197         //失去焦点
198         closer.blur();
199         return false;
200       };
201 
202       /**
203        * 为map添加点击事件监听,渲染弹出popup
204        */
205       _this.maps.on("click", function(evt) {
206         //判断当前单击处是否有要素,捕获到要素时弹出popup
207         var feature = _this.maps.forEachFeatureAtPixel(evt.pixel, function(
208           feature,
209           layer
210         ) {
211           return feature;
212         });
213         if (feature) {
214           let coodinate = evt.coordinate;
215           content.innerHTML = "";
216           addFeatrueInfo(new_cicy_data[feature.values_.key]);
217           overlay.setPosition(coodinate);
218           _this.maps.addOverlay(overlay);
219         }
220       });
221       /**
222        * 动态创建弹窗的具体内容
223        */
224       function addFeatrueInfo(info) {
225         return (content.innerHTML =
226           "<p class='info'>" +
227           info.address +
228           "</p>" +
229           "<p class='info'>" +
230           info.cameraId +
231           "</p>");
232       }
233       /**
234        * 为map添加鼠标移动事件监听,当指向标注时改变鼠标光标状态
235        */
236       _this.maps.on("pointermove", function(e) {
237         var pixel = _this.maps.getEventPixel(e.originalEvent);
238         var hit = _this.maps.hasFeatureAtPixel(pixel);
239         if (!hit) {
240           _this.maps.getTargetElement().style.cursor = "auto";
241         } else {
242           _this.maps.getTargetElement().style.cursor = "pointer";
243         }
244         // _this.maps.getTargetElement().style.cursor = hit ? "pointer" : "";
245       });
246     }
247   },
248   mounted() {
249     this.initMap();
250   }
251 };
252 </script>
253 
254 <style scoped>
255 .label {
256   font-size: 20px;
257 }
258 #map {
259   width: 100%;
260   height: 99vh;
261 }
262 .ol-popup {
263   position: absolute;
264   background-color: #eeeeee;
265   -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
266   filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
267   padding: 15px;
268   border-radius: 10px;
269   border: 1px solid #cccccc;
270   bottom: 12px;
271   left: -100px;
272   width: 180px;
273 }
274 
275 .ol-popup:after,
276 .ol-popup:before {
277   top: 100%;
278   border: solid transparent;
279   content: "";
280   height: 0;
281   width: 0;
282   position: absolute;
283   pointer-events: none;
284 }
285 
286 .ol-popup:after {
287   border-top-color: #eeeeee;
288   border-width: 10px;
289   left: 48px;
290   margin-left: 40px;
291 }
292 
293 .ol-popup:before {
294   border-top-color: #cccccc;
295   border-width: 10px;
296   left: 48px;
297   margin-left: 40px;
298 }
299 
300 .ol-popup-closer {
301   text-decoration: none;
302   position: absolute;
303   top: 2px;
304   right: 8px;
305 }
306 
307 .ol-popup-closer:after {
308   content: "✖";
309 }
310 .info {
311   margin: 0;
312 }
313 </style>

参考文章地址:https://blog.csdn.net/weixin_44009447/article/details/105550064

原文地址:https://www.cnblogs.com/lyt520/p/14021300.html