UNPKG

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.

185 lines (160 loc) 4.29 kB
/** * MapBox 工具函数 */ import type { Position } from 'geojson' import { EARTH_RADIUS_KM } from './useMapBoxConstants' /** * 角度转弧度 */ export const toRadians = (value: number): number => (value * Math.PI) / 180 /** * 计算两点间的距离(公里) * 使用 Haversine 公式 */ export const haversineDistanceKm = (coordA: Position, coordB: Position): number => { const [lngA, latA] = coordA as [number, number] const [lngB, latB] = coordB as [number, number] const dLat = toRadians(latB - latA) const dLng = toRadians(lngB - lngA) const lat1 = toRadians(latA) const lat2 = toRadians(latB) const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLng / 2) * Math.sin(dLng / 2) * Math.cos(lat1) * Math.cos(lat2) const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) return EARTH_RADIUS_KM * c } /** * 检查坐标是否在指定中心点和半径范围内 */ export const isWithinRadius = ( coord: Position, center: Position, radiusKm: number ): boolean => { return haversineDistanceKm(coord, center) <= radiusKm } /** * 过滤在指定范围内的要素 */ export const filterFeaturesByRadius = <T extends { geometry: { coordinates: Position } }>( features: T[], center: Position, radiusKm: number ): T[] => { return features.filter(feature => isWithinRadius(feature.geometry.coordinates, center, radiusKm) ) } /** * 延时执行函数 */ export const delay = (ms: number): Promise<void> => { return new Promise(resolve => setTimeout(resolve, ms)) } /** * 安全的 JSON 解析 */ export const safeJsonParse = (jsonString: string, fallback: any = null): any => { try { return JSON.parse(jsonString) } catch (error) { console.warn('JSON 解析失败:', error) return fallback } } /** * 深度合并对象 */ export const deepMerge = <T extends Record<string, any>>(target: T, source: Partial<T>): T => { const result = { ...target } for (const key in source) { if (source.hasOwnProperty(key)) { const sourceValue = source[key] const targetValue = result[key] if ( sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue) && targetValue && typeof targetValue === 'object' && !Array.isArray(targetValue) ) { result[key] = deepMerge(targetValue, sourceValue) } else { result[key] = sourceValue as T[Extract<keyof T, string>] } } } return result } /** * 防抖函数 */ export const debounce = <T extends (...args: any[]) => any>( func: T, wait: number ): ((...args: Parameters<T>) => void) => { let timeout: number | null = null return (...args: Parameters<T>) => { if (timeout) { clearTimeout(timeout) } timeout = setTimeout(() => { func(...args) }, wait) } } /** * 节流函数 */ export const throttle = <T extends (...args: any[]) => any>( func: T, wait: number ): ((...args: Parameters<T>) => void) => { let lastTime = 0 return (...args: Parameters<T>) => { const now = Date.now() if (now - lastTime >= wait) { lastTime = now func(...args) } } } /** * 生成唯一 ID */ export const generateId = (prefix: string = 'mapbox'): string => { return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` } /** * 验证坐标格式 */ export const isValidCoordinate = (coord: any): coord is [number, number] => { return ( Array.isArray(coord) && coord.length === 2 && typeof coord[0] === 'number' && typeof coord[1] === 'number' && !isNaN(coord[0]) && !isNaN(coord[1]) && coord[0] >= -180 && coord[0] <= 180 && coord[1] >= -90 && coord[1] <= 90 ) } /** * 验证 GeoJSON 要素 */ export const isValidGeoJSONFeature = (feature: any): boolean => { return ( feature && typeof feature === 'object' && feature.type === 'Feature' && feature.geometry && typeof feature.geometry === 'object' && feature.geometry.type && feature.geometry.coordinates ) }