vue3-mapbox-hooks
v3.1.0
Published
Vue 3 Composition API hooks for Mapbox GL JS
Maintainers
Readme
vue3-mapbox-hooks
Vue 3 Composition API hooks for Mapbox GL JS - 一个基于 Vue 3 Composition API 的 Mapbox GL JS 封装库。
特性
- 🗺️ 完整的地图功能 - 支持栅格地图、矢量地图、天地图等多种底图
- 🎨 丰富的可视化 - 标记点、精灵图动画、热力图、轨迹播放
- ✏️ 强大的绘制工具 - 多边形、线段、矩形、圆形绘制,测距测面
- 🎯 标记点状态管理 - 支持切换/叠加模式、多状态配置的标记点选中管理
- 🎯 Vue 3 原生支持 - 基于 Composition API 设计,完美契合 Vue 3 生态
- 📦 开箱即用 - 内置 Mapbox GL JS 和 Turf.js,可按需手动引入
- 🔧 TypeScript 支持 - 完整的类型定义,提供良好的开发体验
安装
npm install vue3-mapbox-hooks快速开始
1. 基础用法
<template>
<div id="map-container" style="width: 100%; height: 500px;"></div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { useMapbox } from 'vue3-mapbox-hooks'
const { map, initMap, addMapMarker } = useMapbox('map-container', {
theme: 'darkblue',
center: [111.0498, 27.7603],
zoom: 6
})
onMounted(() => {
initMap(() => {
console.log('地图加载完成')
// 添加标记点
addMapMarker([
{ coordinates: [111.0498, 27.7603], properties: { name: '标记点1' } }
], {
icon: '/marker-icon.png',
iconSize: 0.5
}, (feature, features) => {
console.log('点击了标记点:', feature, features)
})
})
})
</script>2. 标记点选中切换管理
<script setup lang="ts">
import { onMounted } from 'vue'
import { useMapbox, useMarkerToggle, type UseMarkerToggleReturn } from 'vue3-mapbox-hooks'
const mapbox = useMapbox('map-container')
const { initMap } = mapbox
let markerManager: UseMarkerToggleReturn
onMounted(() => {
initMap(() => {
// 创建标记点切换管理器
markerManager = useMarkerToggle(mapbox, {
normalLayer: {
layerId: 'marker-normal',
icon: { type: 'static', url: '/marker-normal.png' },
iconSize: 0.8
},
selectedLayer: {
layerId: 'uav-selected',
icon: { type: 'static', url: '/marker-selected.png' },
iconSize: 1.0
},
onClick: (feature) => {
console.log('点击了标记点:', feature)
}
})
// 初始化标记点
markerManager.initMarkers([
{ id: 'marker-1', coordinates: [111.0, 27.0], name: '标记点1' },
{ id: 'marker-2', coordinates: [111.5, 27.5], name: '标记点2' }
])
})
})
// 选中标记点(切换模式)
const selectMarker = (id: string) => {
markerManager?.selectMarker(id)
}
// 使用叠加模式选中
const selectMarkerOverlay = (id: string) => {
markerManager?.selectMarkerOverlay(id, { position: 'above' })
}
// 取消选中
const deselect = () => {
markerManager?.deselectMarker()
}
</script>3. 多状态标记点管理
<script setup lang="ts">
import { useMapbox, useMarkerToggle } from 'vue3-mapbox-hooks'
const mapbox = useMapbox('map-container')
// 多状态配置:正常、告警、危险
const markerManager = useMarkerToggle(mapbox, {
normalLayer: {
layerId: 'marker-normal',
icon: { type: 'static', url: '/marker-normal.png' },
iconSize: 0.8
},
selectedLayer: [
{ layerId: 'marker-selected', icon: { type: 'static', url: '/marker-selected.png' } },
{ layerId: 'marker-warning', icon: { type: 'static', url: '/marker-warning.png' } },
{ layerId: 'marker-danger', icon: { type: 'static', url: '/marker-danger.png' } }
]
})
// 使用不同状态
markerManager.initMarkers([{ id: 'd1', coordinates: [111.0, 27.0] }])
// 切换到告警状态(索引1)
markerManager.selectMarkerByIndex('d1', 1)
// 危险状态 + 叠加模式
markerManager.selectMarkerOverlayByIndex('d1', 2, { position: 'above' })
</script>4. 使用绘制工具
使用方法一:通过 useMapbox 创建
<script setup lang="ts">
import { useMapbox } from 'vue3-mapbox-hooks'
const { map, initMap, createDrawTool } = useMapbox('map-container')
let drawTool: any
onMounted(() => {
initMap(() => {
drawTool = createDrawTool()
})
})
// 绘制多边形
const drawPolygon = () => {
drawTool?.drawPolygon('polygon-layer', (coordinates) => {
console.log('绘制完成:', coordinates)
})
}
// 测量距离
const measureDistance = () => {
drawTool?.measureDistance('measure-layer')
}
// 清除所有绘制
const clearAll = () => {
drawTool?.clearMeasureAll()
}
......
</script>使用方法二:使用 useDrawTool Hook
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useMapbox, useDrawTool, type UseDrawToolReturn } from 'vue3-mapbox-hooks'
const { map, initMap } = useMapbox('map-container')
let drawTool: UseDrawToolReturn
onMounted(() => {
initMap(() => {
if (map.value) {
drawTool = useDrawTool(map.value)
}
})
})
// 绘制多边形
const drawPolygon = () => {
drawTool?.drawPolygon('polygon-layer', (coordinates) => {
console.log('绘制完成:', coordinates)
})
}
// 测量距离
const measureDistance = () => {
drawTool?.measureDistance('measure-layer')
}
// 清除所有绘制
const clearAll = () => {
drawTool?.clearMeasureAll()
}
......
</script>5. 轨迹播放
使用方法一:通过 useMapbox 创建
<script setup lang="ts">
import { useMapbox } from 'vue3-mapbox-hooks'
const { map, initMap, createLineTrack } = useMapbox('map-container')
let track: any
onMounted(() => {
initMap(() => {
const points = [
{ coordinates: [111.0, 27.0] },
{ coordinates: [111.5, 27.5] },
{ coordinates: [112.0, 28.0] }
]
track = createLineTrack(points, {
icon: '/car-icon.png'
})
})
})
// 控制播放
const startTrack = () => track?.start()
const pauseTrack = () => track?.pause()
const resetTrack = () => track?.reset()
</script>使用方法二:使用 useLineTrack Hook
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useMapbox, useLineTrack } from 'vue3-mapbox-hooks'
const { map, initMap } = useMapbox('map-container')
// 轨迹坐标点
const trackPoints = ref([
{ coordinates: [111.0, 27.0] },
{ coordinates: [111.5, 27.5] },
{ coordinates: [112.0, 28.0] },
{ coordinates: [112.5, 28.5] }
])
// 创建轨迹播放器
const {
isPlay, // 是否正在播放
progress, // 播放进度 0-100
start, // 开始播放
pause, // 暂停播放
restart, // 继续播放
reset, // 重置轨迹
seekTo // 跳转到指定进度
} = useLineTrack(map, trackPoints, {
icon: '/car-icon.png',
routeColor: '#A01F05',
realRouteColor: '#a53a25',
lineWidth: 6,
carIconSize: 0.25,
arrowIconSize: 0.4
})
onMounted(() => {
initMap(() => {
// 地图加载完成后可以开始播放
// start()
})
})
</script>
<template>
<div id="map-container" style="width: 100%; height: 500px;"></div>
<!-- 播放控制面板 -->
<div class="track-controls">
<button @click="start" :disabled="isPlay">播放</button>
<button @click="pause" :disabled="!isPlay">暂停</button>
<button @click="reset">重置</button>
<span>进度: {{ progress }}%</span>
<input
type="range"
min="0"
max="100"
:value="progress"
@input="e => seekTo(Number(e.target.value))"
/>
</div>
</template>API 文档
useMapbox Hook
核心 Hook,提供地图初始化和基础操作能力。
const {
map, // 地图实例 Ref
initMap, // 初始化地图
switchRasterLayer, // 切换栅格底图
switchMapVectorTheme, // 切换矢量主题
addMapMarker, // 添加标记点
addMapSpriteMarker, // 添加精灵图标记(动画)
addMapHeatmap, // 添加热力图
removeMapLayerAndSourceByLayerId, // 删除图层
createDrawTool, // 创建绘制工具
createLineTrack, // 创建轨迹实例
getMapInstance, // 获取地图实例
destroyMap // 销毁地图
} = useMapbox(el: string, options?: MapboxConfig)MapboxConfig 配置项
| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | theme | string | 'darkblue' | 矢量地图主题 | | center | [number, number] | [111.0498, 27.7603] | 地图中心点 [lng, lat] | | zoom | number | 6 | 初始缩放级别 | | minZoom | number | 7 | 最小缩放级别 | | maxZoom | number | 18 | 最大缩放级别 |
useMarkerToggle Hook
标记点状态管理 Hook,支持切换/叠加模式、多状态配置。
const manager = useMarkerToggle(mapbox: UseMapboxReturn, options: MarkerToggleOptions)参数说明
| 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | mapbox | UseMapboxReturn | ✓ | useMapbox Hook 返回的对象 | | options | MarkerToggleOptions | ✓ | 标记点切换配置选项 |
MarkerToggleOptions 配置项
| 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | normalLayer | LayerConfig | ✓ | 非选中状态图层配置 | | selectedLayer | SelectedLayerConfig | ✓ | 选中状态图层配置(支持单配置或数组) | | onClick | function | - | 点击回调函数 |
LayerConfig 图层配置
interface LayerConfig {
layerId: string // 图层ID
icon: IconConfig // 图标配置
iconSize?: number // 图标大小,默认0.8
cluster?: boolean // 是否聚合,默认false
}
// 图标配置
type IconConfig =
| { type: 'static'; url: string } // 静态图标
| { type: 'sprite'; url: string; frameCount: number; frameWidth: number; frameHeight: number; fps?: number } // 精灵图UseMarkerToggleReturn 返回方法
| 方法 | 说明 |
|------|------|
| initMarkers(markerList, callback) | 初始化标记点(批量添加) |
| addMarker(marker, autoSelect, useOverlay, stateIndex, callback) | 添加单个标记点 |
| removeMarker(markerId) | 移除单个标记点 |
| selectMarker(markerId, callback) | 选中标记点(切换模式) |
| selectMarkerByIndex(markerId, stateIndex, callback) | 多状态切换模式 |
| selectMarkerOverlay(markerId, overlayOptions, callback) | 叠加模式选中 |
| selectMarkerOverlayByIndex(markerId, stateIndex, overlayOptions, callback) | 多状态叠加模式 |
| deselectMarker() | 取消选中 |
| toggleSelect(markerId, callback) | 切换选中状态 |
| toggleSelectByIndex(markerId, stateIndex, callback) | 多状态切换 |
| toggleSelectOverlay(markerId, overlayOptions, callback) | 叠加模式切换 |
| toggleSelectOverlayByIndex(markerId, stateIndex, overlayOptions, callback) | 多状态叠加切换 |
| updatePosition(markerId, newCoordinates, callback) | 更新标记点位置 |
| updateData(markerId, newData, callback) | 更新标记点数据 |
| clearAll() | 清除所有标记点 |
| getAllMarkers() | 获取所有标记点 |
| getMarker(markerId) | 获取指定标记点 |
状态属性(Ref)
| 属性 | 类型 | 说明 | |------|------|------| | selectedId | Ref<string | number | null> | 当前选中的标记点ID | | selectedMarker | Ref<MarkerData | null> | 选中状态的标记点数据 | | currentStateIndex | Ref | 当前使用的选中配置索引 | | isOverlayMode | Ref | 是否处于叠加模式 |
useDrawTool Hook
绘制工具 Hook,提供丰富的地图绘制和测量功能。
const drawTool = useDrawTool(map: mapboxgl.Map, options?: UseDrawToolOptions)参数说明
| 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | map | mapboxgl.Map | ✓ | 地图实例 | | options | UseDrawToolOptions | - | 绘制工具配置选项 |
响应式状态
| 属性 | 类型 | 说明 |
|------|------|------|
| isDrawing | Ref | 是否正在绘制 |
| layerIdList | Ref<string[]> | 当前绘制的图层ID列表 |
| graphicColor | Ref | 绘制颜色 |
| graphicOpacity | Ref | 绘制透明度 |
| bufferDistance | Ref | 缓冲区距离(米) |
方法
| 方法 | 说明 |
|-----------------------------------------------------|------------|
| drawPolygon(layerId, callback, clickLayerEvent) | 绘制多边形 |
| drawLine(layerId, callback) | 绘制线段 |
| drawRectangle(layerId, callback, clickLayerEvent) | 绘制矩形 |
| drawCircle(layerId, callback, clickLayerEvent) | 绘制圆形 |
| drawSector(layerId, callback, clickLayerEvent) | 绘制扇形 |
| drawBuffer(layerId, callback, clickLayerEvent) | 绘制线周边(缓冲区) |
| measureDistance(layerId) | 测量距离 |
| measureArea(layerId) | 测量面积 |
| getMapLocation(layerId, callback) | 地图取点 |
| showGraphic(layerId, coordinates, parts, options) | 回显图形 |
| drawCircleByCenterAndRadius(layerId, options, callback) | 通过中心点和半径绘制圆形 |
| drawRadiusMark(layerId, options) | 绘制半径标注(带刻度尺) |
| clearForLayerIds(layerIds) | 清除指定图层 |
| clearMeasureAll() | 清除所有测量 |
| setGraphicColor(color) | 设置绘制颜色 |
| setGraphicOpacity(opacity) | 设置绘制透明度 |
| setBufferDistance(distance) | 设置缓冲区距离 |
useLineTrack 轨迹播放 Hook
实现轨迹动画播放功能,支持响应式状态、进度控制和自动资源清理。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| map | Ref<mapboxgl.Map \| null> | ✓ | 地图实例 |
| points | Ref<Point[]> \| Point[] | ✓ | 轨迹坐标点数组 |
| options | Partial<UseLineTrackOptions> | - | 配置选项 |
UseLineTrackOptions 配置项
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| layerId | string | 时间戳 | 图层ID前缀 |
| icon | string \| null | null | 车辆图标URL |
| routeColor | string | '#A01F05' | 规划路线颜色 |
| realRouteColor | string | '#a53a25' | 已行驶路线颜色 |
| lineWidth | number | 6 | 路线宽度 |
| carIconSize | number | 0.25 | 车辆图标大小 |
| arrowIconSize | number | 0.4 | 箭头图标大小 |
| arrowSpacing | number | 50 | 箭头间距 |
| interpolationSteps | number | 2000 | 动画插值步数,值越大动画越平滑 |
响应式状态
| 属性 | 类型 | 说明 |
|------|------|------|
| isPlay | Ref<boolean> | 是否正在播放 |
| counter | Ref<number> | 当前动画步数 |
| steps | Ref<number> | 总步数(插值后) |
| aLength | Ref<number> | 原始坐标点数量 |
| progress | Ref<number> | 播放进度 0-100% |
方法
| 方法 | 说明 |
|------|------|
| start() | 开始播放轨迹(首次调用会初始化图层) |
| pause() | 暂停播放 |
| restart() | 继续播放(已结束则从头开始) |
| reset() | 重置轨迹到起点 |
| seekTo(percent: number) | 跳转到指定进度(0-100) |
| clearAllLayers() | 清除所有图层和资源 |
工具函数
// 地图加载
import {
initMap,
loadRasterMap,
loadVectorMap,
loadTiandituMap
} from 'vue3-mapbox-hooks'
// 标记点操作
import {
addMarker,
removeMarker,
addSpriteMarker
} from 'vue3-mapbox-hooks'
// 图层切换
import {
changeRasterMapLayer,
changeMapVectorTheme
} from 'vue3-mapbox-hooks'
// 热力图
import { addHeatmap } from 'vue3-mapbox-hooks'
// 通用工具
import {
groupBy,
countDuplicates,
findMinPointByCoordinates,
getCenterPoints,
parseJSONStrings
} from 'vue3-mapbox-hooks'
// 配置
import {
mapConfig,
setMapConfig,
setRasterMapConfigs
} from 'vue3-mapbox-hooks'全局加载器
如需使用内置Mapbox GL JS 和 Turf.js:
import { loadMapboxLibs, loadMapboxGL, loadTurf } from 'vue3-mapbox-hooks'
import 'vue3-mapbox-hooks/dist/mapbox-gl.css'
// 加载所有库
await loadMapboxLibs()
// 或分别加载
await loadMapboxGL()
await loadTurf()主题样式
内置 5 种矢量地图主题:
normal- 标准地图fresh- 清新地图night- 夜间地图lightblue- 浅蓝地图darkblue- 深蓝地图(默认)
// 切换主题
const { switchMapVectorTheme } = useMapbox('map-container')
switchMapVectorTheme('night')类型定义
完整的 TypeScript 类型支持:
import type {
// Core Hooks
UseMapboxReturn,
UseMarkerToggleReturn,
UseDrawToolReturn,
UseLineTrackReturn,
// Marker Toggle Types
MarkerData,
IconType,
StaticIconConfig,
SpriteIconConfig,
IconConfig,
LayerConfig,
OverlayLayerConfig,
SelectedLayerConfig,
MarkerToggleOptions,
OverlayOptions,
MultiStateOptions,
// Draw Tool Types
UseDrawToolOptions,
DrawRadiusMarkOptions,
DrawCircleByCenterOptions,
GraphicOptions,
// LineTrack Types
UseLineTrackOptions,
// Core Types
MapboxConfig,
Point,
MarkerOptions,
HeatmapOptions,
LineTrackInstance
} from 'vue3-mapbox-hooks'目录结构
vue3-mapbox-hooks/
├── src/
│ ├── core/
│ │ ├── useMapbox.ts # 核心地图 Hook
│ │ ├── useMarkerToggle.ts # 标记点切换管理 Hook
│ │ ├── useDrawTool.ts # 绘制工具 Hook
│ │ └── useLineTrack.ts # 轨迹播放 Hook
│ ├── utils/
│ │ ├── loadMap.ts # 地图加载函数
│ │ ├── common.ts # 通用工具函数
│ │ └── config.ts # 配置文件
│ ├── types/
│ │ └── mapbox.ts # 类型定义
│ ├── assets/
│ │ ├── mapboxstyle/ # 地图样式文件
│ │ ├── map-glyphs/ # 字体文件
│ │ ├── css/ # 样式文件
│ │ └── images/ # 图片资源
│ ├── index.ts # 入口文件
│ ├── global-loader.ts # 全局加载器
│ ├── mapbox-gl.js # Mapbox GL JS
│ └── turf.min.js # Turf.js
├── dist/ # 构建输出
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md依赖
- Peer Dependencies: Vue ^3.0.0
- Bundled: Mapbox GL JS, Turf.js
许可证
关键词: vue3, mapbox, hooks, composition-api, gis, 地图, 可视化, marker-toggle
