场景
uniapp项目,平板端运行,要求点击cesium地图中的广告牌,携带平板设备当前坐标以及目标点坐标,前往高德APP内进行路径规划。
效果
开发位置和应用位置不同,实际应用该功能是在目标点附近。


实现
平板设备坐标通过uniapp自带方法获取,使用GCJ02坐标;目标点坐标通过绘制广告牌时加入的点击回调方法取得坐标,然后再做一个坐标转化,WGS84 转 GCJ02;点击广告牌的提示词使用坐标范围匹配,不同类型应用不同匹配标准,匹配不到则扩大搜索范围。
部分功能应用
1. 获取当前经纬度(单次)
import { getCurrentLocation } from '@/utils/location.js'
// 基本用法
getCurrentLocation().then(location => {
console.log('纬度:', location.latitude)
console.log('经度:', location.longitude)
console.log('海拔:', location.altitude, '米')
console.log('精度:', location.accuracy, '米')
}).catch(err => {
console.error('获取位置失败:', err.message)
})
// 自定义配置
getCurrentLocation({
highAccuracy: true, // 高精度定位
timeout: 5000 // 5秒超时
}).then(location => {
console.log('位置信息:', location)
})
2. 实时监听位置变化
import { watchLocation, stopWatchLocation } from '@/utils/location.js'
// 开始监听
const watchId = watchLocation((location) => {
console.log('实时位置:', location)
console.log('纬度:', location.latitude)
console.log('经度:', location.longitude)
}, {
interval: 3000 // 每3秒更新一次
})
// 停止监听
stopWatchLocation(watchId)
3. 在Vue组件中使用
<template>
<view>
<text>纬度: {{ latitude }}</text>
<text>经度: {{ longitude }}</text>
</view>
</template>
<script>
import { getCurrentLocation, watchLocation } from '@/utils/location.js'
export default {
data() {
return {
locationWatchId: null, // 位置监听ID
targetLocation: {
longitude: 0,
latitude: 0,
},
}
},
onLoad() {
// 获取初始位置
this.getLocation()
// 监听位置变化
this.watchLocation()
},
onUnload() {
// 停止位置监听
if (this.locationWatchId) {
stopWatchLocation(this.locationWatchId)
this.locationWatchId = null
}
},
methods: {
async getLocation() {
try {
const location = await getCurrentLocation()
this.deviceLocation.latitude = location.latitude
this.deviceLocation.longitude = location.longitude
} catch (err) {
console.error('获取位置失败:', err)
}
},
watchLocation() {
this.locationWatchId = watchLocation((location) => {
this.deviceLocation.latitude = location.latitude
this.deviceLocation.longitude = location.longitude
})
}
}
}
</script>
4. 计算距离
import { getDistance } from '@/utils/location.js'
// 计算两点间的距离
const distance = getDistance(39.9, 116.4, 40.0, 116.5)
console.log('距离:', distance, '米') // 距离: 14142.36 米
封装文件
location.js
/**
* 地理位置工具类
* 用于获取平板设备的实时经纬度信息
*/
import { wgs84ToGcj02 } from './coordinate.js'
/**
* 获取当前地理位置
* @param {Object} options 配置选项
* @param {Boolean} options.highAccuracy 是否使用高精度定位,默认true
* @param {Number} options.timeout 超时时间(ms),默认10000
* @param {Number} options.maximumAge 最大缓存时间(ms),默认0
* @returns {Promise} 返回Promise对象
*/
export function getCurrentLocation(options = {}) {
return new Promise((resolve, reject) => {
const {
highAccuracy = true, // 高精度定位
timeout = 10000, // 超时时间10秒
maximumAge = 0 // 不使用缓存
} = options;
uni.getLocation({
type: 'gcj02', // 坐标系类型,gcj02为国测局坐标系
altitude: true, // 获取海拔信息
geocode: false, // 不获取地址信息
highAccuracy: highAccuracy,
success: (res) => {
const locationData = {
latitude: res.latitude, // 纬度
longitude: res.longitude, // 经度
accuracy: res.accuracy, // 精度,单位米
altitude: res.altitude, // 高度,单位米
speed: res.speed, // 速度,单位m/s
horizontalAccuracy: res.horizontalAccuracy, // 水平精度
verticalAccuracy: res.verticalAccuracy, // 垂直精度
timestamp: Date.now() // 时间戳
};
resolve(locationData);
},
fail: (err) => {
reject({
code: err.errCode || -1,
message: err.errMsg || '获取位置失败',
error: err
});
}
});
});
}
/**
* 持续监听位置变化
* @param {Function} callback 回调函数
* @param {Object} options 配置选项
* @returns {Number} 监听器ID
*/
export function watchLocation(callback, options = {}) {
const {
interval = 5000, // 监听间隔,默认5秒
highAccuracy = true, // 高精度定位
maximumAge = 0 // 不使用缓存
} = options;
// 开始定位
uni.startLocationUpdate({
success: () => {
console.log('开始监听位置变化')
},
fail: (err) => {
console.error('开始监听位置失败:', err)
}
})
// 监听位置变化事件
const watchId = uni.onLocationChange((res) => {
const locationData = {
latitude: res.latitude,
longitude: res.longitude,
accuracy: res.accuracy,
altitude: res.altitude,
speed: res.speed,
horizontalAccuracy: res.horizontalAccuracy,
verticalAccuracy: res.verticalAccuracy,
timestamp: Date.now()
};
callback(locationData);
});
return watchId;
}
/**
* 停止位置监听
* @param {Number} watchId 监听器ID
*/
export function stopWatchLocation(watchId) {
// 停止监听位置变化
uni.offLocationChange(() => {
// 回调为空函数即可
})
// 停止定位
uni.stopLocationUpdate({
success: () => {
console.log('已停止位置监听')
},
fail: (err) => {
console.error('停止位置监听失败:', err)
}
})
}
/**
* 检查定位权限
* @returns {Promise} 返回Promise对象
*/
export function checkLocationPermission() {
return new Promise((resolve, reject) => {
// #ifdef APP-PLUS
// App平台检查定位权限
plus.geolocation.getCurrentPosition(
(res) => {
resolve(true);
},
(err) => {
if (err.code === 1) {
// 用户拒绝授权
resolve(false);
} else {
resolve(false);
}
}
);
// #endif
// #ifndef APP-PLUS
// 其他平台默认允许
resolve(true);
// #endif
});
}
/**
* 计算两点之间的距离(单位:米)
* @param {Number} lat1 起点纬度
* @param {Number} lng1 起点经度
* @param {Number} lat2 终点纬度
* @param {Number} lng2 终点经度
* @returns {Number} 距离(米)
*/
export function getDistance(lat1, lng1, lat2, lng2) {
const R = 6371000; // 地球半径(米)
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;
}
/**
* 打开高德地图导航
* @param {Number} fromLng 起点经度 (WGS84坐标系)
* @param {Number} fromLat 起点纬度 (WGS84坐标系)
* @param {Number} toLng 终点经度 (WGS84坐标系)
* @param {Number} toLat 终点纬度 (WGS84坐标系)
* @param {String} poiName 终点名称(可选)
*/
export function openAmapNavigation(fromLng, fromLat, toLng, toLat, poiName = '目的地') {
// 将 WGS84 坐标转换为 GCJ02(高德地图使用 GCJ02)
const [convertedFromLng, convertedFromLat] = wgs84ToGcj02(fromLng, fromLat);
const [convertedToLng, convertedToLat] = wgs84ToGcj02(toLng, toLat);
// #ifdef APP-PLUS
// 在APP中打开高德地图
// 注意:高德地图APP导航只需终点坐标
const amapUrl = `androidamap://route?sourceApplication=ydx&dlat=${convertedToLat}&dlon=${convertedToLng}&dname=${encodeURIComponent(poiName)}&dev=0&t=0`;
plus.runtime.openURL(amapUrl, (err) => {
if (err) {
console.error('打开高德地图失败:', err);
uni.showToast({
title: '请先安装高德地图',
icon: 'none'
});
}
});
// #endif
// #ifndef APP-PLUS
// 在其他环境使用web版高德地图
window.open(`https://uri.amap.com/navigation?to=${convertedToLng},${convertedToLat},${encodeURIComponent(poiName)}`);
// #endif
}
export default {
getCurrentLocation,
watchLocation,
stopWatchLocation,
checkLocationPermission,
getDistance,
openAmapNavigation
};
coordinate.js
/**
* 坐标转换工具
* 支持 WGS84、GCJ02、BD09 之间的相互转换
*/
/**
* 坐标偏移量
*/
const X_PI = 3.14159265358979324 * 3000.0 / 180.0;
const PI = 3.1415926535897932384626;
const A = 6378245.0;
const EE = 0.00669342162296594323;
/**
* WGS84 转 GCJ02 (国测局坐标系,也叫火星坐标系)
* @param {Number} lng 经度
* @param {Number} lat 纬度
* @returns {Array} [lng, lat]
*/
export function wgs84ToGcj02(lng, lat) {
if (outOfChina(lng, lat)) {
return [lng, lat];
}
let dLat = transformLat(lng - 105.0, lat - 35.0);
let dLng = transformLng(lng - 105.0, lat - 35.0);
const radLat = lat / 180.0 * PI;
let magic = Math.sin(radLat);
magic = 1 - EE * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
const mgLat = lat + dLat;
const mgLng = lng + dLng;
return [mgLng, mgLat];
}
/**
* GCJ02 转 WGS84
* @param {Number} lng 经度
* @param {Number} lat 纬度
* @returns {Array} [lng, lat]
*/
export function gcj02ToWgs84(lng, lat) {
if (outOfChina(lng, lat)) {
return [lng, lat];
}
let dLat = transformLat(lng - 105.0, lat - 35.0);
let dLng = transformLng(lng - 105.0, lat - 35.0);
const radLat = lat / 180.0 * PI;
let magic = Math.sin(radLat);
magic = 1 - EE * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
const mgLat = lat + dLat;
const mgLng = lng + dLng;
return [lng * 2 - mgLng, lat * 2 - mgLat];
}
/**
* GCJ02 转 BD09 (百度坐标系)
* @param {Number} lng 经度
* @param {Number} lat 纬度
* @returns {Array} [lng, lat]
*/
export function gcj02ToBd09(lng, lat) {
const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * X_PI);
const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * X_PI);
const bdLng = z * Math.cos(theta) + 0.0065;
const bdLat = z * Math.sin(theta) + 0.006;
return [bdLng, bdLat];
}
/**
* BD09 转 GCJ02
* @param {Number} lng 经度
* @param {Number} lat 纬度
* @returns {Array} [lng, lat]
*/
export function bd09ToGcj02(lng, lat) {
const x = lng - 0.0065;
const y = lat - 0.006;
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI);
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI);
const gcjLng = z * Math.cos(theta);
const gcjLat = z * Math.sin(theta);
return [gcjLng, gcjLat];
}
/**
* WGS84 转 BD09
* @param {Number} lng 经度
* @param {Number} lat 纬度
* @returns {Array} [lng, lat]
*/
export function wgs84ToBd09(lng, lat) {
const gcj = wgs84ToGcj02(lng, lat);
return gcj02ToBd09(gcj[0], gcj[1]);
}
/**
* BD09 转 WGS84
* @param {Number} lng 经度
* @param {Number} lat 纬度
* @returns {Array} [lng, lat]
*/
export function bd09ToWgs84(lng, lat) {
const gcj = bd09ToGcj02(lng, lat);
return gcj02ToWgs84(gcj[0], gcj[1]);
}
/**
* 判断是否在中国范围外
* @param {Number} lng 经度
* @param {Number} lat 纬度
* @returns {Boolean}
*/
function outOfChina(lng, lat) {
return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
}
/**
* 纬度转换
*/
function transformLat(lng, lat) {
let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
return ret;
}
/**
* 经度转换
*/
function transformLng(lng, lat) {
let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
return ret;
}
export default {
wgs84ToGcj02,
gcj02ToWgs84,
gcj02ToBd09,
bd09ToGcj02,
wgs84ToBd09,
bd09ToWgs84
};
694

被折叠的 条评论
为什么被折叠?



