Vue+openlayers实现绘制多边形并且计算出多边形内有多少物体数量
效果:
代码:
<!-- -->
<template>
<div class="querycount">
<button @click="drawPolygon('Polygon')">
{{ isDraw ? "点击绘制多边形查询人数" : "取消绘制" }}
</button>
<div id="map"></div>
</div>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
//引入主要组件
// import { Feature, Map, Overlay, View } from "ol";
import { Map, View, Feature } from "ol";
//引入layer
import ImageLayer from "ol/layer/Image";
import VectorLayer from "ol/layer/Vector";
//引入source
import Static from "ol/source/ImageStatic";
import VectorSource from "ol/source/Vector";
//交互
import { Draw } from "ol/interaction";
//其他
import Projection from "ol/proj/Projection";
import { getCenter } from "ol/extent";
import { Point } from "ol/geom";
import { Style, Icon, Stroke, Fill } from "ol/style";
//import { Style, Icon, Text, Fill, Stroke } from "ol/style";
//导入图片
import mapImage from "@/assets/img/map1.jpg"; //底图
import personImg from "@/assets/img/anchor.png";
//引入图形算法工具类turf
import * as turf from "@turf/turf";
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
map: null,
//贴图
featureSource: new VectorSource(), //人员贴图的source
feature: null, //贴图
features: [], //贴图数组
//多边形
polygonLayer: null,
polygonSource: new VectorSource(),
isDraw: true,
draw: null,
//其他
persons: [], //人的数据,
// polygonPoints: [], //多边形的坐标点,
areaPerson: [], //多边形区域的人员
};
},
//计算属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {
persons(newVal) {
if (newVal) {
this.setFeatures();
}
},
},
//方法集合
methods: {
//初始化地图
initMap() {
//限制范围
let extent = [0, 0, 2560, 1920];
//投影
let projection = new Projection({
//SRS 标识符代码,例如EPSG:4326
code: "xkcd-image",
// 单位。必需,除非 定义 PROJ4 投影。code
units: "pixels",
//SRS 的有效性范围。
extent: extent,
});
//底图Layers
let mapLayer = new ImageLayer({
source: new Static({
url: mapImage,
projection: projection,
imageExtent: extent,
}),
});
//图标小人图层Layers
let featureLayer = new VectorLayer({
source: this.featureSource,
});
//绘制多边形layers
this.polygonLayer = new VectorLayer({
source: this.polygonSource,
style: new Style({
stroke: new Stroke({
color: "rgba(255,0,0,0.6)",
width: 5,
}),
fill: new Fill({
color: "rgba(255,0,0,0.3)",
}),
}),
});
//创建地图
this.map = new Map({
target: "map",
layers: [mapLayer, featureLayer],
view: new View({
//配置投影
projection: projection,
//配置中心
center: getCenter(extent),
//配置zoom
zoom: 2,
//配置最大zoom
maxZoom: 10,
}),
});
//将多边形Layers添加到map中去
this.map.addLayer(this.polygonLayer);
},
//添加Features
setFeatures() {
//创建feature
this.persons.map((item) => {
this.feature = new Feature({
geometry: new Point([item.x, item.y]),
name: item.name,
});
//设置features的样式
this.feature.setStyle(
new Style({
image: new Icon({
//设置icon的锚,默认是中心[0.5,0.5]
anchor: [0, 1],
//设置icon的图片
src: personImg,
}),
})
);
//给到features数组
this.features.push(this.feature);
});
//给features添加到feature矢量图层中去
this.featureSource.addFeatures(this.features);
},
//绘制多边形
drawPolygon(type) {
if (this.isDraw) {
this.isDraw = false;
//添加绘制的实例
this.draw = new Draw({
type: type,
//必须设置source,否则不会保存
source: this.polygonSource,
});
//给地图添加交互
this.map.addInteraction(this.draw);
//绘制完成后查询所在区域的人数
this.draw.on("drawend", this.drawEnd);
} else {
this.isDraw = true;
//清理多边形
this.polygonSource.clear();
//移除交互
this.map.removeInteraction(this.draw);
// //清空多边形的坐标和区域中的人
// this.polygonPoints = [];
this.areaPerson = [];
}
},
//绘制完成后查询所在区域的人数
drawEnd(e) {
//获取绘制的几何
let geo = e.feature.getGeometry();
let geoType = geo.getType();
if (geoType == "Polygon") {
//获取该多边形的坐标点
let points = geo.getCoordinates();
//#region
//*******判断多边形内的点的--------方法一***********
//将多边形的点添加到数组中
// points[0].map((item) => {
// this.polygonPoints.push({ longitude: item[0], latitude: item[1] });
// });
// //判断人员是否在多边形的区域内 Y--将人员添加到区域数组中
// this.persons.forEach((item) => {
// // let pt = turf.point([item.x, item.y]);
// // //定义一个旗帜表示是否在多边形区域
// // let flag = turf.booleanPointInPolygon(pt, polygonPoints);
// let flag = this.isAtRegion(item.x, item.y, this.polygonPoints);
// if (flag) {
// this.areaPerson.push(item);
// }
// });
//#endregion
//**********判断多边形内的点的-------方法二(运用turf.js来计算)************
let polygonPoints = turf.polygon([points[0]]); //多边形的坐标点
//判断人员是否在多边形的区域内 Y--将人员添加到区域数组中
this.persons.forEach((item) => {
let pt = turf.point([item.x, item.y]); //每一个人员的坐标点
//定义一个旗帜表示是否在多边形区域
let flag = turf.booleanPointInPolygon(pt, polygonPoints);
if (flag) {
this.areaPerson.push(item);
}
});
//弹窗输出区域内的人数
alert(`区域内有${this.areaPerson.length}人`);
//移除交互
this.map.removeInteraction(this.draw);
}
},
//判断是否在多边形区域内的算法 参数:人的经度,人的纬度,多边形的坐标点
// isAtRegion(lon, lat, polygonPoints) {
// let num = 0;
// let iCount;
// let dLon1, dLon2, dLat1, dLat2, dLon;
// if (polygonPoints.length < 3) {
// return false;
// }
// iCount = polygonPoints.length;
// for (let i = 0; i < iCount; i++) {
// if (i == iCount - 1) {
// dLon1 = polygonPoints[i].longitude;
// dLat1 = polygonPoints[i].latitude;
// dLon2 = polygonPoints[0].longitude;
// dLat2 = polygonPoints[0].latitude;
// } else {
// dLon1 = polygonPoints[i].longitude;
// dLat1 = polygonPoints[i].latitude;
// dLon2 = polygonPoints[i + 1].longitude;
// dLat2 = polygonPoints[i + 1].latitude;
// }
// if ((lat >= dLat1 && lat < dLat2) || (lat >= dLat2 && lat < dLat1)) {
// if (Math.abs(dLat1 - dLat2) > 0) {
// dLon = dLon1 - ((dLon1 - dLon2) * (dLat1 - lat)) / (dLat1 - dLat2);
// if (dLon < lon) num++;
// }
// }
// }
// if (num % 2 != 0) return true;
// return false;
// },
},
beforeCreate() {}, //生命周期 - 创建之前
//生命周期 - 创建完成(可以访问当前this实例)
created() {
//在此周期给persons添加数据
this.persons = [
{ id: 1, name: "点-1", x: 497.08, y: 187.88, z: 0 },
{ id: 2, name: "点-2", x: 725.32, y: 565.88, z: 0 },
{ id: 3, name: "点-3", x: 643.24, y: 503.96, z: 0 },
];
},
beforeMount() {}, //生命周期 - 挂载之前
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
//初始化地图
this.initMap();
},
beforeUpdate() {}, //生命周期 - 更新之前
updated() {}, //生命周期 - 更新之后
beforeDestroy() {}, //生命周期 - 销毁之前
destroyed() {}, //生命周期 - 销毁完成
activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
#map {
width: 1000px;
height: 800px;
border: 1px solid #333;
margin: 0 auto;
}
button {
display: block;
margin: 10px auto;
}
/* #region */
/* #popup {
width: 200px;
height: 80px;
padding: 0 20px;
border-radius: 5px;
z-index: 1;
opacity: 1;
position: absolute;
bottom: 0;
left: 0;
margin: 0;
background: rgba(0, 60, 136, 0.7);
color: white;
border: 0;
transition: opacity 100ms ease-in;
} */
/* #endregion */
</style>
注意:
此处用了两种方法来进行点在多边形内的判断
法一:自己写的isAtRegion()函数
法二:使用turf.js来进行算法判断(推荐)
如果使用法二,请删除data中的polygonPoints
methods中的isAtRegion()
再去掉方法一下的代码即可