React Mapbox 地图组件库,支持雷达、图像、标记、轨迹等多种 GIS 实体渲染
npm install bbl-mapbox-reactReact Mapbox 地图组件库,支持雷达、图像、标记、轨迹、多边形、折线、圆形等多种 GIS 实体的数据驱动渲染。
``bash`
pnpm add bbl-mapbox-react
`bash`
pnpm add mapbox-gl @turf/turf @svgdotjs/svg.js lodash-es dayjs eventemitter3 hotkeys-js uid pbf @mapbox/vector-tile
`tsx
import { Mapbox } from 'bbl-mapbox-react';
import 'bbl-mapbox-react/style.css';
function App() {
return (
zoom={12}
style="mapbox://styles/mapbox/dark-v11"
entities={[
{
id: 'marker-1',
type: 'marker',
center: [116.4074, 39.9042],
src: '/icon.png',
width: 32,
name: '标记点',
},
]}
/>
);
}
`
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| center | [number, number] | [116.4074, 39.9042] | 地图中心点 [经度, 纬度] |zoom
| | number | 12 | 缩放级别 |pitch
| | number | 0 | 俯仰角度 |bearing
| | number | 0 | 方位角度 |style
| | string | 'mapbox://styles/mapbox/dark-v11' | Mapbox 地图样式 URL |maxBounds
| | [[number, number], [number, number]] | - | 地图边界限制 [[西南], [东北]] |mode
| | 'display' \| 'edit' \| 'picker' | 'display' | 地图模式 |entities
| | MapEntity[] | [] | 实体数据数组 |selectedIds
| | EntityId[] | [] | 选中的实体 ID 数组 |layers
| | LayerConfig[] | [] | 自定义底图图层配置 |interactive
| | InteractionOptions | - | 交互控制配置 |showCoordinates
| | boolean \| CoordinateDisplayConfig | true | 坐标显示控件 |showScale
| | boolean \| ScaleControlConfig | true | 比例尺控件 |showResetView
| | boolean \| ResetViewControlConfig | true | 重置视图控件 |showRoadHighlight
| | boolean \| RoadHighlightControlConfig | false | 路网高亮控件 |popupDefaults
| | PopupDefaults | - | 全局 Popup 默认配置 |renderPopup
| | (entity: MapEntity) => ReactNode | - | Popup 渲染回调 |editConfig
| | EditModeConfig | - | 编辑模式配置 |pickerConfig
| | PickerModeConfig | - | 选址模式配置 |onMapLoad
| | (map: MapboxMap) => void | - | 地图加载完成回调 |onEntityClick
| | (entity: MapEntity) => void | - | 实体点击回调 |onPick
| | (result: PickerResult) => void | - | 选址回调 |onPopupOpen
| | (entityId: EntityId) => void | - | Popup 打开回调 |onPopupClose
| | (entityId: EntityId) => void | - | Popup 关闭回调 |className
| | string | - | 自定义类名 |containerStyle
| | CSSProperties | - | 容器样式 |
所有实体均继承自 BaseEntity,包含以下公共字段:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | string \| number | 唯一标识 |type
| | string | 实体类型 |name
| | string? | 显示名称 |confidence
| | number? | 置信度 0-1,影响透明度 |popup
| | PopupConfig? | Popup 配置 |center
| | [number, number]? | 中心点坐标 |customData
| | T? | 自定义附加数据 |
`ts`
{
type: 'radar',
center: [116.4074, 39.9042],
radius: 5000, // 半径(米)
sectorAngle: 60, // 扇形角度
isAnimating: true, // 是否播放扫描动画
rotationSpeed: 1, // 旋转速度(度/帧)
colorScheme: 'green', // 'blue' | 'green' | 'red' | 'purple' | 'cyan' | 'orange'
opacity: 70, // 透明度 0-100
showRings: true, // 显示距离环
showCenter: true, // 显示中心点
showScanLine: true, // 显示扫描线
}
`ts`
{
type: 'image',
center: [116.4074, 39.9042],
width: 1000, // 宽度(米),高度按比例计算
src: '/map.png', // 图片 URL
rotation: 0, // 旋转角度
}
`ts`
{
type: 'marker',
center: [116.4074, 39.9042],
src: '/icon.png', // 图标 URL
width: 32, // 宽度(像素)
rotation: 0, // 旋转角度
anchor: 'center', // 锚点位置
}
`ts`
{
type: 'unit',
center: [116.4074, 39.9042],
src: '/unit.png',
width: 40,
predicted_traj: [ // 预测轨迹
{ lon: 116.41, lat: 39.91, alt: 0 },
{ lon: 116.42, lat: 39.92, alt: 0 },
],
showTrajectory: 'all', // 轨迹显示数量:number | 'all'
showTrajectoryPoints: false, // 是否显示轨迹点
}
`ts`
{
type: 'polygon',
coordinates: [
[116.40, 39.90],
[116.41, 39.91],
[116.42, 39.90],
],
strokeColor: '#3388ff',
strokeWidth: 2,
fillColor: '#3388ff',
fillOpacity: 0.2,
}
`ts`
{
type: 'polyline',
coordinates: [
[116.40, 39.90],
[116.41, 39.91],
[116.42, 39.90],
],
strokeColor: '#3388ff',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round',
dashArray: [4, 4], // 虚线模式
}
`ts`
{
type: 'circle',
center: [116.4074, 39.9042],
radius: 1000, // 半径(米)
strokeColor: '#3388ff',
fillColor: '#3388ff',
fillOpacity: 0.2,
fillType: 'solid', // 'solid' | 'radial-gradient'
showCenterPoint: true,
gradientAnimation: 'flicker', // 'static' | 'flicker' | 'breath' | 'pulse'
isAnimating: false,
}
`ts`
{
type: 'square',
center: [116.4074, 39.9042],
length: 1000, // 边长(米)
strokeColor: '#3388ff',
fillColor: '#3388ff',
fillOpacity: 0.2,
}
`ts`
{
type: 'rectangle',
bounds: [[116.40, 39.90], [116.42, 39.92]], // 对角点
strokeColor: '#3388ff',
fillColor: '#3388ff',
fillOpacity: 0.2,
}
通过 useRef 获取组件实例,可调用以下方法:
`tsx
const mapRef = useRef
`
| 方法 | 签名 | 说明 |
|------|------|------|
| getMap | () => MapboxMap \| null | 获取 Mapbox GL 地图实例 |flyTo
| | (center, zoom?, options?) => void | 飞行到指定位置 |flyToEntities
| | (ids, zoom?, options?) => void | 飞行到指定实体 |startAnimation
| | (id) => void | 启动实体动画 |stopAnimation
| | (id) => void | 停止实体动画 |toggleAnimation
| | (id) => void | 切换实体动画状态 |openPopup
| | (id) => void | 程序化打开 Popup |closePopup
| | (id) => void | 关闭指定 Popup |closeAllPopups
| | () => void | 关闭所有 Popup |isPopupOpen
| | (id) => boolean | 检查 Popup 是否打开 |toggleUnitTrajectory
| | (ids?) => void | 切换 Unit 轨迹显示 |getMode
| | () => MapMode | 获取当前模式 |setMode
| | (mode) => void | 设置地图模式 |startDrawing
| | (options) => void | 开始绘制 |getPickedLocation
| | () => PickerResult \| null | 获取选址坐标 |clearPickedLocation
| | () => void | 清除选址坐标 |
只读查看模式,支持点击实体、Popup 展示。
编辑模式,支持在地图上绘制和放置实体。
`tsx`
editConfig={{
showEditTools: true,
showRectangleTool: true,
showCircleTool: true,
showPolygonTool: true,
showSquareTool: true,
showPolylineTool: true,
markerTemplates: [
{ id: 'drone', name: '无人机', icon: '/drone.png', width: 40 },
],
onMarkerAdd: (marker) => console.log('新增 Marker', marker),
onRectangleAdd: (rect) => console.log('新增矩形', rect),
onCircleAdd: (circle) => console.log('新增圆形', circle),
onPolygonAdd: (polygon) => console.log('新增多边形', polygon),
onSquareAdd: (square) => console.log('新增正方形', square),
onPolylineAdd: (polyline) => console.log('新增折线', polyline),
onEntityDelete: (entity) => console.log('删除实体', entity),
}}
/>
通过 Ref 的 startDrawing API 程序化触发绘制:
`tsx
// 绘制 Marker
mapRef.current?.startDrawing({
id: 'drone',
name: '无人机',
icon: '/drone.png',
width: 60,
});
// 绘制矩形
mapRef.current?.startDrawing({ mode: 'rectangle' });
// 绘制圆形(自定义样式)
mapRef.current?.startDrawing({
mode: 'circle',
circleStyle: { fillColor: '#ff0000', fillOpacity: 0.3 },
});
// 绘制多边形
mapRef.current?.startDrawing({ mode: 'polygon' });
// 绘制折线
mapRef.current?.startDrawing({ mode: 'polyline' });
`
绘制操作:
- 矩形/正方形/圆形:第一次点击设置起点/中心,第二次点击完成
- 多边形:逐点点击添加顶点,点击第一个点附近闭合,或右键完成
- 折线:逐点点击添加顶点,右键完成
- Esc 键取消当前绘制
- 右键 取消或完成绘制
选址模式,点击地图获取坐标。
`tsx选中坐标: ${result.lng}, ${result.lat}
pickerConfig={{
showMarker: true,
markerColor: '#3388ff',
showCrosshair: true,
}}
onPick={(result) => {
console.log();`
}}
/>
支持三种类型的底图图层叠加:
`tsx`
// 栅格瓦片
{
id: 'satellite',
type: 'raster',
url: 'https://example.com/tiles/{z}/{x}/{y}.png',
opacity: 0.8,
},
// Style JSON
{
id: 'custom-style',
type: 'style',
url: 'http://localhost:8080/styles/basic/style.json',
hasRoadNetwork: true,
},
// TileJSON
{
id: 'terrain',
type: 'tilejson',
url: 'http://localhost:8080/styles/terrain.json',
},
]}
/>
实体级 Popup 可通过 popup 字段配置,也可通过 renderPopup 统一渲染:
`tsx
// 实体级配置
const entities = [
{
id: '1',
type: 'marker',
center: [116.4074, 39.9042],
src: '/icon.png',
width: 32,
popup: {
content: 自定义内容,
trigger: 'click', // 'click' | 'hover'
position: 'top', // 'top' | 'bottom' | 'left' | 'right' | 'center'
animation: 'fade', // 'fade' | 'scale' | 'fade-scale' | 'none'
showCloseButton: true,
closeOnClickOutside: true,
closeOnEscape: true,
hoverDelay: 300,
},
},
];
// 全局渲染回调
renderPopup={(entity) =>
交互控制
`tsx
interactive={{
dragPan: true,
scrollZoom: true,
doubleClickZoom: true,
touchZoomRotate: true,
keyboard: true,
dragRotate: true,
pitchWithRotate: true,
touchPitch: true,
boxZoom: true,
}}
/>
`导出
`ts
// 主组件
export { Mapbox } from './Mapbox';// 类型
export type {
MapboxProps, MapboxRef, MapEntity,
RadarEntity, ImageEntity, MarkerEntity, UnitEntity,
PolygonEntity, PolylineEntity, CircleEntity, SquareEntity, RectangleEntity,
PopupConfig, PopupDefaults, LayerConfig,
InteractionOptions, MapMode, DrawMode, DrawingOptions,
MarkerTemplate, PickerResult, EditModeConfig, PickerModeConfig,
// ...更多类型
};
// 常量
export { COLOR_SCHEMES, RADAR_DEFAULTS, POPUP_DEFAULTS, ROAD_TYPE_OPTIONS };
// 子组件
export {
EntityPopup, CoordinateDisplay, ScaleControl,
ResetViewControl, RoadHighlightControl, EditControl, ContextMenu,
};
// 工具函数
export { destinationPoint, distance, bearing, mergePopupConfig, calculatePopupPosition };
// 渲染器(用于扩展)
export {
MarkerRenderer, UnitRenderer, CircleRenderer,
PolygonRenderer, PolylineRenderer, SquareRenderer, RectangleRenderer,
BaseCanvasRenderer, CanvasImageRenderer, CanvasRadarRenderer, CanvasCircleRenderer,
};
`开发
`bash
安装依赖
pnpm install启动开发服务
pnpm dev构建库
pnpm build:lib构建项目
pnpm build
``GPL-3.0