vue openlayers实现台风轨迹示例详解

 更新时间:2022年11月18日 09:44:22   作者:冬日暖阳一片云  
这篇文章主要为大家介绍了vue openlayers实现台风轨迹示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

功能描述

  • 台风轨迹点实时绘制,根据不同点的类型绘制不同的轨迹点颜色
  • 轨迹线绘制,涉及实时轨迹线段与预报轨迹线,根据台风类型绘制成不同颜色
  • 当前正在发生的台风还需增加当前台风所风圈位置
  • 台风轨迹点点击弹框显示轨迹点信息

openlayers(简称ol)这里不做介绍,刚开始写此类文章,直接上代码

创建一个地图容器

引入地图相关对象

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';

创建地图对象

都是一些基本活

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()

监听地图点击事件

 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
    // 监听地图点击事件
    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')
            // 台风点点击
            // && 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">风速: ${Properties.MOVE_SPEED || '--'} km/h</div>
              <div class="con">中心气压: ${Properties.PRESS || '--'}</div>
              <div class="con">时间: ${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'
            }
          }
        }
      )
    })
  }

开始绘制

准备台风数据和图层

台风数据我是用的JSON。这里就简单描述一下数据中只要用到的字段信息

[
      {
        CODE: "202122",//台风编号
        DB7: null,//七级东北
        DB10: null,//十级东北
        DB12: null,//十二级东北
        DN7: null,//七级东南
        DN10: null,//十级东南
        DN12: null,//十二级东南
        LAT: 5.5,//维度
        LON: 140.9,//经度
        MOVE_DIR: null,//风向
        MOVE_SPEED: null,//风向速度
        OBJECTID: 27848,//id
        PRESS: 998,//中心气压
        SHIJIAN: null,
        STRENGTH: "台风(热带风暴级)",//强度
        TH: null,
        TIME: "2021-12-13-14",//日期
        WIND: 18,//最大风速
        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)

绘制台风名称

// 利用第一个点 创建名称Overlay层 显示台风名称
 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)

绘制台风轨迹点和轨迹线

    //point 为数组对象中每一个点数据
    // 点颜色 根据强度区分不同点的颜色
    let pointColor = this.setPointFillColor(point.STRENGTH)
    // 添加点
    if (point.LON &amp;&amp; point.LAT) {
      const feature = new ol.Feature({
        geometry: new ol.geom.Point([point.LON, point.LAT]),
        layerType: 'typhoonLyer',
        properties: point
      })
      // this.tfStyle为我提前定义到的各种类型的点样式
      feature.setStyle(this.tfStyle[pointColor.index])
     tflayer.getSource().addFeature(feature)
    }
  // 添加线
  let startPoint = [point.LON, point.LAT] 开始点
  let endPonit = [points[index - 1].LON, points[index - 1].LAT] 结束点
  let coords = [startPoint, endPonit]
  let lineDash 线段样式 实线或者虚线
  if (lx !== 'ss') {
    lineDash = [0]
  } else {
    lineDash = (!point.predict &amp;&amp; !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 为提前定义好的点和线的样式,这么做的目的是为了提高性能,减少oplayer中new 一堆重复性的样式堆栈,消耗内存

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函数判别点类型

setPointFillColor (type) {
    let pointFillColor = '#eed139'
    let index = 0
    switch (type) {
      case '台风(热带低压)':
      case '热带低压':
        pointFillColor = '#eed139'
        index = 0
        break
      case '热带风暴':
      case '热带风暴级':
      case '台风(热带风暴)':
      case '台风(热带风暴级)':
        pointFillColor = '#0000ff'
        index = 1
        break
      case '台风(强热带风暴级)':
      case '强热带风暴级':
      case '强热带风暴':
        pointFillColor = '#0f8000'
        index = 2
        break
      case '台风':
        pointFillColor = '#fe9c45'
        index = 3
        break
      case '强台风':
      case '台风(强台风级)':
      case '台风(强台风)':
        pointFillColor = '#fe00fe'
        index = 4
        break
      case '超强台风':
      case '台风(超强台风级)':
      case '台风(超强台风)':
        pointFillColor = '#fe0000'
        index = 5
        break
    }
    return {pointFillColor, index}
  }

以上代码很完整,我加了注释,整体思路总结如下:

  • 先获取台风数据
  • 构造台风轨迹图层并添加到地图容器
  • 循环构造点、线及名称要素对象 添加到台风图层数据源中
  • 添加风圈动画

添加台风风圈动画

根据判断台风类型是否是实时台风还是历史台风进行添加台风风圈,在数据中获取到最后一个实时点位数据,利用Overlay添加一个动态图标,我是利用的gif图片

    let key = LX + '-' + tfbh
    const points = this._typhoonData[key].point
    let fqindex = points.findIndex(item => !item.predict)
    // 添加风圈
    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
    }

让台风轨迹动起来

加载的时候利用定时器,一个点位一个点位的绘制,这样看起来就有动画效果啦

 this._typhoonPlayFlag[key] = setInterval(() => {
      去干些事请
    }, 50)

结尾

这里我只是大致的描述了我绘制台风轨迹的一些思路和大致方法,具体项目中,我把整个过场都封装成一个class 类,毕竟台风可能是有多条的,而且还需要做一些显示隐藏等的一些操作,我这里不做过多描述,仅做为一些思路分享,更多关于vue openlayers台风轨迹的资料请关注脚本之家其它相关文章!

相关文章

  • vue中使用echarts并根据选择条件动态展示echarts图表

    vue中使用echarts并根据选择条件动态展示echarts图表

    虽然老早就看过很多echarts的例子, 但自己接触的项目中一直都没有真正用到过,直到最近才开始真正使用,下面这篇文章主要给大家介绍了关于vue中使用echarts并根据选择条件动态展示echarts图表的相关资料,需要的朋友可以参考下
    2023-12-12
  • Vue3响应式对象数组不能实时DOM更新问题解决办法

    Vue3响应式对象数组不能实时DOM更新问题解决办法

    在写大文件上传时,碰到关于 vue2 跟 vue3 对在循环中使用异步,并动态把普通对象添加进响应式数据,在异步前后修改该普通对象的某个属性,导致 vue2 跟 vue3 的视图更新不一致,引发一系列的思考,所以本文介绍了Vue3响应式对象数组不能实时DOM更新问题解决办法
    2024-07-07
  • vue中使用Cesium加载shp文件、wms服务、WMTS服务问题

    vue中使用Cesium加载shp文件、wms服务、WMTS服务问题

    这篇文章主要介绍了vue中使用Cesium加载shp文件、wms服务、WMTS服务问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • vue 获取到数据但却渲染不到页面上的解决方法

    vue 获取到数据但却渲染不到页面上的解决方法

    这篇文章主要介绍了vue 获取到数据但却渲染不到页面上的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • vue3锚点定位多种方法详解

    vue3锚点定位多种方法详解

    这篇文章主要介绍了vue3的锚点定位多种方法,需要的朋友可以参考下
    2024-01-01
  • Vue+Openlayer实现图形的拖动和旋转变形效果

    Vue+Openlayer实现图形的拖动和旋转变形效果

    Openlayer具有自己的扩展插件ol-ext,可以用来实现图形的拖拽、旋转、缩放、拉伸、移动等操作,本文将主要介绍通过Openlayer实现图形的拖动和旋转,需要的同学可以学习一下
    2021-11-11
  • vue和better-scroll实现列表左右联动效果详解

    vue和better-scroll实现列表左右联动效果详解

    这篇文章主要介绍了vue和better-scroll实现列表左右联动效果,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • vue使用vant中的checkbox实现全选功能

    vue使用vant中的checkbox实现全选功能

    这篇文章主要为大家详细介绍了vue使用vant中的checkbox实现全选功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • Vue ECharts实现机舱座位选择展示功能代码详解

    Vue ECharts实现机舱座位选择展示功能代码详解

    这篇文章主要介绍了Vue ECharts实现机舱座位选择展示,本文给大家分享一段简短的代码通过效果图展示给大家介绍的非常明白,需要的朋友可以参考下
    2022-05-05
  • Vue 表情包输入组件的实现代码

    Vue 表情包输入组件的实现代码

    这篇文章主要介绍了Vue 表情包输入组件的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01

最新评论