实现效果图

实现功能
1. 回显点线面数据
2. 绘制点线面,保存可获取点线面数据
3. 编辑点线面,保存可获取最新编辑后的点线面数据
4. 删除任意点线面(解决删除按钮不能随元素位置变化(地图拖拽/放大缩小时)而变化问题->地图放大缩小拖动时处理删除按钮消失)
完整代码:
bash
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>回显、绘制、编辑、删除任意点线面</title>
<script src="http://api.tianditu.gov.cn/api?v=4.0&tk=应用KEY值"
type="text/javascript"></script>
<style type="text/css">
body,
html {
width: 100%;
height: 100%;
margin: 0;
font-family: '微软雅黑';
}
#map {
height: 400px;
width: 100%;
}
input {
margin-top: 10px;
margin-left: 5px;
font-size: 14px;
}
#contextMenu {
position: absolute;
background: white;
border: 1px solid #ccc;
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.2);
z-index: 1000;
display: none;
}
.context-menu-item {
padding: 2px 12px;
cursor: pointer;
font-size: 14px;
}
.context-menu-item:hover {
background: #f0f0f0;
}
</style>
<script>
var map, zoom = 10, handler;
let isEdit = false; // 是否启用编辑
// 右键菜单相关变量
let contextMenu = null;
let currentFeature = null; // 当前右键点击的元素
let currentIndex = -1; // 当前元素的索引
let featureType = ''; // 元素类型:point/line/polygon
let viewChangeHandler = null;// 地图视图变化监听器
// 点数据
let pointOriginalArr = [
[120.2536, 30.27093]
]
// 线数据
let lineOriginalArr = [
[
[119.86084, 30.41702],
[119.96796, 30.47353],
[119.98718, 30.36758],
],
[
[119.91714, 30.1855],
[120.10666, 30.27923],
]
]
// 面数据
let polygonOriginalArr = [
[
[119.5752, 30.35392],
[119.72488, 30.35273],
[119.65347, 30.26025],
],
[
[120.49118, 30.29109],
[120.70541, 30.30532],
[120.50629, 30.20211],
[120.69855, 30.22703]
]
]
function onLoad () {
// 创建右键菜单
createContextMenu();
//初始化地图对象
map = new T.Map("map");
//设置显示地图的中心点和级别
map.centerAndZoom(new T.LngLat(120.216329, 30.252589), zoom);
// 绑定地图点击事件隐藏菜单
map.addEventListener('click', hideContextMenu);
// 地图视图变化监听
viewChangeHandler = function () {
if (currentFeature) {
updateMenuPosition();
}
};
map.addEventListener('movestart', hideContextMenu);
map.addEventListener('moveend', viewChangeHandler);
map.addEventListener('zoomend', viewChangeHandler);
// 初始显示
showPoint()
showPolyLine()
showPolygon()
}
// 位置更新
function updateMenuPosition () {
if (!currentFeature) return;
let centerLngLat;
switch (featureType) {
case 'point':
centerLngLat = currentFeature.getLngLat();
break;
case 'line':
const lineLnglats = currentFeature.getLngLats();
centerLngLat = getCenter(lineLnglats);
break;
case 'polygon':
const polygonRings = currentFeature.getLngLats();
centerLngLat = getCenter(polygonRings[0]);
break;
}
const containerPoint = map.lngLatToContainerPoint(centerLngLat);
const mapRect = map.getContainer().getBoundingClientRect();
contextMenu.style.left = (containerPoint.x + mapRect.left) + 'px';
contextMenu.style.top = (containerPoint.y + mapRect.top) + 'px';
}
// 几何中心计算方法
function getCenter (lnglats) {
// 确保有效的坐标数组
if (!lnglats || lnglats.length === 0) return null;
// 计算所有坐标点的平均值
const sum = lnglats.reduce((acc, curr) => {
// 处理不同格式的坐标(支持T.LngLat对象和普通数组)
const lng = curr instanceof T.LngLat ? curr.lng : curr[0];
const lat = curr instanceof T.LngLat ? curr.lat : curr[1];
return {
lng: acc.lng + lng,
lat: acc.lat + lat
};
}, { lng: 0, lat: 0 });
// 返回新的T.LngLat对象
return new T.LngLat(
sum.lng / lnglats.length,
sum.lat / lnglats.length
);
}
// 创建右键菜单
function createContextMenu () {
contextMenu = document.createElement('div');
contextMenu.id = 'contextMenu';
contextMenu.innerHTML = `
<div class="context-menu-item" onclick="deleteFeature()">删除</div>
`;
document.body.appendChild(contextMenu);
}
// 显示右键菜单
function showContextMenu (e, feature, index, type) {
// 获取天地图事件中的原生事件对象
const originalEvent = e.originalEvent || e.event || e;
if (originalEvent.preventDefault) {
originalEvent.preventDefault();
}
currentFeature = feature;
currentIndex = index;
featureType = type;
updateMenuPosition(); // 初始定位
contextMenu.style.display = 'block';
// 使用原生事件的坐标,定位菜单项
contextMenu.style.left = originalEvent.clientX + 'px';
contextMenu.style.top = originalEvent.clientY + 'px';
}
// 隐藏右键菜单
function hideContextMenu () {
contextMenu.style.display = 'none';
currentFeature = null;
currentIndex = -1;
featureType = '';
}
// 删除要素
function deleteFeature () {
if (currentIndex === -1) return;
switch (featureType) {
case 'point':
pointOriginalArr.splice(currentIndex, 1);
break;
case 'line':
lineOriginalArr.splice(currentIndex, 1);
break;
case 'polygon':
polygonOriginalArr.splice(currentIndex, 1);
break;
}
refreshMap();
hideContextMenu();
}
// 刷新地图
function refreshMap () {
map.clearOverLays();
showPoint();
showPolyLine();
showPolygon();
}
// 显示点
function showPoint () {
let pointArr = [];
pointOriginalArr.forEach((item, index) => {
let arr = []
arr.push(new T.LngLat(item[0], item[1]))
pointArr.push(arr);
})
pointArr.forEach((item, index) => {
var marker = new T.Marker(item[0], {
icon: new T.Icon({
iconUrl: './imgs/marker-icon.png',
}),
});
map.addOverLay(marker);
// 右键菜单事件绑定(添加event参数传递)
marker.addEventListener('contextmenu', function (apiEvent) {
showContextMenu(apiEvent, marker, index, 'point');
});
if (!isEdit) return;
marker.enableDragging();
marker.addEventListener('dragend', function (e) {
updatePointOriginalList([e.lnglat.lng, e.lnglat.lat], index)
})
})
}
// 更新点的数据,用于最后保存
function updatePointOriginalList (arr, index) {
pointOriginalArr[index] = arr
}
// 显示线
function showPolyLine () {
let lineArr = []
lineOriginalArr.forEach((item, index) => {
let arr = []
item.forEach((item1) => {
arr.push(new T.LngLat(item1[0], item1[1]))
})
lineArr.push(arr)
})
lineArr.forEach((item, index) => {
var line = new T.Polyline(item);
map.addOverLay(line);
// 右键菜单事件绑定(添加event参数传递)
line.addEventListener('contextmenu', function (apiEvent) {
showContextMenu(apiEvent, line, index, 'line');
});
if (!isEdit) return
line.enableEdit();
line.addEventListener('edit', function (e) {
const ht = line.getLngLats()
let arr = []
ht.forEach((item) => {
arr.push([item.lng, item.lat])
})
updateLineOriginalList(arr, index)
})
})
}
// 更新线的数据,用于最后保存
function updateLineOriginalList (arr, index) {
lineOriginalArr[index] = arr
}
// 显示面
function showPolygon () {
let polygonArr = []
polygonOriginalArr.forEach((item, index) => {
let arr = []
item.forEach((item1) => {
arr.push(new T.LngLat(item1[0], item1[1]))
})
polygonArr.push(arr)
})
polygonArr.forEach((item, index) => {
var polygon = new T.Polygon(item);
map.addOverLay(polygon);
// 右键菜单事件绑定(添加event参数传递)
polygon.addEventListener('contextmenu', function (apiEvent) {
showContextMenu(apiEvent, polygon, index, 'polygon');
});
if (!isEdit) return
polygon.enableEdit();
polygon.addEventListener('edit', function (e) {
const ht = polygon.getLngLats()[0]
let arr = []
ht.forEach((item) => {
arr.push([item.lng, item.lat])
})
updatePolygonOriginalList(arr, index)
})
})
}
// 更新面的数据,用于最后保存
function updatePolygonOriginalList (arr, index) {
polygonOriginalArr[index] = arr
}
// 打点
function openMarkerTool () {
if (handler) handler.close();
handler = new T.MarkTool(map, {
follow: true,
icon: new T.Icon({
iconUrl: './imgs/marker-icon.png',
// iconSize: new T.Point(24, 28), // 图标可视区域的大小
}),
});
handler.open();
handler.addEventListener('mouseup', function (e) {
// 这里可以获取到当前点位的坐标
pointOriginalArr.push([e.currentLnglat.lng, e.currentLnglat.lat])
// 重新绘制地图,否则编辑不了
refreshMap();
handler.clear()
})
}
// 画线
function openPolylineTool () {
if (handler) handler.close();
handler = new T.PolylineTool(map);
handler.open();
handler.addEventListener('draw', function (e) {
const currentLnglats = e.currentLnglats
let arr = []
currentLnglats.forEach((item, index) => {
arr.push([item.lng, item.lat])
})
lineOriginalArr.push(arr)
// 重新绘制地图,否则编辑不了
refreshMap();
handler.clear()
})
}
// 画面
function openPolygonTool () {
if (handler) handler.close();
handler = new T.PolygonTool(map);
handler.open();
handler.addEventListener('draw', function (e) {
const currentLnglats = e.currentLnglats
let arr = []
currentLnglats.forEach((item, index) => {
arr.push([item.lng, item.lat])
})
polygonOriginalArr.push(arr)
// 重新绘制地图,否则编辑不了
refreshMap();
handler.clear()
})
}
// 开启编辑
function editClick () {
isEdit = true
map.clearOverLays()
showPoint()
showPolyLine()
showPolygon()
}
// 保存
function saveClick () {
console.log("点数据:", pointOriginalArr); // 两层结构:大数组中,包含点的小数组
console.log("线数据:", lineOriginalArr); // 三层结构:大数组中包含线的数组,线的数组中包含经纬度小数组
console.log("面数据:", polygonOriginalArr); // 三层结构:大数组中包含面的数组,面的数组中包含经纬小数组
isEdit = false
map.clearOverLays()
showPoint()
showPolyLine()
showPolygon()
}
// 清空画布
function clearClick () {
isEdit = false
map.clearOverLays()
pointOriginalArr = []
lineOriginalArr = []
polygonOriginalArr = []
}
</script>
</head>
<body onLoad="onLoad()">
<div id="map"></div>
<div class="line-btn">
<input type="button" value="点工具" onClick="openMarkerTool() " />
<input type="button" value="线工具" onClick="openPolylineTool() " />
<input type="button" value="面工具" onClick="openPolygonTool() " />
<input type="button" value="编辑" onClick="editClick() " />
<input type="button" value="保存" onClick="saveClick() " />
<input type="button" value="清除" onClick="clearClick() " />
</div>
</body>
</html>
复制上面代码,替换
应用KEY值
即可看到功能效果。