194 lines
6.3 KiB
JavaScript
194 lines
6.3 KiB
JavaScript
// 高德静态地图API工具类
|
|
const AMAP_KEY = '4c513a688938fd89b88b296e867f66ec'
|
|
|
|
class StaticMapUtil {
|
|
constructor() {
|
|
this.key = AMAP_KEY
|
|
this.baseUrl = 'https://restapi.amap.com/v3/staticmap'
|
|
}
|
|
|
|
/**
|
|
* 生成静态地图URL
|
|
* @param {Object} options 地图配置选项
|
|
* @returns {String} 静态地图URL
|
|
*/
|
|
generateMapUrl(options = {}) {
|
|
const defaultOptions = {
|
|
location: '116.397128,39.916527', // 默认中心点(北京)
|
|
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 += `&location=${config.location}`
|
|
url += `&zoom=${config.zoom}`
|
|
url += `&size=${config.size}`
|
|
url += `&scale=${config.scale}`
|
|
url += `&traffic=${config.traffic}`
|
|
url += `&format=${config.format}`
|
|
|
|
// 添加标记点
|
|
if (config.markers && config.markers.length > 0) {
|
|
const markersStr = config.markers.map(marker => {
|
|
let markerStr = ''
|
|
if (marker.size) markerStr += `size:${marker.size}|`
|
|
if (marker.color) markerStr += `color:${marker.color}|`
|
|
if (marker.label) markerStr += `label:${marker.label}|`
|
|
markerStr += `${marker.longitude},${marker.latitude}`
|
|
return markerStr
|
|
}).join('|')
|
|
url += `&markers=${encodeURIComponent(markersStr)}`
|
|
}
|
|
|
|
// 添加文字标注
|
|
if (config.labels && config.labels.length > 0) {
|
|
const labelsStr = config.labels.map(label => {
|
|
let labelStr = ''
|
|
if (label.content) labelStr += `content:${label.content}|`
|
|
if (label.font) labelStr += `font:${label.font}|`
|
|
if (label.bold) labelStr += `bold:${label.bold}|`
|
|
if (label.fontSize) labelStr += `fontSize:${label.fontSize}|`
|
|
if (label.fontColor) labelStr += `fontColor:${label.fontColor}|`
|
|
if (label.background) labelStr += `background:${label.background}|`
|
|
labelStr += `${label.longitude},${label.latitude}`
|
|
return labelStr
|
|
}).join('|')
|
|
url += `&labels=${encodeURIComponent(labelsStr)}`
|
|
}
|
|
|
|
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: 'mid',
|
|
color: position.status === 'online' ? 'green' : 'red',
|
|
label: String.fromCharCode(65 + (index % 26)) // A, B, C...
|
|
}))
|
|
|
|
return this.generateMapUrl({
|
|
location: `${center.longitude},${center.latitude}`,
|
|
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 }
|
|
}
|
|
|
|
const sum = validPositions.reduce((acc, pos) => ({
|
|
longitude: acc.longitude + parseFloat(pos.longitude),
|
|
latitude: acc.latitude + parseFloat(pos.latitude)
|
|
}), { longitude: 0, latitude: 0 })
|
|
|
|
return {
|
|
longitude: (sum.longitude / validPositions.length).toFixed(6),
|
|
latitude: (sum.latitude / validPositions.length).toFixed(6)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算最佳缩放级别
|
|
* @param {Array} positions 位置数组
|
|
* @param {Object} center 中心点
|
|
* @returns {Number} 缩放级别
|
|
*/
|
|
calculateOptimalZoom(positions, center) {
|
|
if (positions.length <= 1) return 15
|
|
|
|
const validPositions = positions.filter(p => p.longitude && p.latitude)
|
|
if (validPositions.length <= 1) return 15
|
|
|
|
// 计算最大距离
|
|
let maxDistance = 0
|
|
validPositions.forEach(pos => {
|
|
const distance = this.getDistance(
|
|
center.latitude, center.longitude,
|
|
parseFloat(pos.latitude), parseFloat(pos.longitude)
|
|
)
|
|
maxDistance = Math.max(maxDistance, distance)
|
|
})
|
|
|
|
// 根据最大距离确定缩放级别
|
|
if (maxDistance < 1) return 16 // 1km内
|
|
if (maxDistance < 2) return 15 // 2km内
|
|
if (maxDistance < 5) return 14 // 5km内
|
|
if (maxDistance < 10) return 13 // 10km内
|
|
if (maxDistance < 20) return 12 // 20km内
|
|
if (maxDistance < 50) return 11 // 50km内
|
|
return 10 // 50km以上
|
|
}
|
|
|
|
/**
|
|
* 计算两点间距离(公里)
|
|
* @param {Number} lat1 纬度1
|
|
* @param {Number} lng1 经度1
|
|
* @param {Number} lat2 纬度2
|
|
* @param {Number} lng2 经度2
|
|
* @returns {Number} 距离(公里)
|
|
*/
|
|
getDistance(lat1, lng1, lat2, lng2) {
|
|
const radLat1 = lat1 * Math.PI / 180.0
|
|
const radLat2 = lat2 * Math.PI / 180.0
|
|
const a = radLat1 - radLat2
|
|
const b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0
|
|
let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)))
|
|
s = s * 6378.137
|
|
s = Math.round(s * 10000) / 10000
|
|
return s
|
|
}
|
|
|
|
/**
|
|
* 预加载地图图片
|
|
* @param {String} mapUrl 地图URL
|
|
* @returns {Promise} 图片加载Promise
|
|
*/
|
|
preloadMapImage(mapUrl) {
|
|
return new Promise((resolve, reject) => {
|
|
const img = new Image()
|
|
img.onload = () => resolve(mapUrl)
|
|
img.onerror = reject
|
|
img.src = mapUrl
|
|
})
|
|
}
|
|
}
|
|
|
|
export default new StaticMapUtil()
|