openLayers轨迹

<template>
  <div class="map" id="map">

    <div class="overlay-container" style="display: none">
      <!-- 车辆弹窗 -->
      <div class="overlay" ref="overlay_truck">
        <div class="close" @click="overlay.setPosition(null)">×</div>
        <p class="title">{{overlayData.name}}</p>
        <p class="content"><span>车牌号码:</span>{{overlayData.number}}</p>
        <p class="content"><span>车辆型号:</span>{{overlayData.model}}</p>
        <p class="content"><span>车辆状态:</span>{{overlayData.alarm ? '告警' : '正常'}}</p>

        <el-row style="text-align: center">
          <el-button size="mini" type="primary" @click="onStartAnimationClick(overlayData.id)">查看轨迹</el-button>
          <el-button size="mini" type="primary" >导出轨迹</el-button>
        </el-row>
      </div>
    </div>

    <!--测试按钮-->
    <div class="button-row">
      <button @click="locateTruck(1)">车辆1定位</button>
      <button @click="onStartAnimationClick(1)">轨迹回放</button>
      <br>
      <button @click="locateTruck(2)">车辆2定位</button>
      <button @click="onStartAnimationClick(2)">轨迹回放</button>
    </div>
  </div>
</template>

<script>
  import "ol/ol.css";
  import {Map, Feature, View, Overlay, Graticule} from "ol";
  import {Point, Circle as CircleGeom, Polygon, LineString} from "ol/geom";
  import {Vector as VectorSource, OSM, XYZ, } from "ol/source";
  import {Tile as TileLayer, Vector as VectorLayer} from "ol/layer";
  import {Circle, Fill, Stroke, Style, Text, Icon} from "ol/style";
  import {getVectorContext} from 'ol/render';
  import {Select, Draw} from 'ol/interaction';
  import {click} from 'ol/events/condition';


  export default {
    name: "MapView",
    data(){
      return{
        map: null,
        layers: {
          pointLayer: null,
          traceLayer: null,
        },
        overlay: null,
        overlayData: {},

        animating: false,
        now: '',
        speed: 2,

        trace: [],
        truckData: [
          {
            id: 1, //车辆id?
            name: '测试卡车1',
            alarm: false,
            location: [113.399045209149, 23.167922557035595],
            trace: [
              [113.38481017131984, 23.167432854758143],
              [113.3866398986965, 23.166218294344322],
              [113.38842230553757, 23.16860009463636],
              [113.38878509631053, 23.169940843145127],
              [113.3906148236872, 23.169467637789094],
              [113.39223949540958, 23.169514958324697],
              [113.39370643201329, 23.16984620207392],
              [113.39474748379656, 23.1700512577282],
              [113.39525223617633, 23.170114351775673],
              [113.39552038587809, 23.170098578263804],
              [113.39626174093587, 23.17008280475194],
              [113.39684536087499, 23.170019710704466],
              [113.39728701920728, 23.169956616656997],
              [113.39744475432596, 23.16984620207392],
              [113.39771290402771, 23.1695622788603],
              [113.39774445105145, 23.167937607137915],
              [113.399045209149, 23.167922557035595]
            ]
          },
          {
            id: 2, //车辆id?
            name: '测试卡车2',
            alarm: true,
            location: [113.38432928536788, 23.143003626954737],
            trace: [
              [113.36545258773141, 23.12866953003676],
              [113.36638589917159, 23.12843077594741],
              [113.36625470009082, 23.127797973659423],
              [113.36859282430896, 23.127278390499832],
              [113.36980974276169, 23.1299173260209],
              [113.37011055406465, 23.131476075499663],
              [113.3711223739018, 23.13564641401742],
              [113.37058911750121, 23.137150470532028],
              [113.37038401888559, 23.138011884717663],
              [113.37042503860872, 23.138394735466843],
              [113.37110870066086, 23.141334482290844],
              [113.37348784460212, 23.14052776106938],
              [113.37400742776171, 23.141170403398345],
              [113.37562087020464, 23.144014437535038],
              [113.3757986223382, 23.143891378365662],
              [113.37750777746841, 23.143549547339617],
              [113.37790430145863, 23.143535874098585],
              [113.37961345658886, 23.14394607132984],
              [113.37999630733802, 23.144137496704424],
              [113.382279738592, 23.143399141688167],
              [113.38234810479722, 23.143563220580667],
              [113.38432928536788, 23.143003626954737]
            ]
          }
        ]
      }
    },
    methods: {

      /***
       * 初始化地图
       */
      initMap(){
        this.map = new Map({
          target: "map",
          layers: [
            new TileLayer({
              source: new XYZ({
                url: 'http://t2.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=ce70a52426fabd6c2062fdd14c3426d2',
                crossOrigin: 'anonymous'
              })
            }),
            new TileLayer({
              source: new XYZ({
                url: 'http://t2.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=469cfd9c133f30baaf3f94a9cd848c47',
                crossOrigin: 'anonymous'
              })
            }),
          ],
          view: new View({
            center: [113.3, 23.1],
            zoom: 12,
            projection: 'EPSG:4326',
          }),
          interactions: null,
        });
      },

      /**
       * 初始化图层
       * */
      initLayers(){
        //点位图层
        this.layers.pointLayer = new VectorLayer({
          source: new VectorSource(),
          renderMode: "vector",
          updateWhileInteracting: true,
          updateWhileAnimating: true
        });
        this.map.addLayer(this.layers.pointLayer);
        this.layers.pointLayer.setZIndex(200);

        //轨迹图层
        this.layers.traceLayer = new VectorLayer({
          source: new VectorSource(),
          renderMode: "vector",
          updateWhileInteracting: true,
          updateWhileAnimating: true
        });
        this.map.addLayer(this.layers.traceLayer);
        this.layers.traceLayer.setZIndex(150);

        //加点
        this.addTruckPoint();

        //点位选中
        const clickSelect = new Select({
          condition: click,
          layers: [this.layers.pointLayer]
        });
        clickSelect.on('select', (e)=> {
          const features = e.selected;
          features.forEach((feature)=>{
            this.onPointClick(feature);
            clickSelect.getFeatures().clear();
          });
        });
        this.map.addInteraction(clickSelect);
      },

      /***
       * 初始化点位窗口
       */
      initOverlay(){
        this.overlay = new Overlay({
          element: this.$refs.overlay_truck,
          autoPan: true,
          autoPanAnimation: {
            duration: 250
          },
        });
        this.map.addOverlay(this.overlay);
      },

      /***
       * 加点
       */
      addTruckPoint(){
        this.truckData.forEach(item=>{
          const point = new Feature({
            geometry: new Point(item.location),
            type: "point"
          });
          const colors = item.alarm ? ['#ff5858', '#860700']: ['#00ff61', '#008635']; //是否告警
          point.setStyle(new Style({
            image: new Circle({
              fill: new Fill({
                color: colors[0]
              }),
              stroke: new Stroke({
                color: colors[1],
                width: 1.25
              }),
              radius: 10
            }),
          }));
          point.setProperties(item);  //点位数据
          point.setId(item.id);       //点位id,用来对应列表点击事件

          this.layers.pointLayer.getSource().addFeature(point);
        });
      },

      /***
       * 根据id定位车辆,触发点击事件
       * @param id
       */
      locateTruck(id){
        const feature = this.layers.pointLayer.getSource().getFeatureById(id);
        if(feature){
          this.onPointClick(feature);
        }
      },

      /***
       * 车辆点位的点击事件
       * @param feature
       */
      onPointClick(feature){
        const attributes = feature.getProperties();

        //弹出窗
        this.overlay.setPosition(attributes.geometry.flatCoordinates);
        this.overlayData = attributes;

        //地图移动缩放
        this.map.getView().setZoom(16);
        this.panToCoordinate(attributes.geometry.flatCoordinates);
      },

      /***
       * 开始轨迹回放的事件
       * @param id
       */
      onStartAnimationClick(id){
        this.truckData.forEach(item=>{
          if(id === item.id){
            this.loadTrace(item.trace);
            this.startAnimation();
          }
        });
      },

      /***
       * 读取轨迹数据,生成轨迹图层中的feature
       * @param trace
       */
      loadTrace(trace){
        this.trace = trace;
        this.layers.traceLayer.getSource().clear();   //清除上一次回放数据

        let lineString = new LineString(trace);
        let traceLineString = new Feature({
          type: 'lineString',
          geometry: lineString
        });
        traceLineString.setStyle(new Style({
          stroke: new Stroke({
            width: 4, color: [0, 100, 200, 0.8]
          })
        }));
        this.layers.traceLayer.getSource().addFeature(traceLineString);
      },

      /***
       * 地图移动
       * @param coordinate
       */
      panToCoordinate(coordinate){
        this.map.getView().animate({
          center: coordinate,
          duration: 500
        });
      },

      /***
       * 轨迹点位移动事件
       * @param event
       */
      moveFeature(event){
        const vectorContext = getVectorContext(event);
        const frameState = event.frameState;

        if (this.animating) {
          const elapsedTime = frameState.time - this.now;
          const index = Math.round(this.speed * elapsedTime / 1000);

          if (index >= this.trace.length) {
            this.stopAnimation(true);
            return;
          }

          const currentPoint = new Point(this.trace[index]);
          const feature = new Feature(currentPoint);
          vectorContext.drawFeature(feature, new Style({
            image: new Circle({
              fill: new Fill({
                color: 'dodgerblue'
              }),
              stroke: new Stroke({
                color: 'white',
                width: 1.25
              }),
              radius: 8
            })
          }));

          this.panToCoordinate(currentPoint.getCoordinates())
        }
        // tell OpenLayers to continue the postrender animation
        this.map.render();
      },

      /***
       * 开始轨迹回放
       */
      startAnimation(){
        if (this.animating) {
          this.stopAnimation(false);
        } else {
          this.animating = true;
          this.now = new Date().getTime();
          this.layers.traceLayer.on('postrender', this.moveFeature);
          this.map.render();
        }
      },

      /***
       * 停止轨迹回放
       */
      stopAnimation(){
        this.animating = false;
        this.layers.traceLayer.getSource().clear();
      }

    },
    mounted(){
      this.initMap();
      this.initOverlay();
      this.initLayers();
    }
  }
</script>

<style scoped lang="scss">
.map{
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;

  .button-row{
    position: absolute;
    top:  8px;
    left: 16px;
    z-index: 200;

    button{
      font-size: 16px;
      background: white;
      padding: 8px 16px;
      margin-bottom: 16px;
    }
  }

  .overlay{
    width: 360px;
    height: 180px;
    background: rgba(0,0,0,0.8);
    color: white;
    position: relative;
    text-align: left;
    padding: 16px 8px 0 8px;
    margin-left: -180px;
    margin-top: -200px;

    &::after{
      content: "";
      display: block;
      position: absolute;
      top: 180px;
      left: calc(180px - 6px);
      border-top: 8px solid rgba(0,0,0,0.8);
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
      border-bottom: 6px solid transparent;
    }

    .close{
      position: absolute;
      padding: 0 8px;
      right: 0;
      top: 0;
      font-size: 20px;
      cursor: pointer;
    }

    .title{
      font-weight: bold;
      margin-top: 0;
    }
    .content{
      margin: 8px 0;
      span{
        display: inline-block;
        width: 5.5em;
      }
    }
    .button-row{
      margin: 0 auto;
    }
  }
}
</style>

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值