vue+openlayers 自定义底图运动轨迹回放

openlayers

vue+openlayers运动轨迹回放

<!--
 * @Description: 轨迹回放
 * @Author: Dragon
 * @Email: 153284575@qq.com
 * @Date: 2020-11-20 22:05:31
 * @LastEditTime: 2020-12-29 10:08:46
 * @LastEditors: Dragon
-->

<template>
  <div class="base-tracks">
    <div class="query-wrap">
      <el-row v-if="routeCoords.length > 0">
        <el-col>
          <el-button type="primary" @click="toggle">{{ textContent }}</el-button>
          <el-slider
            class="slider-bar"
            v-model="speed"
            :step="10"
            >
          </el-slider>
          <div class="progress-bar" v-if="progress != 0">
            <div class="bar-box">
              <div class="bar" :style="{ width: progress }">
                <span>{{ progress }}</span>
              </div>
            </div>
          </div>
        </el-col>
      </el-row>
    </div>
    <!-- 地图 -->
    <div id="map" ref="rootmap"></div>
  </div>
</template>

<script>
import "ol/ol.css";
import { Map, View, Feature } from "ol";
import { getCenter } from "ol/extent";
import { Tile as TileLayer, Vector as VectorLayer, Image as ImageLayer } from "ol/layer";
import { Vector, ImageStatic as Static } from "ol/source";
import { Point, LineString } from "ol/geom";
import { Style, Icon, Text, Fill, Stroke, Circle } from "ol/style";
import { Projection } from "ol/proj";
import { getVectorContext } from "ol/render";

import start from "@/assets/start.png";
import end from "@/assets/end.png";
import img from "@/assets/tx-icon-1.png";
import staticMap from "@/assets/map.png";

export default {
  data() {
    return {
      map: null, // 地图
      imgx: 0, // 当前地图宽
      imgy: 0, // 当前地图高
      textContent: "播放",
      animating: false, // 动画是否开始
      speed: 2, // 速度
      now: null, // 当前时间
      vectorLayer: null, // 矢量图层
      routeCoords: [], // 数组点集合(线路坐标)
      routeLength: 0, // 集合点的数量长度
      routeFeature: null, // 画线
      geoMarker: null, // 移动标记
      startMarker: null, // 开始标记
      endMarker: null, // 结束标记
      styles: {
        route: new Style({
          // 线的样式
          stroke: new Stroke({
            width: 6,
            color: [237, 212, 0, 0.8],
          }),
        }),
        // icon: new Style({
        //   // 默认icon样式
        //   image: new Circle({
        //     radius: 7,
        //     fill: new Fill({ color: "red" }),
        //     stroke: new Stroke({
        //       color: "white",
        //       width: 2,
        //     }),
        //   }),
        // }),
        geoMarker: new Style({
          // 移动人物的图标样式
          image: new Icon({
            anchor: [0.5, 0.8], // 居中
            // anchorOrigin: 'top-right',
            // anchorXUnits: 'fraction',
            // anchorYUnits: 'pixels',
            // offsetOrigin: 'top-right',
            // offset:[0,10],
            scale: 0.5, // 图标缩放比例
            opacit: 1, // 透明度
            src: img,
          }),
        }),
        start: new Style({
          // 设置开始标记样式
          image: new Icon({
            anchor: [0.5, 1],
            src: start,
          }),
        }),
        end: new Style({
          // 设置结束标记样式
          image: new Icon({
            anchor: [0.5, 1],
            src: require("@/assets/end.png"),
          }),
        }),
      },
      progress: 0,
    };
  },
  methods: {
    // 初始化地图
    initMap() {
      let that = this;
      let extent = [0, 0, this.imgx, this.imgy];
      let projection = new Projection({
        extent: extent,
      });

      // 默认地图
      let defaultMap = new ImageLayer({
        source: new Static({
          url: staticMap,
          projection: projection,
          imageExtent: extent,
        }),
      });

      // 添加矢量层
      this.vectorLayer = new VectorLayer({
        source: new Vector(),
      });

      this.map = new Map({
        target: "map",
        layers: [defaultMap, that.vectorLayer],
        view: new View({
          projection: projection,
          center: getCenter(extent),
          zoom: 2,
          maxZoom: 18,
        }),
      });
    },

    // 轨迹回放
    moveFeature(event) {
      let vectorContext = getVectorContext(event);
      let frameState = event.frameState;

      if (this.animating) {
        let elapsedTime = frameState.time - this.now;
        let index = Math.round((this.speed * elapsedTime) / 1000);
        this.progress =
          Math.floor(((100 / this.routeLength) * (this.speed * elapsedTime)) / 1000) +
          "%";
        if (index >= this.routeLength) {
          this.progress = "100%";
          this.stop(true);
          return;
        }
        let currentPoint = new Point(this.routeCoords[index]); // 当前点
        let feature = new Feature(currentPoint);
        vectorContext.drawFeature(feature, this.styles.geoMarker);
      }
      this.map.render();
    },

    // 运动轨迹开关
    toggle() {
      if (this.textContent === "重新播放") {
        this.progress = 0;
        this.stop(false);
      } else {
        this.start();
      }
    },

    // 开始动画
    start() {
      if (this.animating) {
        this.stop(false);
      } else {
        // hide geoMarker
        this.animating = true;
        this.textContent = "重新播放";
        this.now = new Date().getTime(); // 开始时的时间
        this.geoMarker.setStyle(null);
        // 设置显示范围
        // this.map.getView().setCenter(center)
        this.vectorLayer.on("postrender", this.moveFeature);
        this.map.render();
      }
    },

    // 停止
    stop(ended) {
      this.textContent = "开始播放";
      this.animating = false;
      // if animation cancelled set the marker at the beginning
      let ii = ended ? this.routeLength - 1 : 0;
      let coord = this.routeCoords[ii];
      this.geoMarker.setGeometry(new Point(coord));
      // this.geoMarker.setStyle(this.createLabelStyle(img)); // 设置走完最后一个点是否展示
      // remove listener // 删除侦听器
      this.vectorLayer.un("postrender", this.moveFeature);
    },

    // 设置坐标样式
    createLabelStyle(img) {
      return new Style({
        image: new Icon({
          anchor: [0.5, 0.8], // 居中
          // anchorOrigin: 'top-right',
          // anchorXUnits: 'fraction',
          // anchorYUnits: 'pixels',
          // offsetOrigin: 'top-right',
          // offset:[0,10],
          scale: 0.5, // 图标缩放比例
          opacit: 1, // 透明度
          src: img, // 图标的url
        }),
      });
    },

    // 获取基站列表
    getTrack() {
      // 获取接口返回数据
      let res = [
        [256.83593750000006, 370.91015624999994],
        [261.71875000000006, 425.59765624999994],
        [253.90625000000006, 469.54296875],
        [338.86718750000006, 488.09765625],
        [406.25000000000006, 488.09765625],
        [471.67968750000006, 488.09765625],
        [544.9218750000001, 471.49609375],
        [547.8515625000001, 416.80859374999994],
        [542.9687500000001, 366.02734374999994],
      ];
      this.routeCoords = res.map((d) => {
        return (d = [d[0], d[1]]);
      });
      this.routeLength = this.routeCoords.length;

      // 画线
      this.routeFeature = new Feature(new LineString(this.routeCoords));
      this.routeFeature.setStyle(this.styles.route);

      // 标记
      this.geoMarker = new Feature(new Point(this.routeCoords[0]));
      this.geoMarker.setStyle(this.styles.geoMarker);
      // 开始点
      this.startMarker = new Feature(new Point(this.routeCoords[0]));
      this.startMarker.setStyle(this.styles.start);
      // 结束点
      this.endMarker = new Feature(
        new Point(this.routeCoords[this.routeLength - 1])
      );
      this.endMarker.setStyle(this.styles.end);

      // 运动集合展示在矢量图上
      this.vectorLayer
        .getSource()
        .addFeatures([
          this.routeFeature,
          this.geoMarker,
          this.startMarker,
          this.endMarker,
        ]);
      this.map.render();
    },
  },
  mounted() {
    let img = new Image();
    img.src = staticMap;
    let that = this;
    img.onload = function (res) {
      that.imgx = res.target.width;
      that.imgy = res.target.height;
      that.initMap();
      that.getTrack();
    };
  },
};
</script>

<style lang="scss">
.base-tracks {
  .slider-bar {
    width: 100px;
    display: inline-block;
    position: relative;
    top: 14px;
    margin-right: 20px;
  }  
  .el-form-item {
    margin: 0;
  }
  .el-select,
  .el-date-editor--datetime {
    margin: 0 20px 20px 0;
  }
  .progress-bar {
    width: 50%;
    height: 30px;
    position: relative;
    box-sizing: border-box;
    display: inline-block;
    .bar-box {
      position: absolute;
      top: 20px;
      left: 0;
      right: 0;
      height: 10px;
      border-radius: 5px;
      background: #034c77;
      margin-right: 20px;
    }
    .bar {
      height: 10px;
      border-radius: 5px;
      background: green;
      position: relative;
      span {
        width: 20px;
        height: 20px;
        line-height: 18px;
        font-size: 12px;
        font-weight: bold;
        text-align: center;
        position: absolute;
        color: #fe0000;
        top: -30px;
        right: 0;
        background-size: 100% 30px;
      }
    }
  }
  #map {
    height: calc(100vh - 120px);
  }
}
</style>
<style scoped>
.new-container {
  padding: 0 20px;
}
</style>

  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小并不小

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值