336 lines
No EOL
8.5 KiB
JavaScript
336 lines
No EOL
8.5 KiB
JavaScript
/**
|
||
* 地图配置文件
|
||
* 包含高德地图配置、权限管理、地图工具函数等
|
||
*/
|
||
|
||
const config = require('../config/config.js');
|
||
|
||
// 高德地图配置
|
||
const MAP_CONFIG = {
|
||
// 高德地图Key - 需要在高德开放平台申请
|
||
amapKey: config.amapKey || '9281427fb1b9c4e1c2acf097a3194781',
|
||
|
||
// 地图默认设置
|
||
defaults: {
|
||
latitude: 39.908823, // 北京天安门
|
||
longitude: 116.39747,
|
||
scale: 16,
|
||
minScale: 3,
|
||
maxScale: 20,
|
||
showLocation: true,
|
||
showScale: true,
|
||
showCompass: true,
|
||
enableOverlooking: false,
|
||
enableZoom: true,
|
||
enableScroll: true,
|
||
enableRotate: false,
|
||
enable3D: false
|
||
},
|
||
|
||
// 定位配置
|
||
location: {
|
||
type: 'gcj02', // 坐标系类型:wgs84、gcj02
|
||
isHighAccuracy: true,
|
||
highAccuracyExpireTime: 4000,
|
||
timeout: 10000,
|
||
cacheTimeout: 60000 // 位置缓存时间
|
||
},
|
||
|
||
// 标记点配置
|
||
markers: {
|
||
// 当前用户标记 - 使用默认样式
|
||
currentUser: {
|
||
width: 30,
|
||
height: 30,
|
||
anchor: { x: 0.5, y: 1 }
|
||
},
|
||
// 好友标记 - 使用默认样式
|
||
friend: {
|
||
width: 25,
|
||
height: 25,
|
||
anchor: { x: 0.5, y: 1 }
|
||
},
|
||
// 陌生人标记 - 使用默认样式
|
||
stranger: {
|
||
width: 20,
|
||
height: 20,
|
||
anchor: { x: 0.5, y: 1 }
|
||
}
|
||
},
|
||
|
||
// 地图样式
|
||
style: {
|
||
normal: 'normal', // 普通地图
|
||
satellite: 'satellite', // 卫星地图
|
||
traffic: 'traffic' // 交通地图
|
||
}
|
||
};
|
||
|
||
// 权限配置
|
||
const PERMISSION_CONFIG = {
|
||
// 位置权限
|
||
location: {
|
||
scope: 'scope.userLocation',
|
||
name: '位置信息',
|
||
description: '用于获取您的位置信息,实现定位和附近功能'
|
||
},
|
||
|
||
// 其他权限
|
||
camera: {
|
||
scope: 'scope.camera',
|
||
name: '摄像头',
|
||
description: '用于拍照和扫码功能'
|
||
},
|
||
|
||
album: {
|
||
scope: 'scope.album',
|
||
name: '相册',
|
||
description: '用于选择图片功能'
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 地图工具类
|
||
*/
|
||
class MapUtils {
|
||
/**
|
||
* 检查位置权限
|
||
*/
|
||
static checkLocationPermission() {
|
||
return new Promise((resolve, reject) => {
|
||
wx.getSetting({
|
||
success: (res) => {
|
||
console.log('权限设置:', res.authSetting);
|
||
|
||
if (res.authSetting['scope.userLocation'] === false) {
|
||
// 用户拒绝过位置权限
|
||
reject({
|
||
type: 'denied',
|
||
message: '位置权限被拒绝,请在设置中开启'
|
||
});
|
||
} else if (res.authSetting['scope.userLocation'] === true) {
|
||
// 用户已授权
|
||
resolve(true);
|
||
} else {
|
||
// 用户未授权,需要请求授权
|
||
resolve(false);
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
console.error('获取权限设置失败:', error);
|
||
reject({
|
||
type: 'error',
|
||
message: '获取权限设置失败'
|
||
});
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 请求位置权限
|
||
*/
|
||
static requestLocationPermission() {
|
||
return new Promise((resolve, reject) => {
|
||
wx.authorize({
|
||
scope: 'scope.userLocation',
|
||
success: () => {
|
||
console.log('位置权限授权成功');
|
||
resolve(true);
|
||
},
|
||
fail: (error) => {
|
||
console.warn('位置权限授权失败:', error);
|
||
// 引导用户去设置页面
|
||
wx.showModal({
|
||
title: '位置权限申请',
|
||
content: 'FindMe需要访问您的位置信息,请在设置中开启位置权限',
|
||
confirmText: '去设置',
|
||
cancelText: '取消',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
wx.openSetting({
|
||
success: (settingRes) => {
|
||
if (settingRes.authSetting['scope.userLocation']) {
|
||
resolve(true);
|
||
} else {
|
||
reject({
|
||
type: 'denied',
|
||
message: '位置权限被拒绝'
|
||
});
|
||
}
|
||
},
|
||
fail: () => {
|
||
reject({
|
||
type: 'error',
|
||
message: '打开设置页面失败'
|
||
});
|
||
}
|
||
});
|
||
} else {
|
||
reject({
|
||
type: 'cancelled',
|
||
message: '用户取消授权'
|
||
});
|
||
}
|
||
}
|
||
});
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取位置(带权限检查)
|
||
*/
|
||
static async getLocation(options = {}) {
|
||
try {
|
||
// 检查权限
|
||
const hasPermission = await this.checkLocationPermission();
|
||
|
||
if (!hasPermission) {
|
||
// 请求权限
|
||
await this.requestLocationPermission();
|
||
}
|
||
|
||
// 获取位置
|
||
return new Promise((resolve, reject) => {
|
||
const locationOptions = {
|
||
...MAP_CONFIG.location,
|
||
...options,
|
||
success: (res) => {
|
||
console.log('获取位置成功:', res);
|
||
resolve({
|
||
latitude: res.latitude,
|
||
longitude: res.longitude,
|
||
accuracy: res.accuracy || 0,
|
||
altitude: res.altitude || 0,
|
||
speed: res.speed || -1,
|
||
timestamp: Date.now()
|
||
});
|
||
},
|
||
fail: (error) => {
|
||
console.error('获取位置失败:', error);
|
||
reject({
|
||
type: 'location_error',
|
||
message: error.errMsg || '定位失败',
|
||
error: error
|
||
});
|
||
}
|
||
};
|
||
|
||
wx.getLocation(locationOptions);
|
||
});
|
||
} catch (error) {
|
||
console.error('位置获取流程失败:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 计算两点距离
|
||
*/
|
||
static calculateDistance(point1, point2) {
|
||
const lat1 = point1.latitude * Math.PI / 180;
|
||
const lon1 = point1.longitude * Math.PI / 180;
|
||
const lat2 = point2.latitude * Math.PI / 180;
|
||
const lon2 = point2.longitude * Math.PI / 180;
|
||
|
||
const R = 6371000; // 地球半径(米)
|
||
const dLat = lat2 - lat1;
|
||
const dLon = lon2 - lon1;
|
||
|
||
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
|
||
Math.cos(lat1) * Math.cos(lat2) *
|
||
Math.sin(dLon/2) * Math.sin(dLon/2);
|
||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||
|
||
return R * c;
|
||
}
|
||
|
||
/**
|
||
* 格式化距离显示
|
||
*/
|
||
static formatDistance(distance) {
|
||
if (distance < 1000) {
|
||
return `${Math.round(distance)}米`;
|
||
} else if (distance < 10000) {
|
||
return `${(distance / 1000).toFixed(1)}公里`;
|
||
} else {
|
||
return `${Math.round(distance / 1000)}公里`;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建标记点
|
||
*/
|
||
static createMarker(data, type = 'friend') {
|
||
const markerConfig = MAP_CONFIG.markers[type] || MAP_CONFIG.markers.friend;
|
||
|
||
return {
|
||
id: data.id || Date.now(),
|
||
latitude: data.latitude,
|
||
longitude: data.longitude,
|
||
width: markerConfig.width,
|
||
height: markerConfig.height,
|
||
anchor: markerConfig.anchor,
|
||
callout: data.showCallout ? {
|
||
content: data.nickname || '用户',
|
||
color: '#333333',
|
||
fontSize: 12,
|
||
borderRadius: 4,
|
||
bgColor: '#ffffff',
|
||
padding: 8,
|
||
display: 'ALWAYS'
|
||
} : null,
|
||
customData: {
|
||
userId: data.userId,
|
||
nickname: data.nickname,
|
||
avatar: data.avatar,
|
||
distance: data.distance,
|
||
lastUpdateTime: data.lastUpdateTime
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 获取地图区域
|
||
*/
|
||
static getMapRegion(centerPoint, markers = []) {
|
||
if (markers.length === 0) {
|
||
return {
|
||
latitude: centerPoint.latitude,
|
||
longitude: centerPoint.longitude,
|
||
scale: MAP_CONFIG.defaults.scale
|
||
};
|
||
}
|
||
|
||
// 计算包含所有标记点的区域
|
||
let minLat = centerPoint.latitude;
|
||
let maxLat = centerPoint.latitude;
|
||
let minLng = centerPoint.longitude;
|
||
let maxLng = centerPoint.longitude;
|
||
|
||
markers.forEach(marker => {
|
||
minLat = Math.min(minLat, marker.latitude);
|
||
maxLat = Math.max(maxLat, marker.latitude);
|
||
minLng = Math.min(minLng, marker.longitude);
|
||
maxLng = Math.max(maxLng, marker.longitude);
|
||
});
|
||
|
||
// 添加边距
|
||
const latPadding = (maxLat - minLat) * 0.3;
|
||
const lngPadding = (maxLng - minLng) * 0.3;
|
||
|
||
return {
|
||
latitude: (minLat + maxLat) / 2,
|
||
longitude: (minLng + maxLng) / 2,
|
||
scale: Math.max(Math.min(18 - Math.log2(Math.max(maxLat - minLat + latPadding, maxLng - minLng + lngPadding) * 111000), 18), 8)
|
||
};
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
MAP_CONFIG,
|
||
PERMISSION_CONFIG,
|
||
MapUtils
|
||
};
|