merge: integrate map engine north reference work
This commit is contained in:
12
.gitattributes
vendored
Normal file
12
.gitattributes
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.webp binary
|
||||||
|
*.ico binary
|
||||||
|
*.pdf binary
|
||||||
|
*.ttf binary
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
15
.gitignore
vendored
15
.gitignore
vendored
@@ -1,5 +1,20 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
.tmp-ts/
|
.tmp-ts/
|
||||||
|
miniprogram_npm/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
coverage/
|
||||||
project.private.config.json
|
project.private.config.json
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.tmp
|
||||||
|
*.swp
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ App<IAppOption>({
|
|||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
wx.login({
|
wx.login({
|
||||||
success: res => {
|
success: () => {
|
||||||
console.log(res.code)
|
|
||||||
// 发送 res.code 到后台换取 openId, sessionKey, unionId
|
// 发送 res.code 到后台换取 openId, sessionKey, unionId
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { worldTileToLonLat, type LonLatPoint } from '../../utils/projection'
|
|||||||
const RENDER_MODE = 'Single WebGL Pipeline'
|
const RENDER_MODE = 'Single WebGL Pipeline'
|
||||||
const PROJECTION_MODE = 'WGS84 -> WorldTile -> Camera -> Screen'
|
const PROJECTION_MODE = 'WGS84 -> WorldTile -> Camera -> Screen'
|
||||||
const MAP_NORTH_OFFSET_DEG = 0
|
const MAP_NORTH_OFFSET_DEG = 0
|
||||||
|
const MAGNETIC_DECLINATION_DEG = -6.91
|
||||||
|
const MAGNETIC_DECLINATION_TEXT = '6.91° W'
|
||||||
const MIN_ZOOM = 15
|
const MIN_ZOOM = 15
|
||||||
const MAX_ZOOM = 20
|
const MAX_ZOOM = 20
|
||||||
const DEFAULT_ZOOM = 17
|
const DEFAULT_ZOOM = 17
|
||||||
@@ -25,12 +27,13 @@ const INERTIA_MIN_SPEED = 0.02
|
|||||||
const PREVIEW_RESET_DURATION_MS = 140
|
const PREVIEW_RESET_DURATION_MS = 140
|
||||||
const UI_SYNC_INTERVAL_MS = 80
|
const UI_SYNC_INTERVAL_MS = 80
|
||||||
const ROTATE_STEP_DEG = 15
|
const ROTATE_STEP_DEG = 15
|
||||||
const AUTO_ROTATE_FRAME_MS = 12
|
const AUTO_ROTATE_FRAME_MS = 8
|
||||||
const AUTO_ROTATE_EASE = 0.2
|
const AUTO_ROTATE_EASE = 0.34
|
||||||
const AUTO_ROTATE_SNAP_DEG = 0.1
|
const AUTO_ROTATE_SNAP_DEG = 0.1
|
||||||
const AUTO_ROTATE_DEADZONE_DEG = 0.35
|
const AUTO_ROTATE_DEADZONE_DEG = 4
|
||||||
const AUTO_ROTATE_MAX_STEP_DEG = 1.35
|
const AUTO_ROTATE_MAX_STEP_DEG = 0.75
|
||||||
const AUTO_ROTATE_HEADING_SMOOTHING = 0.32
|
const AUTO_ROTATE_HEADING_SMOOTHING = 0.32
|
||||||
|
const COMPASS_NEEDLE_SMOOTHING = 0.12
|
||||||
|
|
||||||
const SAMPLE_TRACK_WGS84: LonLatPoint[] = [
|
const SAMPLE_TRACK_WGS84: LonLatPoint[] = [
|
||||||
worldTileToLonLat({ x: DEFAULT_CENTER_TILE_X - 0.72, y: DEFAULT_CENTER_TILE_Y + 0.44 }, DEFAULT_ZOOM),
|
worldTileToLonLat({ x: DEFAULT_CENTER_TILE_X - 0.72, y: DEFAULT_CENTER_TILE_Y + 0.44 }, DEFAULT_ZOOM),
|
||||||
@@ -49,6 +52,9 @@ type GestureMode = 'idle' | 'pan' | 'pinch'
|
|||||||
type RotationMode = 'manual' | 'auto'
|
type RotationMode = 'manual' | 'auto'
|
||||||
type OrientationMode = 'manual' | 'north-up' | 'heading-up'
|
type OrientationMode = 'manual' | 'north-up' | 'heading-up'
|
||||||
type AutoRotateSourceMode = 'sensor' | 'course' | 'fusion'
|
type AutoRotateSourceMode = 'sensor' | 'course' | 'fusion'
|
||||||
|
type NorthReferenceMode = 'magnetic' | 'true'
|
||||||
|
|
||||||
|
const DEFAULT_NORTH_REFERENCE_MODE: NorthReferenceMode = 'magnetic'
|
||||||
|
|
||||||
export interface MapEngineStageRect {
|
export interface MapEngineStageRect {
|
||||||
width: number
|
width: number
|
||||||
@@ -73,6 +79,8 @@ export interface MapEngineViewState {
|
|||||||
orientationMode: OrientationMode
|
orientationMode: OrientationMode
|
||||||
orientationModeText: string
|
orientationModeText: string
|
||||||
sensorHeadingText: string
|
sensorHeadingText: string
|
||||||
|
compassDeclinationText: string
|
||||||
|
northReferenceButtonText: string
|
||||||
autoRotateSourceText: string
|
autoRotateSourceText: string
|
||||||
autoRotateCalibrationText: string
|
autoRotateCalibrationText: string
|
||||||
northReferenceText: string
|
northReferenceText: string
|
||||||
@@ -120,6 +128,8 @@ const VIEW_SYNC_KEYS: Array<keyof MapEngineViewState> = [
|
|||||||
'orientationMode',
|
'orientationMode',
|
||||||
'orientationModeText',
|
'orientationModeText',
|
||||||
'sensorHeadingText',
|
'sensorHeadingText',
|
||||||
|
'compassDeclinationText',
|
||||||
|
'northReferenceButtonText',
|
||||||
'autoRotateSourceText',
|
'autoRotateSourceText',
|
||||||
'autoRotateCalibrationText',
|
'autoRotateCalibrationText',
|
||||||
'northReferenceText',
|
'northReferenceText',
|
||||||
@@ -247,16 +257,84 @@ function formatAutoRotateCalibrationText(pending: boolean, offsetDeg: number | n
|
|||||||
return `Offset ${Math.round(normalizeRotationDeg(offsetDeg))}deg`
|
return `Offset ${Math.round(normalizeRotationDeg(offsetDeg))}deg`
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatNorthReferenceText(): string {
|
function getTrueHeadingDeg(magneticHeadingDeg: number): number {
|
||||||
return 'Map North = 0deg (TFW aligned)'
|
return normalizeRotationDeg(magneticHeadingDeg + MAGNETIC_DECLINATION_DEG)
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatCompassNeedleDeg(headingDeg: number | null): number {
|
function getMagneticHeadingDeg(trueHeadingDeg: number): number {
|
||||||
if (headingDeg === null) {
|
return normalizeRotationDeg(trueHeadingDeg - MAGNETIC_DECLINATION_DEG)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMapNorthOffsetDeg(_mode: NorthReferenceMode): number {
|
||||||
|
return MAP_NORTH_OFFSET_DEG
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompassReferenceHeadingDeg(mode: NorthReferenceMode, magneticHeadingDeg: number): number {
|
||||||
|
if (mode === 'true') {
|
||||||
|
return getTrueHeadingDeg(magneticHeadingDeg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizeRotationDeg(magneticHeadingDeg)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMapReferenceHeadingDegFromSensor(mode: NorthReferenceMode, magneticHeadingDeg: number): number {
|
||||||
|
if (mode === 'magnetic') {
|
||||||
|
return normalizeRotationDeg(magneticHeadingDeg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTrueHeadingDeg(magneticHeadingDeg)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMapReferenceHeadingDegFromCourse(mode: NorthReferenceMode, trueHeadingDeg: number): number {
|
||||||
|
if (mode === 'magnetic') {
|
||||||
|
return getMagneticHeadingDeg(trueHeadingDeg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizeRotationDeg(trueHeadingDeg)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatNorthReferenceText(mode: NorthReferenceMode): string {
|
||||||
|
if (mode === 'magnetic') {
|
||||||
|
return `Compass Magnetic / Heading-Up Magnetic (${MAGNETIC_DECLINATION_TEXT})`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `Compass True / Heading-Up True (${MAGNETIC_DECLINATION_TEXT})`
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCompassDeclinationText(mode: NorthReferenceMode): string {
|
||||||
|
if (mode === 'true') {
|
||||||
|
return MAGNETIC_DECLINATION_TEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatNorthReferenceButtonText(mode: NorthReferenceMode): string {
|
||||||
|
return mode === 'magnetic' ? '北参考:磁北' : '北参考:真北'
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatNorthReferenceStatusText(mode: NorthReferenceMode): string {
|
||||||
|
if (mode === 'magnetic') {
|
||||||
|
return '已切到磁北模式'
|
||||||
|
}
|
||||||
|
|
||||||
|
return '已切到真北模式'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNextNorthReferenceMode(mode: NorthReferenceMode): NorthReferenceMode {
|
||||||
|
return mode === 'magnetic' ? 'true' : 'magnetic'
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCompassNeedleDegForMode(mode: NorthReferenceMode, magneticHeadingDeg: number | null): number {
|
||||||
|
if (magneticHeadingDeg === null) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalizeRotationDeg(360 - headingDeg)
|
const referenceHeadingDeg = mode === 'true'
|
||||||
|
? getTrueHeadingDeg(magneticHeadingDeg)
|
||||||
|
: normalizeRotationDeg(magneticHeadingDeg)
|
||||||
|
|
||||||
|
return normalizeRotationDeg(360 - referenceHeadingDeg)
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatCacheHitRate(memoryHitCount: number, diskHitCount: number, networkFetchCount: number): string {
|
function formatCacheHitRate(memoryHitCount: number, diskHitCount: number, networkFetchCount: number): string {
|
||||||
@@ -295,8 +373,10 @@ export class MapEngine {
|
|||||||
autoRotateTimer: number
|
autoRotateTimer: number
|
||||||
pendingViewPatch: Partial<MapEngineViewState>
|
pendingViewPatch: Partial<MapEngineViewState>
|
||||||
mounted: boolean
|
mounted: boolean
|
||||||
|
northReferenceMode: NorthReferenceMode
|
||||||
sensorHeadingDeg: number | null
|
sensorHeadingDeg: number | null
|
||||||
smoothedSensorHeadingDeg: number | null
|
smoothedSensorHeadingDeg: number | null
|
||||||
|
compassDisplayHeadingDeg: number | null
|
||||||
autoRotateHeadingDeg: number | null
|
autoRotateHeadingDeg: number | null
|
||||||
courseHeadingDeg: number | null
|
courseHeadingDeg: number | null
|
||||||
targetAutoRotationDeg: number | null
|
targetAutoRotationDeg: number | null
|
||||||
@@ -341,9 +421,11 @@ export class MapEngine {
|
|||||||
orientationMode: 'manual',
|
orientationMode: 'manual',
|
||||||
orientationModeText: formatOrientationModeText('manual'),
|
orientationModeText: formatOrientationModeText('manual'),
|
||||||
sensorHeadingText: '--',
|
sensorHeadingText: '--',
|
||||||
|
compassDeclinationText: formatCompassDeclinationText(DEFAULT_NORTH_REFERENCE_MODE),
|
||||||
|
northReferenceButtonText: formatNorthReferenceButtonText(DEFAULT_NORTH_REFERENCE_MODE),
|
||||||
autoRotateSourceText: formatAutoRotateSourceText('fusion', false),
|
autoRotateSourceText: formatAutoRotateSourceText('fusion', false),
|
||||||
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, MAP_NORTH_OFFSET_DEG),
|
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, getMapNorthOffsetDeg(DEFAULT_NORTH_REFERENCE_MODE)),
|
||||||
northReferenceText: formatNorthReferenceText(),
|
northReferenceText: formatNorthReferenceText(DEFAULT_NORTH_REFERENCE_MODE),
|
||||||
compassNeedleDeg: 0,
|
compassNeedleDeg: 0,
|
||||||
centerTileX: DEFAULT_CENTER_TILE_X,
|
centerTileX: DEFAULT_CENTER_TILE_X,
|
||||||
centerTileY: DEFAULT_CENTER_TILE_Y,
|
centerTileY: DEFAULT_CENTER_TILE_Y,
|
||||||
@@ -388,13 +470,15 @@ export class MapEngine {
|
|||||||
this.autoRotateTimer = 0
|
this.autoRotateTimer = 0
|
||||||
this.pendingViewPatch = {}
|
this.pendingViewPatch = {}
|
||||||
this.mounted = false
|
this.mounted = false
|
||||||
|
this.northReferenceMode = DEFAULT_NORTH_REFERENCE_MODE
|
||||||
this.sensorHeadingDeg = null
|
this.sensorHeadingDeg = null
|
||||||
this.smoothedSensorHeadingDeg = null
|
this.smoothedSensorHeadingDeg = null
|
||||||
|
this.compassDisplayHeadingDeg = null
|
||||||
this.autoRotateHeadingDeg = null
|
this.autoRotateHeadingDeg = null
|
||||||
this.courseHeadingDeg = null
|
this.courseHeadingDeg = null
|
||||||
this.targetAutoRotationDeg = null
|
this.targetAutoRotationDeg = null
|
||||||
this.autoRotateSourceMode = 'fusion'
|
this.autoRotateSourceMode = 'fusion'
|
||||||
this.autoRotateCalibrationOffsetDeg = MAP_NORTH_OFFSET_DEG
|
this.autoRotateCalibrationOffsetDeg = getMapNorthOffsetDeg(DEFAULT_NORTH_REFERENCE_MODE)
|
||||||
this.autoRotateCalibrationPending = false
|
this.autoRotateCalibrationPending = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,12 +754,13 @@ export class MapEngine {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.state.rotationDeg) {
|
const targetRotationDeg = MAP_NORTH_OFFSET_DEG
|
||||||
|
if (Math.abs(normalizeAngleDeltaDeg(this.state.rotationDeg - targetRotationDeg)) <= 0.01) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const exactCenter = this.getExactCenterFromTranslate(this.state.tileTranslateX, this.state.tileTranslateY)
|
const exactCenter = this.getExactCenterFromTranslate(this.state.tileTranslateX, this.state.tileTranslateY)
|
||||||
const resolvedViewport = this.resolveViewportForExactCenter(exactCenter.x, exactCenter.y, 0)
|
const resolvedViewport = this.resolveViewportForExactCenter(exactCenter.x, exactCenter.y, targetRotationDeg)
|
||||||
|
|
||||||
this.clearInertiaTimer()
|
this.clearInertiaTimer()
|
||||||
this.clearPreviewResetTimer()
|
this.clearPreviewResetTimer()
|
||||||
@@ -685,10 +770,10 @@ export class MapEngine {
|
|||||||
this.commitViewport(
|
this.commitViewport(
|
||||||
{
|
{
|
||||||
...resolvedViewport,
|
...resolvedViewport,
|
||||||
rotationDeg: 0,
|
rotationDeg: targetRotationDeg,
|
||||||
rotationText: formatRotationText(0),
|
rotationText: formatRotationText(targetRotationDeg),
|
||||||
},
|
},
|
||||||
`旋转角度已归零 (${this.buildVersion})`,
|
`旋转角度已回到真北参考 (${this.buildVersion})`,
|
||||||
true,
|
true,
|
||||||
() => {
|
() => {
|
||||||
this.resetPreviewState()
|
this.resetPreviewState()
|
||||||
@@ -724,6 +809,10 @@ export class MapEngine {
|
|||||||
this.setHeadingUpMode()
|
this.setHeadingUpMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleCycleNorthReferenceMode(): void {
|
||||||
|
this.cycleNorthReferenceMode()
|
||||||
|
}
|
||||||
|
|
||||||
handleAutoRotateCalibrate(): void {
|
handleAutoRotateCalibrate(): void {
|
||||||
if (this.state.orientationMode !== 'heading-up') {
|
if (this.state.orientationMode !== 'heading-up') {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -765,22 +854,25 @@ export class MapEngine {
|
|||||||
this.targetAutoRotationDeg = null
|
this.targetAutoRotationDeg = null
|
||||||
this.autoRotateCalibrationPending = false
|
this.autoRotateCalibrationPending = false
|
||||||
|
|
||||||
|
const mapNorthOffsetDeg = MAP_NORTH_OFFSET_DEG
|
||||||
|
this.autoRotateCalibrationOffsetDeg = mapNorthOffsetDeg
|
||||||
const exactCenter = this.getExactCenterFromTranslate(this.state.tileTranslateX, this.state.tileTranslateY)
|
const exactCenter = this.getExactCenterFromTranslate(this.state.tileTranslateX, this.state.tileTranslateY)
|
||||||
const resolvedViewport = this.resolveViewportForExactCenter(exactCenter.x, exactCenter.y, MAP_NORTH_OFFSET_DEG)
|
const resolvedViewport = this.resolveViewportForExactCenter(exactCenter.x, exactCenter.y, mapNorthOffsetDeg)
|
||||||
|
|
||||||
this.commitViewport(
|
this.commitViewport(
|
||||||
{
|
{
|
||||||
...resolvedViewport,
|
...resolvedViewport,
|
||||||
rotationDeg: MAP_NORTH_OFFSET_DEG,
|
rotationDeg: mapNorthOffsetDeg,
|
||||||
rotationText: formatRotationText(MAP_NORTH_OFFSET_DEG),
|
rotationText: formatRotationText(mapNorthOffsetDeg),
|
||||||
rotationMode: 'manual',
|
rotationMode: 'manual',
|
||||||
rotationModeText: formatRotationModeText('north-up'),
|
rotationModeText: formatRotationModeText('north-up'),
|
||||||
rotationToggleText: formatRotationToggleText('north-up'),
|
rotationToggleText: formatRotationToggleText('north-up'),
|
||||||
orientationMode: 'north-up',
|
orientationMode: 'north-up',
|
||||||
orientationModeText: formatOrientationModeText('north-up'),
|
orientationModeText: formatOrientationModeText('north-up'),
|
||||||
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, this.autoRotateCalibrationOffsetDeg),
|
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, mapNorthOffsetDeg),
|
||||||
|
northReferenceText: formatNorthReferenceText(this.northReferenceMode),
|
||||||
},
|
},
|
||||||
`地图已固定为北朝上 (${this.buildVersion})`,
|
`地图已固定为真北朝上 (${this.buildVersion})`,
|
||||||
true,
|
true,
|
||||||
() => {
|
() => {
|
||||||
this.resetPreviewState()
|
this.resetPreviewState()
|
||||||
@@ -791,7 +883,7 @@ export class MapEngine {
|
|||||||
|
|
||||||
setHeadingUpMode(): void {
|
setHeadingUpMode(): void {
|
||||||
this.autoRotateCalibrationPending = false
|
this.autoRotateCalibrationPending = false
|
||||||
this.autoRotateCalibrationOffsetDeg = MAP_NORTH_OFFSET_DEG
|
this.autoRotateCalibrationOffsetDeg = getMapNorthOffsetDeg(this.northReferenceMode)
|
||||||
this.targetAutoRotationDeg = null
|
this.targetAutoRotationDeg = null
|
||||||
this.setState({
|
this.setState({
|
||||||
rotationMode: 'auto',
|
rotationMode: 'auto',
|
||||||
@@ -800,6 +892,7 @@ export class MapEngine {
|
|||||||
orientationMode: 'heading-up',
|
orientationMode: 'heading-up',
|
||||||
orientationModeText: formatOrientationModeText('heading-up'),
|
orientationModeText: formatOrientationModeText('heading-up'),
|
||||||
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, this.autoRotateCalibrationOffsetDeg),
|
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, this.autoRotateCalibrationOffsetDeg),
|
||||||
|
northReferenceText: formatNorthReferenceText(this.northReferenceMode),
|
||||||
statusText: `正在启用朝向朝上模式 (${this.buildVersion})`,
|
statusText: `正在启用朝向朝上模式 (${this.buildVersion})`,
|
||||||
}, true)
|
}, true)
|
||||||
if (this.refreshAutoRotateTarget()) {
|
if (this.refreshAutoRotateTarget()) {
|
||||||
@@ -813,12 +906,20 @@ export class MapEngine {
|
|||||||
? this.sensorHeadingDeg
|
? this.sensorHeadingDeg
|
||||||
: interpolateAngleDeg(this.smoothedSensorHeadingDeg, this.sensorHeadingDeg, AUTO_ROTATE_HEADING_SMOOTHING)
|
: interpolateAngleDeg(this.smoothedSensorHeadingDeg, this.sensorHeadingDeg, AUTO_ROTATE_HEADING_SMOOTHING)
|
||||||
|
|
||||||
this.autoRotateHeadingDeg = this.smoothedSensorHeadingDeg
|
const compassHeadingDeg = getCompassReferenceHeadingDeg(this.northReferenceMode, this.smoothedSensorHeadingDeg)
|
||||||
|
this.compassDisplayHeadingDeg = this.compassDisplayHeadingDeg === null
|
||||||
|
? compassHeadingDeg
|
||||||
|
: interpolateAngleDeg(this.compassDisplayHeadingDeg, compassHeadingDeg, COMPASS_NEEDLE_SMOOTHING)
|
||||||
|
|
||||||
|
this.autoRotateHeadingDeg = this.resolveAutoRotateInputHeadingDeg()
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
sensorHeadingText: formatHeadingText(this.smoothedSensorHeadingDeg),
|
sensorHeadingText: formatHeadingText(compassHeadingDeg),
|
||||||
|
compassDeclinationText: formatCompassDeclinationText(this.northReferenceMode),
|
||||||
|
northReferenceButtonText: formatNorthReferenceButtonText(this.northReferenceMode),
|
||||||
autoRotateSourceText: formatAutoRotateSourceText(this.autoRotateSourceMode, this.courseHeadingDeg !== null),
|
autoRotateSourceText: formatAutoRotateSourceText(this.autoRotateSourceMode, this.courseHeadingDeg !== null),
|
||||||
compassNeedleDeg: formatCompassNeedleDeg(this.smoothedSensorHeadingDeg),
|
compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.smoothedSensorHeadingDeg),
|
||||||
|
northReferenceText: formatNorthReferenceText(this.northReferenceMode),
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!this.refreshAutoRotateTarget()) {
|
if (!this.refreshAutoRotateTarget()) {
|
||||||
@@ -839,6 +940,58 @@ export class MapEngine {
|
|||||||
statusText: `${message} (${this.buildVersion})`,
|
statusText: `${message} (${this.buildVersion})`,
|
||||||
}, true)
|
}, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cycleNorthReferenceMode(): void {
|
||||||
|
const nextMode = getNextNorthReferenceMode(this.northReferenceMode)
|
||||||
|
const nextMapNorthOffsetDeg = getMapNorthOffsetDeg(nextMode)
|
||||||
|
const compassHeadingDeg = this.smoothedSensorHeadingDeg === null
|
||||||
|
? null
|
||||||
|
: getCompassReferenceHeadingDeg(nextMode, this.smoothedSensorHeadingDeg)
|
||||||
|
|
||||||
|
this.northReferenceMode = nextMode
|
||||||
|
this.autoRotateCalibrationOffsetDeg = nextMapNorthOffsetDeg
|
||||||
|
this.compassDisplayHeadingDeg = compassHeadingDeg
|
||||||
|
|
||||||
|
if (this.state.orientationMode === 'north-up') {
|
||||||
|
const exactCenter = this.getExactCenterFromTranslate(this.state.tileTranslateX, this.state.tileTranslateY)
|
||||||
|
const resolvedViewport = this.resolveViewportForExactCenter(exactCenter.x, exactCenter.y, MAP_NORTH_OFFSET_DEG)
|
||||||
|
this.commitViewport(
|
||||||
|
{
|
||||||
|
...resolvedViewport,
|
||||||
|
rotationDeg: MAP_NORTH_OFFSET_DEG,
|
||||||
|
rotationText: formatRotationText(MAP_NORTH_OFFSET_DEG),
|
||||||
|
northReferenceText: formatNorthReferenceText(nextMode),
|
||||||
|
sensorHeadingText: formatHeadingText(compassHeadingDeg),
|
||||||
|
compassDeclinationText: formatCompassDeclinationText(nextMode),
|
||||||
|
northReferenceButtonText: formatNorthReferenceButtonText(nextMode),
|
||||||
|
compassNeedleDeg: formatCompassNeedleDegForMode(nextMode, this.smoothedSensorHeadingDeg),
|
||||||
|
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, nextMapNorthOffsetDeg),
|
||||||
|
},
|
||||||
|
`${formatNorthReferenceStatusText(nextMode)} (${this.buildVersion})`,
|
||||||
|
true,
|
||||||
|
() => {
|
||||||
|
this.resetPreviewState()
|
||||||
|
this.syncRenderer()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
northReferenceText: formatNorthReferenceText(nextMode),
|
||||||
|
sensorHeadingText: formatHeadingText(compassHeadingDeg),
|
||||||
|
compassDeclinationText: formatCompassDeclinationText(nextMode),
|
||||||
|
northReferenceButtonText: formatNorthReferenceButtonText(nextMode),
|
||||||
|
compassNeedleDeg: formatCompassNeedleDegForMode(nextMode, this.smoothedSensorHeadingDeg),
|
||||||
|
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, nextMapNorthOffsetDeg),
|
||||||
|
statusText: `${formatNorthReferenceStatusText(nextMode)} (${this.buildVersion})`,
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
if (this.state.orientationMode === 'heading-up' && this.refreshAutoRotateTarget()) {
|
||||||
|
this.scheduleAutoRotate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setCourseHeading(headingDeg: number | null): void {
|
setCourseHeading(headingDeg: number | null): void {
|
||||||
this.courseHeadingDeg = headingDeg === null ? null : normalizeRotationDeg(headingDeg)
|
this.courseHeadingDeg = headingDeg === null ? null : normalizeRotationDeg(headingDeg)
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -851,8 +1004,12 @@ export class MapEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolveAutoRotateInputHeadingDeg(): number | null {
|
resolveAutoRotateInputHeadingDeg(): number | null {
|
||||||
const sensorHeadingDeg = this.smoothedSensorHeadingDeg
|
const sensorHeadingDeg = this.smoothedSensorHeadingDeg === null
|
||||||
const courseHeadingDeg = this.courseHeadingDeg
|
? null
|
||||||
|
: getMapReferenceHeadingDegFromSensor(this.northReferenceMode, this.smoothedSensorHeadingDeg)
|
||||||
|
const courseHeadingDeg = this.courseHeadingDeg === null
|
||||||
|
? null
|
||||||
|
: getMapReferenceHeadingDegFromCourse(this.northReferenceMode, this.courseHeadingDeg)
|
||||||
|
|
||||||
if (this.autoRotateSourceMode === 'sensor') {
|
if (this.autoRotateSourceMode === 'sensor') {
|
||||||
return sensorHeadingDeg
|
return sensorHeadingDeg
|
||||||
|
|||||||
@@ -1,247 +0,0 @@
|
|||||||
import { getTileSizePx, type CameraState } from '../camera/camera'
|
|
||||||
import {
|
|
||||||
TileStore,
|
|
||||||
type TileStoreCallbacks,
|
|
||||||
type TileStoreStats,
|
|
||||||
} from '../tile/tileStore'
|
|
||||||
import { type LonLatPoint } from '../../utils/projection'
|
|
||||||
import { type MapLayer } from '../layer/mapLayer'
|
|
||||||
import { TileLayer } from '../layer/tileLayer'
|
|
||||||
import { TrackLayer } from '../layer/trackLayer'
|
|
||||||
import { GpsLayer } from '../layer/gpsLayer'
|
|
||||||
|
|
||||||
const RENDER_FRAME_MS = 16
|
|
||||||
|
|
||||||
export interface CanvasMapScene {
|
|
||||||
tileSource: string
|
|
||||||
zoom: number
|
|
||||||
centerTileX: number
|
|
||||||
centerTileY: number
|
|
||||||
viewportWidth: number
|
|
||||||
viewportHeight: number
|
|
||||||
visibleColumns: number
|
|
||||||
overdraw: number
|
|
||||||
translateX: number
|
|
||||||
translateY: number
|
|
||||||
rotationRad: number
|
|
||||||
previewScale: number
|
|
||||||
previewOriginX: number
|
|
||||||
previewOriginY: number
|
|
||||||
track: LonLatPoint[]
|
|
||||||
gpsPoint: LonLatPoint
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CanvasMapRendererStats = TileStoreStats
|
|
||||||
|
|
||||||
function buildCamera(scene: CanvasMapScene): CameraState {
|
|
||||||
return {
|
|
||||||
centerWorldX: scene.centerTileX,
|
|
||||||
centerWorldY: scene.centerTileY,
|
|
||||||
viewportWidth: scene.viewportWidth,
|
|
||||||
viewportHeight: scene.viewportHeight,
|
|
||||||
visibleColumns: scene.visibleColumns,
|
|
||||||
rotationRad: scene.rotationRad,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CanvasMapRenderer {
|
|
||||||
canvas: any
|
|
||||||
ctx: any
|
|
||||||
dpr: number
|
|
||||||
scene: CanvasMapScene | null
|
|
||||||
tileStore: TileStore
|
|
||||||
tileLayer: TileLayer
|
|
||||||
layers: MapLayer[]
|
|
||||||
renderTimer: number
|
|
||||||
animationTimer: number
|
|
||||||
destroyed: boolean
|
|
||||||
animationPaused: boolean
|
|
||||||
pulseFrame: number
|
|
||||||
lastStats: CanvasMapRendererStats
|
|
||||||
onStats?: (stats: CanvasMapRendererStats) => void
|
|
||||||
onTileError?: (message: string) => void
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
onStats?: (stats: CanvasMapRendererStats) => void,
|
|
||||||
onTileError?: (message: string) => void,
|
|
||||||
) {
|
|
||||||
this.onStats = onStats
|
|
||||||
this.onTileError = onTileError
|
|
||||||
this.canvas = null
|
|
||||||
this.ctx = null
|
|
||||||
this.dpr = 1
|
|
||||||
this.scene = null
|
|
||||||
this.tileStore = new TileStore({
|
|
||||||
onTileReady: () => {
|
|
||||||
this.scheduleRender()
|
|
||||||
},
|
|
||||||
onTileError: (message) => {
|
|
||||||
if (this.onTileError) {
|
|
||||||
this.onTileError(message)
|
|
||||||
}
|
|
||||||
this.scheduleRender()
|
|
||||||
},
|
|
||||||
} satisfies TileStoreCallbacks)
|
|
||||||
this.tileLayer = new TileLayer()
|
|
||||||
this.layers = [
|
|
||||||
this.tileLayer,
|
|
||||||
new TrackLayer(),
|
|
||||||
new GpsLayer(),
|
|
||||||
]
|
|
||||||
this.renderTimer = 0
|
|
||||||
this.animationTimer = 0
|
|
||||||
this.destroyed = false
|
|
||||||
this.animationPaused = false
|
|
||||||
this.pulseFrame = 0
|
|
||||||
this.lastStats = {
|
|
||||||
visibleTileCount: 0,
|
|
||||||
readyTileCount: 0,
|
|
||||||
memoryTileCount: 0,
|
|
||||||
diskTileCount: 0,
|
|
||||||
memoryHitCount: 0,
|
|
||||||
diskHitCount: 0,
|
|
||||||
networkFetchCount: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attachCanvas(canvasNode: any, width: number, height: number, dpr: number): void {
|
|
||||||
this.canvas = canvasNode
|
|
||||||
this.ctx = canvasNode.getContext('2d')
|
|
||||||
this.dpr = dpr || 1
|
|
||||||
|
|
||||||
canvasNode.width = Math.max(1, Math.floor(width * this.dpr))
|
|
||||||
canvasNode.height = Math.max(1, Math.floor(height * this.dpr))
|
|
||||||
|
|
||||||
if (typeof this.ctx.setTransform === 'function') {
|
|
||||||
this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0)
|
|
||||||
} else {
|
|
||||||
this.ctx.scale(this.dpr, this.dpr)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tileStore.attachCanvas(canvasNode)
|
|
||||||
this.startAnimation()
|
|
||||||
this.scheduleRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
updateScene(scene: CanvasMapScene): void {
|
|
||||||
this.scene = scene
|
|
||||||
this.scheduleRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
setAnimationPaused(paused: boolean): void {
|
|
||||||
this.animationPaused = paused
|
|
||||||
if (!paused) {
|
|
||||||
this.scheduleRender()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy(): void {
|
|
||||||
this.destroyed = true
|
|
||||||
if (this.renderTimer) {
|
|
||||||
clearTimeout(this.renderTimer)
|
|
||||||
this.renderTimer = 0
|
|
||||||
}
|
|
||||||
if (this.animationTimer) {
|
|
||||||
clearTimeout(this.animationTimer)
|
|
||||||
this.animationTimer = 0
|
|
||||||
}
|
|
||||||
this.tileStore.destroy()
|
|
||||||
this.canvas = null
|
|
||||||
this.ctx = null
|
|
||||||
this.scene = null
|
|
||||||
}
|
|
||||||
|
|
||||||
startAnimation(): void {
|
|
||||||
if (this.animationTimer) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const tick = () => {
|
|
||||||
if (this.destroyed) {
|
|
||||||
this.animationTimer = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.animationPaused) {
|
|
||||||
this.pulseFrame = (this.pulseFrame + 1) % 360
|
|
||||||
this.scheduleRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.animationTimer = setTimeout(tick, 33) as unknown as number
|
|
||||||
}
|
|
||||||
|
|
||||||
tick()
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduleRender(): void {
|
|
||||||
if (this.renderTimer || !this.ctx || !this.scene || this.destroyed) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renderTimer = setTimeout(() => {
|
|
||||||
this.renderTimer = 0
|
|
||||||
this.renderFrame()
|
|
||||||
}, RENDER_FRAME_MS) as unknown as number
|
|
||||||
}
|
|
||||||
|
|
||||||
emitStats(stats: CanvasMapRendererStats): void {
|
|
||||||
if (
|
|
||||||
stats.visibleTileCount === this.lastStats.visibleTileCount
|
|
||||||
&& stats.readyTileCount === this.lastStats.readyTileCount
|
|
||||||
&& stats.memoryTileCount === this.lastStats.memoryTileCount
|
|
||||||
&& stats.diskTileCount === this.lastStats.diskTileCount
|
|
||||||
&& stats.memoryHitCount === this.lastStats.memoryHitCount
|
|
||||||
&& stats.diskHitCount === this.lastStats.diskHitCount
|
|
||||||
&& stats.networkFetchCount === this.lastStats.networkFetchCount
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastStats = stats
|
|
||||||
if (this.onStats) {
|
|
||||||
this.onStats(stats)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderFrame(): void {
|
|
||||||
if (!this.ctx || !this.scene) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const scene = this.scene
|
|
||||||
const ctx = this.ctx
|
|
||||||
const camera = buildCamera(scene)
|
|
||||||
const tileSize = getTileSizePx(camera)
|
|
||||||
|
|
||||||
ctx.clearRect(0, 0, scene.viewportWidth, scene.viewportHeight)
|
|
||||||
ctx.fillStyle = '#dbeed4'
|
|
||||||
ctx.fillRect(0, 0, scene.viewportWidth, scene.viewportHeight)
|
|
||||||
|
|
||||||
if (!tileSize) {
|
|
||||||
this.emitStats(this.tileStore.getStats(0, 0))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const previewScale = scene.previewScale || 1
|
|
||||||
const previewOriginX = scene.previewOriginX || scene.viewportWidth / 2
|
|
||||||
const previewOriginY = scene.previewOriginY || scene.viewportHeight / 2
|
|
||||||
|
|
||||||
ctx.save()
|
|
||||||
ctx.translate(previewOriginX, previewOriginY)
|
|
||||||
ctx.scale(previewScale, previewScale)
|
|
||||||
ctx.translate(-previewOriginX, -previewOriginY)
|
|
||||||
|
|
||||||
for (const layer of this.layers) {
|
|
||||||
layer.draw({
|
|
||||||
ctx,
|
|
||||||
camera,
|
|
||||||
scene,
|
|
||||||
pulseFrame: this.pulseFrame,
|
|
||||||
tileStore: this.tileStore,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.restore()
|
|
||||||
this.emitStats(this.tileStore.getStats(this.tileLayer.lastVisibleTileCount, this.tileLayer.lastReadyTileCount))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import { type MapLayer } from '../layer/mapLayer'
|
|
||||||
import { buildCamera, type MapScene } from './mapRenderer'
|
|
||||||
import { type TileStore } from '../tile/tileStore'
|
|
||||||
|
|
||||||
export class CanvasOverlayRenderer {
|
|
||||||
canvas: any
|
|
||||||
ctx: any
|
|
||||||
dpr: number
|
|
||||||
layers: MapLayer[]
|
|
||||||
|
|
||||||
constructor(layers: MapLayer[]) {
|
|
||||||
this.canvas = null
|
|
||||||
this.ctx = null
|
|
||||||
this.dpr = 1
|
|
||||||
this.layers = layers
|
|
||||||
}
|
|
||||||
|
|
||||||
attachCanvas(canvasNode: any, width: number, height: number, dpr: number): void {
|
|
||||||
this.canvas = canvasNode
|
|
||||||
this.ctx = canvasNode.getContext('2d')
|
|
||||||
this.dpr = dpr || 1
|
|
||||||
|
|
||||||
canvasNode.width = Math.max(1, Math.floor(width * this.dpr))
|
|
||||||
canvasNode.height = Math.max(1, Math.floor(height * this.dpr))
|
|
||||||
|
|
||||||
if (typeof this.ctx.setTransform === 'function') {
|
|
||||||
this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0)
|
|
||||||
} else {
|
|
||||||
this.ctx.scale(this.dpr, this.dpr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
this.canvas = null
|
|
||||||
this.ctx = null
|
|
||||||
}
|
|
||||||
|
|
||||||
render(scene: MapScene, tileStore: TileStore, pulseFrame: number): void {
|
|
||||||
if (!this.ctx) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const camera = buildCamera(scene)
|
|
||||||
const ctx = this.ctx
|
|
||||||
const previewScale = scene.previewScale || 1
|
|
||||||
const previewOriginX = scene.previewOriginX || scene.viewportWidth / 2
|
|
||||||
const previewOriginY = scene.previewOriginY || scene.viewportHeight / 2
|
|
||||||
|
|
||||||
ctx.clearRect(0, 0, scene.viewportWidth, scene.viewportHeight)
|
|
||||||
ctx.save()
|
|
||||||
ctx.translate(previewOriginX, previewOriginY)
|
|
||||||
ctx.scale(previewScale, previewScale)
|
|
||||||
ctx.translate(-previewOriginX, -previewOriginY)
|
|
||||||
|
|
||||||
for (const layer of this.layers) {
|
|
||||||
layer.draw({
|
|
||||||
ctx,
|
|
||||||
camera,
|
|
||||||
scene,
|
|
||||||
pulseFrame,
|
|
||||||
tileStore,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.restore()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
// index.ts
|
// index.ts
|
||||||
// 获取应用实例
|
// 获取应用实例
|
||||||
const app = getApp<IAppOption>()
|
|
||||||
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
||||||
|
|
||||||
Component({
|
Component({
|
||||||
@@ -42,7 +41,6 @@ Component({
|
|||||||
wx.getUserProfile({
|
wx.getUserProfile({
|
||||||
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
|
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
console.log(res)
|
|
||||||
this.setData({
|
this.setData({
|
||||||
userInfo: res.userInfo,
|
userInfo: res.userInfo,
|
||||||
hasUserInfo: true
|
hasUserInfo: true
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { MapEngine, type MapEngineStageRect, type MapEngineViewState } from '../../engine/map/mapEngine'
|
import { MapEngine, type MapEngineStageRect, type MapEngineViewState } from '../../engine/map/mapEngine'
|
||||||
|
|
||||||
const INTERNAL_BUILD_VERSION = 'map-build-58'
|
type MapPageData = MapEngineViewState & {
|
||||||
|
showDebugPanel: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const INTERNAL_BUILD_VERSION = 'map-build-75'
|
||||||
|
|
||||||
let mapEngine: MapEngine | null = null
|
let mapEngine: MapEngine | null = null
|
||||||
|
|
||||||
@@ -18,7 +22,7 @@ function getFallbackStageRect(): MapEngineStageRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {} as MapEngineViewState,
|
data: { showDebugPanel: false } as MapPageData,
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
mapEngine = new MapEngine(INTERNAL_BUILD_VERSION, {
|
mapEngine = new MapEngine(INTERNAL_BUILD_VERSION, {
|
||||||
@@ -27,7 +31,7 @@ Page({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
this.setData(mapEngine.getInitialData())
|
this.setData({ ...mapEngine.getInitialData(), showDebugPanel: false })
|
||||||
},
|
},
|
||||||
|
|
||||||
onReady() {
|
onReady() {
|
||||||
@@ -149,11 +153,23 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleCycleNorthReferenceMode() {
|
||||||
|
if (mapEngine) {
|
||||||
|
mapEngine.handleCycleNorthReferenceMode()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
handleAutoRotateCalibrate() {
|
handleAutoRotateCalibrate() {
|
||||||
if (mapEngine) {
|
if (mapEngine) {
|
||||||
mapEngine.handleAutoRotateCalibrate()
|
mapEngine.handleAutoRotateCalibrate()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleToggleDebugPanel() {
|
||||||
|
this.setData({
|
||||||
|
showDebugPanel: !this.data.showDebugPanel,
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -42,24 +42,13 @@
|
|||||||
<view class="compass-widget__center"></view>
|
<view class="compass-widget__center"></view>
|
||||||
</view>
|
</view>
|
||||||
<view class="compass-widget__label">{{sensorHeadingText}}</view>
|
<view class="compass-widget__label">{{sensorHeadingText}}</view>
|
||||||
|
<view class="compass-widget__hint" wx:if="{{compassDeclinationText}}">{{compassDeclinationText}}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view class="info-panel" scroll-y enhanced show-scrollbar="true">
|
<scroll-view class="info-panel" scroll-y enhanced show-scrollbar="true">
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Build</text>
|
|
||||||
<text class="info-panel__value">{{buildVersion}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Renderer</text>
|
|
||||||
<text class="info-panel__value">{{renderMode}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row info-panel__row--stack">
|
|
||||||
<text class="info-panel__label">Projection</text>
|
|
||||||
<text class="info-panel__value">{{projectionMode}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
<view class="info-panel__row">
|
||||||
<text class="info-panel__label">Heading Mode</text>
|
<text class="info-panel__label">Heading Mode</text>
|
||||||
<text class="info-panel__value">{{orientationModeText}}</text>
|
<text class="info-panel__value">{{orientationModeText}}</text>
|
||||||
@@ -68,22 +57,10 @@
|
|||||||
<text class="info-panel__label">Sensor Heading</text>
|
<text class="info-panel__label">Sensor Heading</text>
|
||||||
<text class="info-panel__value">{{sensorHeadingText}}</text>
|
<text class="info-panel__value">{{sensorHeadingText}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-panel__row">
|
<view class="info-panel__row info-panel__row--stack">
|
||||||
<text class="info-panel__label">North Ref</text>
|
<text class="info-panel__label">North Ref</text>
|
||||||
<text class="info-panel__value">{{northReferenceText}}</text>
|
<text class="info-panel__value">{{northReferenceText}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Auto Source</text>
|
|
||||||
<text class="info-panel__value">{{autoRotateSourceText}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Calibration</text>
|
|
||||||
<text class="info-panel__value">{{autoRotateCalibrationText}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row info-panel__row--stack">
|
|
||||||
<text class="info-panel__label">Tile URL</text>
|
|
||||||
<text class="info-panel__value">{{tileSource}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
<view class="info-panel__row">
|
||||||
<text class="info-panel__label">Zoom</text>
|
<text class="info-panel__label">Zoom</text>
|
||||||
<text class="info-panel__value">{{zoom}}</text>
|
<text class="info-panel__value">{{zoom}}</text>
|
||||||
@@ -92,47 +69,78 @@
|
|||||||
<text class="info-panel__label">Rotation</text>
|
<text class="info-panel__label">Rotation</text>
|
||||||
<text class="info-panel__value">{{rotationText}}</text>
|
<text class="info-panel__value">{{rotationText}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Center Tile</text>
|
|
||||||
<text class="info-panel__value">{{centerText}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Tile Size</text>
|
|
||||||
<text class="info-panel__value">{{tileSizePx}}px</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Visible Tiles</text>
|
|
||||||
<text class="info-panel__value">{{visibleTileCount}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Ready Tiles</text>
|
|
||||||
<text class="info-panel__value">{{readyTileCount}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Memory Tiles</text>
|
|
||||||
<text class="info-panel__value">{{memoryTileCount}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Disk Tiles</text>
|
|
||||||
<text class="info-panel__value">{{diskTileCount}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Cache Hit</text>
|
|
||||||
<text class="info-panel__value">{{cacheHitRateText}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Disk Hits</text>
|
|
||||||
<text class="info-panel__value">{{diskHitCount}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row">
|
|
||||||
<text class="info-panel__label">Net Fetches</text>
|
|
||||||
<text class="info-panel__value">{{networkFetchCount}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-panel__row info-panel__row--stack">
|
<view class="info-panel__row info-panel__row--stack">
|
||||||
<text class="info-panel__label">Status</text>
|
<text class="info-panel__label">Status</text>
|
||||||
<text class="info-panel__value">{{statusText}}</text>
|
<text class="info-panel__value">{{statusText}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="control-row">
|
||||||
|
<view class="control-chip control-chip--secondary" bindtap="handleToggleDebugPanel">{{showDebugPanel ? '隐藏调试' : '查看调试'}}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<block wx:if="{{showDebugPanel}}">
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Build</text>
|
||||||
|
<text class="info-panel__value">{{buildVersion}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Renderer</text>
|
||||||
|
<text class="info-panel__value">{{renderMode}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row info-panel__row--stack">
|
||||||
|
<text class="info-panel__label">Projection</text>
|
||||||
|
<text class="info-panel__value">{{projectionMode}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Auto Source</text>
|
||||||
|
<text class="info-panel__value">{{autoRotateSourceText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Calibration</text>
|
||||||
|
<text class="info-panel__value">{{autoRotateCalibrationText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row info-panel__row--stack">
|
||||||
|
<text class="info-panel__label">Tile URL</text>
|
||||||
|
<text class="info-panel__value">{{tileSource}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Center Tile</text>
|
||||||
|
<text class="info-panel__value">{{centerText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Tile Size</text>
|
||||||
|
<text class="info-panel__value">{{tileSizePx}}px</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Visible Tiles</text>
|
||||||
|
<text class="info-panel__value">{{visibleTileCount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Ready Tiles</text>
|
||||||
|
<text class="info-panel__value">{{readyTileCount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Memory Tiles</text>
|
||||||
|
<text class="info-panel__value">{{memoryTileCount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Disk Tiles</text>
|
||||||
|
<text class="info-panel__value">{{diskTileCount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Cache Hit</text>
|
||||||
|
<text class="info-panel__value">{{cacheHitRateText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Disk Hits</text>
|
||||||
|
<text class="info-panel__value">{{diskHitCount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-panel__row">
|
||||||
|
<text class="info-panel__label">Net Fetches</text>
|
||||||
|
<text class="info-panel__value">{{networkFetchCount}}</text>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
<view class="control-row">
|
<view class="control-row">
|
||||||
<view class="control-chip control-chip--primary" bindtap="handleRecenter">回到首屏</view>
|
<view class="control-chip control-chip--primary" bindtap="handleRecenter">回到首屏</view>
|
||||||
<view class="control-chip control-chip--secondary" bindtap="handleRotationReset">旋转归零</view>
|
<view class="control-chip control-chip--secondary" bindtap="handleRotationReset">旋转归零</view>
|
||||||
@@ -142,6 +150,9 @@
|
|||||||
<view class="control-chip {{orientationMode === 'north-up' ? 'control-chip--active' : ''}}" bindtap="handleSetNorthUpMode">北朝上</view>
|
<view class="control-chip {{orientationMode === 'north-up' ? 'control-chip--active' : ''}}" bindtap="handleSetNorthUpMode">北朝上</view>
|
||||||
<view class="control-chip {{orientationMode === 'heading-up' ? 'control-chip--active' : ''}}" bindtap="handleSetHeadingUpMode">朝向朝上</view>
|
<view class="control-chip {{orientationMode === 'heading-up' ? 'control-chip--active' : ''}}" bindtap="handleSetHeadingUpMode">朝向朝上</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="control-row">
|
||||||
|
<view class="control-chip control-chip--secondary" bindtap="handleCycleNorthReferenceMode">{{northReferenceButtonText}}</view>
|
||||||
|
</view>
|
||||||
<view class="control-row" wx:if="{{orientationMode === 'heading-up'}}">
|
<view class="control-row" wx:if="{{orientationMode === 'heading-up'}}">
|
||||||
<view class="control-chip" bindtap="handleAutoRotateCalibrate">按当前方向校准</view>
|
<view class="control-chip" bindtap="handleAutoRotateCalibrate">按当前方向校准</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -213,6 +213,15 @@
|
|||||||
box-shadow: 0 8rpx 18rpx rgba(22, 48, 32, 0.08);
|
box-shadow: 0 8rpx 18rpx rgba(22, 48, 32, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compass-widget__hint {
|
||||||
|
margin-top: 8rpx;
|
||||||
|
font-size: 18rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: #d62828;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
.info-panel {
|
.info-panel {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user