编辑
2024-03-28
MapBox
00

目录

甲、引入相关插件
乙、初始化mapboxgl初始化MapboxDraw
1)地图展示
2) 初始化map,drwa:displayControlsDefault: false
丙、重要指令
丁、准备就绪,封装绘制工具箱
1) iniMap: 初始化地图监听与赋值
2) 创建操作函数
3) 其他操作函数
戍、源码[AI生成的注释,将就看]

自定义工具箱替换@mapbox/mapbox-gl-draw自带工具箱

自定义
画线,计算长度
画面,计算面积
标注
删除

mapbox

改造后改造前
image.pngimg

目的就是为了还原UI

前端与UI早晚得打一架


  • ✅ 自定义按钮
  • ✅ 使用按钮关联事件
  • ✅ 测量距离
  • ✅ 测量面积

甲、引入相关插件

  1. mapbox-gl
  2. @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

自主申请mapboxaccess_token

1)地图展示
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> )
2) 初始化map,drwa:displayControlsDefault: false
tsx
import { 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

触发删除图层


丁、准备就绪,封装绘制工具箱

1) iniMap: 初始化地图监听与赋值

监听创建draw.create
监听更新draw.update

2) 创建操作函数

drawPolygon,drawLine,drawPoint,deleteDraw

3) 其他操作函数

clearMeasure: 清除Map上的标注,当清除Draw中图层时,需要手动清除自定义标注
getCenterOfLine: 计算中心坐标给标注插眼
createLabel: 绘制标注文本的
addLengthLabel: 添加长度标注
addAreaLabel: 添加面积标注
updateMeasure: 图层更新


戍、源码[AI生成的注释,将就看]

ts
import { 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 } }
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:还是夸张一点

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

还是夸张一点技术专栏 © 2019 - 2023 | 滇ICP备2022001556号
世间情动不过盛夏白瓷梅子汤,碎冰碰壁当啷响。