天地图实战:手把手教你用原生JS实现多边形绘制与顶点坐标获取(附完整代码)
2026/6/20 17:59:15 网站建设 项目流程

天地图原生开发实战:从多边形绘制到交互功能全解析

在GIS应用开发中,地图交互功能往往是核心需求之一。当我们需要让用户在地图上手动划定区域时——无论是物流配送范围、巡检区域还是服务覆盖范围——多边形绘制与坐标获取都是必不可少的技能。本文将带你深入探索如何不依赖任何前端框架,仅用原生JavaScript实现天地图的多边形绘制、顶点坐标获取以及完整的交互功能链。

1. 环境准备与基础配置

在开始编码前,我们需要确保开发环境正确配置。天地图作为国内主流的地图服务之一,其API设计与百度地图、高德地图等存在显著差异,这也是许多开发者初次接触时容易困惑的地方。

首先,在HTML中引入天地图JavaScript API。最新版本的API通常通过CDN引入:

<script type="text/javascript" src="https://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥"></script>

提示:申请天地图开发者密钥时,注意选择适合的服务类型。Web端应用通常选择"浏览器端"而非"服务端"。

初始化地图实例时,建议设置合理的初始视图和控件:

const map = new T.Map('map-container', { projection: 'EPSG:4326', // 使用WGS84坐标系 center: new T.LngLat(116.404, 39.915), // 默认中心点坐标 zoom: 12 // 初始缩放级别 }); // 添加基本控件 map.addControl(new T.Control.Zoom()); map.addControl(new T.Control.OverView());

2. 多边形绘制工具的实现

天地图提供了专门的T.PolygonTool类来处理多边形绘制,相比直接操作鼠标事件,使用官方工具类能大幅减少代码量并提高稳定性。

2.1 初始化绘制工具

创建多边形绘制工具时,可以通过配置对象自定义绘制样式:

const polygonTool = new T.PolygonTool(map, { showLabel: true, // 显示面积标签 color: '#3388ff', // 边线颜色 weight: 3, // 边线宽度 opacity: 0.8, // 边线透明度 fillColor: '#3388ff', // 填充颜色 fillOpacity: 0.3 // 填充透明度 });

启动绘制工具只需调用open()方法:

document.getElementById('draw-btn').addEventListener('click', () => { polygonTool.open(); });

2.2 捕获绘制完成事件

绘制完成后,我们需要获取多边形的顶点坐标。天地图会在draw事件中返回完整的坐标信息:

polygonTool.addEventListener('draw', (e) => { const vertices = e.currentLnglats; // 获取顶点坐标数组 console.log('多边形顶点坐标:', vertices); // 坐标格式转换示例:转为{lng, lat}对象数组 const formattedCoords = vertices.map(coord => ({ lng: coord.getLng(), lat: coord.getLat() })); // 可以在此处将坐标发送到后端或进行其他处理 savePolygonToDatabase(formattedCoords); });

注意:currentLnglats返回的是T.LngLat对象数组,直接使用前可能需要格式转换。

3. 高级交互功能实现

基础绘制功能实现后,我们通常需要添加更多交互元素来提升用户体验。下面实现双击多边形弹出操作菜单的功能。

3.1 自定义菜单设计与样式

首先在HTML中添加菜单结构,这里使用纯CSS实现而非依赖UI框架:

<div id="polygon-context-menu" class="context-menu"> <ul> <li id="menu-edit">编辑多边形</li> <li id="menu-delete">删除多边形</li> <li id="menu-cancel">取消</li> </ul> </div>

对应的CSS样式:

.context-menu { position: absolute; z-index: 1000; background: white; border: 1px solid #ddd; border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); display: none; } .context-menu ul { list-style: none; padding: 0; margin: 0; } .context-menu li { padding: 8px 15px; cursor: pointer; font-size: 14px; } .context-menu li:hover { background-color: #f5f5f5; }

3.2 实现双击交互逻辑

为绘制完成的多边形添加双击事件监听:

let currentPolygon = null; // 存储当前操作的多边形 polygonTool.addEventListener('draw', (e) => { const polygon = e.currentPolygon; currentPolygon = polygon; // 保存引用 // 添加双击事件监听 polygon.addEventListener('dblclick', (evt) => { showContextMenu(evt); }); }); function showContextMenu(event) { const menu = document.getElementById('polygon-context-menu'); const mapContainer = document.getElementById('map-container'); // 计算菜单位置 const containerRect = mapContainer.getBoundingClientRect(); const x = event.clientX - containerRect.left; const y = event.clientY - containerRect.top; menu.style.left = `${x}px`; menu.style.top = `${y}px`; menu.style.display = 'block'; // 点击其他地方隐藏菜单 document.addEventListener('click', hideContextMenu); }

3.3 实现菜单功能

为菜单项添加具体功能:

document.getElementById('menu-delete').addEventListener('click', () => { if (currentPolygon) { map.removeOverLay(currentPolygon); currentPolygon = null; } hideContextMenu(); }); document.getElementById('menu-edit').addEventListener('click', () => { if (currentPolygon) { // 进入编辑模式 polygonTool.edit(currentPolygon); } hideContextMenu(); }); function hideContextMenu() { const menu = document.getElementById('polygon-context-menu'); menu.style.display = 'none'; document.removeEventListener('click', hideContextMenu); }

4. 性能优化与错误处理

在实际项目中,我们需要考虑更多边界情况和性能问题。

4.1 内存管理

长时间使用地图应用可能导致内存泄漏,特别是在频繁创建和删除覆盖物时:

// 删除多边形时的完整处理 function removePolygon(polygon) { try { // 移除所有事件监听器 polygon.off('dblclick'); // 从地图移除 map.removeOverLay(polygon); // 如果是当前操作的多边形,清除引用 if (currentPolygon === polygon) { currentPolygon = null; } } catch (error) { console.error('删除多边形时出错:', error); } }

4.2 坐标验证

从用户绘制的多边形获取坐标后,应该进行基本验证:

function validatePolygon(coords) { if (!Array.isArray(coords) || coords.length < 3) { throw new Error('多边形至少需要3个顶点'); } // 检查坐标是否有效 coords.forEach(coord => { if (coord.lng < -180 || coord.lng > 180 || coord.lat < -90 || coord.lat > 90) { throw new Error(`无效坐标值: ${coord.lng}, ${coord.lat}`); } }); // 检查多边形是否闭合(首尾坐标相同) const first = coords[0]; const last = coords[coords.length - 1]; if (first.lng !== last.lng || first.lat !== last.lat) { coords.push({...first}); // 自动闭合多边形 } return coords; }

4.3 大数量处理

当需要同时显示大量多边形时,可以采用以下优化策略:

// 使用图层组管理多个多边形 const polygonLayer = new T.LayerGroup(); map.addLayer(polygonLayer); // 添加多边形到图层组 function addPolygonToLayer(coords) { const polygon = new T.Polygon(coords.map(c => new T.LngLat(c.lng, c.lat)), { color: '#3388ff', weight: 2, fillOpacity: 0.3 }); polygonLayer.addLayer(polygon); return polygon; } // 清空所有多边形 function clearAllPolygons() { polygonLayer.clearLayers(); }

5. 实际应用扩展

掌握了基础功能后,我们可以进一步扩展应用场景。

5.1 多边形编辑功能

天地图的PolygonTool提供了内置的编辑功能:

function enableEditMode(polygon) { polygonTool.close(); // 先关闭绘制模式 // 进入编辑模式 polygonTool.edit(polygon); // 监听编辑完成事件 polygonTool.on('edit', (e) => { const newCoords = e.currentLnglats; console.log('编辑后的坐标:', newCoords); }); }

5.2 与后端API集成

将多边形数据保存到后端时,通常需要适当的序列化:

async function savePolygonToServer(coords, name) { try { const response = await fetch('/api/polygons', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name, coordinates: coords, type: 'Polygon' }) }); if (!response.ok) { throw new Error(`保存失败: ${response.statusText}`); } return await response.json(); } catch (error) { console.error('保存多边形时出错:', error); throw error; } }

5.3 从数据库加载并显示多边形

从后端获取数据后重新在地图上渲染:

async function loadAndDisplayPolygons() { try { const response = await fetch('/api/polygons'); const polygons = await response.json(); polygons.forEach(polygonData => { const coords = polygonData.coordinates.map(c => new T.LngLat(c.lng, c.lat)); const polygon = new T.Polygon(coords, { color: '#3388ff', weight: 2, fillOpacity: 0.3 }); // 添加双击事件 polygon.on('dblclick', (e) => { currentPolygon = polygon; showContextMenu(e); }); map.addOverLay(polygon); }); } catch (error) { console.error('加载多边形时出错:', error); } }

在项目开发过程中,我发现天地图的API虽然功能全面,但在事件处理机制上与其他地图服务有所不同。特别是在处理覆盖物交互时,需要特别注意事件冒泡和委托的问题。一个实用的技巧是为所有多边形添加唯一标识符,这样在处理交互时能够准确定位到具体的多边形实例。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询