atchain-mapbox-vue
Version:
A Vue 3 MapBox component library with subway lines, stations, markers and polygons support. Zero dependencies except Vue 3 and Mapbox GL JS.
263 lines (224 loc) • 5.41 kB
text/typescript
/**
* MapBox 核心地图管理
*/
import { shallowRef, type Ref } from 'vue'
import type { Map as MapboxMap } from 'mapbox-gl'
import mapboxgl from 'mapbox-gl'
// 地图实例和状态
const mapInstance = shallowRef<MapboxMap | null>(null)
const mapLoaded = shallowRef(false)
/**
* 地图配置接口
*/
export interface MapConfig {
token: string
style: string
center: [number, number]
zoom: number
container: string | HTMLElement
}
/**
* 地图事件回调接口
*/
export interface MapEventCallbacks {
onLoad?: () => void
onError?: (error: Error) => void
onMove?: () => void
onMoveEnd?: () => void
onZoom?: () => void
onZoomEnd?: () => void
}
/**
* 使用地图核心功能
*/
export const useMapBoxCore = () => {
/**
* 设置地图实例
*/
const setMapInstance = (map: MapboxMap) => {
mapInstance.value = map
mapLoaded.value = false
}
/**
* 清理地图实例
*/
const clearMapInstance = () => {
if (mapInstance.value) {
mapInstance.value.remove()
mapInstance.value = null
mapLoaded.value = false
}
}
/**
* 设置地图加载状态
*/
const setMapLoaded = (loaded: boolean) => {
mapLoaded.value = loaded
}
/**
* 创建地图实例
*/
const createMap = (config: MapConfig, callbacks: MapEventCallbacks = {}): MapboxMap => {
const {
token,
style,
center,
zoom,
container
} = config
const {
onLoad,
onError,
onMove,
onMoveEnd,
onZoom,
onZoomEnd
} = callbacks
// 设置访问令牌
mapboxgl.accessToken = token
// 创建地图
const map = new mapboxgl.Map({
container,
style,
center,
zoom
})
// 绑定事件
map.on('load', () => {
setMapLoaded(true)
onLoad?.()
})
map.on('error', (e) => {
console.error('地图加载错误:', e.error)
onError?.(e.error)
})
if (onMove) {
map.on('move', onMove)
}
if (onMoveEnd) {
map.on('moveend', onMoveEnd)
}
if (onZoom) {
map.on('zoom', onZoom)
}
if (onZoomEnd) {
map.on('zoomend', onZoomEnd)
}
// 设置实例
setMapInstance(map)
return map
}
/**
* 获取地图中心点
*/
const getMapCenter = (): [number, number] | null => {
if (!mapInstance.value) return null
const center = mapInstance.value.getCenter()
return [center.lng, center.lat]
}
/**
* 获取地图缩放级别
*/
const getMapZoom = (): number | null => {
if (!mapInstance.value) return null
return mapInstance.value.getZoom()
}
/**
* 设置地图中心点
*/
const setMapCenter = (center: [number, number], zoom?: number) => {
if (!mapInstance.value) return
if (zoom !== undefined) {
mapInstance.value.setCenter(center).setZoom(zoom)
} else {
mapInstance.value.setCenter(center)
}
}
/**
* 飞行到指定位置
*/
const flyTo = (center: [number, number], zoom?: number, options?: any) => {
if (!mapInstance.value) return
mapInstance.value.flyTo({
center,
zoom: zoom || mapInstance.value.getZoom(),
...options
})
}
/**
* 适应边界
*/
const fitBounds = (bounds: [[number, number], [number, number]], options?: any) => {
if (!mapInstance.value) return
mapInstance.value.fitBounds(bounds, options)
}
/**
* 检查地图是否已加载
*/
const isMapLoaded = (): boolean => {
return mapLoaded.value && mapInstance.value !== null
}
/**
* 检查图层是否存在
*/
const hasLayer = (layerId: string): boolean => {
if (!mapInstance.value) return false
return !!mapInstance.value.getLayer(layerId)
}
/**
* 检查数据源是否存在
*/
const hasSource = (sourceId: string): boolean => {
if (!mapInstance.value) return false
return !!mapInstance.value.getSource(sourceId)
}
/**
* 安全地移除图层
*/
const removeLayer = (layerId: string): boolean => {
if (!mapInstance.value || !hasLayer(layerId)) return false
try {
mapInstance.value.removeLayer(layerId)
return true
} catch (error) {
console.warn(`移除图层失败: ${layerId}`, error)
return false
}
}
/**
* 安全地移除数据源
*/
const removeSource = (sourceId: string): boolean => {
if (!mapInstance.value || !hasSource(sourceId)) return false
try {
mapInstance.value.removeSource(sourceId)
return true
} catch (error) {
console.warn(`移除数据源失败: ${sourceId}`, error)
return false
}
}
return {
// 状态
mapInstance: mapInstance as Readonly<Ref<MapboxMap | null>>,
mapLoaded: mapLoaded as Readonly<Ref<boolean>>,
// 核心方法
setMapInstance,
clearMapInstance,
setMapLoaded,
createMap,
// 地图操作
getMapCenter,
getMapZoom,
setMapCenter,
flyTo,
fitBounds,
// 状态检查
isMapLoaded,
hasLayer,
hasSource,
// 清理方法
removeLayer,
removeSource
}
}