From 5f28cfe935281d23ea7c0c82bf91fd0f2d3334e0 Mon Sep 17 00:00:00 2001 From: cwchen <1048842385@qq.com> Date: Wed, 14 Jan 2026 16:49:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=90=8E=E7=9A=84=E5=9C=B0?= =?UTF-8?q?=E7=90=86=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/static/map.html | 188 +++++++++++--------------------------------- 1 file changed, 45 insertions(+), 143 deletions(-) diff --git a/src/static/map.html b/src/static/map.html index e991984..0ed7ec2 100644 --- a/src/static/map.html +++ b/src/static/map.html @@ -421,7 +421,6 @@ lastLocationTime: 0, // 上次位置更新时间 lastLocationPoint: null, // 上次位置点,用于计算移动速度 isMoving: false, // 是否在移动状态 - screenOrientation: 'landscape', // 屏幕方向:'landscape'(横屏)或 'portrait'(竖屏) elements: { panel: null, tree: null, @@ -712,8 +711,8 @@ point.lat ); - // 位置变化超过1米就更新,或者精度提升超过5米(降低阈值减少延迟) - if (distance > 1 || + // 位置变化超过2米就更新,或者精度提升超过5米 + if (distance > 2 || (accuracy < this.state.currentLocation.accuracy - 5) || (accuracy < 50 && this.state.currentLocation.accuracy >= 50)) { shouldUpdate = true; @@ -789,8 +788,8 @@ point.lat ); - // 位置变化超过1米就更新,或者精度提升超过5米(降低阈值减少延迟) - if (distance > 1 || + // 位置变化超过2米就更新,或者精度提升超过5米 + if (distance > 2 || (accuracy < this.state.currentLocation.accuracy - 5) || (accuracy < 50 && this.state.currentLocation.accuracy >= 50)) { shouldUpdate = true; @@ -837,7 +836,7 @@ enableHighAccuracy: true, // 使用GPS精确定位 timeout: 6000 // 6秒超时 }); - }, 300); // 每0.3秒更新一次,提高实时性和灵敏度,减少延迟 + }, 500); // 每0.5秒更新一次,提高实时性和灵敏度 // 保存geolocation实例,以便后续使用 this.baiduGeolocation = geolocation; @@ -1350,20 +1349,17 @@ return; } - // 移动时立即更新位置,减少延迟;静止时使用requestAnimationFrame平滑更新 - if (this.isMoving) { - // 移动时直接更新,不使用requestAnimationFrame延迟 - this._doUpdateLocationMarker(); - } else { - // 静止时使用requestAnimationFrame平滑更新 - if (this.updateMarkerTimer) { - cancelAnimationFrame(this.updateMarkerTimer); - } - this.updateMarkerTimer = requestAnimationFrame(() => { - this.updateMarkerTimer = null; - this._doUpdateLocationMarker(); - }); + // 如果已经有待处理的更新,取消它,重新调度(确保使用最新数据) + if (this.updateMarkerTimer) { + cancelAnimationFrame(this.updateMarkerTimer); } + + // 使用requestAnimationFrame实现平滑更新,保持实时性 + // 对于位置更新,立即执行;对于方向更新,异步执行 + this.updateMarkerTimer = requestAnimationFrame(() => { + this.updateMarkerTimer = null; + this._doUpdateLocationMarker(); + }); }, /** @@ -1378,8 +1374,7 @@ try { // 优先更新位置(立即执行,不等待方向更新) if (typeof this.overlays.locationMarker.setPosition === 'function') { - // 直接更新位置,实时跟随移动 - // 移动时立即更新,静止时也可以立即更新(已通过updateLocationMarker控制) + // 直接更新位置,实时跟随移动(不检查距离,每次都更新以确保平滑) this.overlays.locationMarker.setPosition(point); } else { // 如果不支持setPosition,检查位置是否变化(降低阈值,提高灵敏度) @@ -1397,16 +1392,16 @@ } // 实时更新方向(使用角度差值计算,考虑0-360度边界) - // 统一使用1度阈值,确保方向更新及时准确 - const headingThreshold = 1; + // 移动时提高阈值(2度),减少抖动;静止时降低阈值(1度),保持响应性 + const headingThreshold = this.isMoving ? 2 : 1; const headingChanged = !this.lastHeading || Math.abs(this.angleDifference(this.state.currentHeading, this.lastHeading)) >= headingThreshold; if (headingChanged) { const oldHeading = this.lastHeading; this.lastHeading = this.state.currentHeading; - // 移动时立即更新图标,减少延迟;静止时使用requestAnimationFrame平滑更新 - const updateIcon = () => { + // 异步更新图标(使用requestAnimationFrame确保平滑,不阻塞位置更新) + requestAnimationFrame(() => { this.createRotatedLocationIcon(this.state.currentHeading).then((icon) => { if (this.overlays.locationMarker) { // 优先使用setIcon更新(不删除重建) @@ -1425,15 +1420,7 @@ // 恢复旧的方向值 this.lastHeading = oldHeading; }); - }; - - if (this.isMoving) { - // 移动时立即更新,不使用requestAnimationFrame延迟 - updateIcon(); - } else { - // 静止时使用requestAnimationFrame平滑更新 - requestAnimationFrame(updateIcon); - } + }); } } catch (e) { // 如果更新失败,重新创建标记 @@ -1562,24 +1549,18 @@ // 转换公式:画布角度 = 90度 - 地图角度(因为画布的0度对应地图的90度) // 应用方向偏移量(用于校正方向偏差) - let adjustedHeading = this.normalizeHeading(heading + (this.headingOffset || 0)); - - // 根据屏幕方向进一步调整(如果需要) - // 注意:方向校正已经在handleOrientation中处理,这里通常不需要再次调整 - // 但如果图标旋转仍有问题,可以在这里添加额外的校正 + const adjustedHeading = this.normalizeHeading(heading + (this.headingOffset || 0)); // 转换为画布旋转角度 // 标准转换:画布的0度(向右)对应地图的90度(正东) // 所以:画布角度 = 90度 - 地图角度 - - // 根据屏幕方向调整旋转角度 let rotation = (90 - adjustedHeading) * Math.PI / 180; - // 如果横屏和竖屏方向表现不同,可以在这里进一步调整 - // 例如:竖屏时可能需要额外的180度反转 - // if (this.screenOrientation === 'portrait') { - // rotation = (270 - adjustedHeading) * Math.PI / 180; - // } + // 如果方向仍然不对,可以尝试以下方案(取消注释): + // 方案1:反转180度 + // rotation = (270 - adjustedHeading) * Math.PI / 180; + // 方案2:直接使用heading(如果图标本身已经指向正确方向) + // rotation = -adjustedHeading * Math.PI / 180; ctx.rotate(rotation); @@ -1606,18 +1587,6 @@ return heading; }, - /** - * 检测屏幕方向 - */ - detectScreenOrientation() { - const width = window.innerWidth || window.screen.width; - const height = window.innerHeight || window.screen.height; - // 如果宽度大于高度,认为是横屏;否则是竖屏 - this.screenOrientation = width > height ? 'landscape' : 'portrait'; - console.log('屏幕方向:', this.screenOrientation, `(${width}x${height})`); - return this.screenOrientation; - }, - /** * 计算两个角度之间的最短差值(考虑0-360度边界) */ @@ -1628,20 +1597,6 @@ return diff; }, - /** - * 判断方向是否为南北方向(需要反转) - * 南北方向:0度(正北)、180度(正南),以及0-45度、135-225度、315-360度范围 - * 东西方向:90度(正东)、270度(正西),以及45-135度、225-315度范围 - */ - isNorthSouthDirection(heading) { - // 归一化到0-360度 - const normalized = this.normalizeHeading(heading); - // 南北方向:0-45度、135-225度、315-360度 - return (normalized >= 0 && normalized <= 45) || - (normalized >= 135 && normalized <= 225) || - (normalized >= 315 && normalized <= 360); - }, - /** * 移动平均滤波(减少抖动) * 移动时使用更强的平滑,静止时使用较弱的平滑 @@ -1653,8 +1608,8 @@ } // 根据移动状态动态调整历史记录大小 - // 移动时使用较少样本(3个)减少延迟,静止时使用较多样本(5个)保持平滑 - const targetHistorySize = this.isMoving ? 3 : 5; + // 移动时使用更多样本(10个)进行更强的平滑,静止时使用较少样本(5个)保持响应性 + const targetHistorySize = this.isMoving ? 10 : 5; if (!this.headingHistorySize) { this.headingHistorySize = targetHistorySize; } else { @@ -1669,7 +1624,7 @@ } // 如果历史记录不足,直接返回原始值 - const minHistorySize = this.isMoving ? 1 : 2; // 移动时减少样本要求,降低延迟,提高响应性 + const minHistorySize = this.isMoving ? 5 : 3; // 移动时需要更多样本 if (this.headingHistory.length < minHistorySize) { return rawHeading; } @@ -1725,22 +1680,6 @@ this.headingHistory = []; this.lastOrientationUpdateTime = 0; - // 检测屏幕方向 - this.detectScreenOrientation(); - - // 监听屏幕方向变化 - if (window.addEventListener) { - window.addEventListener('resize', () => { - this.detectScreenOrientation(); - }); - // 监听orientationchange事件(移动设备) - window.addEventListener('orientationchange', () => { - setTimeout(() => { - this.detectScreenOrientation(); - }, 100); // 延迟100ms确保方向已改变 - }); - } - console.log('开始监听设备方向(优先使用旋转矢量传感器)...'); // 1. 优先尝试使用旋转矢量传感器(通过DeviceOrientationEvent的quaternion) @@ -1849,22 +1788,17 @@ const oldHeading = this.state.currentHeading; const diff = Math.abs(this.angleDifference(newHeading, oldHeading)); - // 统一使用1度阈值,确保方向更新及时准确 - const threshold = 1; + // 移动时提高阈值(2度),减少抖动;静止时降低阈值(1度),保持响应性 + const threshold = this.isMoving ? 2 : 1; if (diff >= threshold || oldHeading === 0) { this.state.currentHeading = newHeading; console.log('方向更新:', newHeading.toFixed(1), '度', '变化:', diff.toFixed(1), '度', this.isMoving ? '(移动中)' : '(静止)'); if (this.state.currentLocation) { - // 移动时立即更新,静止时使用requestAnimationFrame - if (this.isMoving) { - this.updateLocationMarker(); // 移动时直接调用,已在updateLocationMarker中处理 - } else { - requestAnimationFrame(() => { - this.updateLocationMarker(); - }); - } + requestAnimationFrame(() => { + this.updateLocationMarker(); + }); } } }, @@ -1933,10 +1867,15 @@ else if (event.alpha !== null && event.alpha !== undefined && !isNaN(event.alpha)) { // event.alpha 是绕Z轴旋转的角度(0-360度) // 在某些设备上,alpha是逆时针的,需要转换为顺时针 - // 根据实际测试,Android设备通常需要反转 - // 尝试反转:360 - alpha - rawHeading = (360 - event.alpha) % 360; - console.log('使用传统传感器(alpha):', event.alpha.toFixed(1), '度 ->', rawHeading.toFixed(1), '度'); + // 根据设备类型调整: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) { @@ -1948,45 +1887,8 @@ } if (rawHeading !== null && !isNaN(rawHeading)) { - // 根据屏幕方向和移动状态分别校正方向角度 - let correctedHeading = rawHeading; - const isPortrait = this.screenOrientation === 'portrait'; - const isLandscape = this.screenOrientation === 'landscape'; - - // 横屏 + 移动:需要反转180度 - if (this.isMoving && isLandscape) { - correctedHeading = (rawHeading + 180) % 360; - console.log('横屏+移动时方向反转:', rawHeading.toFixed(1), '度 ->', correctedHeading.toFixed(1), '度'); - } - // 横屏 + 静止:保持原始方向或需要特定校正 - else if (!this.isMoving && isLandscape) { - // 横屏静止时,可能需要加180度或保持原样,根据实际测试调整 - // correctedHeading = (rawHeading + 180) % 360; // 如果需要反转,取消注释 - correctedHeading = rawHeading; // 暂时保持原样 - console.log('横屏+静止时方向:', rawHeading.toFixed(1), '度 ->', correctedHeading.toFixed(1), '度'); - } - // 竖屏 + 移动:根据移动方向判断是否需要反转 - // 东西方向(90度、270度)时方向是准的,不需要反转 - // 南北方向(0度、180度)时方向是反的,需要反转180度 - else if (this.isMoving && isPortrait) { - if (this.isNorthSouthDirection(rawHeading)) { - // 南北方向,需要反转180度 - correctedHeading = (rawHeading + 180) % 360; - console.log('竖屏+移动(南北方向)时方向反转:', rawHeading.toFixed(1), '度 ->', correctedHeading.toFixed(1), '度'); - } else { - // 东西方向,保持原样 - correctedHeading = rawHeading; - console.log('竖屏+移动(东西方向)时方向保持:', rawHeading.toFixed(1), '度'); - } - } - // 竖屏 + 静止:需要反转180度 - else if (!this.isMoving && isPortrait) { - correctedHeading = (rawHeading + 180) % 360; - console.log('竖屏+静止时方向反转:', rawHeading.toFixed(1), '度 ->', correctedHeading.toFixed(1), '度'); - } - // 使用移动平均滤波平滑方向数据(减少抖动) - const smoothedHeading = this.smoothHeading(correctedHeading); + const smoothedHeading = this.smoothHeading(rawHeading); // 更新方向(如果变化足够大) this.updateHeadingIfChanged(smoothedHeading);