1 Star 41 Fork 11

st19911224/Vue-Openlayers

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
04.md 7.96 KB
一键复制 编辑 原始数据 按行查看 历史
shaotao 提交于 4年前 . feat: part5:历史围栏

一、前言

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

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

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

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

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

今天我们来学习下围栏功能,围栏即在地图上绘制一块规则或不规则的区域,通过判断坐标是否在区域内来处理位置与区域之间的关系,常见的应用场景有:

  • 签到打卡,在打卡操作前,判断用户是否已经在对应的地理围栏区域内;
  • 范围监控,比如共享单车是否驶出了规定地理围栏区域;
  • 等等...

老样子,看看官方有没有提供基础的案例:

draw-shapes

draw-features

二、具体实现

分析咱们需要实现的功能:

  1. 实现右键菜单,打开新增围栏弹窗
  2. 新增围栏
  3. 查看围栏
  4. 判断点位是否在围栏区域内 本篇先介绍上半部分。

1. 实现右键菜单

首先实现一个右键菜单,在地图上右键时,直接以右键的位置为中心弹出一个围栏绘制弹层。

具体实现步骤:

  • 添加右键菜单 overlay 到 map 上
  • 通过 getViewport()获取地图所在的 Dom,重写它的右键事件

第一步可直接查看之前的文章vue+OpenLayers 项目实践(一):基本绘制与点击弹窗,这里不过多说明,此处主要提供下右键相关的代码

// 右键点击
this.openMap.getViewport().oncontextmenu = (e) => {
  // 取消默认右键事件
  e.preventDefault();
  this.showMenuPopup = true;
  // 设置弹窗位置跟随鼠标
  let coordinates = this.openMap.getEventCoordinate(e);
  this.position = coordinates;
  this.menuPopup.setPosition(coordinates);
};

image.png

2. 新增围栏

通过点击新增围栏,弹出弹窗。在 components 文件夹下新增 Fences.vue。

<template>
  <el-dialog
    title="编辑围栏"
    :visible="dialogVisible"
    custom-class="fence"
    append-to-body
    @close="handleClose"
    width="1200px"
    destroy-on-close
  >
    <div id="fence-map" class="map-box"></div>
  </el-dialog>
</template>

<script>
import { Map, View } from "ol";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { Vector as VectorSource } from "ol/source";
import { Style, Fill, Stroke, Circle as sCircle } from "ol/style";
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,
      fenceSource: 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.fenceSource = new VectorSource({ wrapX: false });

      const _vector = new VectorLayer({
        source: this.fenceSource,
        style: new Style({
          fill: new Fill({
            color: "rgba(49,173,252, 0.2)",
          }),
          stroke: new Stroke({
            color: "#0099FF",
            width: 3,
          }),
          image: new sCircle({
            radius: 7,
            fill: new Fill({
              color: "#0099FF",
            }),
          }),
        }),
      });
      this.openMap = new Map({
        target: "fence-map",
        layers: [_tileLayer, _vector],
        view: new View({
          center: this.location,
          zoom: 10,
        }),
        controls: [],
      });
    },
    handleClose() {
      this.$emit("close");
    }
  },
};
</script>

<style lang="scss" scoped>
.fence {
  .el-dialog__header {
    padding: 20px;
  }
  .el-dialog__body {
    padding: 0;
  }
}
.map-box {
  width: 100%;
  height: 60vh;
}
</style>

同时需要在 Home.vue 中设置弹窗:

<template>
...
<!-- 组件容器 -->
<component
  v-if="operateDialogVisible"
  :is="currentComponent"
  :visible="operateDialogVisible"
  :location="position"
  @close="handleOperateClose"
></component>
...
</template>

data(){
...
operateDialogVisible: false,
currentComponent: null,
position: null,
}

// 添加方法
// 打开弹窗
handleOperate(component) {
  this.menuPopup = false;
  this.operateDialogVisible = true;
  this.currentComponent = component;
},
// 关闭弹窗
handleOperateClose() {
  this.operateDialogVisible = false;
},

在 fences 组件中添加围栏,主要 api 为"ol/interaction/Draw",首先在页面上加入设置围栏的按钮,实现圆形跟多边形绘制。

<div class="map-area">
  <el-card class="tool-window" style="width: 380px">
    <el-form label-width="80px">
      <el-form-item label="围栏名称">
        <el-input
          size="small"
          v-model="name"
          placeholder="请输入围栏名称"
        ></el-input>
      </el-form-item>
      <el-form-item label="围栏样式">
        <el-radio-group v-model="tool" size="small" @change="setType">
          <el-radio-button label="Circle">圆形</el-radio-button>
          <el-radio-button label="Polygon">多边形</el-radio-button>
        </el-radio-group>
      </el-form-item>
      <el-form-item>
        <el-button type="warning" size="small" @click="handleClear"
          >清除</el-button
        >
        <el-button type="primary" size="small" @click="handleSave"
          >保存</el-button
        >
        <el-button size="small" @click="handleClose">取消</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</div>

image.png 页面样式如图。 现在来实现围栏绘制。

首先引入 Draw

import Draw from "ol/interaction/Draw";
// data中添加属性
data() {
    return {
      ...
      fenceSource: null,
      fenceDraw: null,
      tool: "Circle",
      name: "",
    };
},
// 实现addInteraction方法
addInteraction() {
  this.fenceDraw = new Draw({
    source: this.fenceSource,
    type: this.tool,
  });
  this.openMap.addInteraction(this.fenceDraw);
},
// 切换类型
setType() {
  this.fenceSource.clear();
  this.openMap.removeInteraction(this.fenceDraw);
  this.addInteraction();
},
// 按钮方法
handleClear() {
  this.fenceSource.clear();
},
handleSave() {
  // 保存
},
// initMap中调用
initMap(){
  ...
  this.addInteraction();
}

image.png

OK,本篇实现了围栏的前期绘制功能,下篇继续介绍围栏其他的功能点。

最后

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

感谢大家阅读

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

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

Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/shtao_056/vue-openlayers.git
git@gitee.com:shtao_056/vue-openlayers.git
shtao_056
vue-openlayers
Vue-Openlayers
master

搜索帮助