前期准备
-
使用maplibre初始化一个实例地图
此处地图初始化与量算工具分开在两个不同文件定义,首先确保已经在别的文件中实例化好地图及draw控件。 -
量算工具调用
在需要添加量算工具的位置使用调用文件,调用定义量算工具的文件,本文使用前端框架为angular。在HTML文件中可使用如下调用:<maplibre-measure [map]="map" [draw]="draw"></maplibre-measure>
此处是调用 maplibre-measure 文件,也是我们接下来具体实现量算功能的文件。确保 map 是传进来的实例地图, draw 是地图绘图控件,二者都在初始化地图时定义好。
实现量算功能
-
接收传入的 map 及 draw 控件
@Input() public map: any; @Input() draw: any;
使用 input 装饰器接收刚才传入的 map 及 draw 。
-
调用、销毁及初始化方法
ngOnChanges(changes: SimpleChanges) { if (changes.map && !changes.map.firstChange) { this.map.on('draw.create', (event) => { const feature = event.features[0]; if (feature.geometry.type === 'LineString') { this.measureLength(feature); } else if (feature.geometry.type === 'Polygon') { this.measureArea(feature); } }); } } ngOnDestroy() { if (this.draw && this.map) { this.map.removeControl(this.draw); } } ngOnInit() {} initLine() { this.draw.deleteAll(); this.clear(); this.draw.changeMode('draw_line_string'); } initPolygon() { this.draw.deleteAll(); this.clear(); this.draw.changeMode('draw_polygon'); }
当监听到地图有变化时,判断用户绘制的是线段还是面,如果是线段调用量算长度方法,如果是面调用量算面积方法。
-
量算长度
这里实现量算线段长度并在第一个点与终点之间选择合适的位置xiameasureLength(feature: any) { if (feature && feature.geometry && feature.geometry.type === 'LineString') { const coordinates = feature.geometry.coordinates; let totalLength = 0; for (let i = 0; i < coordinates.length - 1; i++) { const point1 = turf.point([coordinates[i][0], coordinates[i][1]]); const point2 = turf.point([coordinates[i + 1][0], coordinates[i + 1][1]]); const distance = turf.distance(point1, point2, { units: 'kilometers' }); totalLength += distance; } const midpoint = { x: (coordinates[0][0] + coordinates[coordinates.length - 1][0]) / 2, y: (coordinates[0][1] + coordinates[coordinates.length - 1][1]) / 2, }; if (coordinates.length === 2) { midpoint.y -= 0.005; // 向下偏移 } const marker = { type: 'Feature', geometry: { type: 'Point', coordinates: [midpoint.x, midpoint.y], }, properties: { title: `${totalLength.toFixed(2)} 公里`, }, }; const sourceId = 'marker-source'; const layerId = 'marker-layer'; this.map.addSource(sourceId, { type: 'geojson', data: { type: 'FeatureCollection', features: [marker], }, }); this.map.addLayer({ id: 'marker-label', type: 'symbol', source: sourceId, layout: { 'text-field': ['get', 'title'], 'text-font': ['DIN Pro Italic', 'Arial Unicode MS Regular'], 'text-size': 15, }, paint: { 'text-color': '#FF0000', }, }); return totalLength.toFixed(2); } }
4.量算面积
这里实现面积计算,并在区域中央显示该数值measureArea(feature: any) { if (feature && feature.geometry && feature.geometry.type === 'Polygon') { const polygon = feature.geometry.coordinates; const area = turf.area(turf.polygon(polygon)); const areaInSqKm = area / 1000000; const centroid = turf.centroid(turf.polygon(polygon)); const marker = { type: 'Feature', geometry: centroid.geometry, properties: { title: `${areaInSqKm.toFixed(2)} 平方公里`, }, }; const sourceId = 'area-marker-source'; const layerId = 'area-marker-layer'; this.map.addSource(sourceId, { type: 'geojson', data: { type: 'FeatureCollection', features: [marker], }, }); this.map.addLayer({ id: 'area-marker-label', type: 'symbol', source: sourceId, layout: { 'text-field': ['get', 'title'], 'text-font': ['DIN Pro Italic', 'Arial Unicode MS Regular'], 'text-size': 15, }, paint: { 'text-color': '#FF0000', }, }); return areaInSqKm.toFixed(2); } }
5.clear() 方法定义
clear() { if (this.draw) { this.draw.deleteAll(); } if (this.map.getLayer('marker-label')) { this.map.removeLayer('marker-label'); } if (this.map.getLayer('area-marker-label')) { this.map.removeLayer('area-marker-label'); } if (this.map.getSource('marker-source')) { this.map.removeSource('marker-source'); } if (this.map.getSource('area-marker-source')) { this.map.removeSource('area-marker-source'); } }
HTML调用量算功能
<div class="list">
<div class="list-body">
<div class="list-grid-item list-grid-item-large">
<span (click)="initLine()"
><i class="fas fa-ruler" style="font-size: 12px; min-width: 15px; margin-right: 5px"></i> 量算长度</span
>
</div>
<div class="list-grid-item list-grid-item-large">
<span (click)="initPolygon()"
><i class="fas fa-ruler-combined" style="font-size: 12px; min-width: 15px; margin-right: 5px"></i>
量算面积</span
>
</div>
<div class="list-grid-item list-grid-item-large">
<span (click)="clear()"
><i class="fas fa-trash" style="font-size: 12px; min-width: 15px; margin-right: 5px"></i> 清除量算</span
>
</div>
</div>
</div>