336 lines
8.5 KiB
JavaScript
336 lines
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
|
|||
|
|
};
|