Vue中开启关闭风场
<template> <div class="box"> <div ref="emap" id="map"></div> <div id="popup" class="ol-popup"> <a href="#" id="popup-closer" class="ol-popup-closer"></a> <div id="popup-content"></div> </div> <div class="close_on"> <!-- <el-button type="primary" size="default" @click="addWind"></el-button> <el-button type="primary" size="default" @click="closeWind">关闭风场</el-button> --> <el-button :loading="loading" type="primary" size="mini"> <span v-if="online" @click="addWind">开启风场</span> <span v-else @click="closeWind">关闭风场</span> </el-button> </div> </div> </template> <script> import 'ol/ol.css' import Map from 'ol/Map' import Stamen from 'ol/source/Stamen' import VectorSource from 'ol/source/Vector' import View from 'ol/View' import { Heatmap as HeatmapLayer, Tile as TileLayer, Vector as LayerVec } from 'ol/layer' import GeoJSON from 'ol/format/GeoJSON' import olsourceOSM from 'ol/source/OSM' import { get as getProjection, transform, fromLonLat } from 'ol/proj' import { Vector as SourceVec, Cluster } from 'ol/source' import { Feature, Overlay } from 'ol' import { Point } from 'ol/geom' import { Style, Icon, Stroke, Fill, Text, Circle } from 'ol/style' import { WindLayer } from 'ol-wind' export default { name: 'heatmap', data() { return { map: null, center: [113.0521, 34.6006], heatData: { type: 'FeatureCollection', features: [ { type: 'Point', coordinates: [104.4, 31.19], count: 100 }, { type: 'Point', coordinates: [113.3, 30.6], count: 19 }, { type: 'Point', coordinates: [123.3, 30.6], count: 419 }, { type: 'Point', coordinates: [105.3, 30.6], count: 319 }, { type: 'Point', coordinates: [106.3, 30.6], count: 719 }, { type: 'Point', coordinates: [109.3, 31.6], count: 519 }, { type: 'Point', coordinates: [109.3, 30.6], count: 319 }, { type: 'Point', coordinates: [108.3, 32.6], count: 139 }, { type: 'Point', coordinates: [118.3, 31.6], count: 129 }, { type: 'Point', coordinates: [108.3, 33.6], count: 190 }, { type: 'Point', coordinates: [108.3, 32.6], count: 189 }, { type: 'Point', coordinates: [100.3, 30.6], count: 1 }, { type: 'Point', coordinates: [109.3, 30.6], count: 119 }, { type: 'Point', coordinates: [108.3, 31.6], count: 200 }, { type: 'Point', coordinates: [118.3, 30.6], count: 300 }, ], }, view: null, points: [ { address: '河南省商丘市', name: '测试', id: '1000', lon: ['113.28', '34.54'], }, { address: '河南省郑州市', name: '同样是测试', id: '1001', lon: ['113.28', '35.54'], }, ], layer: null, windLayers: null, online: true, loading: false, } }, methods: { initMap() { let _this = this let projection = getProjection('EPSG:4326') // 热力图层 let vector = new HeatmapLayer({ source: new VectorSource({ features: new GeoJSON().readFeatures(this.heatData, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857', }), }), blur: 20, radius: 10, }) // 底图1 let tile = new TileLayer({ source: new olsourceOSM(), }) // 地图中心 let view = new View({ center: transform(this.center, 'EPSG:4326', 'EPSG:3857'), zoom: 5, minZoom: 5, maxZoom: 13, }) // 实例化底图 this.map = new Map({ layers: [tile, vector], target: 'map', view, }) // 创建点标记样式 let createLabelStyle = function(feature) { let imgs = '' if (feature.values_.id == '1000') { imgs = '/static/warning_icon/normal_green.png' } else { imgs = '/static/warning_icon/normal_red.png' } return new Style({ image: new Icon({ scale: 1, opacity: 1, src: imgs, }), }) } // 显示点标记 for (let i = 0; i < this.points.length; i++) { addMarker(this.points[i]) } function addMarker(info) { let iconFeature = new Feature({ geometry: new Point(fromLonLat(info.lon)), name: info.name, id: info.id, address: info.address, lon: info.lon, }) // 调用 createLabelStyle, 添加样式 iconFeature.setStyle(createLabelStyle(iconFeature)) // 矢量图层数据源 let vectorSource = new VectorSource({ features: [iconFeature], }) // 矢量标注图层 let vectorLayer = new LayerVec({ source: vectorSource, }) _this.map.addLayer(vectorLayer) } /*********************显示弹出层**************************/ let container = document.getElementById('popup') let content = document.getElementById('popup-content') let popupCloser = document.getElementById('popup-closer') // 创建覆盖物图层 let overlay = new Overlay({ element: container, autoPan: true, }) // 鼠标移入改变样式 this.map.on('pointermove', function(e) { let pixel = _this.map.getEventPixel(e.originalEvent) let hit = _this.map.hasFeatureAtPixel(pixel) _this.map.getTargetElement().style.cursor = hit ? 'pointer' : '' }) // 设置显示内容 function addInfo(info) { return (content.innerHTML = "<p class='info'>" + info.address + '</p>' + "<p class='info'>" + info.id + '</p>' + "<p class='info'>" + info.name + '</p>') } // 鼠标点击覆盖物 this.map.on('click', function(e) { let feature = _this.map.forEachFeatureAtPixel(e.pixel, function(feature, layer) { return feature }) if (feature) { if (!feature.values_.id) { return false } let coodinate = e.coordinate content.innerHTML = '' addInfo(feature.values_) overlay.setPosition(fromLonLat(feature.values_.lon)) _this.map.addOverlay(overlay) } }) // 点击关闭事件 popupCloser.addEventListener('click', function() { overlay.setPosition(undefined) }) }, addWind() { // 开启风场 let _this = this _this.loading = true _this.$ajax .get('https://sakitam-fdd.github.io/wind-layer/data/wind.json') .then(res => { let Data = res.data this.windLayers = new WindLayer(Data, { windOptions: { colorScale: [ 'rgb(36,104, 180)', 'rgb(60,157, 194)', 'rgb(128,205,193 )', 'rgb(151,218,168 )', 'rgb(198,231,181)', 'rgb(238,247,217)', 'rgb(255,238,159)', 'rgb(252,217,125)', 'rgb(255,182,100)', 'rgb(252,150,75)', 'rgb(250,112,52)', 'rgb(245,64,32)', 'rgb(237,45,28)', 'rgb(220,24,32)', 'rgb(180,0,35)', ], lineWidth: 2, frameRate: 20, globalAlpha: 0.6, velocityScale: 1 / 50, paths: 3000, generateParticleOption: false, }, }) _this.$nextTick(() => { _this.map.addLayer(_this.windLayers) _this.online = false _this.loading = false _this.$message({ type: 'success', message: '开启风场成功', }) }) }) .catch(e => { console.log(e) }) }, closeWind() { // 关闭风场 this.map.removeLayer(this.windLayers) this.online = this.online ? false : true this.$message({ type: 'success', message: '关闭风场成功!', }) }, }, mounted() { this.initMap() }, } </script> <style> #popup-content .info { margin: 0px; padding: 0px; } </style> <style scoped> .box { position: relative; } .label { font-size: 20px; } #map { width: 100%; height: 99vh; } .ol-popup { position: absolute; background-color: #eeeeee; -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: -100px; width: 180px; } .ol-popup:after, .ol-popup:before { top: 100%; border: solid transparent; content: ''; height: 0; width: 0; position: absolute; pointer-events: none; } .ol-popup:after { border-top-color: #eeeeee; border-width: 10px; left: 48px; margin-left: 40px; } .ol-popup:before { border-top-color: #cccccc; border-width: 10px; left: 48px; margin-left: 40px; } .ol-popup-closer { text-decoration: none; position: absolute; top: 2px; right: 8px; } .ol-popup-closer:after { content: '✖'; } .close_on { position: absolute; top: 10px; right: 10px; } </style> 参考链接:
https://github.com/sakitam-fdd/wind-layer(官方github)
https://sakitam-fdd.github.io/wind-layer/ 参考文章:https://blog.csdn.net/u010065726/article/details/106338194/ 注意:需要安装ol和ol-wind, npm i ol ol-wind --save
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异