主要是使用turf来判定点位,如果是后台生成的点位,天地图推荐使用D3绘制判定,也是支持的,项目中区域绘制不是固定的,就不采用后台方案
<template>
<div class="map-container">
<div id="map-canvas"></div>
<div id="infos">
<button @click="openPolygonTool">绘制多边形</button>
<button @click="clearPolygon">清空</button>
</div>
</div>
</template>
<script>
/**
* 人员位置修改,使用轮询或者ws,暴露个setPoint方法,传入经纬度,修改data_info
* 如果是绘制 polygon,绘制完成也传递经纬度,给后台保存,区域判定 polygon 和 circle目前都可以
* 目前是一次只能绘制一个区域,看后面要不要改成多个区域判定
*/
import * as turf from "@turf/turf";
export default {
name: "tdtMap",
data() {
return {
tk: "XXX", // 天地图 key
data_info: [
[116.597854, 39.911988, "人员2"],
[116.406605, 39.921585, "人员3"],
[116.412222, 39.912345, "人员1"],
],
map: null,
countries: [],
polygonTool: null,
handler: null,
T: null,
};
},
methods: {
openPolygonTool() {
if (this.countries.length) {
this.countries = [];
this.map.getOverlays().forEach((item) => {
// 清除polygon
if (item.getType() === 5) {
this.map.removeOverLay(item);
}
});
}
if (this.handler) this.handler.close();
this.handler = new this.T.PolygonTool(this.map);
this.handler.open();
this.handler.on(
"draw",
({
type,
target,
currentLnglats,
currentArea,
currentPolygon,
allPolygons,
}) => {
currentLnglats.forEach((item) => {
this.countries.push([item.lng, item.lat]);
});
this.countries.push([currentLnglats[0].lng, currentLnglats[0].lat]); // 闭合多边形
this.initMarker();
}
);
},
clearPolygon() {
this.countries = [];
this.map.clearOverLays();
},
initMarker() {
if (this.countries.length) {
this.data_info.forEach((item) => {
item[2] = item[2].split(",")[0];
if (
this.pointInArea(
{ point: [item[0], item[1]], polygon: [this.countries] },
"polygon"
)
) {
item[2] += `,在区域内`;
} else {
item[2] += `,不在区域内`;
}
});
this.map.getOverlays().forEach((item) => {
if (item.getType() === 2) {
this.map.removeOverLay(item);
}
});
this.initPoint();
}
},
initPoint() {
for (let i = 0; i < this.data_info.length; i++) {
let marker = new this.T.Marker(
new this.T.LngLat(this.data_info[i][0], this.data_info[i][1])
);
let content = `${this.data_info[i][2]}`;
let status = this.data_info[i][2].split(",")[1];
this.map.addOverLay(marker);
marker.enableDragging();
this.addClickHandler(content, marker);
if (!marker.qQ.drag && !marker.qQ.dragend) {
marker.on("drag", ({ type, target, lnglat }) =>
this.markerDrag({ marker, type, target, lnglat, content })
);
marker.on("dragend", ({ type, target, lnglat }) =>
this.markerDragEnd({ marker, type, target, lnglat, content })
);
}
}
},
openInfo(content, e) {
let point = e.lnglat;
let marker = new this.T.Marker(point);
let markerInfoWin = new this.T.InfoWindow(content, {
offset: new this.T.Point(0, -30),
});
this.map.openInfoWindow(markerInfoWin, point);
},
addClickHandler(content, marker) {
marker.addEventListener("click", (e) => {
this.openInfo(content, e);
});
},
markerDrag({ marker, type, target, lnglat, content }) {
this.map.closeInfoWindow();
},
markerDragEnd({ marker, type, target, lnglat, content }) {
let [user, status] = content.split(",");
let point = [lnglat.lng, lnglat.lat];
let text;
this.data_info.forEach((item) => {
if (item[2].includes(user)) {
item[0] = lnglat.lng;
item[1] = lnglat.lat;
if (this.countries.length) {
if (
this.pointInArea(
{ point: point, polygon: [this.countries] },
"polygon"
)
) {
item[2] = `${user},在区域内`;
} else {
item[2] = `${user},不在区域内`;
}
}
text = item[2];
}
});
this.addClickHandler(text, marker);
},
pointInArea(data, type) {
if (type === "polygon") {
let { point, polygon } = data;
let pt = turf.point(point);
let poly = turf.polygon(polygon);
return turf.booleanPointInPolygon(pt, poly);
} else if (type === "circle") {
let { point, center, radius } = data;
return this.pointInCircle(point, center, radius);
}
},
pointInCircle(point, center, radius) {
const distance = turf.distance(turf.point(point), turf.point(center), {
units: "metres",
});
return distance <= radius;
},
},
mounted() {
window.T ? (window.T = null) : null;
const script = document.createElement("script");
script.src = `http://api.tianditu.gov.cn/api?v=4.0&tk=${this.tk}`;
script.type = "text/javascript";
script.onload = () => {
// 此处可以在外部库加载完成后执行一些初始化操作
this.T = window.T;
this.map = new this.T.Map("map-canvas");
this.map.centerAndZoom(new this.T.LngLat(116.599, 39.9539), 12);
this.initPoint();
};
// 将 script 标签添加到页面
document.head.appendChild(script);
},
};
</script>
<style scoped>
.map-container {
width: 100%;
height: 100%;
position: relative;
}
#map-canvas {
width: 100%;
height: 100%;
fill: #000000;
}
#infos {
position: fixed;
top: 10px;
left: 10px;
z-index: 999;
background: #fff;
padding: 10px;
border-radius: 5px;
box-shadow: 0 0 5px #ccc;
}
</style>
这里是原生实现,注释对应的代码块实现支持圆形和POLYGON路径区域判定,实际上还是POLYGON,大差不大
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>天地图-地图API-范例-加载geojson数据</title>
<link href="../../../../images/favicon.ico" type="image/x-icon" rel="Shortcut Icon" />
<style type="text/css">
html {
height: 100%
}
body {
height: 100%;
margin: 0;
padding: 0
}
#map-canvas {
height: 100%;
fill: #000000;
}
/* .geojson {
pointer-events: auto !important;
} */
#infos {
position: fixed;
top: 10px;
left: 10px;
z-index: 999;
background: #fff;
padding: 10px;
border-radius: 5px;
box-shadow: 0 0 5px #ccc;
}
</style>
</head>
<body>
<div id="map-canvas"></div>
<div id="infos">
<button id="btnPolygon">画图</button>
</div>
<script src=" http://api.tianditu.gov.cn/api?v=4.0&tk=XXX"
type="text/javascript"></script>
<script src="http://cdn.bootcss.com/d3/3.5.17/d3.js " charset="utf-8"></script>
<script src="http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/D3SvgOverlay.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@6.3.0/turf.min.js"></script>
<script>
let data_info = [[116.597854, 39.911988, "人员2"],
[116.406605, 39.921585, "人员3"],
[116.412222, 39.912345, "人员1"]];
let map = new T.Map("map-canvas");
map.centerAndZoom(new T.LngLat(116.499, 39.9539), 10)
let countries = [];
// CIRCLE
let circleLnglat = new T.LngLat(116.40769, 39.89945)
let circle = new T.Circle(circleLnglat, 2000, { color: "blue", weight: .1, opacity: 0.5, fillColor: "#000", fillOpacity: 0.5, });
map.addOverLay(circle);
function init() {
let radius = circle.getRadius()
let center = [116.40769, 39.89945]
// console.log(circleLnglat)
data_info.forEach(item => {
if (pointInArea({ point: [item[0], item[1]], center, radius }, 'circle')) {
item[2] += `,在区域内`
} else {
item[2] += `,不在区域内`
}
})
initPoint()
}
init()
// PATH || POLYGON
// let countriesOverlay = new T.D3Overlay(init, redraw);
// d3.json("./data.json", function (data) {
// countries = data.features;
// data_info.forEach(item => {
// if (pointInArea({ point: [item[0], item[1]], polygon: countries[0].geometry.coordinates }, 'polygon')) {
// item[2] += `,在区域内`
// } else {
// item[2] += `,不在区域内`
// }
// })
// initPoint()
// map.addOverLay(countriesOverlay)
// countriesOverlay.bringToBack();
// });
// function init(sel, transform) { // 初始化样式
// let upd = sel.selectAll('path.geojson').data(countries);
// upd.enter()
// .append('path')
// .attr("class", "geojson")
// .attr('stroke', 'black')
// .attr('fill', function (d, i) {
// return d3.hsl('red')
// })
// .attr('fill-opacity', '0.3')
// .attr('cursor', 'pointer')
// }
// function redraw(sel, transform) { // 给区域设置路径 、绘制
// sel.selectAll('path.geojson').each(
// function (d, i) {
// d3.select(this).attr('d', transform.pathFromGeojson)
// .on('click', function (d, i) {
// // console.log(arguments)
// })
// }
// )
// }
// end
function initPoint() {
for (var i = 0; i < data_info.length; i++) {
let marker = new T.Marker(new T.LngLat(data_info[i][0], data_info[i][1])); // 创建标注
let content = `${data_info[i][2]}`; // 创建标注
let status = data_info[i][2].split(',')[1]
map.addOverLay(marker); // 将标注添加到地图中
marker.enableDragging(); // 可拖拽
addClickHandler(content, marker);
if (!marker.qQ.drag && !marker.qQ.dragend) {
marker.on('drag', ({ type, target, lnglat }) => markerDrag({ marker, type, target, lnglat, content }))
marker.on('dragend', ({ type, target, lnglat }) => markerDragEnd({ marker, type, target, lnglat, content }))
}
}
}
function openInfo(content, e) {
let point = e.lnglat;
marker = new T.Marker(point);// 创建标注
let markerInfoWin = new T.InfoWindow(content, { offset: new T.Point(0, -30) }); // 创建信息窗口对象
map.openInfoWindow(markerInfoWin, point); //开启信息窗口
}
function addClickHandler(content, marker) {
marker.addEventListener("click", function (e) {
openInfo(content, e)
});
}
function markerDrag({ marker, type, target, lnglat, content }) {
map.closeInfoWindow();
}
function markerDragEnd({ marker, type, target, lnglat, content }) {
let [user, status] = content.split(',')
let point = [lnglat.lng, lnglat.lat]
let text;
// CIRCLE
data_info.forEach(item => {
if (item[2].includes(user)) {
item[0] = lnglat.lng
item[1] = lnglat.lat
if (pointInArea({ point: point, center: [116.40769, 39.89945], radius: circle.getRadius() }, 'circle')) {
item[2] = `${user},在区域内`
} else {
item[2] = `${user},不在区域内`
}
text = item[2]
}
})
// PATH || POLYGON
// data_info.forEach(item => {
// if (item[2].includes(user)) {
// item[0] = lnglat.lng
// item[1] = lnglat.lat
// if (pointInArea({ point: point, polygon: countries[0].geometry.coordinates }, 'polygon')) {
// item[2] = `${user},在区域内`
// } else {
// item[2] = `${user},不在区域内`
// }
// text = item[2]
// }
// })
addClickHandler(text, marker);
}
// 判断点是否在区域内
function pointInArea(data, type) {
if (type === 'polygon') {
let { point, polygon } = data
let pt = turf.point(point);
let poly = turf.polygon(polygon);
return turf.booleanPointInPolygon(pt, poly);
} else if (type === 'circle') {
let { point, center, radius } = data
return pointInCircle(point, center, radius)
}
}
// 判断是否在圆内
function pointInCircle(point, center, radius) {
const distance = turf.distance(turf.point(point), turf.point(center), { units: 'metres' });
return distance <= radius;
}
</script>
</body>
</html>
数据: