vue+OpenLayers 项目实践(六):历史轨迹绘制

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」。

前言

由于最近项目需要,需要在vue项目中使用OpenLayers来进行 GIS 地图的开发,网上对 OpenLayers 文章并不算太大,借此机会分享下自己在项目中实际使用的一些心得。

本系列将陆续分享项目过程中实现的一些功能点。

本文主要讲解地图上的轨迹绘制,以及相关的一些功能。

具体实现

本文需要实现的功能:

  • 修改文章一中的弹窗卡片添加历史轨迹按钮
  • 点击历史轨迹弹出轨迹地图弹窗
  • 添加时间筛选,可通过筛选时间进行查询
  • 绘制轨迹

ok,接下来一步步进行实现:

1. 添加按钮

修改vue+OpenLayers 项目实践(一):基本绘制与点击弹窗中实现的弹窗,添加上按钮。

// Home.vue
<!-- 信息弹框 -->
<div ref="popup" class="popup" v-show="showPopup">
  <div class="info">
    <ul>
      <li>信息1:xxx</li>
      <li>信息2:xxx</li>
      <li>信息3:xxx</li>
    </ul>
    <div class="btns-box">
      <el-button @click.native="handleOperate('dialog-route')">
        历史轨迹
      </el-button>
    </div>
  </div>
</div>
复制代码

image.png 实际项目中还需要去传点位id等参数,根据不同的点位,获取不同的轨迹路线,此处由于只是教学demo,就不具体去实现,同学们可以根据自己的项目实际需求去完善代码。

这里需要将左键点击的位置传给position,方便弹窗view的center设置,修改Home.vue中的mouseClick方法

image.png

2. 添加弹窗组件

接下来实现弹窗组件dialog-route,在components文件夹下新建Route.vue文件,同时在Home.vue文件夹中引入。

components: {
  DialogFence: () => import("@/components/Fences"),
  DialogRoute: () => import("@/components/Route"),
},
复制代码

新增Route.vue

<!--
 * @Author: Shao Tao
 * @Date: 2021-11-18 10:28:33
 * @LastEditTime: 2021-11-18 10:47:59
 * @LastEditors: Shao Tao
 * @Description: 
 * @FilePath: \vue-openlayers\src\components\Route.vue
-->
<template>
  <el-dialog
    title="历史轨迹"
    :visible="dialogVisible"
    custom-class="route"
    append-to-body
    @close="handleClose"
    width="1200px"
    destroy-on-close
  >
    <div id="fence-map" class="map-box"></div>
    <div class="map-area">
      <el-card class="tool-window" style="width: 380px"> </el-card>
    </div>
  </el-dialog>
</template>

<script>
import { Map, View } from "ol";
import { Tile as TileLayer } from "ol/layer";

import { getMap } from "@/utils/webStorage";
import mapType from "@/utils/openlayers/maptype";
export default {
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    location: {
      type: Array,
      default: () => {
        return [];
      },
    },
  },
  data() {
    return {
      dialogVisible: false,
      locaMap: null,
      openMap: null,
      routeSource: null,
    };
  },
  watch: {
    visible: {
      handler: function (value) {
        if (value) {
          this.dialogVisible = true;
          this.locaMap = getMap() || "0";
          this.$nextTick(() => {
            this.initMap();
          });
        }
      },
      immediate: true,
    },
  },
  mounted() {},
  methods: {
    initMap() {
      const _maplist = mapType;
      const _tileLayer = new TileLayer({
        source: _maplist.find((e) => e.id === this.locaMap).value,
      });
      this.openMap = new Map({
        target: "fence-map",
        layers: [_tileLayer],
        view: new View({
          center: this.location,
          zoom: 10,
        }),
        controls: [],
      });
    },
    handleClose() {
      this.$emit("close");
    },
  },
};
</script>

<style lang="scss" scoped>
.route {
  .el-dialog__header {
    padding: 20px;
  }
  .el-dialog__body {
    padding: 0;
    .map-area {
      box-shadow: inset 5em 1em #000000;
      position: relative;
      .tool-window {
        width: 200px;
        position: absolute;
        bottom: 20px;
        right: 20px;
        .button {
          font-size: 20px;
        }
      }
    }
  }
}
.map-box {
  width: 100%;
  height: 60vh;
}
</style>

复制代码

image.png OK,点击按钮后弹窗功能实现,接下来修改弹窗左下角的card,添加一个时间选择。

3. 添加时间筛选

时间项目中,历史轨迹往往会有大量的数据,如果一次性的请求渲染显然不现实,所以需要通过时间进行分割,根据时间区间进行请求。

el-card中添加时间选择组件以及一个查询按钮。

<el-card class="tool-window" style="width: 380px">
    <el-date-picker
      v-model="dateRange"
      type="daterange"
      value-format="yyyy-MM-dd"
      start-placeholder="开始时间"
      end-placeholder="结束时间"
      style="width: 100%"
    >
    </el-date-picker>
    <div style="margin-top: 15px">
      <el-button type="primary" @click="getList">查询</el-button>
    </div>
</el-card>
复制代码

添加getList方法,去请求数据,这里就直接用假数据演示了。

getList() {
  let _data = [
    [108.945951, 34.465262],
    [109.04724, 34.262504],
    [108.580321, 34.076162],
    [110.458983, 35.071209],
    [105.734862, 35.49272],
  ];
  this.routes = _data.map((item) => {
    return olProj.fromLonLat(item);
  });
  this.drawRoute();
},
// 绘制轨迹
drawRoute() {},
复制代码

image.png 接下来继续实现drawRoute方法。

4. 绘制轨迹

绘制轨迹需要调用LineString类,同时需要在轨迹上描绘出点标记,还需要用到Point;

// 绘制轨迹
drawRoute() {
  if (this.routeGeometry) {
    this.routeSource.clear();
  }
  this.routeGeometry = new LineString(this.routes);
  let route = new Feature(this.routeGeometry);
  // 绘制点
  let opints = this.drawPoint();
  this.routeSource.addFeatures([route, ...opints]);
},
// 画点
drawPoint() {
  let iconFeatures = [];
  this.routes.forEach((item) => {
    let _feature = new Feature(new Point(item));
    let _style = new Style({
      image: new sCircle({
        radius: 10,
        stroke: new Stroke({
          color: "#fff",
        }),
        fill: new Fill({
          color: "#3399CC",
        }),
      }),
    });
    _feature.setStyle(_style);
    iconFeatures.push(_feature);
  });
  return iconFeatures;
},
复制代码

最后将view定位到轨迹的位置,使得整条轨迹能够在地图上居中显示。

// 绘制轨迹
drawRoute() {
  ...
  // 按轨迹边界缩放
  this.mapFit();
},
mapFit() {
  let view = this.openMap.getView();
  view.fit(this.routeGeometry, {
    padding: [120, 120, 120, 120],
  });
},
复制代码

ok,到此整条轨迹就显示在地图上了。

image.png

需要注意的是在getList里,我们拿到的经纬度数组一定要通过olProj.fromLonLat去转换一下,不然无法正常的在地图上展示。

最终效果

map.gif

往期目录:

  1. vue+OpenLayers 项目实践(一):基本绘制与点击弹窗

  2. vue+OpenLayers 项目实践(二):多地图切换

  3. vue+OpenLayers 项目实践(三):Cluster 设置集群

  4. vue+OpenLayers 项目实践(四):设置围栏

  5. vue+OpenLayers 项目实践(五):历史围栏

最后

gitee 地址:gitee.com/shtao_056/v…

感谢大家阅读

如果能帮助到您,那更是我的万分荣幸。

后面应该会陆续的更新更多的功能使用,以及项目中遇到的一些问题,感兴趣的小伙伴可以点个收藏/关注。

Guess you like

Origin juejin.im/post/7031769090515533860