vue?openlayers實(shí)現(xiàn)臺風(fēng)軌跡示例詳解
功能描述
- 臺風(fēng)軌跡點(diǎn)實(shí)時(shí)繪制,根據(jù)不同點(diǎn)的類型繪制不同的軌跡點(diǎn)顏色
- 軌跡線繪制,涉及實(shí)時(shí)軌跡線段與預(yù)報(bào)軌跡線,根據(jù)臺風(fēng)類型繪制成不同顏色
- 當(dāng)前正在發(fā)生的臺風(fēng)還需增加當(dāng)前臺風(fēng)所風(fēng)圈位置
- 臺風(fēng)軌跡點(diǎn)點(diǎn)擊彈框顯示軌跡點(diǎn)信息
openlayers(簡稱ol)這里不做介紹,剛開始寫此類文章,直接上代碼
創(chuàng)建一個(gè)地圖容器
引入地圖相關(guān)對象
import Map from 'ol/Map'; import View from 'ol/View'; import XYZ from 'ol/source/XYZ'; import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
創(chuàng)建地圖對象
都是一些基本活
const center = [-5639523.95, -3501274.52]; const map = new Map({ target: document.getElementById('map'), view: new View({ center: center, zoom: 10, minZoom: 2, maxZoom: 19, }), layers: [ ], }); this.addEventMapClick()
監(jiān)聽地圖點(diǎn)擊事件
addEventMapClick () { const nameDom = document.createElement('div') nameDom.setAttribute('class', 'typhoon-popup') const nameOverlay = new ol.Overlay({ element: nameDom, position: [0, 0], positioning: 'right-center', stopEvent: false, insertFirst: false, autoPanAnimation: { duration: 250 } }) this.viewer.addOverlay(nameOverlay) this._popup = nameOverlay // 監(jiān)聽地圖點(diǎn)擊事件 this.viewer.on('singleclick', e => { this._popup.getElement().parentElement.style.display = 'none' this.viewer.forEachFeatureAtPixel( e.pixel, (result) => { if (result) { let Properties = result.get('properties') let layerType = result.get('layerType') // 臺風(fēng)點(diǎn)點(diǎn)擊 // && layerType === 'typhoonpoint' if (layerType === 'typhoonLyer') { let html = `<div class="typhoonLyer"><div class="con">名稱: ${Properties.CODE || ''} ${Properties.NAME_CN || ''} ${Properties.NAME_EN || ''}</div> <div class="con">風(fēng)速: ${Properties.MOVE_SPEED || '--'} km/h</div> <div class="con">中心氣壓: ${Properties.PRESS || '--'}</div> <div class="con">時(shí)間: ${Properties.time || '--'}</div> <div class="con">中心位置: ${Properties.LON}/${Properties.LAT}</div></div>` this._popup.getElement().innerHTML = html this._popup.setPosition([Properties.LON, Properties.LAT]) // this._popup.setOffset([25, 0]) this._popup.getElement().parentElement.style.display = 'block' } else { this._popup.getElement().parentElement.style.display = 'none' } } } ) }) }
開始繪制
準(zhǔn)備臺風(fēng)數(shù)據(jù)和圖層
臺風(fēng)數(shù)據(jù)我是用的JSON。這里就簡單描述一下數(shù)據(jù)中只要用到的字段信息
[ { CODE: "202122",//臺風(fēng)編號 DB7: null,//七級東北 DB10: null,//十級東北 DB12: null,//十二級東北 DN7: null,//七級東南 DN10: null,//十級東南 DN12: null,//十二級東南 LAT: 5.5,//維度 LON: 140.9,//經(jīng)度 MOVE_DIR: null,//風(fēng)向 MOVE_SPEED: null,//風(fēng)向速度 OBJECTID: 27848,//id PRESS: 998,//中心氣壓 SHIJIAN: null, STRENGTH: "臺風(fēng)(熱帶風(fēng)暴級)",//強(qiáng)度 TH: null, TIME: "2021-12-13-14",//日期 WIND: 18,//最大風(fēng)速 XB7: null,//七級西北 XB10: null,//十級西北 XB12: null,//十二級西北 XN7: null,//七級西南 XN10: null,//十級西南 XN12: null,//十二級西南 }, ]
let tfsource = new ol.source.Vector({ crossOrigin: 'anonymous', features: [] }) let tflayer = new ol.layer.Vector({ source: tfsource }) map.addLayer(tflayer)
繪制臺風(fēng)名稱
// 利用第一個(gè)點(diǎn) 創(chuàng)建名稱Overlay層 顯示臺風(fēng)名稱 const nameDom = document.createElement('div') nameDom.setAttribute('class', 'typhoon-name-panel') nameDom.classList.add(lx) nameDom.innerHTML = label const position = [point.LON, point.LAT] const nameOverlay = new ol.Overlay({ element: nameDom, position: position, wz: position, positioning: 'center-left', offset: [15, 0] }) map.addOverlay(nameOverlay) map.getView().setCenter(position)
繪制臺風(fēng)軌跡點(diǎn)和軌跡線
//point 為數(shù)組對象中每一個(gè)點(diǎn)數(shù)據(jù) // 點(diǎn)顏色 根據(jù)強(qiáng)度區(qū)分不同點(diǎn)的顏色 let pointColor = this.setPointFillColor(point.STRENGTH) // 添加點(diǎn) if (point.LON && point.LAT) { const feature = new ol.Feature({ geometry: new ol.geom.Point([point.LON, point.LAT]), layerType: 'typhoonLyer', properties: point }) // this.tfStyle為我提前定義到的各種類型的點(diǎn)樣式 feature.setStyle(this.tfStyle[pointColor.index]) tflayer.getSource().addFeature(feature) } // 添加線 let startPoint = [point.LON, point.LAT] 開始點(diǎn) let endPonit = [points[index - 1].LON, points[index - 1].LAT] 結(jié)束點(diǎn) let coords = [startPoint, endPonit] let lineDash 線段樣式 實(shí)線或者虛線 if (lx !== 'ss') { lineDash = [0] } else { lineDash = (!point.predict && !points[index - 1].predict) ? [0] : [10] } // this.tfLinStyle 為提前定義好的線段樣式 let lineStyle = lineDash[0] === 0 ? this.tfLinStyle[pointColor.index] : this.tfLinStyle[6] let feature = new ol.Feature({ geometry: new ol.geom.LineString(coords), layerType: 'typhoonLyer', properties: point }) feature.setStyle(lineStyle) tflayer.getSource().addFeature(feature)
代碼解析 文中提到的this.tfLinStyle 和 this.tfStyle 為提前定義好的點(diǎn)和線的樣式,這么做的目的是為了提高性能,減少oplayer中new 一堆重復(fù)性的樣式堆棧,消耗內(nèi)存
this.tfStyle = [ new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: '#eed139' }), stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.6)', width: 1 }) }) }), new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: '#0000ff' }), stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.6)', width: 1 }) }) }), new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: '#0f8000' }), stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.6)', width: 1 }) }) }), new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: '#fe9c45' }), stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.6)', width: 1 }) }) }), new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: '#fe00fe' }), stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.6)', width: 1 }) }) }), new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: '#fe0000' }), stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.6)', width: 1 }) }) }) ] this.tfLinStyle = [ new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#eed139', width: 2, lineDash: [0] }) }), new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#0000ff', width: 2, lineDash: [0] }) }), new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#0f8000', width: 2, lineDash: [0] }) }), new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#fe9c45', width: 2, lineDash: [0] }) }), new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#fe00fe', width: 2, lineDash: [0] }) }), new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#fe0000', width: 2, lineDash: [0] }) }), new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#fe0000', width: 2, lineDash: [10] }) })]
setPointFillColor函數(shù)判別點(diǎn)類型
setPointFillColor (type) { let pointFillColor = '#eed139' let index = 0 switch (type) { case '臺風(fēng)(熱帶低壓)': case '熱帶低壓': pointFillColor = '#eed139' index = 0 break case '熱帶風(fēng)暴': case '熱帶風(fēng)暴級': case '臺風(fēng)(熱帶風(fēng)暴)': case '臺風(fēng)(熱帶風(fēng)暴級)': pointFillColor = '#0000ff' index = 1 break case '臺風(fēng)(強(qiáng)熱帶風(fēng)暴級)': case '強(qiáng)熱帶風(fēng)暴級': case '強(qiáng)熱帶風(fēng)暴': pointFillColor = '#0f8000' index = 2 break case '臺風(fēng)': pointFillColor = '#fe9c45' index = 3 break case '強(qiáng)臺風(fēng)': case '臺風(fēng)(強(qiáng)臺風(fēng)級)': case '臺風(fēng)(強(qiáng)臺風(fēng))': pointFillColor = '#fe00fe' index = 4 break case '超強(qiáng)臺風(fēng)': case '臺風(fēng)(超強(qiáng)臺風(fēng)級)': case '臺風(fēng)(超強(qiáng)臺風(fēng))': pointFillColor = '#fe0000' index = 5 break } return {pointFillColor, index} }
以上代碼很完整,我加了注釋,整體思路總結(jié)如下:
- 先獲取臺風(fēng)數(shù)據(jù)
- 構(gòu)造臺風(fēng)軌跡圖層并添加到地圖容器
- 循環(huán)構(gòu)造點(diǎn)、線及名稱要素對象 添加到臺風(fēng)圖層數(shù)據(jù)源中
- 添加風(fēng)圈動畫
添加臺風(fēng)風(fēng)圈動畫
根據(jù)判斷臺風(fēng)類型是否是實(shí)時(shí)臺風(fēng)還是歷史臺風(fēng)進(jìn)行添加臺風(fēng)風(fēng)圈,在數(shù)據(jù)中獲取到最后一個(gè)實(shí)時(shí)點(diǎn)位數(shù)據(jù),利用Overlay添加一個(gè)動態(tài)圖標(biāo),我是利用的gif圖片
let key = LX + '-' + tfbh const points = this._typhoonData[key].point let fqindex = points.findIndex(item => !item.predict) // 添加風(fēng)圈 if (fqindex) { const nameDom = document.createElement('div') nameDom.setAttribute('class', 'typhoon-area') let nameOverlay = new ol.Overlay({ position: [points[fqindex].LON, points[fqindex].LAT], positioning: 'center-bottom', element: nameDom, // 綁定上面添加的元素 stopEvent: false, offset: [-15, -15]// 圖片偏移量 }) this.viewer.addOverlay(nameOverlay) this._tfenterCollection[key]['areaoverlay'] = nameOverlay }
讓臺風(fēng)軌跡動起來
加載的時(shí)候利用定時(shí)器,一個(gè)點(diǎn)位一個(gè)點(diǎn)位的繪制,這樣看起來就有動畫效果啦
this._typhoonPlayFlag[key] = setInterval(() => { 去干些事請 }, 50)
結(jié)尾
這里我只是大致的描述了我繪制臺風(fēng)軌跡的一些思路和大致方法,具體項(xiàng)目中,我把整個(gè)過場都封裝成一個(gè)class 類,畢竟臺風(fēng)可能是有多條的,而且還需要做一些顯示隱藏等的一些操作,我這里不做過多描述,僅做為一些思路分享,更多關(guān)于vue openlayers臺風(fēng)軌跡的資料請關(guān)注腳本之家其它相關(guān)文章!
- 在Vue?3中使用OpenLayers加載GPX數(shù)據(jù)并顯示圖形效果
- vue+openlayers+nodejs+postgis實(shí)現(xiàn)軌跡運(yùn)動效果
- Vue使用openlayers加載天地圖
- Vue+OpenLayers?創(chuàng)建地圖并顯示鼠標(biāo)所在經(jīng)緯度(完整代碼)
- vue利用openlayers實(shí)現(xiàn)動態(tài)軌跡
- Vue結(jié)合openlayers按照經(jīng)緯度坐標(biāo)實(shí)現(xiàn)錨地標(biāo)記及繪制多邊形區(qū)域
- Vue openLayers實(shí)現(xiàn)圖層數(shù)據(jù)切換與加載流程詳解
- Vue利用openlayers實(shí)現(xiàn)點(diǎn)擊彈窗的方法詳解
- Vue使用openlayers實(shí)現(xiàn)繪制圓形和多邊形
- 在Vue 3中使用OpenLayers讀取WKB數(shù)據(jù)并顯示圖形效果
相關(guān)文章
Vue3+Element+Ts實(shí)現(xiàn)表單的基礎(chǔ)搜索重置等功能
本文主要介紹了Vue3+Element+Ts實(shí)現(xiàn)表單的基礎(chǔ)搜索重置等功能,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12源碼分析Vue.js的監(jiān)聽實(shí)現(xiàn)教程
這篇文章主要通過源碼分析介紹了Vue.js的監(jiān)聽實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),相信對大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。2017-04-04