|
|
@@ -55,12 +55,15 @@ const AUTO_ROTATE_EASE = 0.34
|
|
|
const AUTO_ROTATE_SNAP_DEG = 0.1
|
|
|
const AUTO_ROTATE_DEADZONE_DEG = 4
|
|
|
const AUTO_ROTATE_MAX_STEP_DEG = 0.75
|
|
|
-const AUTO_ROTATE_HEADING_SMOOTHING = 0.32
|
|
|
-const COMPASS_NEEDLE_SMOOTHING = 0.12
|
|
|
+const AUTO_ROTATE_HEADING_SMOOTHING = 0.46
|
|
|
+const COMPASS_NEEDLE_MIN_SMOOTHING = 0.24
|
|
|
+const COMPASS_NEEDLE_MAX_SMOOTHING = 0.56
|
|
|
const SMART_HEADING_BLEND_START_SPEED_KMH = 1.2
|
|
|
const SMART_HEADING_MOVEMENT_SPEED_KMH = 3.0
|
|
|
-const SMART_HEADING_MIN_DISTANCE_METERS = 8
|
|
|
+const SMART_HEADING_MIN_DISTANCE_METERS = 12
|
|
|
const SMART_HEADING_MAX_ACCURACY_METERS = 25
|
|
|
+const SMART_HEADING_MOVEMENT_MIN_SMOOTHING = 0.12
|
|
|
+const SMART_HEADING_MOVEMENT_MAX_SMOOTHING = 0.24
|
|
|
const GPS_TRACK_MAX_POINTS = 200
|
|
|
const GPS_TRACK_MIN_STEP_METERS = 3
|
|
|
const MAP_TAP_MOVE_THRESHOLD_PX = 14
|
|
|
@@ -384,6 +387,35 @@ function interpolateAngleDeg(currentDeg: number, targetDeg: number, factor: numb
|
|
|
return normalizeRotationDeg(currentDeg + normalizeAngleDeltaDeg(targetDeg - currentDeg) * factor)
|
|
|
}
|
|
|
|
|
|
+function getCompassNeedleSmoothingFactor(currentDeg: number, targetDeg: number): number {
|
|
|
+ const deltaDeg = Math.abs(normalizeAngleDeltaDeg(targetDeg - currentDeg))
|
|
|
+ if (deltaDeg <= 4) {
|
|
|
+ return COMPASS_NEEDLE_MIN_SMOOTHING
|
|
|
+ }
|
|
|
+ if (deltaDeg >= 36) {
|
|
|
+ return COMPASS_NEEDLE_MAX_SMOOTHING
|
|
|
+ }
|
|
|
+
|
|
|
+ const progress = (deltaDeg - 4) / (36 - 4)
|
|
|
+ return COMPASS_NEEDLE_MIN_SMOOTHING
|
|
|
+ + (COMPASS_NEEDLE_MAX_SMOOTHING - COMPASS_NEEDLE_MIN_SMOOTHING) * progress
|
|
|
+}
|
|
|
+
|
|
|
+function getMovementHeadingSmoothingFactor(speedKmh: number | null): number {
|
|
|
+ if (speedKmh === null || !Number.isFinite(speedKmh) || speedKmh <= SMART_HEADING_BLEND_START_SPEED_KMH) {
|
|
|
+ return SMART_HEADING_MOVEMENT_MIN_SMOOTHING
|
|
|
+ }
|
|
|
+
|
|
|
+ if (speedKmh >= SMART_HEADING_MOVEMENT_SPEED_KMH) {
|
|
|
+ return SMART_HEADING_MOVEMENT_MAX_SMOOTHING
|
|
|
+ }
|
|
|
+
|
|
|
+ const progress = (speedKmh - SMART_HEADING_BLEND_START_SPEED_KMH)
|
|
|
+ / (SMART_HEADING_MOVEMENT_SPEED_KMH - SMART_HEADING_BLEND_START_SPEED_KMH)
|
|
|
+ return SMART_HEADING_MOVEMENT_MIN_SMOOTHING
|
|
|
+ + (SMART_HEADING_MOVEMENT_MAX_SMOOTHING - SMART_HEADING_MOVEMENT_MIN_SMOOTHING) * progress
|
|
|
+}
|
|
|
+
|
|
|
function formatGameSessionStatusText(status: 'idle' | 'running' | 'finished' | 'failed'): string {
|
|
|
if (status === 'running') {
|
|
|
return '进行中'
|
|
|
@@ -705,16 +737,19 @@ export class MapEngine {
|
|
|
autoRotateTimer: number
|
|
|
pendingViewPatch: Partial<MapEngineViewState>
|
|
|
mounted: boolean
|
|
|
+ diagnosticUiEnabled: boolean
|
|
|
northReferenceMode: NorthReferenceMode
|
|
|
sensorHeadingDeg: number | null
|
|
|
smoothedSensorHeadingDeg: number | null
|
|
|
compassDisplayHeadingDeg: number | null
|
|
|
+ smoothedMovementHeadingDeg: number | null
|
|
|
autoRotateHeadingDeg: number | null
|
|
|
courseHeadingDeg: number | null
|
|
|
targetAutoRotationDeg: number | null
|
|
|
autoRotateSourceMode: AutoRotateSourceMode
|
|
|
autoRotateCalibrationOffsetDeg: number | null
|
|
|
autoRotateCalibrationPending: boolean
|
|
|
+ lastStatsUiSyncAt: number
|
|
|
minZoom: number
|
|
|
maxZoom: number
|
|
|
defaultZoom: number
|
|
|
@@ -776,14 +811,18 @@ export class MapEngine {
|
|
|
y,
|
|
|
z,
|
|
|
})
|
|
|
- this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ }
|
|
|
},
|
|
|
onError: (message) => {
|
|
|
this.accelerometerErrorText = `不可用: ${message}`
|
|
|
- this.setState({
|
|
|
- ...this.getTelemetrySensorViewPatch(),
|
|
|
- statusText: `加速度计启动失败 (${this.buildVersion})`,
|
|
|
- }, true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState({
|
|
|
+ ...this.getTelemetrySensorViewPatch(),
|
|
|
+ statusText: `加速度计启动失败 (${this.buildVersion})`,
|
|
|
+ }, true)
|
|
|
+ }
|
|
|
},
|
|
|
})
|
|
|
this.compassController = new CompassHeadingController({
|
|
|
@@ -803,10 +842,14 @@ export class MapEngine {
|
|
|
y,
|
|
|
z,
|
|
|
})
|
|
|
- this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ }
|
|
|
},
|
|
|
onError: () => {
|
|
|
- this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ }
|
|
|
},
|
|
|
})
|
|
|
this.deviceMotionController = new DeviceMotionController({
|
|
|
@@ -818,17 +861,21 @@ export class MapEngine {
|
|
|
beta,
|
|
|
gamma,
|
|
|
})
|
|
|
- this.setState({
|
|
|
- ...this.getTelemetrySensorViewPatch(),
|
|
|
- autoRotateSourceText: this.getAutoRotateSourceText(),
|
|
|
- }, true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState({
|
|
|
+ ...this.getTelemetrySensorViewPatch(),
|
|
|
+ autoRotateSourceText: this.getAutoRotateSourceText(),
|
|
|
+ }, true)
|
|
|
+ }
|
|
|
|
|
|
if (this.state.orientationMode === 'heading-up' && this.refreshAutoRotateTarget()) {
|
|
|
this.scheduleAutoRotate()
|
|
|
}
|
|
|
},
|
|
|
onError: () => {
|
|
|
- this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState(this.getTelemetrySensorViewPatch(), true)
|
|
|
+ }
|
|
|
},
|
|
|
})
|
|
|
this.locationController = new LocationController({
|
|
|
@@ -840,7 +887,7 @@ export class MapEngine {
|
|
|
gpsTracking: this.locationController.listening,
|
|
|
gpsTrackingText: message,
|
|
|
...this.getLocationControllerViewPatch(),
|
|
|
- }, true)
|
|
|
+ })
|
|
|
},
|
|
|
onError: (message) => {
|
|
|
this.setState({
|
|
|
@@ -848,10 +895,12 @@ export class MapEngine {
|
|
|
gpsTrackingText: message,
|
|
|
...this.getLocationControllerViewPatch(),
|
|
|
statusText: `${message} (${this.buildVersion})`,
|
|
|
- }, true)
|
|
|
+ })
|
|
|
},
|
|
|
onDebugStateChange: () => {
|
|
|
- this.setState(this.getLocationControllerViewPatch(), true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState(this.getLocationControllerViewPatch(), true)
|
|
|
+ }
|
|
|
},
|
|
|
})
|
|
|
this.heartRateController = new HeartRateInputController({
|
|
|
@@ -872,7 +921,7 @@ export class MapEngine {
|
|
|
heartRateDeviceText: deviceName,
|
|
|
heartRateScanText: this.getHeartRateScanText(),
|
|
|
...this.getHeartRateControllerViewPatch(),
|
|
|
- }, true)
|
|
|
+ })
|
|
|
},
|
|
|
onError: (message) => {
|
|
|
this.clearHeartRateSignal()
|
|
|
@@ -886,7 +935,7 @@ export class MapEngine {
|
|
|
heartRateScanText: this.getHeartRateScanText(),
|
|
|
...this.getHeartRateControllerViewPatch(),
|
|
|
statusText: `${message} (${this.buildVersion})`,
|
|
|
- }, true)
|
|
|
+ })
|
|
|
},
|
|
|
onConnectionChange: (connected, deviceName) => {
|
|
|
if (!connected) {
|
|
|
@@ -906,17 +955,21 @@ export class MapEngine {
|
|
|
heartRateScanText: this.getHeartRateScanText(),
|
|
|
heartRateDiscoveredDevices: this.formatHeartRateDevices(this.heartRateController.discoveredDevices),
|
|
|
...this.getHeartRateControllerViewPatch(),
|
|
|
- }, true)
|
|
|
+ })
|
|
|
},
|
|
|
onDeviceListChange: (devices) => {
|
|
|
- this.setState({
|
|
|
- heartRateDiscoveredDevices: this.formatHeartRateDevices(devices),
|
|
|
- heartRateScanText: this.getHeartRateScanText(),
|
|
|
- ...this.getHeartRateControllerViewPatch(),
|
|
|
- }, true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState({
|
|
|
+ heartRateDiscoveredDevices: this.formatHeartRateDevices(devices),
|
|
|
+ heartRateScanText: this.getHeartRateScanText(),
|
|
|
+ ...this.getHeartRateControllerViewPatch(),
|
|
|
+ }, true)
|
|
|
+ }
|
|
|
},
|
|
|
onDebugStateChange: () => {
|
|
|
- this.setState(this.getHeartRateControllerViewPatch(), true)
|
|
|
+ if (this.diagnosticUiEnabled) {
|
|
|
+ this.setState(this.getHeartRateControllerViewPatch(), true)
|
|
|
+ }
|
|
|
},
|
|
|
})
|
|
|
this.feedbackDirector = new FeedbackDirector({
|
|
|
@@ -1119,22 +1172,53 @@ export class MapEngine {
|
|
|
this.autoRotateTimer = 0
|
|
|
this.pendingViewPatch = {}
|
|
|
this.mounted = false
|
|
|
+ this.diagnosticUiEnabled = false
|
|
|
this.northReferenceMode = DEFAULT_NORTH_REFERENCE_MODE
|
|
|
this.sensorHeadingDeg = null
|
|
|
this.smoothedSensorHeadingDeg = null
|
|
|
this.compassDisplayHeadingDeg = null
|
|
|
+ this.smoothedMovementHeadingDeg = null
|
|
|
this.autoRotateHeadingDeg = null
|
|
|
this.courseHeadingDeg = null
|
|
|
this.targetAutoRotationDeg = null
|
|
|
this.autoRotateSourceMode = 'smart'
|
|
|
this.autoRotateCalibrationOffsetDeg = getMapNorthOffsetDeg(DEFAULT_NORTH_REFERENCE_MODE)
|
|
|
this.autoRotateCalibrationPending = false
|
|
|
+ this.lastStatsUiSyncAt = 0
|
|
|
}
|
|
|
|
|
|
getInitialData(): MapEngineViewState {
|
|
|
return { ...this.state }
|
|
|
}
|
|
|
|
|
|
+ setDiagnosticUiEnabled(enabled: boolean): void {
|
|
|
+ if (this.diagnosticUiEnabled === enabled) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ this.diagnosticUiEnabled = enabled
|
|
|
+
|
|
|
+ if (!enabled) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ this.setState({
|
|
|
+ ...this.getTelemetrySensorViewPatch(),
|
|
|
+ ...this.getLocationControllerViewPatch(),
|
|
|
+ ...this.getHeartRateControllerViewPatch(),
|
|
|
+ heartRateDiscoveredDevices: this.formatHeartRateDevices(this.heartRateController.discoveredDevices),
|
|
|
+ autoRotateSourceText: this.getAutoRotateSourceText(),
|
|
|
+ visibleTileCount: this.state.visibleTileCount,
|
|
|
+ readyTileCount: this.state.readyTileCount,
|
|
|
+ memoryTileCount: this.state.memoryTileCount,
|
|
|
+ diskTileCount: this.state.diskTileCount,
|
|
|
+ memoryHitCount: this.state.memoryHitCount,
|
|
|
+ diskHitCount: this.state.diskHitCount,
|
|
|
+ networkFetchCount: this.state.networkFetchCount,
|
|
|
+ cacheHitRateText: this.state.cacheHitRateText,
|
|
|
+ }, true)
|
|
|
+ }
|
|
|
+
|
|
|
getGameInfoSnapshot(): MapEngineGameInfoSnapshot {
|
|
|
const definition = this.gameRuntime.definition
|
|
|
const sessionState = this.gameRuntime.state
|
|
|
@@ -1253,12 +1337,14 @@ export class MapEngine {
|
|
|
this.currentGpsTrack = []
|
|
|
this.currentGpsAccuracyMeters = null
|
|
|
this.currentGpsInsideMap = false
|
|
|
+ this.smoothedMovementHeadingDeg = null
|
|
|
this.courseOverlayVisible = false
|
|
|
this.setCourseHeading(null)
|
|
|
}
|
|
|
|
|
|
clearStartSessionResidue(): void {
|
|
|
this.currentGpsTrack = []
|
|
|
+ this.smoothedMovementHeadingDeg = null
|
|
|
this.courseOverlayVisible = false
|
|
|
this.setCourseHeading(null)
|
|
|
}
|
|
|
@@ -1534,7 +1620,7 @@ export class MapEngine {
|
|
|
panelAverageSpeedUnitText: telemetryPresentation.averageSpeedUnitText,
|
|
|
panelAccuracyValueText: telemetryPresentation.accuracyValueText,
|
|
|
panelAccuracyUnitText: telemetryPresentation.accuracyUnitText,
|
|
|
- }, true)
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
updateSessionTimerLoop(): void {
|
|
|
@@ -1798,6 +1884,7 @@ export class MapEngine {
|
|
|
|
|
|
this.currentGpsPoint = nextPoint
|
|
|
this.currentGpsAccuracyMeters = accuracyMeters
|
|
|
+ this.updateMovementHeadingDeg()
|
|
|
|
|
|
const gpsWorldPoint = lonLatToWorldTile(nextPoint, this.state.zoom)
|
|
|
const gpsTileX = Math.floor(gpsWorldPoint.x)
|
|
|
@@ -2167,7 +2254,7 @@ export class MapEngine {
|
|
|
compassDeclinationText: formatCompassDeclinationText(this.northReferenceMode),
|
|
|
northReferenceButtonText: formatNorthReferenceButtonText(this.northReferenceMode),
|
|
|
northReferenceText: formatNorthReferenceText(this.northReferenceMode),
|
|
|
- compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.smoothedSensorHeadingDeg),
|
|
|
+ compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.compassDisplayHeadingDeg),
|
|
|
...this.getGameViewPatch(gameStatusText),
|
|
|
}
|
|
|
|
|
|
@@ -2683,18 +2770,26 @@ export class MapEngine {
|
|
|
const compassHeadingDeg = getCompassReferenceHeadingDeg(this.northReferenceMode, this.smoothedSensorHeadingDeg)
|
|
|
this.compassDisplayHeadingDeg = this.compassDisplayHeadingDeg === null
|
|
|
? compassHeadingDeg
|
|
|
- : interpolateAngleDeg(this.compassDisplayHeadingDeg, compassHeadingDeg, COMPASS_NEEDLE_SMOOTHING)
|
|
|
+ : interpolateAngleDeg(
|
|
|
+ this.compassDisplayHeadingDeg,
|
|
|
+ compassHeadingDeg,
|
|
|
+ getCompassNeedleSmoothingFactor(this.compassDisplayHeadingDeg, compassHeadingDeg),
|
|
|
+ )
|
|
|
|
|
|
this.autoRotateHeadingDeg = this.resolveAutoRotateInputHeadingDeg()
|
|
|
|
|
|
this.setState({
|
|
|
- sensorHeadingText: formatHeadingText(compassHeadingDeg),
|
|
|
- ...this.getTelemetrySensorViewPatch(),
|
|
|
- compassDeclinationText: formatCompassDeclinationText(this.northReferenceMode),
|
|
|
- northReferenceButtonText: formatNorthReferenceButtonText(this.northReferenceMode),
|
|
|
- autoRotateSourceText: this.getAutoRotateSourceText(),
|
|
|
- compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.smoothedSensorHeadingDeg),
|
|
|
- northReferenceText: formatNorthReferenceText(this.northReferenceMode),
|
|
|
+ compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.compassDisplayHeadingDeg),
|
|
|
+ ...(this.diagnosticUiEnabled
|
|
|
+ ? {
|
|
|
+ sensorHeadingText: formatHeadingText(compassHeadingDeg),
|
|
|
+ ...this.getTelemetrySensorViewPatch(),
|
|
|
+ compassDeclinationText: formatCompassDeclinationText(this.northReferenceMode),
|
|
|
+ northReferenceButtonText: formatNorthReferenceButtonText(this.northReferenceMode),
|
|
|
+ autoRotateSourceText: this.getAutoRotateSourceText(),
|
|
|
+ northReferenceText: formatNorthReferenceText(this.northReferenceMode),
|
|
|
+ }
|
|
|
+ : {}),
|
|
|
})
|
|
|
|
|
|
if (!this.refreshAutoRotateTarget()) {
|
|
|
@@ -2740,7 +2835,7 @@ export class MapEngine {
|
|
|
...this.getTelemetrySensorViewPatch(),
|
|
|
compassDeclinationText: formatCompassDeclinationText(nextMode),
|
|
|
northReferenceButtonText: formatNorthReferenceButtonText(nextMode),
|
|
|
- compassNeedleDeg: formatCompassNeedleDegForMode(nextMode, this.smoothedSensorHeadingDeg),
|
|
|
+ compassNeedleDeg: formatCompassNeedleDegForMode(nextMode, this.compassDisplayHeadingDeg),
|
|
|
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, nextMapNorthOffsetDeg),
|
|
|
},
|
|
|
`${formatNorthReferenceStatusText(nextMode)} (${this.buildVersion})`,
|
|
|
@@ -2759,7 +2854,7 @@ export class MapEngine {
|
|
|
...this.getTelemetrySensorViewPatch(),
|
|
|
compassDeclinationText: formatCompassDeclinationText(nextMode),
|
|
|
northReferenceButtonText: formatNorthReferenceButtonText(nextMode),
|
|
|
- compassNeedleDeg: formatCompassNeedleDegForMode(nextMode, this.smoothedSensorHeadingDeg),
|
|
|
+ compassNeedleDeg: formatCompassNeedleDegForMode(nextMode, this.compassDisplayHeadingDeg),
|
|
|
autoRotateCalibrationText: formatAutoRotateCalibrationText(false, nextMapNorthOffsetDeg),
|
|
|
statusText: `${formatNorthReferenceStatusText(nextMode)} (${this.buildVersion})`,
|
|
|
}, true)
|
|
|
@@ -2780,7 +2875,7 @@ export class MapEngine {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- getMovementHeadingDeg(): number | null {
|
|
|
+ getRawMovementHeadingDeg(): number | null {
|
|
|
if (!this.currentGpsInsideMap) {
|
|
|
return null
|
|
|
}
|
|
|
@@ -2809,6 +2904,23 @@ export class MapEngine {
|
|
|
return null
|
|
|
}
|
|
|
|
|
|
+ updateMovementHeadingDeg(): void {
|
|
|
+ const rawMovementHeadingDeg = this.getRawMovementHeadingDeg()
|
|
|
+ if (rawMovementHeadingDeg === null) {
|
|
|
+ this.smoothedMovementHeadingDeg = null
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const smoothingFactor = getMovementHeadingSmoothingFactor(this.telemetryRuntime.state.currentSpeedKmh)
|
|
|
+ this.smoothedMovementHeadingDeg = this.smoothedMovementHeadingDeg === null
|
|
|
+ ? rawMovementHeadingDeg
|
|
|
+ : interpolateAngleDeg(this.smoothedMovementHeadingDeg, rawMovementHeadingDeg, smoothingFactor)
|
|
|
+ }
|
|
|
+
|
|
|
+ getMovementHeadingDeg(): number | null {
|
|
|
+ return this.smoothedMovementHeadingDeg
|
|
|
+ }
|
|
|
+
|
|
|
getPreferredSensorHeadingDeg(): number | null {
|
|
|
return this.smoothedSensorHeadingDeg === null
|
|
|
? null
|
|
|
@@ -2959,7 +3071,7 @@ export class MapEngine {
|
|
|
}
|
|
|
|
|
|
applyStats(stats: MapRendererStats): void {
|
|
|
- this.setState({
|
|
|
+ const statsPatch = {
|
|
|
visibleTileCount: stats.visibleTileCount,
|
|
|
readyTileCount: stats.readyTileCount,
|
|
|
memoryTileCount: stats.memoryTileCount,
|
|
|
@@ -2968,7 +3080,27 @@ export class MapEngine {
|
|
|
diskHitCount: stats.diskHitCount,
|
|
|
networkFetchCount: stats.networkFetchCount,
|
|
|
cacheHitRateText: formatCacheHitRate(stats.memoryHitCount, stats.diskHitCount, stats.networkFetchCount),
|
|
|
- })
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!this.diagnosticUiEnabled) {
|
|
|
+ this.state = {
|
|
|
+ ...this.state,
|
|
|
+ ...statsPatch,
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const now = Date.now()
|
|
|
+ if (now - this.lastStatsUiSyncAt < 500) {
|
|
|
+ this.state = {
|
|
|
+ ...this.state,
|
|
|
+ ...statsPatch,
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ this.lastStatsUiSyncAt = now
|
|
|
+ this.setState(statsPatch)
|
|
|
}
|
|
|
|
|
|
setState(patch: Partial<MapEngineViewState>, immediateUi = false): void {
|