自定义工具箱替换@mapbox/mapbox-gl-draw
自带工具箱
自定义
画线
,计算长度
画面
,计算面积
标注
删除
改造后 | 改造前 |
---|---|
目的就是为了还原UI
前端与UI早晚得打一架
mapbox-gl
@mapbox/mapbox-gl-draw
tsx import mapboxgl from 'mapbox-gl'
import MapboxDraw from "@mapbox/mapbox-gl-draw";
import 'mapbox-gl/dist/mapbox-gl.css';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
mapboxgl
初始化MapboxDraw
自主申请
mapbox
的access_token
tsx const mapContainer = useRef<mapboxgl.Map | null>(null);
const map = useRef<MapboxDraw | null>(null);
return (
<div className="w-full h-full relative">
<div ref={mapContainer} className="w-full h-full"/>
</div>
)
map
,drwa
:displayControlsDefault: false
tsximport { useMapToolBarHook } from "@/hooks/map-toolbar-hook";
const {initMap, drawPolygon, deleteDraw, drawLine, drawPoint} = useMapToolBarHook()
// 初始化Draw, 设置displayControlsDefault: false
// 注意: MapboxDraw初始化放到hooks中不生效,缘由可能可能是在hooks初始化时 无法与地图关联生成相关API
const DrawControl: MapboxDraw = new MapboxDraw({
displayControlsDefault: false ,
controls: {
line_string: false,
polygon: false,
trash: false
}
});
useEffect(( => {
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: mapbox://styles/xxxxxx,
zoom: 10,
projection: 'equirectangular'
});
map.current.on('load', function () {
initMap(map.current, DrawControl);
});
}, []))
监听创建
draw.create
监听更新
draw.update
触发画面
draw_polygon
触发划线
draw_line_string
触发画标注
draw_point
触发删除图层
iniMap
: 初始化地图监听与赋值监听创建
draw.create
监听更新draw.update
drawPolygon
,drawLine
,drawPoint
,deleteDraw
clearMeasure
: 清除Map上的标注,当清除Draw中图层时,需要手动清除自定义标注
getCenterOfLine
: 计算中心坐标给标注插眼
createLabel
: 绘制标注文本的
addLengthLabel
: 添加长度标注
addAreaLabel
: 添加面积标注
updateMeasure
: 图层更新
[AI生成的注释,将就看]
tsimport { useRef } from "react";
import MapboxDraw from "@mapbox/mapbox-gl-draw";
import { FeaturesMeta, MapLabelMeta } from "@/types/map-features";
import * as turf from '@turf/turf';
import { AllGeoJSON, Feature, FeatureCollection, Geometry, GeometryCollection, LineString } from "@turf/turf";
export const useMapToolBarHook = () => {
const useMap = useRef<mapboxgl.Map | null>(null);
const DrawControl = useRef<MapboxDraw | null>(null);
/**
* 函数“clearMeasure”使用提供的ID从地图中删除图层和源。
* @param {string} [id] - “clearMeasure”函数中的“id”参数是一个字符串,表示要从地图中删除的图层和源的标识符。
*/
const clearMeasure = (id?: string) => {
try {
useMap.current.removeLayer(id);
useMap.current.removeSource(id);
}catch (error) {
console.log(error);
}
}
/**
* `initMap` 函数使用绘图控件和用于测量要素的事件侦听器来初始化地图。
* @param map - `map` 参数是 Mapbox GL JS 地图对象的实例。它表示您要在其上初始化 Mapbox Draw 控件以绘制和编辑要素的地图。
* @param {MapboxDraw} drawControl - `drawControl` 参数是 MapboxDraw
* 控件的一个实例,该控件允许用户在地图上绘制点、线和多边形等形状。它提供了在地图上绘制和编辑要素的工具。
*/
const initMap = (map: mapboxgl.Map, drawControl: MapboxDraw) => {
useMap.current = map;
DrawControl.current = drawControl
useMap.current.addControl(DrawControl.current);
useMap.current.on('draw.create', createMeasure);
useMap.current.on('draw.update', updateMeasure);
useMap.current.on('draw.changeMode', clearMeasure);
}
/**
* 函数“getCenterOfLine”计算给定线几何形状的中点坐标。
* @param {Feature<any> | FeatureCollection<any> | GeometryCollection} coords - getCenterOfLine 函数中的
* coords 参数表示 GeoJSON 对象,可以是以下类型之一:Feature<any>、FeatureCollection<any> 或
* GeometryCollection。该参数用于计算Geo表示的线的中心点
* @returns `getCenterOfLine` 函数返回由 `coords` 参数表示的给定线的中点坐标。
*/
const getCenterOfLine = (coords: Feature<any> | FeatureCollection<any> | GeometryCollection) => {
const totalLength: number = turf.length(coords, { units: 'kilometers' });
const midPoint = turf.along(coords as Feature<LineString> | LineString, totalLength / 2);
return midPoint.geometry.coordinates;
}
/**
* 函数“createLabel”使用 Mapbox GL JS 在地图上生成具有指定文本和坐标的标签特征。
* @param {string} text - createLabel 函数中的 text 参数是一个字符串,表示将在地图上显示的标签的文本内容。
* @param {Feature<any> | FeatureCollection<any> | GeometryCollection} coords -
* “createLabel”函数中的“coords”参数应为 GeoJSON 要素、要素集合或几何集合,表示应放置标签的坐标。它的类型应该是 `Feature<any> |特征集合<任意>
* |几何集合`.
* @param {FeaturesMeta} feature -
* “createLabel”函数中的“feature”参数的类型为“FeaturesMeta”。它用于提供有关地图应用程序中特定功能的元数据信息。此元数据可以包括要素
* ID、其属性以及与其关联的任何其他相关信息等详细信息。
* @returns `createLabel` 函数返回 `label` 对象,它是一个 GeoJSON
* FeatureCollection,包含单个要素,该要素具有表示指定坐标处标签文本的点几何图形。标签对象还可以使用 Mapbox GL JS 库作为源和图层添加到地图中。
*/
const createLabel = (text: string, coords: Feature<any> | FeatureCollection<any> | GeometryCollection, feature: FeaturesMeta) => {
const _id = `label-${feature.id}`;
const label = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: coords
},
properties: {
text
}
}
]
};
useMap.current.addSource(_id, { data: label as any, type: 'geojson' });
useMap.current.addLayer({
id: _id,
source: _id,
type: 'symbol',
layout: {
'text-field': ['get', 'text'],
'text-size': 16,
'text-offset': [0, -1]
},
paint: {
'text-color': '#ffffff'
}
});
return label;
}
/**
* 函数“addLengthLabel”计算以公里为单位的长度,创建带有长度的标签,并将其与地图上的特定要素关联起来。
* @param {number} length - “length”参数是一个数字,表示需要格式化并以公里为单位显示的长度值。
* @param {Feature<any> | FeatureCollection<any> | GeometryCollection} coords - `addLengthLabel` 函数中的
* `coords` 参数应该是一个 GeoJSON 对象,表示单个要素 (`Feature`) 或要素集合 (`FeatureCollection`) 或几何图形集合
* (`GeometryCollection`)。该参数用于指定标签所在的地理坐标
* @param {FeaturesMeta} feature - `addLengthLabel` 函数中的 `feature` 参数属于 `FeaturesMeta`
* 类型。它用于提供有关要添加长度标签的特征的其他元数据或信息。此元数据可能包括特征类型、其属性或任何其他相关
*/
const addLengthLabel = (length: number, coords: Feature<any> | FeatureCollection<any> | GeometryCollection, feature: FeaturesMeta) => {
const label = `${length.toFixed(2)} km`;
createLabel(label, coords, feature)
}
/**
* `addAreaLabel` 函数计算要素的面积并创建面积以平方公里为单位的标签。
* @param {number} area - “area”参数是一个代表面积(以平方公里为单位)的数字。
* @param {Feature<any> | FeatureCollection<any> | GeometryCollection} coords - `addAreaLabel` 函数中的
* `coords` 参数应该是一个 GeoJSON 对象,表示单个要素 (`Feature`)、要素集合 (`FeatureCollection`) 或几何图形集合
* (`GeometryCollection`)。它用于指定地理坐标或几何图形
* @param {FeaturesMeta} feature - `addAreaLabel` 函数中的 `feature` 参数属于 `FeaturesMeta`
* 类型。它用于提供有关地图或地理环境中特定特征的附加元数据或信息。此信息可用于增强该特征的可视化或交互。
*/
const addAreaLabel = (area: number, coords: Feature<any> | FeatureCollection<any> | GeometryCollection, feature: FeaturesMeta)=> {
const label = `${area.toFixed(2)} km²`;
createLabel(label, coords, feature)
}
const createMeasure = (e: any,) => {
updateMeasure(e, true)
}
/**
* 函数“updateMeasure”接收一个要素对象,根据几何类型计算长度或面积,并将带有测量值的标签添加到地图上。
* @param {any} e - updateMeasure 函数中的 e
* 参数通常是一个事件对象,其中包含有关触发该函数的事件的信息。在这种情况下,“e”似乎应该有一个“features”属性,它是一个特征数组。然后该函数提取第一个
* @param [iscreate=false] - updateMeasure 函数中的 iscreate
* 参数是一个布尔参数,用于确定是否正在创建新的测量。当“iscreate”设置为“true”时,表示正在创建新的测量。如果设置了“iscreate”
* @returns `updateMeasure` 函数不显式返回任何值。它是一个空函数,根据输入参数和提供的功能执行某些操作。
*/
const updateMeasure = (e: any, iscreate = false) => {
const features: FeaturesMeta = e.features[0];
if(!features)return;
// 清除旧的标注
!iscreate && clearMeasure(`label-${features.id}`);
const getGeometryHandler = {
LineString: (feature: FeaturesMeta) => {
const length = turf.length(feature as Feature<any> | FeatureCollection<any> | GeometryCollection, { units: 'kilometers' });
const coords: any = getCenterOfLine(feature as Feature<any> | FeatureCollection<any> | GeometryCollection);
addLengthLabel(length, coords, feature);
},
Polygon: (feature: FeaturesMeta) => {
const area = turf.area(feature as Feature<any> | FeatureCollection<any> | Geometry) / 1000000; // 平方千米
const coords: any = turf.centroid(feature as unknown as AllGeoJSON).geometry.coordinates;
addAreaLabel(area, coords, feature);
},
};
const { type } = features.geometry;
const handler = getGeometryHandler[type];
if (handler) {
handler(features);
}
}
/**
* “drawPolygon”函数更改使用 DrawControl 绘制多边形的模式。
*/
const drawPolygon = () => {
DrawControl.current.changeMode('draw_polygon');
}
/**
* “drawLine”函数将 DrawControl 的模式更改为“draw_line_string”。
*/
const drawLine = () => {
DrawControl.current.changeMode('draw_line_string');
}
/**
* `drawPoint` 函数将 DrawControl 的模式更改为“draw_point”。
*/
const drawPoint = () => {
DrawControl.current.changeMode('draw_point');
}
/**
* “deleteDraw”函数删除地图上选定的绘制要素,并清除任何关联的测量(如果适用)。
* @returns 如果 `_id` 为真且其长度为 0,则不会返回任何内容,因为函数将提前退出。否则,函数将使用 `DrawControl.current.delete(_id)` 方法删除所选特征。
*/
const deleteDraw = () => {
let _id = DrawControl.current.getSelectedIds();
if(_id && _id.length === 0)return;
const _point: MapLabelMeta = DrawControl.current.getSelected();
_point.features.length > 0 && _point.features[0].geometry.type !== "Point" && clearMeasure(`label-${_id[0]}`);
DrawControl.current.delete(_id)
}
return {
initMap,
drawPolygon,
deleteDraw,
drawLine,
drawPoint
}
}
本文作者:还是夸张一点
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!