基于mineMap的地图台风灾害预警轨迹可视化方案
1.需求概要
可视化界面显示气象云图及台风中心运动变化,实时数据显示;
2.效果预览

方案实施
1.>图层构成分析:
可视范围内构成的应该包含基础图层和动态移动图层,运动线路,运动风标,及运动信息框;
2.>结构拆分:
//:基于单图层创建多个根据风力大小为半径的风面圆图层;
数据组装:
/**
* @Description:圆心处理
* @Author: ShiWei
* @Date: 2020-09-07
*/
makeWindGeo(fea,i) {
const cen = turf.point(fea[i].geometry.coordinates)
// 圆形展示
return turf.sector(cen, fea[i].properties.r10, 0, 360)
},
if( winData.length!==0){
let dataObj=winData.data;
let r7=Math.floor(Math.random() * 200 + 20);
let r10= Math.floor(Math.random() * 300 + 50);
dataObj.map((item,index) =>{
let properties={wl:parseFloat(item.mws),r10:r10,r7:r7,startTime:item.startTime,
endTime:item.endTime,
centerPres:item.centerPres,
mws:item.mws,
mwsMax:item.mws};
let point=[];
//单点信息
point.push(parseFloat(item.lon),parseFloat(item.lat))
stp.push(this.mapController.makeFeature("Point",point,properties))
features.push(this.makeWindGeo(stp,index))
})
let source = this.mapController.makeFeatureCollection(features)
this.mapController.addSource(this.map, "circle-source-1", source)
this.drwWinCircle('win-circle','circle-source-1',this.map)
/**
* @Description: 绘制圆形风力面 采用单图层绘制多个同类面
* @Author: ShiWei
* @Date: 2020-09-07
*/
drwWinCircle(id,source,map){
if (map.getLayer(id)) {
map.removeLayer(id)
}
map.addLayer({
"id": id,
"type": "fill",
"source": source,
"paint": {
"fill-color": "#35e2ce",
"fill-opacity": 0.2,
}
});
},
2.同操作拆分出风面中心点point,及轨迹线路
if( winData.length!==0){
let dataObj=winData.data;
let r7=Math.floor(Math.random() * 200 + 20);
let r10= Math.floor(Math.random() * 300 + 50);
dataObj.map((item,index) =>{
let properties={wl:parseFloat(item.mws),r10:r10,r7:r7,startTime:item.startTime,
endTime:item.endTime,
centerPres:item.centerPres,
mws:item.mws,
mwsMax:item.mws};
let point=[];
//单点信息
point.push(parseFloat(item.lon),parseFloat(item.lat))
//风力轨迹坐标
line.push(point);
stp.push(this.mapController.makeFeature("Point",point,properties))
infos.push({point:point,properties})
//中心点
winCenter.push(this.mapController.makeFeature("Point",point,properties))
features.push(this.makeWindGeo(stp,index))
})
features.map((ite,idx)=>{
markerList.push(ite.geometry.coordinates[0][0])
})
let source = this.mapController.makeFeatureCollection(features)
let winCenterSource = this.mapController.makeFeatureCollection(winCenter)
this.mapController.addSource(this.map, "center-source-1", winCenterSource)
this.drwWinCenter('win-center','center-source-1',this.map)
let geo = {
type: "FeatureCollection",
features: [{
type: "Feature",
geometry: {"type": "LineString", "coordinates": line},
properties: {}
}]
}
//运动数装倒序组装
this.infoList=infos.reverse();
this.mapController.addSource(this.map, "line-source-1", geo);
this.drwWinLine('line-win',"line-source-1",this.map)
this.addMarker(this.map,line)
this.moveList=line.reverse();
minemaputil.fitBounds(this.map, source, { padding: 200 });
}
3.绘制中心点及轨迹路线
/**
* @Description:风圈中心位置标识
* @Author: ShiWei
* @Date: 2020-09-08
*/
drwWinCenter(id,source,map){
if (map.getLayer(id)) {
map.removeLayer(id)
}
map.addLayer({
"id": id,
"type": "circle",
"source": source,
"paint": {
"circle-color": {
"property": "wl",
"stops": [
[0, "rgba(255,255,255,0.60)"],
[1, "rgba(230,230,230,0.60)"],
[2, "rgba(204,204,204,0.60)"],
[3, "rgba(179,179,179,0.60)"],
[4, "rgba(154,154,154,0.60)"],
[5, "rgba(62,217,230,0.60)"],
[6, "rgba(79,214,203,0.60)"],
[7, "rgba(85,207,137,0.60)"],
[8, "rgba(109,214,106,0.60)"],
[9, "rgba(160,230,69,0.60)"],
[10, "rgba(213,230,69,0.60)"],
[11, "rgba(255,232,79,0.60)"],
[12, "rgba(245,188,56,0.60)"],
[13, "rgba(245,144,56,0.60)"],
[14, "rgba(235,103,47,0.60)"],
[15, "rgba(218,73,43,0.60)"],
[16, "rgba(190,46,45,0.60)"],
[17, "rgba(129,56,184,0.60)"],
[18, "rgba(67,2,116,0.60)"]
]
},
"circle-radius": 10
}
});
},
/**
* @Description:绘制风力轨迹线路
* @Author: ShiWei
* @Date: 2020-09-08
*/
drwWinLine(id,source,map){
map.addLayer({
"id": id,
"type": "line",
"source": source,
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
"line-color": "#64a7c2",
"line-width": 2,
"line-opacity": 0.6
}
});
},
4.风标
/**
* @Description:风圈引导标记
* @Author: ShiWei
* @Date: 2020-09-08
*/
addMarker(map,data){
if(this.markerLister) {
this.markerLister.remove();
}
let el = document.createElement('div');
el.style.zIndex = 120;
el.className = 'pin-wheel-marker';
let p = document.createElement('div');
p.className = 'pin-wheel-inner';
el.appendChild(p);
this.markerLister= new minemap.Marker(el, {offset: [-17, -17]}).setLngLat(data[data.length-1]).addTo(map);
this.addInfoMarker(0)
},
5.动态信息窗
/**
* @Description:动态信息窗体
* @Author: ShiWei
* @Date: 2020-09-08
*/
addInfoMarker(i){
let data=this.infoList;
if(this.infoMarker) {
this.infoMarker.remove();
}
let el=document.createElement('div');
el.className="info-content";
let line=document.createElement('li')
line.className='info-line'
el.appendChild(line)
let infoM=document.createElement('div');
infoM.className='info-cls'
let info=document.createElement('div');
info.className='info-menu'
let tt = document.createElement('li');
tt.innerHTML='持续时间'+data[i].properties.startTime+'--'+data[i].properties.startTime;
info.appendChild(tt);
let qy=document.createElement('li');
qy.innerHTML='中心气压'+data[i].properties.centerPres+'百帕';
info.appendChild(qy);
let fsMin =document.createElement('li');
fsMin.innerHTML='最小风速'+data[i].properties.mws+'米/秒';
info.appendChild(fsMin);
infoM.appendChild(info)
el.appendChild(infoM)
this.infoMarker= new minemap.Marker(el, {offset: [8, -60]}).setLngLat(data[i].point).addTo(this.map);
},
实时播放,暂停,重置
/**
* @Description:播放风力轨迹
* @Author: ShiWei
* @Date: 2020-09-08
*/
winStart(){
if(this.moveList.length>0){
let count=0;
if(this.tep!==""){
count=this.tep;
}else {
count=0;
}
this.moveTimer=setInterval(()=>{
this.markerLister.setLngLat(this.moveList[count])
this.addInfoMarker(count)
this.tep=count;
count++;
if(count===this.moveList.length){
clearInterval(this.moveTimer);
this.moveTimer=null;
this.markerLister.setLngLat(this.moveList[0])
this.addInfoMarker(0)
}
},2000)
}
},
/**
* @Description:暂停
* @Author: ShiWei
* @Date: 2020-09-08
*/
winStop(){
if( this.moveTimer){
clearInterval(this.moveTimer);
this.moveTimer=null;
}
this.moveTimer=setInterval(()=>{
let count=this.tep;
this.markerLister.setLngLat(this.moveList[count])
this.addInfoMarker(count)
this.tep=count;
count++;
if(count===this.moveList.length){
clearInterval(this.moveTimer);
this.moveTimer=null;
this.markerLister.setLngLat(this.moveList[0])
this.addInfoMarker(0)
}
},2000)
},
/**
* @Description:重置
* @Author: ShiWei
* @Date: 2020-09-08
*/
rest(){
this.tep="";
clearInterval(this.moveTimer);
this.moveTimer=null;
this.markerLister.setLngLat(this.moveList[0])
this.addInfoMarker(0)
},
注意:利用turf将坐标转换成多边形;利用reverse()将数据顺序倒序达到预期效果
1 const cen = turf.point(fea[i].geometry.coordinates) // 圆形展示 return turf.sector(cen, fea[i].properties.r10, 0, 360) 2. reverse()
