182 lines
5.7 KiB
JavaScript
182 lines
5.7 KiB
JavaScript
// 腾讯静态地图API工具类
|
|
const QQMAP_KEY = 'RO5BZ-ECZ63-7US3C-RT5QW-TIDZE-2FF35'
|
|
|
|
class StaticMapUtil {
|
|
constructor() {
|
|
this.key = QQMAP_KEY
|
|
this.baseUrl = 'https://apis.map.qq.com/ws/staticmap/v2/'
|
|
}
|
|
|
|
/**
|
|
* 生成静态地图URL
|
|
* @param {Object} options 地图配置选项
|
|
* @returns {String} 静态地图URL
|
|
*/
|
|
generateMapUrl(options = {}) {
|
|
const defaultOptions = {
|
|
center: '39.916527,116.397128', // 默认中心点(北京)
|
|
zoom: 13, // 缩放级别
|
|
size: '750*500', // 图片尺寸
|
|
scale: 2, // 高清显示
|
|
markers: [], // 标记点
|
|
labels: [], // 文字标注
|
|
paths: [], // 路径
|
|
traffic: 0, // 交通路况 0-不显示 1-显示
|
|
format: 'png' // 图片格式
|
|
}
|
|
|
|
const config = { ...defaultOptions, ...options }
|
|
|
|
let url = `${this.baseUrl}?key=${this.key}`
|
|
url += `¢er=${config.center}`
|
|
url += `&zoom=${config.zoom}`
|
|
url += `&size=${config.size}`
|
|
url += `&scale=${config.scale}`
|
|
|
|
// 腾讯地图添加标记点
|
|
if (config.markers && config.markers.length > 0) {
|
|
config.markers.forEach((marker, index) => {
|
|
url += `&markers=size:${marker.size || 'medium'}|color:${marker.color || '0x2196F3'}|label:${marker.label || ' '}|${marker.latitude},${marker.longitude}`
|
|
})
|
|
}
|
|
|
|
// 添加路径
|
|
if (config.paths && config.paths.length > 0) {
|
|
const pathsStr = config.paths.map(path => {
|
|
let pathStr = `color:${path.color || '0xFF0000'}|weight:${path.weight || 5}|`
|
|
pathStr += path.points.map(point => `${point.latitude},${point.longitude}`).join(';')
|
|
return pathStr
|
|
}).join('|')
|
|
url += `&path=${encodeURIComponent(pathsStr)}`
|
|
}
|
|
|
|
return url
|
|
}
|
|
|
|
/**
|
|
* 为场地列表生成静态地图URL
|
|
* @param {Array} positions 场地列表
|
|
* @param {Object} options 额外选项
|
|
* @returns {String} 静态地图URL
|
|
*/
|
|
generatePositionsMapUrl(positions = [], options = {}) {
|
|
if (!positions || positions.length === 0) {
|
|
return this.generateMapUrl(options)
|
|
}
|
|
|
|
// 计算地图中心点和缩放级别
|
|
const center = this.calculateCenter(positions)
|
|
const zoom = this.calculateOptimalZoom(positions, center)
|
|
|
|
// 生成标记点
|
|
const markers = positions.map((position, index) => ({
|
|
longitude: parseFloat(position.longitude),
|
|
latitude: parseFloat(position.latitude),
|
|
size: 'medium',
|
|
color: position.status === 'online' ? '0x4CAF50' : '0xF44336',
|
|
label: String.fromCharCode(65 + (index % 26)) // A, B, C...
|
|
}))
|
|
|
|
return this.generateMapUrl({
|
|
center: `${center.latitude},${center.longitude}`,
|
|
zoom: zoom,
|
|
markers: markers,
|
|
...options
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 计算多个点的中心位置
|
|
* @param {Array} positions 位置数组
|
|
* @returns {Object} 中心点坐标
|
|
*/
|
|
calculateCenter(positions) {
|
|
if (positions.length === 0) {
|
|
return { longitude: 116.397128, latitude: 39.916527 }
|
|
}
|
|
|
|
const validPositions = positions.filter(p => p.longitude && p.latitude)
|
|
if (validPositions.length === 0) {
|
|
return { longitude: 116.397128, latitude: 39.916527 }
|
|
}
|
|
|
|
if (validPositions.length === 1) {
|
|
return {
|
|
longitude: parseFloat(validPositions[0].longitude),
|
|
latitude: parseFloat(validPositions[0].latitude)
|
|
}
|
|
}
|
|
|
|
let sumLat = 0
|
|
let sumLng = 0
|
|
validPositions.forEach(position => {
|
|
sumLat += parseFloat(position.latitude)
|
|
sumLng += parseFloat(position.longitude)
|
|
})
|
|
|
|
return {
|
|
latitude: sumLat / validPositions.length,
|
|
longitude: sumLng / validPositions.length
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算最佳缩放级别
|
|
* @param {Array} positions 位置数组
|
|
* @param {Object} center 中心点
|
|
* @returns {Number} 缩放级别
|
|
*/
|
|
calculateOptimalZoom(positions, center) {
|
|
if (!positions || positions.length <= 1) {
|
|
return 13 // 默认缩放级别
|
|
}
|
|
|
|
const validPositions = positions.filter(p => p.longitude && p.latitude)
|
|
if (validPositions.length <= 1) {
|
|
return 13
|
|
}
|
|
|
|
// 计算最大距离
|
|
let maxDistance = 0
|
|
validPositions.forEach(position => {
|
|
const distance = this.calculateHaversineDistance(
|
|
center.latitude, center.longitude,
|
|
parseFloat(position.latitude), parseFloat(position.longitude)
|
|
)
|
|
maxDistance = Math.max(maxDistance, distance)
|
|
})
|
|
|
|
// 基于距离计算缩放级别
|
|
if (maxDistance > 10) return 10 // 10km以上
|
|
if (maxDistance > 5) return 11 // 5-10km
|
|
if (maxDistance > 2) return 12 // 2-5km
|
|
if (maxDistance > 1) return 13 // 1-2km
|
|
if (maxDistance > 0.5) return 14 // 500m-1km
|
|
if (maxDistance > 0.2) return 15 // 200-500m
|
|
return 16 // 200m以内
|
|
}
|
|
|
|
/**
|
|
* 计算两点间距离(公里)
|
|
* @param {Number} lat1 第一点纬度
|
|
* @param {Number} lng1 第一点经度
|
|
* @param {Number} lat2 第二点纬度
|
|
* @param {Number} lng2 第二点经度
|
|
* @returns {Number} 距离(公里)
|
|
*/
|
|
calculateHaversineDistance(lat1, lng1, lat2, lng2) {
|
|
const R = 6371 // 地球半径(公里)
|
|
const dLat = (lat2 - lat1) * Math.PI / 180
|
|
const dLng = (lng2 - lng1) * Math.PI / 180
|
|
|
|
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
|
|
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
|
|
Math.sin(dLng/2) * Math.sin(dLng/2)
|
|
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
|
|
return R * c
|
|
}
|
|
}
|
|
|
|
// 导出实例
|
|
module.exports = new StaticMapUtil() |