完善设置面板并整理动画阶段总结
This commit is contained in:
50
GeminiAnlysis.md
Normal file
50
GeminiAnlysis.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# CMR-Mini 项目深度分析报告 (GeminiAnalysis.md)
|
||||
|
||||
## 1. 项目定位与核心愿景
|
||||
**CMR-Mini** 是一个运行在微信小程序环境中的高性能**定向越野 (Orienteering)** 实时竞赛/练习引擎。其核心竞争力在于通过自研的 **WebGL 地图渲染管线** 提供流畅的地图交互,并结合高精度多传感器融合技术(GPS、罗盘、心率、加速度计等)实现精准的运动反馈。
|
||||
|
||||
## 2. 核心系统架构分析
|
||||
|
||||
### 2.1 地图渲染引擎 (Map Engine)
|
||||
* **渲染技术**:采用 `Single WebGL Pipeline`。相比微信原生地图组件,具有更高的定制化能力,特别是在“Heading-Up”(朝向朝上)模式下的性能表现。
|
||||
* **瓦片管理**:通过 `TileStore` 实现三级缓存(内存 -> 磁盘 -> 网络),并支持 `tilePersistentCache`。
|
||||
* **投影逻辑**:采用 `WGS84 -> WorldTile -> Camera -> Screen` 的标准 GIS 变换链,能够精准处理地理坐标到屏幕像素的映射。
|
||||
|
||||
### 2.2 传感器融合系统 (Sensor System)
|
||||
* **CompassHeadingController**:核心逻辑在于罗盘数据 (`wx.onCompassChange`) 与设备姿态 (`wx.onDeviceMotionChange`) 的协同。
|
||||
* **LocationController**:支持真实 GPS 数据与 Mock 模拟器(通过 WebSocket 连接 `mock-gps-sim` 工具)的无缝切换。
|
||||
* **TelemetryRuntime**:实现了运动参数的实时计算,包括速度、距离目标点距离、心率分区等指标。
|
||||
|
||||
### 2.3 游戏逻辑与规则 (Game Logic)
|
||||
* **GameRuntime**:驱动对局状态机,支持“顺序赛 (Classic Sequential)”与“积分赛 (Score-O)”。
|
||||
* **PunchPolicy**:实现了自动进入检查点范围触发、手动打点、跳过点位等业务逻辑。
|
||||
|
||||
## 3. 指北针 (Compass) 平滑度瓶颈分析
|
||||
根据目前的实现,指北针的卡顿感主要源于以下三个层面:
|
||||
|
||||
1. **采样频率与插值逻辑**:
|
||||
* 目前使用 `interpolateHeadingDeg` 进行线性差值,且 `ABSOLUTE_HEADING_CORRECTION` 为固定系数 (0.44)。这种静态系数在“静态微调”时显得不够敏锐,在“快速旋转”时又显得滞后。
|
||||
2. **Android/iOS 差异化丢帧**:
|
||||
* Android 传感器回调频率不稳定。
|
||||
* 逻辑中对 `direction` 进行了严格的数值有效性判断,若系统由于硬件抖动返回短时异常值,会导致视觉上的“跳帧”。
|
||||
3. **UI 同步周期限制**:
|
||||
* `MapEngine` 的 `UI_SYNC_INTERVAL_MS` 设置为 80ms,这意味着视觉反馈的最高帧率仅为 12.5Hz,远低于屏幕刷新率,导致指针转动不够丝滑。
|
||||
|
||||
## 4. 优化技术路线建议
|
||||
|
||||
### 4.1 引入指数加权移动平均 (EWMA) 的动态系数
|
||||
建议根据旋转角速度动态调整平滑系数。当检测到瞬时角位移较大时,降低平滑度以追求响应速度;当位移较小时,增加平滑度以过滤手抖带来的噪声。
|
||||
|
||||
### 4.2 视觉平滑:使用 CSS Transform 或 WebGL 帧间补偿
|
||||
目前数据是由控制器下发到 UI 的。建议:
|
||||
* **方案 A (推荐)**:在 UI 层(`.wxml`/`.wxss`)利用 `transition: transform 0.1s linear;` 实现视觉层面的自动补帧。
|
||||
* **方案 B**:在 WebGL 渲染循环内进行帧间插值,将数据的 12.5Hz 提升到 渲染循环的 60Hz。
|
||||
|
||||
### 4.3 预测与死区 (Dead-zone) 过滤
|
||||
在 `CompassHeadingController` 中加入微小位移的死区过滤逻辑,避免由于硬件高频微小抖动导致的视图高频重绘,降低系统功耗的同时提升视觉稳定性。
|
||||
|
||||
## 5. 结论
|
||||
CMR-Mini 已经建立了一个非常坚实的专业定向越野引擎基础。后续的优化重点应从“功能的实现”转向“交互的极致平滑”,特别是针对指北针这类核心导向组件,需要更精细化的信号处理策略。
|
||||
|
||||
---
|
||||
*Generated by Gemini CLI Analysis Tool*
|
||||
192
animation-pipeline-summary.md
Normal file
192
animation-pipeline-summary.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# 动画体系阶段性小结
|
||||
|
||||
## 1. 当前定位
|
||||
|
||||
目前动画体系已经从“页面里临时加 class”的阶段,进入了**有主链、有分层、有性能分级**的阶段。
|
||||
|
||||
当前主链可以概括为:
|
||||
|
||||
- 事件触发
|
||||
- `feedbackConfig`
|
||||
- `UiEffectDirector`
|
||||
- `FeedbackDirector`
|
||||
- `MapEngine`
|
||||
- 页面层 / 渲染层消费
|
||||
|
||||
也就是:
|
||||
|
||||
**事件 -> 效果配置 -> 宿主提交 -> 页面 / Renderer 落地**
|
||||
|
||||
这说明动画已经不再是零散实现,而开始进入架构化管理。
|
||||
|
||||
---
|
||||
|
||||
## 2. 已经完成的内容
|
||||
|
||||
### 2.1 HUD 动效
|
||||
|
||||
已经完成:
|
||||
|
||||
- 打点成功后的 `进度` 动效
|
||||
- 打点成功后的 `点距` 动效
|
||||
- HUD 数字轻量过渡:
|
||||
- 计时
|
||||
- 里程
|
||||
- 速度
|
||||
- 心率
|
||||
|
||||
这些动效已经接入正式链路,不是页面单独临时处理。
|
||||
|
||||
### 2.2 地图空间动画
|
||||
|
||||
已经完成:
|
||||
|
||||
- 当前目标点状态强调
|
||||
- 可打点状态强调
|
||||
- 已完成点状态过渡
|
||||
- 已跳过点灰态与标记
|
||||
- 开始点 / 终点完成后的 settle 外环
|
||||
- 轻量地图 pulse
|
||||
|
||||
### 2.3 局部 UI / Stage 动效
|
||||
|
||||
已经完成:
|
||||
|
||||
- 轻量 stage flash
|
||||
- 顶部提示和局部反馈的基础动画承载链
|
||||
|
||||
### 2.4 动画性能分级
|
||||
|
||||
已经完成 2 级动画分级:
|
||||
|
||||
- `standard`
|
||||
- `lite`
|
||||
|
||||
当前 `lite` 的主要策略包括:
|
||||
|
||||
- 减少 pulse 层数
|
||||
- 降低几何分段
|
||||
- 降低渲染动画频率
|
||||
- 关闭部分 HUD 动画
|
||||
- 关闭或减弱某些 stage/UI 动效
|
||||
|
||||
这意味着动画体系已经开始考虑**低端机表现**,不是只追求效果。
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前架构上的价值
|
||||
|
||||
动画体系现在已经带来了几个明确收益:
|
||||
|
||||
- 动效不再散落在多个页面细节里
|
||||
- 高频状态变化有了统一反馈语言
|
||||
- 地图状态和 HUD 状态开始形成一致体验
|
||||
- 性能分级已经进入体系,可服务低端机
|
||||
|
||||
从架构角度看,这意味着:
|
||||
|
||||
**动画已经成为正式能力层,而不是临时视觉补丁。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前还不够完整的地方
|
||||
|
||||
虽然主链已经成型,但当前还没有完全形成“动画字典”和完整 profile 体系。
|
||||
|
||||
目前仍然存在这些不足:
|
||||
|
||||
- 哪些事件触发哪些动画,还没有整理成统一字典
|
||||
- 部分高频状态切换还不够连续
|
||||
- `跳点` 已有逻辑和状态,但动画语言还不完整
|
||||
- 危险/高压状态动画还没有正式开始
|
||||
- 动画 profile 还没有真正配置化
|
||||
|
||||
所以当前阶段可以定义为:
|
||||
|
||||
**第一阶段后半段:主链已成型,但还需要把高频体验打磨完整。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 下一阶段最值得做的事情
|
||||
|
||||
### 5.1 先整理动画字典
|
||||
|
||||
建议先把动画按事件梳理出来,例如:
|
||||
|
||||
- `session_started`
|
||||
- `control_ready`
|
||||
- `control_completed:start`
|
||||
- `control_completed:control`
|
||||
- `control_completed:finish`
|
||||
- `control_skipped`
|
||||
- `gps_lock_changed`
|
||||
- `guidance_state_changed`
|
||||
- `heart_rate_zone_changed`
|
||||
|
||||
并明确每个事件对应:
|
||||
|
||||
- 地图动画
|
||||
- HUD 动画
|
||||
- UI 动画
|
||||
- `lite` 下是否保留
|
||||
|
||||
这一步是当前最值得优先完成的工作。
|
||||
|
||||
### 5.2 补完整“目标状态切换连续感”
|
||||
|
||||
继续打磨:
|
||||
|
||||
- 当前目标
|
||||
- 进入可打点
|
||||
- 打点成功
|
||||
- 切到下一个目标
|
||||
|
||||
让这一整段切换更连贯、更有节奏。
|
||||
|
||||
### 5.3 补齐“跳点”动画
|
||||
|
||||
建议下一步把跳点也正式纳入动画体系:
|
||||
|
||||
- 跳点确认后
|
||||
- 当前点灰化
|
||||
- 下一个目标接管强调
|
||||
- HUD 给出轻量反馈
|
||||
|
||||
### 5.4 再做危险 / 高压反馈
|
||||
|
||||
这部分适合进入下一阶段:
|
||||
|
||||
- 高心率反馈
|
||||
- 危险区反馈
|
||||
- 幽灵追逐反馈
|
||||
- 边缘呼吸 / 紧张感动效
|
||||
|
||||
这条线很适合后续玩法扩展。
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议的实施顺序
|
||||
|
||||
推荐继续推进的顺序:
|
||||
|
||||
1. 动画字典整理
|
||||
2. 目标切换连续感补齐
|
||||
3. 跳点动画补齐
|
||||
4. 危险 / 高压状态动画
|
||||
5. 更进一步的配置化 profile
|
||||
|
||||
---
|
||||
|
||||
## 7. 结论
|
||||
|
||||
当前动画体系已经是一个明确的阶段性成果:
|
||||
|
||||
- 有主链
|
||||
- 有分层
|
||||
- 有高频核心动画
|
||||
- 有性能分级
|
||||
|
||||
接下来最该做的不是“继续零散加动画”,而是:
|
||||
|
||||
**把现有能力收成动画字典,并优先打磨目标切换与跳点这两条高频体验链。**
|
||||
|
||||
@@ -59,6 +59,7 @@ const AUTO_ROTATE_MAX_STEP_DEG = 0.75
|
||||
const AUTO_ROTATE_HEADING_SMOOTHING = 0.46
|
||||
const COMPASS_NEEDLE_FRAME_MS = 16
|
||||
const COMPASS_NEEDLE_SNAP_DEG = 0.08
|
||||
const COMPASS_BOOTSTRAP_RETRY_DELAY_MS = 700
|
||||
const COMPASS_TUNING_PRESETS: Record<CompassTuningProfile, {
|
||||
needleMinSmoothing: number
|
||||
needleMaxSmoothing: number
|
||||
@@ -830,6 +831,7 @@ export class MapEngine {
|
||||
viewSyncTimer: number
|
||||
autoRotateTimer: number
|
||||
compassNeedleTimer: number
|
||||
compassBootstrapRetryTimer: number
|
||||
pendingViewPatch: Partial<MapEngineViewState>
|
||||
mounted: boolean
|
||||
diagnosticUiEnabled: boolean
|
||||
@@ -838,6 +840,7 @@ export class MapEngine {
|
||||
smoothedSensorHeadingDeg: number | null
|
||||
compassDisplayHeadingDeg: number | null
|
||||
targetCompassDisplayHeadingDeg: number | null
|
||||
lastCompassSampleAt: number
|
||||
compassSource: 'compass' | 'motion' | null
|
||||
compassTuningProfile: CompassTuningProfile
|
||||
smoothedMovementHeadingDeg: number | null
|
||||
@@ -1282,6 +1285,7 @@ export class MapEngine {
|
||||
this.viewSyncTimer = 0
|
||||
this.autoRotateTimer = 0
|
||||
this.compassNeedleTimer = 0
|
||||
this.compassBootstrapRetryTimer = 0
|
||||
this.pendingViewPatch = {}
|
||||
this.mounted = false
|
||||
this.diagnosticUiEnabled = false
|
||||
@@ -1290,6 +1294,7 @@ export class MapEngine {
|
||||
this.smoothedSensorHeadingDeg = null
|
||||
this.compassDisplayHeadingDeg = null
|
||||
this.targetCompassDisplayHeadingDeg = null
|
||||
this.lastCompassSampleAt = 0
|
||||
this.compassSource = null
|
||||
this.compassTuningProfile = 'balanced'
|
||||
this.smoothedMovementHeadingDeg = null
|
||||
@@ -1406,6 +1411,7 @@ export class MapEngine {
|
||||
this.clearViewSyncTimer()
|
||||
this.clearAutoRotateTimer()
|
||||
this.clearCompassNeedleTimer()
|
||||
this.clearCompassBootstrapRetryTimer()
|
||||
this.clearPunchFeedbackTimer()
|
||||
this.clearContentCardTimer()
|
||||
this.clearMapPulseTimer()
|
||||
@@ -1424,6 +1430,11 @@ export class MapEngine {
|
||||
|
||||
handleAppShow(): void {
|
||||
this.feedbackDirector.setAppAudioMode('foreground')
|
||||
if (this.mounted) {
|
||||
this.lastCompassSampleAt = 0
|
||||
this.compassController.start()
|
||||
this.scheduleCompassBootstrapRetry()
|
||||
}
|
||||
}
|
||||
|
||||
handleAppHide(): void {
|
||||
@@ -2351,7 +2362,9 @@ export class MapEngine {
|
||||
})
|
||||
this.syncRenderer()
|
||||
this.accelerometerErrorText = null
|
||||
this.lastCompassSampleAt = 0
|
||||
this.compassController.start()
|
||||
this.scheduleCompassBootstrapRetry()
|
||||
this.gyroscopeController.start()
|
||||
this.deviceMotionController.start()
|
||||
}
|
||||
@@ -2980,6 +2993,8 @@ export class MapEngine {
|
||||
}
|
||||
|
||||
handleCompassHeading(headingDeg: number): void {
|
||||
this.lastCompassSampleAt = Date.now()
|
||||
this.clearCompassBootstrapRetryTimer()
|
||||
this.applyHeadingSample(headingDeg, 'compass')
|
||||
}
|
||||
|
||||
@@ -3584,6 +3599,29 @@ export class MapEngine {
|
||||
}
|
||||
}
|
||||
|
||||
clearCompassBootstrapRetryTimer(): void {
|
||||
if (this.compassBootstrapRetryTimer) {
|
||||
clearTimeout(this.compassBootstrapRetryTimer)
|
||||
this.compassBootstrapRetryTimer = 0
|
||||
}
|
||||
}
|
||||
|
||||
scheduleCompassBootstrapRetry(): void {
|
||||
this.clearCompassBootstrapRetryTimer()
|
||||
if (!this.mounted) {
|
||||
return
|
||||
}
|
||||
|
||||
this.compassBootstrapRetryTimer = setTimeout(() => {
|
||||
this.compassBootstrapRetryTimer = 0
|
||||
if (!this.mounted || this.lastCompassSampleAt > 0) {
|
||||
return
|
||||
}
|
||||
this.compassController.stop()
|
||||
this.compassController.start()
|
||||
}, COMPASS_BOOTSTRAP_RETRY_DELAY_MS) as unknown as number
|
||||
}
|
||||
|
||||
syncCompassDisplayState(): void {
|
||||
this.setState({
|
||||
compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.compassDisplayHeadingDeg),
|
||||
|
||||
@@ -29,15 +29,37 @@ type ScaleRulerMajorMarkData = {
|
||||
topPx: number
|
||||
label: string
|
||||
}
|
||||
type SideButtonMode = 'all' | 'left' | 'right' | 'hidden'
|
||||
type SideButtonMode = 'shown' | 'hidden'
|
||||
type SideActionButtonState = 'muted' | 'default' | 'active'
|
||||
type SideButtonPlacement = 'left' | 'right'
|
||||
type CenterScaleRulerAnchorMode = 'screen-center' | 'compass-center'
|
||||
type UserNorthReferenceMode = 'magnetic' | 'true'
|
||||
type CompassTuningProfile = 'smooth' | 'balanced' | 'responsive'
|
||||
type SettingLockKey =
|
||||
| 'lockAnimationLevel'
|
||||
| 'lockSideButtonPlacement'
|
||||
| 'lockAutoRotate'
|
||||
| 'lockCompassTuning'
|
||||
| 'lockScaleRulerVisible'
|
||||
| 'lockScaleRulerAnchor'
|
||||
| 'lockNorthReference'
|
||||
| 'lockHeartRateDevice'
|
||||
type StoredUserSettings = {
|
||||
animationLevel?: AnimationLevel
|
||||
autoRotateEnabled?: boolean
|
||||
compassTuningProfile?: CompassTuningProfile
|
||||
northReferenceMode?: UserNorthReferenceMode
|
||||
sideButtonPlacement?: SideButtonPlacement
|
||||
showCenterScaleRuler?: boolean
|
||||
centerScaleRulerAnchorMode?: CenterScaleRulerAnchorMode
|
||||
lockAnimationLevel?: boolean
|
||||
lockSideButtonPlacement?: boolean
|
||||
lockAutoRotate?: boolean
|
||||
lockCompassTuning?: boolean
|
||||
lockScaleRulerVisible?: boolean
|
||||
lockScaleRulerAnchor?: boolean
|
||||
lockNorthReference?: boolean
|
||||
lockHeartRateDevice?: boolean
|
||||
}
|
||||
type MapPageData = MapEngineViewState & {
|
||||
showDebugPanel: boolean
|
||||
@@ -68,6 +90,16 @@ type MapPageData = MapEngineViewState & {
|
||||
compassTicks: CompassTickData[]
|
||||
compassLabels: CompassLabelData[]
|
||||
sideButtonMode: SideButtonMode
|
||||
sideButtonPlacement: SideButtonPlacement
|
||||
autoRotateEnabled: boolean
|
||||
lockAnimationLevel: boolean
|
||||
lockSideButtonPlacement: boolean
|
||||
lockAutoRotate: boolean
|
||||
lockCompassTuning: boolean
|
||||
lockScaleRulerVisible: boolean
|
||||
lockScaleRulerAnchor: boolean
|
||||
lockNorthReference: boolean
|
||||
lockHeartRateDevice: boolean
|
||||
sideToggleIconSrc: string
|
||||
sideButton2Class: string
|
||||
sideButton4Class: string
|
||||
@@ -334,12 +366,45 @@ function loadStoredUserSettings(): StoredUserSettings {
|
||||
if (normalized.northReferenceMode === 'magnetic' || normalized.northReferenceMode === 'true') {
|
||||
settings.northReferenceMode = normalized.northReferenceMode
|
||||
}
|
||||
if (typeof normalized.autoRotateEnabled === 'boolean') {
|
||||
settings.autoRotateEnabled = normalized.autoRotateEnabled
|
||||
}
|
||||
if (normalized.compassTuningProfile === 'smooth' || normalized.compassTuningProfile === 'balanced' || normalized.compassTuningProfile === 'responsive') {
|
||||
settings.compassTuningProfile = normalized.compassTuningProfile
|
||||
}
|
||||
if (normalized.sideButtonPlacement === 'left' || normalized.sideButtonPlacement === 'right') {
|
||||
settings.sideButtonPlacement = normalized.sideButtonPlacement
|
||||
}
|
||||
if (typeof normalized.showCenterScaleRuler === 'boolean') {
|
||||
settings.showCenterScaleRuler = normalized.showCenterScaleRuler
|
||||
}
|
||||
if (normalized.centerScaleRulerAnchorMode === 'screen-center' || normalized.centerScaleRulerAnchorMode === 'compass-center') {
|
||||
settings.centerScaleRulerAnchorMode = normalized.centerScaleRulerAnchorMode
|
||||
}
|
||||
if (typeof normalized.lockAnimationLevel === 'boolean') {
|
||||
settings.lockAnimationLevel = normalized.lockAnimationLevel
|
||||
}
|
||||
if (typeof normalized.lockSideButtonPlacement === 'boolean') {
|
||||
settings.lockSideButtonPlacement = normalized.lockSideButtonPlacement
|
||||
}
|
||||
if (typeof normalized.lockAutoRotate === 'boolean') {
|
||||
settings.lockAutoRotate = normalized.lockAutoRotate
|
||||
}
|
||||
if (typeof normalized.lockCompassTuning === 'boolean') {
|
||||
settings.lockCompassTuning = normalized.lockCompassTuning
|
||||
}
|
||||
if (typeof normalized.lockScaleRulerVisible === 'boolean') {
|
||||
settings.lockScaleRulerVisible = normalized.lockScaleRulerVisible
|
||||
}
|
||||
if (typeof normalized.lockScaleRulerAnchor === 'boolean') {
|
||||
settings.lockScaleRulerAnchor = normalized.lockScaleRulerAnchor
|
||||
}
|
||||
if (typeof normalized.lockNorthReference === 'boolean') {
|
||||
settings.lockNorthReference = normalized.lockNorthReference
|
||||
}
|
||||
if (typeof normalized.lockHeartRateDevice === 'boolean') {
|
||||
settings.lockHeartRateDevice = normalized.lockHeartRateDevice
|
||||
}
|
||||
return settings
|
||||
} catch {
|
||||
return {}
|
||||
@@ -351,26 +416,24 @@ function persistStoredUserSettings(settings: StoredUserSettings) {
|
||||
wx.setStorageSync(USER_SETTINGS_STORAGE_KEY, settings)
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function toggleStoredSettingLock(settings: StoredUserSettings, key: SettingLockKey): StoredUserSettings {
|
||||
return {
|
||||
...settings,
|
||||
[key]: !settings[key],
|
||||
}
|
||||
}
|
||||
function buildSideButtonVisibility(mode: SideButtonMode) {
|
||||
return {
|
||||
sideButtonMode: mode,
|
||||
showLeftButtonGroup: mode === 'all' || mode === 'left' || mode === 'right',
|
||||
showRightButtonGroups: mode === 'all' || mode === 'right',
|
||||
showBottomDebugButton: mode !== 'hidden',
|
||||
showLeftButtonGroup: mode === 'shown',
|
||||
showRightButtonGroups: false,
|
||||
showBottomDebugButton: true,
|
||||
}
|
||||
}
|
||||
|
||||
function getNextSideButtonMode(currentMode: SideButtonMode): SideButtonMode {
|
||||
if (currentMode === 'all') {
|
||||
return 'left'
|
||||
}
|
||||
if (currentMode === 'left') {
|
||||
return 'right'
|
||||
}
|
||||
if (currentMode === 'right') {
|
||||
return 'hidden'
|
||||
}
|
||||
return 'left'
|
||||
return currentMode === 'shown' ? 'hidden' : 'shown'
|
||||
}
|
||||
function buildCompassTicks(): CompassTickData[] {
|
||||
const ticks: CompassTickData[] = []
|
||||
@@ -409,9 +472,6 @@ function getFallbackStageRect(): MapEngineStageRect {
|
||||
}
|
||||
|
||||
function getSideToggleIconSrc(mode: SideButtonMode): string {
|
||||
if (mode === 'left') {
|
||||
return '../../assets/btn_more2.png'
|
||||
}
|
||||
if (mode === 'hidden') {
|
||||
return '../../assets/btn_more1.png'
|
||||
}
|
||||
@@ -641,6 +701,15 @@ Page({
|
||||
hudPanelIndex: 0,
|
||||
configSourceText: '顺序赛配置',
|
||||
centerScaleRulerAnchorMode: 'screen-center',
|
||||
autoRotateEnabled: false,
|
||||
lockAnimationLevel: false,
|
||||
lockSideButtonPlacement: false,
|
||||
lockAutoRotate: false,
|
||||
lockCompassTuning: false,
|
||||
lockScaleRulerVisible: false,
|
||||
lockScaleRulerAnchor: false,
|
||||
lockNorthReference: false,
|
||||
lockHeartRateDevice: false,
|
||||
gameInfoTitle: '当前游戏',
|
||||
gameInfoSubtitle: '未开始',
|
||||
gameInfoLocalRows: [],
|
||||
@@ -653,6 +722,7 @@ Page({
|
||||
panelDistanceUnitText: '',
|
||||
panelProgressText: '0/0',
|
||||
showPunchHintBanner: true,
|
||||
sideButtonPlacement: 'left',
|
||||
gameSessionStatus: 'idle',
|
||||
gameModeText: '顺序赛',
|
||||
gpsLockEnabled: false,
|
||||
@@ -730,9 +800,9 @@ Page({
|
||||
centerScaleRulerMajorMarks: [],
|
||||
compassTicks: buildCompassTicks(),
|
||||
compassLabels: buildCompassLabels(),
|
||||
...buildSideButtonVisibility('left'),
|
||||
...buildSideButtonVisibility('shown'),
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: 'left',
|
||||
sideButtonMode: 'shown',
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: false,
|
||||
@@ -787,6 +857,9 @@ Page({
|
||||
} as MapPageData
|
||||
|
||||
const derivedPatch: Partial<MapPageData> = {}
|
||||
if (typeof nextPatch.orientationMode === 'string') {
|
||||
nextData.autoRotateEnabled = nextPatch.orientationMode === 'heading-up'
|
||||
}
|
||||
if (
|
||||
this.data.showCenterScaleRuler
|
||||
&& hasAnyPatchKey(nextPatch as Record<string, unknown>, CENTER_SCALE_RULER_DEP_KEYS)
|
||||
@@ -886,9 +959,19 @@ Page({
|
||||
if (storedUserSettings.animationLevel) {
|
||||
mapEngine.handleSetAnimationLevel(storedUserSettings.animationLevel)
|
||||
}
|
||||
const initialAutoRotateEnabled = storedUserSettings.autoRotateEnabled !== false
|
||||
if (initialAutoRotateEnabled) {
|
||||
mapEngine.handleSetHeadingUpMode()
|
||||
} else {
|
||||
mapEngine.handleSetManualMode()
|
||||
}
|
||||
if (storedUserSettings.compassTuningProfile) {
|
||||
mapEngine.handleSetCompassTuningProfile(storedUserSettings.compassTuningProfile)
|
||||
}
|
||||
if (storedUserSettings.northReferenceMode) {
|
||||
mapEngine.handleSetNorthReferenceMode(storedUserSettings.northReferenceMode)
|
||||
}
|
||||
const initialSideButtonPlacement = storedUserSettings.sideButtonPlacement || 'left'
|
||||
|
||||
mapEngine.setDiagnosticUiEnabled(false)
|
||||
centerScaleRulerInputCache = {
|
||||
@@ -914,6 +997,16 @@ Page({
|
||||
hudPanelIndex: 0,
|
||||
configSourceText: '顺序赛配置',
|
||||
centerScaleRulerAnchorMode: initialCenterScaleRulerAnchorMode,
|
||||
autoRotateEnabled: initialAutoRotateEnabled,
|
||||
lockAnimationLevel: !!storedUserSettings.lockAnimationLevel,
|
||||
lockSideButtonPlacement: !!storedUserSettings.lockSideButtonPlacement,
|
||||
lockAutoRotate: !!storedUserSettings.lockAutoRotate,
|
||||
lockCompassTuning: !!storedUserSettings.lockCompassTuning,
|
||||
lockScaleRulerVisible: !!storedUserSettings.lockScaleRulerVisible,
|
||||
lockScaleRulerAnchor: !!storedUserSettings.lockScaleRulerAnchor,
|
||||
lockNorthReference: !!storedUserSettings.lockNorthReference,
|
||||
lockHeartRateDevice: !!storedUserSettings.lockHeartRateDevice,
|
||||
sideButtonPlacement: initialSideButtonPlacement,
|
||||
gameInfoTitle: '当前游戏',
|
||||
gameInfoSubtitle: '未开始',
|
||||
gameInfoLocalRows: [],
|
||||
@@ -996,9 +1089,9 @@ Page({
|
||||
stageFxClass: '',
|
||||
compassTicks: buildCompassTicks(),
|
||||
compassLabels: buildCompassLabels(),
|
||||
...buildSideButtonVisibility('left'),
|
||||
...buildSideButtonVisibility('shown'),
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: 'left',
|
||||
sideButtonMode: 'shown',
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: initialShowCenterScaleRuler,
|
||||
@@ -1218,24 +1311,6 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
handleSetCompassTuningSmooth() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleSetCompassTuningProfile('smooth')
|
||||
}
|
||||
},
|
||||
|
||||
handleSetCompassTuningBalanced() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleSetCompassTuningProfile('balanced')
|
||||
}
|
||||
},
|
||||
|
||||
handleSetCompassTuningResponsive() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleSetCompassTuningProfile('responsive')
|
||||
}
|
||||
},
|
||||
|
||||
handleAutoRotateCalibrate() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleAutoRotateCalibrate()
|
||||
@@ -1339,6 +1414,9 @@ Page({
|
||||
},
|
||||
|
||||
handleClearPreferredHeartRateDevice() {
|
||||
if (this.data.lockHeartRateDevice) {
|
||||
return
|
||||
}
|
||||
if (mapEngine) {
|
||||
mapEngine.handleClearPreferredHeartRateDevice()
|
||||
}
|
||||
@@ -1462,6 +1540,7 @@ Page({
|
||||
const localRows = snapshot.localRows.concat([
|
||||
{ label: '比例尺开关', value: this.data.showCenterScaleRuler ? '开启' : '关闭' },
|
||||
{ label: '比例尺锚点', value: this.data.centerScaleRulerAnchorMode === 'compass-center' ? '指北针圆心' : '屏幕中心' },
|
||||
{ label: '按钮习惯', value: this.data.sideButtonPlacement === 'right' ? '右手' : '左手' },
|
||||
{ label: '比例尺可见', value: this.data.centerScaleRulerVisible ? 'true' : 'false' },
|
||||
{ label: '比例尺中心X', value: `${this.data.centerScaleRulerCenterXPx}px` },
|
||||
{ label: '比例尺零点Y', value: `${this.data.centerScaleRulerZeroYPx}px` },
|
||||
@@ -1575,7 +1654,7 @@ Page({
|
||||
handleSystemSettingsPanelTap() {},
|
||||
|
||||
handleSetAnimationLevelStandard() {
|
||||
if (!mapEngine) {
|
||||
if (this.data.lockAnimationLevel || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetAnimationLevel('standard')
|
||||
@@ -1586,7 +1665,7 @@ Page({
|
||||
},
|
||||
|
||||
handleSetAnimationLevelLite() {
|
||||
if (!mapEngine) {
|
||||
if (this.data.lockAnimationLevel || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetAnimationLevel('lite')
|
||||
@@ -1596,8 +1675,89 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
handleSetSideButtonPlacementLeft() {
|
||||
if (this.data.lockSideButtonPlacement) {
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
sideButtonPlacement: 'left',
|
||||
})
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
sideButtonPlacement: 'left',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetSideButtonPlacementRight() {
|
||||
if (this.data.lockSideButtonPlacement) {
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
sideButtonPlacement: 'right',
|
||||
})
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
sideButtonPlacement: 'right',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetAutoRotateEnabledOn() {
|
||||
if (this.data.lockAutoRotate || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetHeadingUpMode()
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
autoRotateEnabled: true,
|
||||
})
|
||||
},
|
||||
|
||||
handleSetAutoRotateEnabledOff() {
|
||||
if (this.data.lockAutoRotate || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetManualMode()
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
autoRotateEnabled: false,
|
||||
})
|
||||
},
|
||||
|
||||
handleSetCompassTuningSmooth() {
|
||||
if (this.data.lockCompassTuning || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetCompassTuningProfile('smooth')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
compassTuningProfile: 'smooth',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetCompassTuningBalanced() {
|
||||
if (this.data.lockCompassTuning || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetCompassTuningProfile('balanced')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
compassTuningProfile: 'balanced',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetCompassTuningResponsive() {
|
||||
if (this.data.lockCompassTuning || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetCompassTuningProfile('responsive')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
compassTuningProfile: 'responsive',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetNorthReferenceMagnetic() {
|
||||
if (!mapEngine) {
|
||||
if (this.data.lockNorthReference || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetNorthReferenceMode('magnetic')
|
||||
@@ -1608,7 +1768,7 @@ Page({
|
||||
},
|
||||
|
||||
handleSetNorthReferenceTrue() {
|
||||
if (!mapEngine) {
|
||||
if (this.data.lockNorthReference || !mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetNorthReferenceMode('true')
|
||||
@@ -1618,6 +1778,18 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
handleToggleSettingLock(event: WechatMiniprogram.TouchEvent) {
|
||||
const key = event.currentTarget.dataset.key as SettingLockKey | undefined
|
||||
if (!key) {
|
||||
return
|
||||
}
|
||||
const nextValue = !this.data[key]
|
||||
this.setData({
|
||||
[key]: nextValue,
|
||||
} as Record<string, boolean>)
|
||||
persistStoredUserSettings(toggleStoredSettingLock(loadStoredUserSettings(), key))
|
||||
},
|
||||
|
||||
handleOverlayTouch() {},
|
||||
|
||||
handlePunchAction() {
|
||||
@@ -1674,16 +1846,24 @@ Page({
|
||||
}
|
||||
},
|
||||
handleToggleMapRotateMode() {
|
||||
if (!mapEngine) {
|
||||
if (!mapEngine || this.data.lockAutoRotate) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.data.orientationMode === 'heading-up') {
|
||||
mapEngine.handleSetManualMode()
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
autoRotateEnabled: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
mapEngine.handleSetHeadingUpMode()
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
autoRotateEnabled: true,
|
||||
})
|
||||
},
|
||||
handleToggleDebugPanel() {
|
||||
const nextShowDebugPanel = !this.data.showDebugPanel
|
||||
@@ -1788,6 +1968,9 @@ Page({
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerVisibleOn() {
|
||||
if (this.data.lockScaleRulerVisible) {
|
||||
return
|
||||
}
|
||||
this.applyCenterScaleRulerSettings(true, this.data.centerScaleRulerAnchorMode)
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
@@ -1797,6 +1980,9 @@ Page({
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerVisibleOff() {
|
||||
if (this.data.lockScaleRulerVisible) {
|
||||
return
|
||||
}
|
||||
this.applyCenterScaleRulerSettings(false, this.data.centerScaleRulerAnchorMode)
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
@@ -1806,6 +1992,9 @@ Page({
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerAnchorScreenCenter() {
|
||||
if (this.data.lockScaleRulerAnchor) {
|
||||
return
|
||||
}
|
||||
this.applyCenterScaleRulerSettings(this.data.showCenterScaleRuler, 'screen-center')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
@@ -1815,6 +2004,9 @@ Page({
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerAnchorCompassCenter() {
|
||||
if (this.data.lockScaleRulerAnchor) {
|
||||
return
|
||||
}
|
||||
this.applyCenterScaleRulerSettings(this.data.showCenterScaleRuler, 'compass-center')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
|
||||
@@ -85,36 +85,30 @@
|
||||
<view class="game-punch-hint__close" catchtouchstart="handlePunchHintTap" catchtouchmove="handlePunchHintTap" catchtouchend="handlePunchHintTap" catchtap="handleClosePunchHint">×</view>
|
||||
</view>
|
||||
|
||||
<cover-view class="map-side-toggle" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel}}" style="top: {{topInsetHeight}}px;" bindtap="handleCycleSideButtons">
|
||||
<cover-view class="map-side-toggle {{sideButtonPlacement === 'right' ? 'map-side-toggle--right' : 'map-side-toggle--left'}}" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel}}" style="top: {{topInsetHeight}}px;" bindtap="handleCycleSideButtons">
|
||||
<cover-view class="map-side-button map-side-button--icon">
|
||||
<cover-image class="map-side-button__image" src="{{sideToggleIconSrc}}"></cover-image>
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-side-column map-side-column--left map-side-column--left-group" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showLeftButtonGroup}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-column {{sideButtonPlacement === 'right' ? 'map-side-column--right-group' : 'map-side-column--left'}} map-side-column--left-group" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showLeftButtonGroup}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-button map-side-button--icon" bindtap="handleToggleMapRotateMode"><cover-image class="map-side-button__rotate-image {{orientationMode === 'heading-up' ? 'map-side-button__rotate-image--active' : ''}}" src="../../assets/btn_map_rotate_cropped.png"></cover-image></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--muted"><cover-view class="map-side-button__text">1</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton2Class}}" bindtap="handleToggleGpsLock"><cover-view class="map-side-button__text">2</cover-view></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">3</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton4Class}}" bindtap="handleForceExitGame"><cover-image class="map-side-button__action-image" src="../../assets/btn_exit.png"></cover-image></cover-view>
|
||||
<cover-view class="{{sideButton2Class}}" bindtap="handleToggleGpsLock">
|
||||
<cover-image
|
||||
wx:if="{{gpsLockEnabled}}"
|
||||
class="map-side-button__action-image"
|
||||
src="../../assets/btn_locked.png"
|
||||
></cover-image>
|
||||
<cover-image
|
||||
wx:else
|
||||
class="map-side-button__action-image"
|
||||
src="../../assets/btn_unlock.png"
|
||||
></cover-image>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-side-column map-side-column--right-main" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">5</cover-view></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">6</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">7</cover-view></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">8</cover-view></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--muted"><cover-view class="map-side-button__text">9</cover-view></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">10</cover-view></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-side-column map-side-column--right-sub" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="{{sideButton11Class}}" bindtap="handleOpenGameInfoPanel"><cover-image class="map-side-button__action-image" src="../../assets/btn_info.png"></cover-image></cover-view>
|
||||
<cover-view class="{{sideButton12Class}}" bindtap="handleOpenSystemSettingsPanel"><cover-view class="map-side-button__text">12</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">13</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">14</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">15</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton16Class}}" bindtap="handleSkipAction"><cover-image class="map-side-button__action-image" src="../../assets/btn_skip_cp.png"></cover-image></cover-view>
|
||||
<cover-view class="{{sideButton11Class}}" bindtap="handleOpenGameInfoPanel"><cover-image class="map-side-button__action-image" src="../../assets/btn_info.png"></cover-image></cover-view>
|
||||
<cover-view class="{{sideButton12Class}}" bindtap="handleOpenSystemSettingsPanel"><cover-image class="map-side-button__action-image" src="../../assets/btn_settings.png"></cover-image></cover-view>
|
||||
<cover-view class="{{sideButton4Class}}" bindtap="handleForceExitGame"><cover-image class="map-side-button__action-image" src="../../assets/btn_exit.png"></cover-image></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-punch-button {{punchButtonEnabled ? 'map-punch-button--active' : ''}} {{punchButtonFxClass}}" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel}}" bindtap="handlePunchAction">
|
||||
@@ -298,71 +292,173 @@
|
||||
<scroll-view class="game-info-modal__content" scroll-y enhanced show-scrollbar="true">
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">01. 动画性能</view>
|
||||
<view class="debug-section__desc">根据设备性能切换动画强度,低端机建议精简</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockAnimationLevel ? 'debug-section__lock--active' : ''}}" data-key="lockAnimationLevel" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockAnimationLevel ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前级别</text>
|
||||
<text class="info-panel__value">{{animationLevel === 'lite' ? '精简' : '标准'}}</text>
|
||||
<text class="info-panel__value">{{animationLevel === 'lite' ? '精简' : '标准'}}{{lockAnimationLevel ? ' · 已锁定' : ' · 可编辑'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{animationLevel === 'standard' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetAnimationLevelStandard">标准</view>
|
||||
<view class="control-chip {{animationLevel === 'lite' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetAnimationLevelLite">精简</view>
|
||||
<view class="control-chip {{animationLevel === 'standard' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockAnimationLevel ? 'control-chip--disabled' : ''}}" bindtap="handleSetAnimationLevelStandard">标准</view>
|
||||
<view class="control-chip {{animationLevel === 'lite' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockAnimationLevel ? 'control-chip--disabled' : ''}}" bindtap="handleSetAnimationLevelLite">精简</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">02. 比例尺显示</view>
|
||||
<view class="debug-section__desc">控制比例尺显示与否,默认沿用你的本地偏好</view>
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">02. 按钮习惯</view>
|
||||
<view class="debug-section__desc">切换功能按钮显示在左侧还是右侧,适配左手/右手操作习惯</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockSideButtonPlacement ? 'debug-section__lock--active' : ''}}" data-key="lockSideButtonPlacement" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockSideButtonPlacement ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前习惯</text>
|
||||
<text class="info-panel__value">{{sideButtonPlacement === 'right' ? '右手' : '左手'}}{{lockSideButtonPlacement ? ' · 已锁定' : ' · 可编辑'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{sideButtonPlacement === 'left' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockSideButtonPlacement ? 'control-chip--disabled' : ''}}" bindtap="handleSetSideButtonPlacementLeft">左手</view>
|
||||
<view class="control-chip {{sideButtonPlacement === 'right' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockSideButtonPlacement ? 'control-chip--disabled' : ''}}" bindtap="handleSetSideButtonPlacementRight">右手</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">03. 自动转图</view>
|
||||
<view class="debug-section__desc">控制地图是否跟随朝向自动旋转,外部按钮与这里保持同步</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockAutoRotate ? 'debug-section__lock--active' : ''}}" data-key="lockAutoRotate" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockAutoRotate ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前状态</text>
|
||||
<text class="info-panel__value">{{showCenterScaleRuler ? '显示' : '隐藏'}}</text>
|
||||
<text class="info-panel__value">{{autoRotateEnabled ? '开启' : '关闭'}}{{lockAutoRotate ? ' · 已锁定' : ' · 可编辑'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{showCenterScaleRuler ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerVisibleOn">显示</view>
|
||||
<view class="control-chip {{!showCenterScaleRuler ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerVisibleOff">隐藏</view>
|
||||
<view class="control-chip {{autoRotateEnabled ? 'control-chip--active' : 'control-chip--secondary'}} {{lockAutoRotate ? 'control-chip--disabled' : ''}}" bindtap="handleSetAutoRotateEnabledOn">开启</view>
|
||||
<view class="control-chip {{!autoRotateEnabled ? 'control-chip--active' : 'control-chip--secondary'}} {{lockAutoRotate ? 'control-chip--disabled' : ''}}" bindtap="handleSetAutoRotateEnabledOff">关闭</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">03. 比例尺基准点</view>
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">04. 指北针响应</view>
|
||||
<view class="debug-section__desc">切换指针的平滑与跟手程度,影响指北针响应手感</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockCompassTuning ? 'debug-section__lock--active' : ''}}" data-key="lockCompassTuning" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockCompassTuning ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前档位</text>
|
||||
<text class="info-panel__value">{{compassTuningProfileText}}{{lockCompassTuning ? ' · 已锁定' : ' · 可编辑'}}</text>
|
||||
</view>
|
||||
<view class="control-row control-row--triple">
|
||||
<view class="control-chip {{compassTuningProfile === 'smooth' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockCompassTuning ? 'control-chip--disabled' : ''}}" bindtap="handleSetCompassTuningSmooth">顺滑</view>
|
||||
<view class="control-chip {{compassTuningProfile === 'balanced' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockCompassTuning ? 'control-chip--disabled' : ''}}" bindtap="handleSetCompassTuningBalanced">平衡</view>
|
||||
<view class="control-chip {{compassTuningProfile === 'responsive' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockCompassTuning ? 'control-chip--disabled' : ''}}" bindtap="handleSetCompassTuningResponsive">跟手</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">05. 比例尺显示</view>
|
||||
<view class="debug-section__desc">控制比例尺显示与否,默认沿用你的本地偏好</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockScaleRulerVisible ? 'debug-section__lock--active' : ''}}" data-key="lockScaleRulerVisible" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockScaleRulerVisible ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前状态</text>
|
||||
<text class="info-panel__value">{{showCenterScaleRuler ? '显示' : '隐藏'}}{{lockScaleRulerVisible ? ' · 已锁定' : ' · 可编辑'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{showCenterScaleRuler ? 'control-chip--active' : 'control-chip--secondary'}} {{lockScaleRulerVisible ? 'control-chip--disabled' : ''}}" bindtap="handleSetCenterScaleRulerVisibleOn">显示</view>
|
||||
<view class="control-chip {{!showCenterScaleRuler ? 'control-chip--active' : 'control-chip--secondary'}} {{lockScaleRulerVisible ? 'control-chip--disabled' : ''}}" bindtap="handleSetCenterScaleRulerVisibleOff">隐藏</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">06. 比例尺基准点</view>
|
||||
<view class="debug-section__desc">设置比例尺零点锚定位置,可跟随屏幕中心或指北针圆心</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockScaleRulerAnchor ? 'debug-section__lock--active' : ''}}" data-key="lockScaleRulerAnchor" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockScaleRulerAnchor ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前锚点</text>
|
||||
<text class="info-panel__value">{{centerScaleRulerAnchorMode === 'compass-center' ? '指北针圆心' : '屏幕中心'}}</text>
|
||||
<text class="info-panel__value">{{centerScaleRulerAnchorMode === 'compass-center' ? '指北针圆心' : '屏幕中心'}}{{lockScaleRulerAnchor ? ' · 已锁定' : ' · 可编辑'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{centerScaleRulerAnchorMode === 'screen-center' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerAnchorScreenCenter">屏幕中心</view>
|
||||
<view class="control-chip {{centerScaleRulerAnchorMode === 'compass-center' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerAnchorCompassCenter">指北针圆心</view>
|
||||
<view class="control-chip {{centerScaleRulerAnchorMode === 'screen-center' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockScaleRulerAnchor ? 'control-chip--disabled' : ''}}" bindtap="handleSetCenterScaleRulerAnchorScreenCenter">屏幕中心</view>
|
||||
<view class="control-chip {{centerScaleRulerAnchorMode === 'compass-center' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockScaleRulerAnchor ? 'control-chip--disabled' : ''}}" bindtap="handleSetCenterScaleRulerAnchorCompassCenter">指北针圆心</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">04. 北参考</view>
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">07. 北参考</view>
|
||||
<view class="debug-section__desc">切换磁北/真北作为地图与指北针参考</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockNorthReference ? 'debug-section__lock--active' : ''}}" data-key="lockNorthReference" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockNorthReference ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前参考</text>
|
||||
<text class="info-panel__value">{{northReferenceText}}</text>
|
||||
<text class="info-panel__value">{{northReferenceText}}{{lockNorthReference ? ' · 已锁定' : ' · 可编辑'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{northReferenceMode === 'magnetic' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetNorthReferenceMagnetic">磁北</view>
|
||||
<view class="control-chip {{northReferenceMode === 'true' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetNorthReferenceTrue">真北</view>
|
||||
<view class="control-chip {{northReferenceMode === 'magnetic' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockNorthReference ? 'control-chip--disabled' : ''}}" bindtap="handleSetNorthReferenceMagnetic">磁北</view>
|
||||
<view class="control-chip {{northReferenceMode === 'true' ? 'control-chip--active' : 'control-chip--secondary'}} {{lockNorthReference ? 'control-chip--disabled' : ''}}" bindtap="handleSetNorthReferenceTrue">真北</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">05. 心率设备</view>
|
||||
<view class="debug-section__header-row">
|
||||
<view class="debug-section__header-main">
|
||||
<view class="debug-section__title">08. 心率设备</view>
|
||||
<view class="debug-section__desc">清除已记住的首选心率带设备,下次重新选择</view>
|
||||
</view>
|
||||
<view class="debug-section__lock {{lockHeartRateDevice ? 'debug-section__lock--active' : ''}}" data-key="lockHeartRateDevice" bindtap="handleToggleSettingLock">
|
||||
<text class="debug-section__lock-text">{{lockHeartRateDevice ? '已锁' : '可改'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip control-chip--secondary" bindtap="handleClearPreferredHeartRateDevice">清除首选设备</view>
|
||||
<view class="control-chip control-chip--secondary {{lockHeartRateDevice ? 'control-chip--disabled' : ''}}" bindtap="handleClearPreferredHeartRateDevice">清除首选设备</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
@@ -429,6 +525,7 @@
|
||||
<view class="debug-section__title">Sensors</view>
|
||||
<view class="debug-section__desc">定位、罗盘与心率带连接状态</view>
|
||||
</view>
|
||||
<view class="debug-group-title">定位</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">GPS</text>
|
||||
<text class="info-panel__value">{{gpsTrackingText}}</text>
|
||||
@@ -469,6 +566,7 @@
|
||||
<text class="info-panel__label">Mock Speed</text>
|
||||
<text class="info-panel__value">{{mockSpeedText}}</text>
|
||||
</view>
|
||||
<view class="debug-group-title">心率</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">Heart Rate</text>
|
||||
<text class="info-panel__value">{{heartRateStatusText}}</text>
|
||||
@@ -532,6 +630,7 @@
|
||||
<text class="info-panel__label">Mock BPM</text>
|
||||
<text class="info-panel__value">{{mockHeartRateText}}</text>
|
||||
</view>
|
||||
<view class="debug-group-title">方向</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">Heading Mode</text>
|
||||
<text class="info-panel__value">{{orientationModeText}}</text>
|
||||
@@ -560,11 +659,6 @@
|
||||
<text class="info-panel__label">Compass Tune</text>
|
||||
<text class="info-panel__value">{{compassTuningProfileText}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{compassTuningProfile === 'smooth' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCompassTuningSmooth">顺滑</view>
|
||||
<view class="control-chip {{compassTuningProfile === 'balanced' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCompassTuningBalanced">平衡</view>
|
||||
<view class="control-chip {{compassTuningProfile === 'responsive' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCompassTuningResponsive">跟手</view>
|
||||
</view>
|
||||
<view class="info-panel__row info-panel__row--stack">
|
||||
<text class="info-panel__label">Accel</text>
|
||||
<text class="info-panel__value">{{accelerometerText}}</text>
|
||||
|
||||
@@ -305,10 +305,17 @@
|
||||
|
||||
.map-side-toggle {
|
||||
position: absolute;
|
||||
left: 24rpx;
|
||||
z-index: 19;
|
||||
}
|
||||
|
||||
.map-side-toggle--left {
|
||||
left: 24rpx;
|
||||
}
|
||||
|
||||
.map-side-toggle--right {
|
||||
right: 24rpx;
|
||||
}
|
||||
|
||||
.map-side-column {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
@@ -322,6 +329,10 @@
|
||||
left: 24rpx;
|
||||
}
|
||||
|
||||
.map-side-column--right-group {
|
||||
right: 24rpx;
|
||||
}
|
||||
|
||||
.map-side-column--left-group {
|
||||
padding-top: 106rpx;
|
||||
}
|
||||
@@ -1417,6 +1428,18 @@
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.debug-section__header-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.debug-section__header-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.debug-section__title {
|
||||
font-size: 24rpx;
|
||||
line-height: 1.2;
|
||||
@@ -1433,6 +1456,36 @@
|
||||
color: #6a826f;
|
||||
}
|
||||
|
||||
.debug-section__lock {
|
||||
min-width: 76rpx;
|
||||
height: 52rpx;
|
||||
padding: 0 16rpx;
|
||||
flex: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(233, 242, 228, 0.92);
|
||||
box-shadow: inset 0 0 0 1rpx rgba(22, 48, 32, 0.08);
|
||||
}
|
||||
|
||||
.debug-section__lock--active {
|
||||
background: rgba(45, 106, 79, 0.18);
|
||||
box-shadow: inset 0 0 0 2rpx rgba(45, 106, 79, 0.18);
|
||||
}
|
||||
|
||||
.debug-section__lock-text {
|
||||
font-size: 20rpx;
|
||||
line-height: 1;
|
||||
font-weight: 700;
|
||||
color: #45624b;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.debug-section__lock--active .debug-section__lock-text {
|
||||
color: #2d6a4f;
|
||||
}
|
||||
|
||||
.info-panel__row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -1593,6 +1646,16 @@
|
||||
.debug-section .control-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.debug-group-title {
|
||||
margin-top: 18rpx;
|
||||
margin-bottom: 8rpx;
|
||||
font-size: 20rpx;
|
||||
font-weight: 800;
|
||||
letter-spacing: 2rpx;
|
||||
color: #6a826f;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.control-row--triple .control-chip {
|
||||
font-size: 23rpx;
|
||||
}
|
||||
@@ -1624,6 +1687,10 @@
|
||||
color: #f7fbf2;
|
||||
}
|
||||
|
||||
.control-chip--disabled {
|
||||
opacity: 0.48;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"coverView": false,
|
||||
"postcss": false,
|
||||
"minified": false,
|
||||
"minified": true,
|
||||
"enhance": false,
|
||||
"showShadowRootInWxmlPanel": false,
|
||||
"packNpmRelationList": [],
|
||||
|
||||
Reference in New Issue
Block a user