1. 程式人生 > 實用技巧 >Vue中動態新增彈窗

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 var new_cicy_data = []; 130 for (let i = 0; i < _this.points.length; i++) { 131 new_cicy_data[i] = _this.points[i]; 132 _this.points[i].ol = []; 133 _this.points[i].ol[0] = parseFloat(_this.points[i].lon); 134 _this.points[i].ol[1] = parseFloat(_this.points[i].lat); 135 _this.points[i].key = i; 136 } 137 138 var createLabelStyle = function(feature) { 139 return new Style({ 140 image: new Icon({ 141 scale: 1, 142 //透明度 143 opacity: 1, 144 //圖示的url 145 src: "/static/img/normal_green.png" 146 }) 147 }); 148 }; 149 for (let i = 0; i < new_cicy_data.length; i++) { 150 show_dian(new_cicy_data[i]); 151 } 152 //標點渲染 153 function show_dian(info) { 154 //例項化Vector要素,通過向量圖層新增到地圖容器中 155 let iconFeature = new Feature({ 156 //座標點 157 geometry: new Point(fromLonLat(info.ol)), 158 //名稱屬性 159 name: info.cameraId, 160 //address: info.address, 161 key: info.key 162 }); 163 iconFeature.setStyle(createLabelStyle(iconFeature)); 164 //向量標註的資料來源 165 let vectorSource = new VectorSource({ 166 features: [iconFeature] 167 }); 168 //向量標註圖層 169 let vectorLayer = new LayerVec({ 170 source: vectorSource 171 }); 172 _this.maps.addLayer(vectorLayer); 173 //例項化Vector要素,通過向量圖層新增到地圖容器中 end 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>" + 227 info.address + 228 "</p>" + 229 "<br />" + 230 "<p>" + 231 info.cameraId + 232 "</p>"); 233 } 234 /** 235 * 為map新增滑鼠移動事件監聽,當指向標註時改變滑鼠游標狀態 236 */ 237 _this.maps.on("pointermove", function(e) { 238 var pixel = _this.maps.getEventPixel(e.originalEvent); 239 var hit = _this.maps.hasFeatureAtPixel(pixel); 240 _this.maps.getTargetElement().style.cursor = hit ? "pointer" : ""; 241 }); 242 } 243 }, 244 mounted() { 245 this.initMap(); 246 } 247 }; 248 </script> 249 250 <style scoped> 251 .label { 252 font-size: 20px; 253 } 254 #map { 255 width: 100%; 256 height: 99vh; 257 } 258 .ol-popup { 259 position: absolute; 260 background-color: #eeeeee; 261 -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); 262 filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); 263 padding: 15px; 264 border-radius: 10px; 265 border: 1px solid #cccccc; 266 bottom: 12px; 267 left: -100px; 268 width: 180px; 269 } 270 271 .ol-popup:after, 272 .ol-popup:before { 273 top: 100%; 274 border: solid transparent; 275 content: ""; 276 height: 0; 277 width: 0; 278 position: absolute; 279 pointer-events: none; 280 } 281 282 .ol-popup:after { 283 border-top-color: #eeeeee; 284 border-width: 10px; 285 left: 48px; 286 margin-left: 40px; 287 } 288 289 .ol-popup:before { 290 border-top-color: #cccccc; 291 border-width: 10px; 292 left: 48px; 293 margin-left: 40px; 294 } 295 296 .ol-popup-closer { 297 text-decoration: none; 298 position: absolute; 299 top: 2px; 300 right: 8px; 301 } 302 303 .ol-popup-closer:after { 304 content: "✖"; 305 } 306 </style>

參考文章:https://blog.csdn.net/weixin_44009447/article/details/105550064