<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>判断塔吊(范围)是否超出限定区域</title>
<link rel="stylesheet" href="https://netnr.eu.org/bootstrap@5.3.3/dist/css/bootstrap.min.css" />
<script src="https://webapi.amap.com/maps?v=1.4.15&key=309f07ac6bc48160e80b480ae511e1e9&plugin=AMap.PolyEditor,AMap.CircleEditor">
</script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div id="container" style="height: 80vh;"></div>
</div>
<div class="col-lg-4">
<h4 class="mt-3">判断塔吊(范围)是否超出限定区域</h4>
<div class="mb-3">
<input type="text" class="form-control-plaintext" value="地图初始化坐标: 116.40139,39.90061" readonly>
</div>
<div class="input-group mb-3">
<span class="input-group-text">区域坐标</span>
<textarea class="form-control txt-path-area" rows="7">
116.399653, 39.900874
116.401992, 39.901722
116.4033, 39.900255
116.402099, 39.898988
116.400188, 39.899349
</textarea>
</div>
<div class="mb-3">
<button class="btn btn-primary btn-view-area">显示区域</button>
<button class="btn btn-primary btn-remove-area">删除区域</button>
<button class="btn btn-outline-primary btn-start-edit-area">开始编辑区域</button>
<button class="btn btn-outline-primary btn-end-edit-area">结束编辑区域</button>
</div>
<hr />
<div class="input-group mb-3">
<span class="input-group-text">塔吊坐标</span>
<input class="form-control txt-path-device" value="116.40139,39.900379">
</div>
<div class="input-group mb-3">
<span class="input-group-text">塔吊半径</span>
<input class="form-control txt-radius-device" value="50">
<span class="input-group-text">米</span>
</div>
<div class="mb-3">
<button class="btn btn-info btn-view-device">显示塔吊</button>
<button class="btn btn-info btn-remove-device">删除塔吊</button>
<button class="btn btn-outline-info btn-start-edit-device">开始编辑塔吊</button>
<button class="btn btn-outline-info btn-end-edit-device">结束编辑塔吊</button>
</div>
<hr />
<div class="mb-3">
<button class="btn btn-warning btn-inarea1">判断塔吊(中心)是否超出限定区域</button>
<span class="result1 badge text-bg-danger"></span>
</div>
<div class="mb-3">
<button class="btn btn-warning btn-inarea2">判断塔吊(范围)是否超出限定区域</button>
<span class="result2 badge text-bg-danger"></span>
</div>
</div>
</div>
</div>
</body>
</html>
let nrMap = {
init: () => {
nrMap.map = new AMap.Map("container", {
center: [116.40139, 39.90061],
zoom: 14
});
nrMap.bindEvent();
},
map: null, // 地图对象
polygon: null, // 多边形对象
polygonEditor: null, // 多边形编辑器
bindEvent: () => {
// 监听地图的右键点击事件
nrMap.map.on('rightclick', function (e) {
var lng = e.lnglat.getLng(); // 获取经度
var lat = e.lnglat.getLat(); // 获取纬度
let path = `${lng},${lat}`;
if (confirm(`${lng},${lat}`)) {
navigator.clipboard.writeText(path);
}
});
// 显示区域
document.querySelector('.btn-view-area').addEventListener('click', () => {
let pathArea = document.querySelector('.txt-path-area').value.split('\n')
.filter(x => x.includes(","))
.map(x => x.split(',').map(x => parseFloat(x)));
nrMap.drawArea(pathArea);
});
// 删除区域
document.querySelector('.btn-remove-area').addEventListener('click', () => {
if (nrMap.polygonEditor) {
nrMap.polygonEditor.close();
nrMap.map.remove(nrMap.polygon);
}
});
// 开始编辑区域
document.querySelector('.btn-start-edit-area').addEventListener('click', () => {
nrMap.polygonEditor.open();
});
// 结束编辑区域
document.querySelector('.btn-end-edit-area').addEventListener('click', () => {
nrMap.polygonEditor.close();
// 获取多边形的顶点
let path = nrMap.polygon.getPath().map(x => `${x.lng},${x.lat}`).join('\n');
document.querySelector('.txt-path-area').value = path;
});
// 显示塔吊
document.querySelector('.btn-view-device').addEventListener('click', () => {
let center = document.querySelector('.txt-path-device').value.split(',').map(x => parseFloat(x));
let radius = parseFloat(document.querySelector('.txt-radius-device').value);
nrMap.drawCircle(center, radius);
});
// 删除塔吊
document.querySelector('.btn-remove-device').addEventListener('click', () => {
if (nrMap.circle) {
nrMap.map.remove(nrMap.circle);
nrMap.circle = null;
nrMap.marker.setMap(null);
nrMap.marker = null;
}
});
// 开始编辑塔吊
document.querySelector('.btn-start-edit-device').addEventListener('click', () => {
// 编辑塔吊后不能拖拽
nrMap.circleEditor = new AMap.CircleEditor(nrMap.map, nrMap.circle);
nrMap.circleEditor.open();
});
// 结束编辑塔吊
document.querySelector('.btn-end-edit-device').addEventListener('click', () => {
nrMap.circleEditor.close();
let center = nrMap.circle.getCenter();
// 更新塔吊中心标点
nrMap.newMarker(center);
document.querySelector('.txt-radius-device').value = nrMap.circle.getRadius();
document.querySelector('.txt-path-device').value = `${center.lng}, ${center.lat}`;
});
// 判断塔吊中心是否超出区域
document.querySelector('.btn-inarea1').addEventListener('click', () => {
let pathArea = document.querySelector('.txt-path-area').value.split('\n')
.filter(x => x.includes(","))
.map(x => x.split(',').map(x => parseFloat(x)));
let center = document.querySelector('.txt-path-device').value.split(',').map(x => parseFloat(x));
let radius = parseFloat(document.querySelector('.txt-radius-device').value);
let isInArea = AMap.GeometryUtil.isPointInRing(center, pathArea);
let domResult = document.querySelector('.result1');
domResult.classList.remove('text-bg-danger');
domResult.classList.remove('text-bg-success');
domResult.classList.add(isInArea ? 'text-bg-success' : 'text-bg-danger');
domResult.innerText = isInArea ? '在限定区域内' : '不在限定区域内';
});
// 判断塔吊范围是否超出区域
document.querySelector('.btn-inarea2').addEventListener('click', () => {
let domResult = document.querySelector('.result2');
domResult.classList.remove('text-bg-danger');
domResult.classList.remove('text-bg-success');
if (nrMap.polygon == null || nrMap.circle == null) {
domResult.classList.add('text-bg-danger');
domResult.innerText = '请先点显示区域和塔吊';
return;
}
let pathArea = document.querySelector('.txt-path-area').value.split('\n')
.filter(x => x.includes(","))
.map(x => x.split(',').map(x => parseFloat(x)));
let center = document.querySelector('.txt-path-device').value.split(',').map(x => parseFloat(x));
let radius = parseFloat(document.querySelector('.txt-radius-device').value);
let isInArea = AMap.GeometryUtil.isPointInRing(center, pathArea);
if (isInArea) {
let point = new AMap.LngLat(center[0], center[1]); // 要计算距离的点
let min = nrMap.getPointToPolygonMinLength(point, nrMap.polygon);
if (min >= radius) {
domResult.classList.add('text-bg-success');
domResult.innerText = '在限定区域内';
} else {
domResult.classList.add('text-bg-danger');
domResult.innerText = '不在限定区域内';
}
} else {
domResult.classList.add('text-bg-danger');
domResult.innerText = '不在限定区域内';
}
});
},
// 画区域
drawArea: (path) => {
if (nrMap.polygon) {
nrMap.polygonEditor.close();
nrMap.map.remove(nrMap.polygon);
}
nrMap.polygon = new AMap.Polygon({
path: path,
strokeColor: "#0f5132",
strokeWeight: 6,
strokeOpacity: 0.2,
fillOpacity: 0.2,
fillColor: '#198754',
zIndex: 50,
draggable: true
})
nrMap.map.add(nrMap.polygon)
// 缩放地图到合适的视野级别
nrMap.map.setFitView([nrMap.polygon])
// 拖动区域
nrMap.polygon.on('dragend', () => {
let path = nrMap.polygon.getPath();
// 获取多边形的顶点
let pathStr = path.map(x => `${x.lng}, ${x.lat}`).join('\n');
document.querySelector('.txt-path-area').value = pathStr;
})
// 编辑多边形
nrMap.polygonEditor = new AMap.PolyEditor(nrMap.map, nrMap.polygon)
},
// 画圆
drawCircle: (center, radius) => {
if (nrMap.circle) {
nrMap.map.remove(nrMap.circle);
}
// 更新塔吊中心标点
nrMap.newMarker(center);
nrMap.circle = new AMap.Circle({
center: center,
radius: radius,
strokeColor: "#FF33FF",
strokeWeight: 6,
strokeOpacity: 0.2,
fillOpacity: 0.6,
fillColor: '#0dcaf0',
zIndex: 50,
draggable: true
})
nrMap.map.add(nrMap.circle)
// 缩放地图到合适的视野级别
if (nrMap.polygon == null) {
nrMap.map.setFitView([nrMap.circle]);
}
// 拖动圆形
nrMap.circle.on('dragend', () => {
let center = nrMap.circle.getCenter();
// 更新塔吊中心标点
nrMap.newMarker(center);
document.querySelector('.txt-path-device').value = `${center.lng}, ${center.lat}`;
})
},
// 点到多边形的最短距离
getPointToPolygonMinLength: (point, polygon) => {
// 获取多边形的路径(顶点坐标)
var path = polygon.getPath();
// 计算点到多边形每条边的距离,并找到最小值
var minDistance = Infinity;
for (var i = 0; i < path.length; i++) {
var start = path[i];
var end = path[(i + 1) % path.length];
var distance = AMap.GeometryUtil.distanceToSegment(point, start, end);
minDistance = Math.min(minDistance, distance);
}
return minDistance;
},
newMarker: (center) => {
if (nrMap.marker) {
nrMap.marker.setMap(null);
nrMap.marker = null;
}
nrMap.marker = new AMap.Marker({
position: center,
label: {
offset: new AMap.Pixel(16, 18), //修改label相对于marker的位置
content: "塔吊",
}
});
nrMap.marker.setMap(nrMap.map);
}
}
nrMap.init();