图标定位修改
This commit is contained in:
parent
6a6c6b1ac5
commit
0ca54d558d
|
|
@ -414,6 +414,10 @@
|
|||
baiduGeolocation: null,
|
||||
lastHeading: null, // 记录上一次的方向,用于避免频繁更新图标
|
||||
updateMarkerTimer: null, // 防抖定时器
|
||||
headingHistory: [], // 方向历史记录,用于平滑滤波(移动平均)
|
||||
headingHistorySize: 5, // 历史记录大小(5个样本的移动平均)
|
||||
lastOrientationUpdateTime: 0, // 上次方向更新时间,用于节流
|
||||
headingOffset: 0, // 方向偏移量,用于校正方向偏差(度),如果需要反转方向可以设置为180
|
||||
elements: {
|
||||
panel: null,
|
||||
tree: null,
|
||||
|
|
@ -549,7 +553,7 @@
|
|||
// 开始监听位置变化(异步获取位置,不会立即有位置信息)
|
||||
this.startWatchingPosition();
|
||||
|
||||
// 开始监听设备方向变化
|
||||
// 开始监听设备方向变化(使用设备方向传感器)
|
||||
this.startWatchingOrientation();
|
||||
},
|
||||
|
||||
|
|
@ -657,6 +661,8 @@
|
|||
lat: point.lat,
|
||||
accuracy: accuracy
|
||||
};
|
||||
|
||||
// 方向由设备方向传感器提供,不在这里设置
|
||||
this.updateLocationMarker();
|
||||
isFirstLocation = false;
|
||||
|
||||
|
|
@ -702,8 +708,10 @@
|
|||
point.lat
|
||||
);
|
||||
|
||||
// 如果位置变化超过3米,或者精度提升超过10米,则更新
|
||||
if (distance > 3 || accuracy < this.state.currentLocation.accuracy - 10) {
|
||||
// 位置变化超过2米就更新,或者精度提升超过5米
|
||||
if (distance > 2 ||
|
||||
(accuracy < this.state.currentLocation.accuracy - 5) ||
|
||||
(accuracy < 50 && this.state.currentLocation.accuracy >= 50)) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -715,6 +723,8 @@
|
|||
lat: point.lat,
|
||||
accuracy: accuracy
|
||||
};
|
||||
|
||||
// 方向由设备方向传感器提供,不在这里更新
|
||||
this.updateLocationMarker();
|
||||
}
|
||||
}
|
||||
|
|
@ -754,9 +764,9 @@
|
|||
point.lat
|
||||
);
|
||||
|
||||
// 如果位置变化超过5米,或者精度提升超过10米,则更新
|
||||
if (distance > 5 ||
|
||||
(accuracy < this.state.currentLocation.accuracy - 10) ||
|
||||
// 位置变化超过2米就更新,或者精度提升超过5米
|
||||
if (distance > 2 ||
|
||||
(accuracy < this.state.currentLocation.accuracy - 5) ||
|
||||
(accuracy < 50 && this.state.currentLocation.accuracy >= 50)) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
|
@ -777,15 +787,17 @@
|
|||
lat: point.lat,
|
||||
accuracy: accuracy
|
||||
};
|
||||
|
||||
// 方向由设备方向传感器实时提供,不在这里更新
|
||||
this.updateLocationMarker();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
enableHighAccuracy: true, // 使用GPS精确定位
|
||||
timeout: 8000 // 8秒超时
|
||||
timeout: 6000 // 6秒超时
|
||||
});
|
||||
}, 2000); // 每2秒更新一次,实时跟踪移动
|
||||
}, 500); // 每0.5秒更新一次,提高实时性和灵敏度
|
||||
|
||||
// 保存geolocation实例,以便后续使用
|
||||
this.baiduGeolocation = geolocation;
|
||||
|
|
@ -1285,7 +1297,7 @@
|
|||
},
|
||||
|
||||
/**
|
||||
* 更新定位标记(使用requestAnimationFrame实现平滑更新,避免闪烁)
|
||||
* 更新定位标记(实时更新,优先更新位置)
|
||||
*/
|
||||
updateLocationMarker() {
|
||||
// 确保地图已加载完成
|
||||
|
|
@ -1304,6 +1316,7 @@
|
|||
}
|
||||
|
||||
// 使用requestAnimationFrame实现平滑更新,保持实时性
|
||||
// 对于位置更新,立即执行;对于方向更新,异步执行
|
||||
this.updateMarkerTimer = requestAnimationFrame(() => {
|
||||
this.updateMarkerTimer = null;
|
||||
this._doUpdateLocationMarker();
|
||||
|
|
@ -1320,35 +1333,33 @@
|
|||
// 如果标记已存在,直接更新(避免删除重建)
|
||||
if (this.overlays.locationMarker) {
|
||||
try {
|
||||
// 更新位置(百度地图GL API支持setPosition)
|
||||
// 优先更新位置(立即执行,不等待方向更新)
|
||||
if (typeof this.overlays.locationMarker.setPosition === 'function') {
|
||||
// 直接更新位置,实时跟随移动(不检查距离,每次都更新以确保平滑)
|
||||
this.overlays.locationMarker.setPosition(point);
|
||||
} else {
|
||||
// 如果不支持setPosition,检查位置是否变化
|
||||
// 如果不支持setPosition,检查位置是否变化(降低阈值,提高灵敏度)
|
||||
const currentPoint = this.overlays.locationMarker.getPosition();
|
||||
// 降低坐标变化阈值,从0.000001(约0.1米)到0.000005(约0.5米),但实际应该总是更新
|
||||
if (!currentPoint ||
|
||||
Math.abs(currentPoint.lng - lng) > 0.00001 ||
|
||||
Math.abs(currentPoint.lat - lat) > 0.00001) {
|
||||
Math.abs(currentPoint.lng - lng) > 0.000005 ||
|
||||
Math.abs(currentPoint.lat - lat) > 0.000005) {
|
||||
// 位置变化,需要更新(但尽量不删除重建)
|
||||
const needsRecreate = true;
|
||||
if (needsRecreate) {
|
||||
// 保存当前图标,避免重新创建
|
||||
const currentIcon = this.overlays.locationMarker.getIcon();
|
||||
this.map.removeOverlay(this.overlays.locationMarker);
|
||||
this.overlays.locationMarker = new BMapGL.Marker(point, { icon: currentIcon });
|
||||
this.map.addOverlay(this.overlays.locationMarker);
|
||||
}
|
||||
const currentIcon = this.overlays.locationMarker.getIcon();
|
||||
this.map.removeOverlay(this.overlays.locationMarker);
|
||||
this.overlays.locationMarker = new BMapGL.Marker(point, { icon: currentIcon });
|
||||
this.map.addOverlay(this.overlays.locationMarker);
|
||||
}
|
||||
}
|
||||
|
||||
// 实时更新方向(降低阈值到1度,保持实时性)
|
||||
const headingChanged = !this.lastHeading || Math.abs(this.state.currentHeading - this.lastHeading) >= 1;
|
||||
// 实时更新方向(使用角度差值计算,考虑0-360度边界)
|
||||
const headingChanged = !this.lastHeading || Math.abs(this.angleDifference(this.state.currentHeading, this.lastHeading)) >= 1;
|
||||
|
||||
if (headingChanged) {
|
||||
const oldHeading = this.lastHeading;
|
||||
this.lastHeading = this.state.currentHeading;
|
||||
|
||||
// 实时更新图标(使用requestAnimationFrame确保平滑)
|
||||
// 异步更新图标(使用requestAnimationFrame确保平滑,不阻塞位置更新)
|
||||
requestAnimationFrame(() => {
|
||||
this.createRotatedLocationIcon(this.state.currentHeading).then((icon) => {
|
||||
if (this.overlays.locationMarker) {
|
||||
|
|
@ -1492,10 +1503,24 @@
|
|||
|
||||
// 旋转画布(heading是相对于正北的角度,需要转换为相对于画布的角度)
|
||||
// 百度地图中,heading是相对于正北的角度(0-360),顺时针为正
|
||||
// 画布中,0度是向右,需要转换
|
||||
// 如果方向反了,尝试反转:使用 (90 - heading) 或 (270 - heading)
|
||||
// 或者添加180度来反转:heading + 180
|
||||
const rotation = (90 - heading) * Math.PI / 180; // 反转方向:从 (heading - 90) 改为 (90 - heading)
|
||||
// 画布坐标系:0度向右,90度向下,180度向左,270度向上
|
||||
// 地图坐标系:0度正北,90度正东,180度正南,270度正西
|
||||
// 转换公式:画布角度 = 90度 - 地图角度(因为画布的0度对应地图的90度)
|
||||
|
||||
// 应用方向偏移量(用于校正方向偏差)
|
||||
const adjustedHeading = this.normalizeHeading(heading + (this.headingOffset || 0));
|
||||
|
||||
// 转换为画布旋转角度
|
||||
// 标准转换:画布的0度(向右)对应地图的90度(正东)
|
||||
// 所以:画布角度 = 90度 - 地图角度
|
||||
let rotation = (90 - adjustedHeading) * Math.PI / 180;
|
||||
|
||||
// 如果方向仍然不对,可以尝试以下方案(取消注释):
|
||||
// 方案1:反转180度
|
||||
// rotation = (270 - adjustedHeading) * Math.PI / 180;
|
||||
// 方案2:直接使用heading(如果图标本身已经指向正确方向)
|
||||
// rotation = -adjustedHeading * Math.PI / 180;
|
||||
|
||||
ctx.rotate(rotation);
|
||||
|
||||
// 绘制图片(居中,保持原始宽高比)
|
||||
|
|
@ -1512,85 +1537,306 @@
|
|||
},
|
||||
|
||||
/**
|
||||
* 开始监听设备方向变化
|
||||
* 平滑方向角度(处理0-360度边界问题)
|
||||
*/
|
||||
normalizeHeading(heading) {
|
||||
// 确保角度在0-360范围内
|
||||
while (heading < 0) heading += 360;
|
||||
while (heading >= 360) heading -= 360;
|
||||
return heading;
|
||||
},
|
||||
|
||||
/**
|
||||
* 计算两个角度之间的最短差值(考虑0-360度边界)
|
||||
*/
|
||||
angleDifference(a, b) {
|
||||
let diff = a - b;
|
||||
if (diff > 180) diff -= 360;
|
||||
if (diff < -180) diff += 360;
|
||||
return diff;
|
||||
},
|
||||
|
||||
/**
|
||||
* 移动平均滤波(减少抖动)
|
||||
*/
|
||||
smoothHeading(rawHeading) {
|
||||
// 初始化历史记录数组和大小(如果不存在)
|
||||
if (!this.headingHistory) {
|
||||
this.headingHistory = [];
|
||||
}
|
||||
if (!this.headingHistorySize) {
|
||||
this.headingHistorySize = 5; // 默认5个样本的移动平均
|
||||
}
|
||||
|
||||
// 添加到历史记录
|
||||
this.headingHistory.push(rawHeading);
|
||||
if (this.headingHistory.length > this.headingHistorySize) {
|
||||
this.headingHistory.shift();
|
||||
}
|
||||
|
||||
// 如果历史记录不足,直接返回原始值
|
||||
if (this.headingHistory.length < 3) {
|
||||
return rawHeading;
|
||||
}
|
||||
|
||||
// 处理0-360度边界问题:计算相对于第一个值的差值
|
||||
const baseHeading = this.headingHistory[0];
|
||||
const normalizedHistory = this.headingHistory.map(h => {
|
||||
let diff = this.angleDifference(h, baseHeading);
|
||||
return baseHeading + diff;
|
||||
});
|
||||
|
||||
// 计算平均值
|
||||
const sum = normalizedHistory.reduce((a, b) => a + b, 0);
|
||||
const avg = sum / normalizedHistory.length;
|
||||
|
||||
return this.normalizeHeading(avg);
|
||||
},
|
||||
|
||||
/**
|
||||
* 从四元数计算方向角(heading)- 修正版本
|
||||
*/
|
||||
quaternionToHeading(qx, qy, qz, qw) {
|
||||
// 四元数到欧拉角转换(提取heading/azimuth)
|
||||
// 使用标准公式计算Z轴旋转角度(heading)
|
||||
// 注意:四元数顺序可能是 [w, x, y, z] 或 [x, y, z, w],需要根据实际情况调整
|
||||
// 这里假设是 [x, y, z, w] 格式
|
||||
|
||||
// 方法1:使用标准四元数到欧拉角转换公式(ZYX顺序)
|
||||
// 计算heading(azimuth/yaw)- 绕Z轴旋转
|
||||
const siny_cosp = 2 * (qw * qz + qx * qy);
|
||||
const cosy_cosp = 1 - 2 * (qy * qy + qz * qz);
|
||||
let heading = Math.atan2(siny_cosp, cosy_cosp) * 180 / Math.PI;
|
||||
|
||||
// 转换为0-360度范围
|
||||
heading = this.normalizeHeading(heading);
|
||||
|
||||
// 如果方向反了,可以添加180度校正
|
||||
// heading = (heading + 180) % 360;
|
||||
|
||||
return heading;
|
||||
},
|
||||
|
||||
/**
|
||||
* 开始监听设备方向变化(优化:优先使用旋转矢量传感器)
|
||||
*/
|
||||
startWatchingOrientation() {
|
||||
// 绑定方法,确保在事件监听器中能正确访问 this
|
||||
this.handleOrientation = this.handleOrientation.bind(this);
|
||||
this.handleMotion = this.handleMotion.bind(this);
|
||||
this.updateHeadingIfChanged = this.updateHeadingIfChanged.bind(this);
|
||||
|
||||
console.log('开始监听设备方向...');
|
||||
// 初始化方向历史记录
|
||||
this.headingHistory = [];
|
||||
this.lastOrientationUpdateTime = 0;
|
||||
|
||||
// 检查是否支持 DeviceOrientationEvent
|
||||
if (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') {
|
||||
// iOS 13+ 需要请求权限
|
||||
console.log('请求设备方向权限...');
|
||||
DeviceOrientationEvent.requestPermission()
|
||||
.then(response => {
|
||||
if (response === 'granted') {
|
||||
console.log('设备方向权限已授予');
|
||||
window.addEventListener('deviceorientation', this.handleOrientation);
|
||||
} else {
|
||||
console.warn('设备方向权限被拒绝');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('请求设备方向权限失败:', error);
|
||||
});
|
||||
} else if (window.DeviceOrientationEvent) {
|
||||
// 其他设备直接监听
|
||||
console.log('直接监听设备方向事件');
|
||||
window.addEventListener('deviceorientation', this.handleOrientation);
|
||||
} else {
|
||||
console.log('DeviceOrientationEvent不支持,尝试使用uni-app Compass API');
|
||||
// 如果不支持,尝试使用 Compass API(uni-app)
|
||||
if (typeof plus !== 'undefined' && plus.compass) {
|
||||
this.state.watchOrientationId = plus.compass.watchHeading(
|
||||
(heading) => {
|
||||
const newHeading = heading.magneticHeading;
|
||||
if (Math.abs(newHeading - this.state.currentHeading) > 1) {
|
||||
this.state.currentHeading = newHeading;
|
||||
console.log('方向更新(来自Compass):', newHeading);
|
||||
// 只有在有位置信息时才更新标记
|
||||
if (this.state.currentLocation) {
|
||||
this.updateLocationMarker();
|
||||
}
|
||||
console.log('开始监听设备方向(优先使用旋转矢量传感器)...');
|
||||
|
||||
// 1. 优先尝试使用旋转矢量传感器(通过DeviceOrientationEvent的quaternion)
|
||||
if (window.DeviceOrientationEvent) {
|
||||
// 检查是否支持quaternion(旋转矢量传感器)
|
||||
const testEvent = new DeviceOrientationEvent('test', {});
|
||||
if (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') {
|
||||
// iOS 13+ 需要请求权限
|
||||
console.log('请求设备方向权限(尝试使用旋转矢量传感器)...');
|
||||
DeviceOrientationEvent.requestPermission()
|
||||
.then(response => {
|
||||
if (response === 'granted') {
|
||||
console.log('设备方向权限已授予,监听旋转矢量传感器');
|
||||
window.addEventListener('deviceorientation', this.handleOrientation, { passive: false });
|
||||
} else {
|
||||
console.warn('设备方向权限被拒绝,尝试传统传感器');
|
||||
this.fallbackToTraditionalSensor();
|
||||
}
|
||||
},
|
||||
(error) => console.error('获取方向失败:', error),
|
||||
{ frequency: 100 }
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('请求设备方向权限失败:', error);
|
||||
this.fallbackToTraditionalSensor();
|
||||
});
|
||||
} else {
|
||||
console.warn('设备方向功能不可用');
|
||||
// 其他设备直接监听
|
||||
console.log('直接监听设备方向事件(尝试旋转矢量传感器)');
|
||||
window.addEventListener('deviceorientation', this.handleOrientation, { passive: false });
|
||||
}
|
||||
} else {
|
||||
// 2. 尝试使用DeviceMotionEvent(可能包含旋转矢量数据)
|
||||
if (window.DeviceMotionEvent) {
|
||||
console.log('尝试使用DeviceMotionEvent(旋转矢量传感器)');
|
||||
if (typeof DeviceMotionEvent !== 'undefined' && typeof DeviceMotionEvent.requestPermission === 'function') {
|
||||
DeviceMotionEvent.requestPermission()
|
||||
.then(response => {
|
||||
if (response === 'granted') {
|
||||
window.addEventListener('devicemotion', this.handleMotion, { passive: false });
|
||||
} else {
|
||||
this.fallbackToTraditionalSensor();
|
||||
}
|
||||
})
|
||||
.catch(() => this.fallbackToTraditionalSensor());
|
||||
} else {
|
||||
window.addEventListener('devicemotion', this.handleMotion, { passive: false });
|
||||
}
|
||||
} else {
|
||||
// 3. 降级到传统传感器
|
||||
console.log('旋转矢量传感器不可用,使用传统传感器');
|
||||
this.fallbackToTraditionalSensor();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理设备方向变化
|
||||
* 处理DeviceMotion事件(可能包含旋转矢量数据)
|
||||
*/
|
||||
handleMotion(event) {
|
||||
const now = Date.now();
|
||||
if (now - this.lastOrientationUpdateTime < 50) {
|
||||
return;
|
||||
}
|
||||
this.lastOrientationUpdateTime = now;
|
||||
|
||||
// 检查是否有旋转速率数据(融合传感器)
|
||||
if (event.rotationRate) {
|
||||
const { alpha, beta, gamma } = event.rotationRate;
|
||||
if (alpha !== null && alpha !== undefined && !isNaN(alpha)) {
|
||||
// 使用旋转速率计算方向(需要积分,这里简化处理)
|
||||
// 实际应用中,旋转矢量传感器通常通过DeviceOrientationEvent的quaternion提供
|
||||
const rawHeading = this.normalizeHeading(alpha);
|
||||
const smoothedHeading = this.smoothHeading(rawHeading);
|
||||
this.updateHeadingIfChanged(smoothedHeading);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 降级到传统传感器
|
||||
*/
|
||||
fallbackToTraditionalSensor() {
|
||||
console.log('使用传统方向传感器(DeviceOrientationEvent alpha)');
|
||||
// 使用传统的DeviceOrientationEvent(如果没有quaternion)
|
||||
if (window.DeviceOrientationEvent) {
|
||||
if (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') {
|
||||
DeviceOrientationEvent.requestPermission()
|
||||
.then(response => {
|
||||
if (response === 'granted') {
|
||||
window.addEventListener('deviceorientation', this.handleOrientation, { passive: false });
|
||||
} else {
|
||||
this.fallbackToCompassAPI();
|
||||
}
|
||||
})
|
||||
.catch(() => this.fallbackToCompassAPI());
|
||||
} else {
|
||||
window.addEventListener('deviceorientation', this.handleOrientation, { passive: false });
|
||||
}
|
||||
} else {
|
||||
this.fallbackToCompassAPI();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新方向(如果变化足够大)
|
||||
*/
|
||||
updateHeadingIfChanged(newHeading) {
|
||||
const oldHeading = this.state.currentHeading;
|
||||
const diff = Math.abs(this.angleDifference(newHeading, oldHeading));
|
||||
|
||||
if (diff >= 1 || oldHeading === 0) {
|
||||
this.state.currentHeading = newHeading;
|
||||
if (this.state.currentLocation) {
|
||||
requestAnimationFrame(() => {
|
||||
this.updateLocationMarker();
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 降级到Compass API(uni-app)
|
||||
*/
|
||||
fallbackToCompassAPI() {
|
||||
if (typeof plus !== 'undefined' && plus.compass) {
|
||||
this.state.watchOrientationId = plus.compass.watchHeading(
|
||||
(heading) => {
|
||||
const rawHeading = heading.magneticHeading;
|
||||
// 使用平滑滤波处理Compass数据
|
||||
const smoothedHeading = this.smoothHeading(rawHeading);
|
||||
const oldHeading = this.state.currentHeading;
|
||||
const diff = Math.abs(this.angleDifference(smoothedHeading, oldHeading));
|
||||
|
||||
// 只有当方向变化超过1度时才更新
|
||||
if (diff >= 1 || oldHeading === 0) {
|
||||
this.state.currentHeading = smoothedHeading;
|
||||
// 只有在有位置信息时才更新标记
|
||||
if (this.state.currentLocation) {
|
||||
requestAnimationFrame(() => {
|
||||
this.updateLocationMarker();
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => console.error('获取方向失败:', error),
|
||||
{ frequency: 100 } // 100ms更新一次
|
||||
);
|
||||
} else {
|
||||
console.warn('设备方向功能完全不可用');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理设备方向变化(优化:优先使用旋转矢量传感器)
|
||||
*/
|
||||
handleOrientation(event) {
|
||||
// alpha: 绕Z轴旋转(指南针方向,0-360度)
|
||||
// 注意:某些设备可能使用不同的属性
|
||||
let newHeading = null;
|
||||
const now = Date.now();
|
||||
// 节流:限制更新频率到每50ms一次(20Hz),平衡实时性和性能
|
||||
if (now - this.lastOrientationUpdateTime < 50) {
|
||||
return;
|
||||
}
|
||||
this.lastOrientationUpdateTime = now;
|
||||
|
||||
let rawHeading = null;
|
||||
|
||||
if (event.alpha !== null && event.alpha !== undefined && !isNaN(event.alpha)) {
|
||||
newHeading = event.alpha;
|
||||
} else if (event.webkitCompassHeading !== null && event.webkitCompassHeading !== undefined) {
|
||||
// iOS Safari 可能使用 webkitCompassHeading
|
||||
newHeading = event.webkitCompassHeading;
|
||||
// 1. 优先使用旋转矢量传感器(四元数数据)- 最稳定
|
||||
if (event.quaternion && Array.isArray(event.quaternion) && event.quaternion.length >= 4) {
|
||||
// 旋转矢量传感器提供的四元数数据 [x, y, z, w]
|
||||
const [qx, qy, qz, qw] = event.quaternion;
|
||||
rawHeading = this.quaternionToHeading(qx, qy, qz, qw);
|
||||
console.log('使用旋转矢量传感器(四元数):', rawHeading.toFixed(1), '度');
|
||||
}
|
||||
// 2. 检查是否有quaternion属性(某些浏览器可能以对象形式提供)
|
||||
else if (event.quaternion && typeof event.quaternion === 'object') {
|
||||
const q = event.quaternion;
|
||||
if (q.x !== undefined && q.y !== undefined && q.z !== undefined && q.w !== undefined) {
|
||||
rawHeading = this.quaternionToHeading(q.x, q.y, q.z, q.w);
|
||||
console.log('使用旋转矢量传感器(四元数对象):', rawHeading.toFixed(1), '度');
|
||||
}
|
||||
}
|
||||
// 3. 降级到传统传感器(alpha)
|
||||
else if (event.alpha !== null && event.alpha !== undefined && !isNaN(event.alpha)) {
|
||||
// event.alpha 是绕Z轴旋转的角度(0-360度)
|
||||
// 在某些设备上,alpha是逆时针的,需要转换为顺时针
|
||||
// 根据设备类型调整:Android通常需要反转,iOS可能不需要
|
||||
// 先尝试不反转
|
||||
rawHeading = event.alpha;
|
||||
|
||||
// 如果方向反了,可以尝试反转(取消下面的注释):
|
||||
// rawHeading = (360 - event.alpha) % 360;
|
||||
|
||||
// 或者使用headingOffset来校正(更灵活)
|
||||
// this.headingOffset = 180; // 在初始化时设置
|
||||
}
|
||||
// 4. iOS Safari 使用 webkitCompassHeading
|
||||
else if (event.webkitCompassHeading !== null && event.webkitCompassHeading !== undefined) {
|
||||
rawHeading = event.webkitCompassHeading;
|
||||
}
|
||||
// 5. 某些平板设备使用 absolute 模式
|
||||
else if (event.absolute !== undefined && event.absolute && event.alpha !== null) {
|
||||
rawHeading = (360 - event.alpha) % 360;
|
||||
}
|
||||
|
||||
if (newHeading !== null && !isNaN(newHeading)) {
|
||||
// 只有当方向变化超过1度时才更新,避免频繁更新
|
||||
const oldHeading = this.state.currentHeading;
|
||||
if (Math.abs(newHeading - oldHeading) > 1 || oldHeading === 0) {
|
||||
this.state.currentHeading = newHeading;
|
||||
console.log('方向更新:', newHeading, '度');
|
||||
// 只有在有位置信息时才更新标记
|
||||
if (this.state.currentLocation) {
|
||||
this.updateLocationMarker();
|
||||
}
|
||||
}
|
||||
if (rawHeading !== null && !isNaN(rawHeading)) {
|
||||
// 使用移动平均滤波平滑方向数据(减少抖动)
|
||||
const smoothedHeading = this.smoothHeading(rawHeading);
|
||||
|
||||
// 更新方向(如果变化足够大)
|
||||
this.updateHeadingIfChanged(smoothedHeading);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -1653,10 +1899,19 @@
|
|||
this.state.watchOrientationId = null;
|
||||
}
|
||||
|
||||
// 移除方向事件监听
|
||||
// 移除方向事件监听(包括旋转矢量传感器和传统传感器)
|
||||
if (this.handleOrientation) {
|
||||
window.removeEventListener('deviceorientation', this.handleOrientation);
|
||||
}
|
||||
if (this.handleMotion) {
|
||||
window.removeEventListener('devicemotion', this.handleMotion);
|
||||
}
|
||||
|
||||
// 清理方向历史记录
|
||||
if (this.headingHistory) {
|
||||
this.headingHistory = [];
|
||||
}
|
||||
this.lastOrientationUpdateTime = 0;
|
||||
|
||||
// 移除定位标记
|
||||
if (this.overlays.locationMarker && this.map) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue