OpenLayers 7实现多边形/多多边形选点分割及测量展示
OpenLayers 7 多边形分割功能实现
关键前置准备
确保已引入OpenLayers 7和JSTS库(用于多边形拓扑分割):
<script src="https://cdn.jsdelivr.net/npm/openlayers@7.4.0/dist/ol.js"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/openlayers@7.4.0/dist/ol.css"> <script src="https://cdn.jsdelivr.net/npm/jsts@2.0.0/dist/jsts.min.js"></script>
完整功能代码
// 全局变量定义 let map; let vectorLayer; let splitLineLayer; let selectInteraction; let pDrawInteraction; let selectedFeature; let sketch; let measureTooltip; let measureTooltipElement; const regularStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#3399CC', width: 1.5 }), fill: new ol.style.Fill({ color: 'rgba(0, 153, 204, 0.1)' }) }); const highlightStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#FF0000', width: 2 }), fill: new ol.style.Fill({ color: 'rgba(255, 0, 0, 0.2)' }) }); const lineStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'navy', width: 3, lineDash: [4, 8], lineDashOffset: 6 }), image: new ol.style.Circle({ fill: new ol.style.Fill({ color: '#69cfba' }), radius: 5, stroke: new ol.style.Stroke({ color: 'black', width: 2 }) }) }); // 初始化地图 function initMap() { vectorLayer = new ol.layer.Vector({ source: new ol.source.Vector(), style: regularStyle }); splitLineLayer = new ol.layer.Vector({ source: new ol.source.Vector() }); map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer, splitLineLayer ], view: new ol.View({ center: ol.proj.fromLonLat([0, 0]), zoom: 10 }) }); // 添加要素选择交互 addSelectInteraction(); } // 添加选择交互:点击选中多边形 function addSelectInteraction() { selectInteraction = new ol.interaction.Select({ style: highlightStyle, filter: function(feature) { const geomType = feature.getGeometry().getType(); return geomType === 'Polygon' || geomType === 'MultiPolygon'; } }); map.addInteraction(selectInteraction); // 监听选中事件,准备启动分割线绘制 selectInteraction.on('select', function(evt) { selectedFeature = evt.selected.length > 0 ? evt.selected[0] : null; if (selectedFeature) { // 移除之前的绘制交互 if (pDrawInteraction) map.removeInteraction(pDrawInteraction); // 启动分割线绘制 startSubDivLineDrawInteraction('LineString', splitLineLayer.getSource()); } }); } // 启动分割线绘制交互 function startSubDivLineDrawInteraction(gtype, source) { pDrawInteraction = new ol.interaction.Draw({ source: source, type: gtype, style: lineStyle, // 限制起点必须在选中要素内 condition: function(event) { if (!selectedFeature) return false; const coord = event.coordinate; return selectedFeature.getGeometry().intersectsCoordinate(coord); } }); map.addInteraction(pDrawInteraction); createMeasureTooltip(map); let listener; // 绘制开始:实时监听分割线变化,展示长度 pDrawInteraction.on('drawstart', function(evt) { sketch = evt.feature; listener = sketch.getGeometry().on('change', function(geomEvt) { const line = geomEvt.target; const length = line.getLength(); // 更新长度提示框 const midPoint = line.getFlatMidpoint(); measureTooltip.setPosition(midPoint); measureTooltipElement.innerHTML = `<b>${formatLength(line)}</b>`; // 实时尝试分割(可选,也可在drawend时处理) trySplitPolygon(line); }); }); // 绘制结束:完成分割并清理 pDrawInteraction.on('drawend', function(e) { map.removeInteraction(pDrawInteraction); ol.Observable.unByKey(listener); // 最终分割处理 trySplitPolygon(e.feature.getGeometry()); }); } // 创建测量提示框 function createMeasureTooltip(map) { if (measureTooltipElement) { measureTooltipElement.parentNode.removeChild(measureTooltipElement); } measureTooltipElement = document.createElement('div'); measureTooltipElement.className = 'mtooltip mtooltip-measure'; measureTooltip = new ol.Overlay({ element: measureTooltipElement, offset: [0, -15], positioning: 'bottom-center' }); map.addOverlay(measureTooltip); document.querySelector('.ol-overlay-container').style.zIndex = '1000'; } // 格式化长度 function formatLength(line) { const length = line.getLength(); return length >= 1000 ? `${(length / 1000).toFixed(3)} KM` : `${length.toFixed(3)} Meter`; } // 格式化面积 function formatArea(polygon) { const area = ol.sphere.getArea(polygon); if (area >= 10000) { return `${Math.round((area / 10000) * 100) / 100} HECT`; } else { return `${Math.round(area * 100) / 100} SQ M`; } } // 尝试分割多边形 function trySplitPolygon(lineGeom) { if (!selectedFeature) return; const parser = new jsts.io.OL3Parser(); let selectedGeom = selectedFeature.getGeometry(); let jstsSelectedGeom; // 处理MultiPolygon:分解为单个Polygon处理(示例取第一个,如需批量处理可扩展循环) if (selectedGeom.getType() === 'MultiPolygon') { const polygons = selectedGeom.getPolygons(); jstsSelectedGeom = parser.read(polygons[0]); } else { jstsSelectedGeom = parser.read(selectedGeom); } const jstsLineGeom = parser.read(lineGeom); try { // 执行分割:用线切割多边形 const splitter = new jsts.operation.split.SplitOp(); const splitResult = splitter.split(jstsSelectedGeom, jstsLineGeom); const splitGeoms = splitResult.getGeometries(); // 仅当分割出两个多边形时处理 if (splitGeoms.length === 2) { // 清除原有要素和Overlay vectorLayer.getSource().removeFeature(selectedFeature); map.getOverlays().clear(); // 添加分割后的多边形并展示面积 splitGeoms.forEach(function(jstsGeom) { const olGeom = parser.write(jstsGeom); const newFeature = new ol.Feature({ geometry: olGeom }); vectorLayer.getSource().addFeature(newFeature); // 创建面积Overlay const areaOverlay = new ol.Overlay({ element: document.createElement('div'), offset: [0, -15], positioning: 'bottom-center' }); const area = ol.sphere.getArea(olGeom); areaOverlay.getElement().innerHTML = `<b>${formatArea(olGeom)}</b>`; areaOverlay.setPosition(olGeom.getFlatInteriorPoint()); map.addOverlay(areaOverlay); }); // 添加分割线并展示长度 const lineFeature = new ol.Feature({ geometry: lineGeom }); splitLineLayer.getSource().addFeature(lineFeature); const lineOverlay = new ol.Overlay({ element: document.createElement('div'), offset: [0, -15], positioning: 'bottom-center' }); lineOverlay.getElement().innerHTML = `<b>${formatLength(lineGeom)}</b>`; lineOverlay.setPosition(lineGeom.getFlatMidpoint()); map.addOverlay(lineOverlay); } } catch (e) { // 分割失败(如线未完全穿过多边形),清除临时Overlay map.getOverlays().clear(); } } // 初始化地图 window.onload = initMap;
关键功能说明
- 要素选择:通过
ol.interaction.Select实现,仅允许选择Polygon/MultiPolygon类型要素,选中后自动启动分割线绘制。 - 分割线绘制限制:通过
condition配置,确保分割线起点必须在选中要素范围内,避免无效绘制。 - 实时长度展示:在绘制过程中监听线几何变化,通过
Overlay实时显示分割线长度。 - 多边形分割:使用JSTS的
SplitOp工具完成拓扑分割,支持Polygon和MultiPolygon(示例中处理MultiPolygon的第一个子多边形,如需批量处理可扩展循环逻辑)。 - 面积与长度展示:分割完成后,为每个新多边形创建面积Overlay,为分割线创建长度Overlay,定位在几何中心点/中点。
内容的提问来源于stack exchange,提问作者Marudi Abhinaya
相关产品推荐
相关产品推荐

