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