由于最近项目需要,需要在vue项目中使用OpenLayers来进行 GIS 地图的开发,网上对 OpenLayers 文章并不算太大,借此机会分享下自己在项目中实际使用的一些心得。
本系列将陆续分享项目过程中实现的一些功能点。 往期目录:
今天我们来学习下围栏功能,围栏即在地图上绘制一块规则或不规则的区域,通过判断坐标是否在区域内来处理位置与区域之间的关系,常见的应用场景有:
老样子,看看官方有没有提供基础的案例:
分析咱们需要实现的功能:
首先实现一个右键菜单,在地图上右键时,直接以右键的位置为中心弹出一个围栏绘制弹层。
具体实现步骤:
第一步可直接查看之前的文章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);
};
通过点击新增围栏,弹出弹窗。在 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>
页面样式如图。
现在来实现围栏绘制。
首先引入 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();
}
OK,本篇实现了围栏的前期绘制功能,下篇继续介绍围栏其他的功能点。
gitee 地址:gitee.com/shtao_056/v…
感谢大家阅读
如果能帮助到您,那更是我的万分荣幸。
后面应该会陆续的更新更多的功能使用,以及项目中遇到的一些问题,感兴趣的小伙伴可以点个收藏/关注。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。