feat: initialize mini program map engine
This commit is contained in:
206
miniprogram/engine/sensor/compassHeadingController.ts
Normal file
206
miniprogram/engine/sensor/compassHeadingController.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
export interface CompassHeadingControllerCallbacks {
|
||||
onHeading: (headingDeg: number) => void
|
||||
onError: (message: string) => void
|
||||
}
|
||||
|
||||
type SensorSource = 'compass' | 'motion' | null
|
||||
|
||||
const ABSOLUTE_HEADING_CORRECTION = 0.24
|
||||
|
||||
function normalizeHeadingDeg(headingDeg: number): number {
|
||||
const normalized = headingDeg % 360
|
||||
return normalized < 0 ? normalized + 360 : normalized
|
||||
}
|
||||
|
||||
function normalizeHeadingDeltaDeg(deltaDeg: number): number {
|
||||
let normalized = deltaDeg
|
||||
|
||||
while (normalized > 180) {
|
||||
normalized -= 360
|
||||
}
|
||||
|
||||
while (normalized < -180) {
|
||||
normalized += 360
|
||||
}
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
function interpolateHeadingDeg(currentDeg: number, targetDeg: number, factor: number): number {
|
||||
return normalizeHeadingDeg(currentDeg + normalizeHeadingDeltaDeg(targetDeg - currentDeg) * factor)
|
||||
}
|
||||
|
||||
export class CompassHeadingController {
|
||||
callbacks: CompassHeadingControllerCallbacks
|
||||
listening: boolean
|
||||
source: SensorSource
|
||||
compassCallback: ((result: WechatMiniprogram.OnCompassChangeCallbackResult) => void) | null
|
||||
motionCallback: ((result: WechatMiniprogram.OnDeviceMotionChangeCallbackResult) => void) | null
|
||||
absoluteHeadingDeg: number | null
|
||||
pitchDeg: number | null
|
||||
rollDeg: number | null
|
||||
motionReady: boolean
|
||||
compassReady: boolean
|
||||
|
||||
constructor(callbacks: CompassHeadingControllerCallbacks) {
|
||||
this.callbacks = callbacks
|
||||
this.listening = false
|
||||
this.source = null
|
||||
this.compassCallback = null
|
||||
this.motionCallback = null
|
||||
this.absoluteHeadingDeg = null
|
||||
this.pitchDeg = null
|
||||
this.rollDeg = null
|
||||
this.motionReady = false
|
||||
this.compassReady = false
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.listening) {
|
||||
return
|
||||
}
|
||||
|
||||
this.absoluteHeadingDeg = null
|
||||
this.pitchDeg = null
|
||||
this.rollDeg = null
|
||||
this.motionReady = false
|
||||
this.compassReady = false
|
||||
this.source = null
|
||||
|
||||
if (typeof wx.startCompass === 'function' && typeof wx.onCompassChange === 'function') {
|
||||
this.startCompassSource()
|
||||
return
|
||||
}
|
||||
|
||||
this.callbacks.onError('当前环境不支持罗盘方向监听')
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
this.detachCallbacks()
|
||||
|
||||
if (this.motionReady) {
|
||||
wx.stopDeviceMotionListening({ complete: () => {} })
|
||||
}
|
||||
|
||||
if (this.compassReady) {
|
||||
wx.stopCompass({ complete: () => {} })
|
||||
}
|
||||
|
||||
this.listening = false
|
||||
this.source = null
|
||||
this.absoluteHeadingDeg = null
|
||||
this.pitchDeg = null
|
||||
this.rollDeg = null
|
||||
this.motionReady = false
|
||||
this.compassReady = false
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.stop()
|
||||
}
|
||||
|
||||
startMotionSource(previousMessage: string): void {
|
||||
if (typeof wx.startDeviceMotionListening !== 'function' || typeof wx.onDeviceMotionChange !== 'function') {
|
||||
this.callbacks.onError(previousMessage)
|
||||
return
|
||||
}
|
||||
|
||||
const callback = (result: WechatMiniprogram.OnDeviceMotionChangeCallbackResult) => {
|
||||
if (typeof result.alpha !== 'number' || Number.isNaN(result.alpha)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.pitchDeg = typeof result.beta === 'number' && !Number.isNaN(result.beta)
|
||||
? result.beta * 180 / Math.PI
|
||||
: null
|
||||
this.rollDeg = typeof result.gamma === 'number' && !Number.isNaN(result.gamma)
|
||||
? result.gamma * 180 / Math.PI
|
||||
: null
|
||||
|
||||
const alphaDeg = result.alpha * 180 / Math.PI
|
||||
this.applyAbsoluteHeading(normalizeHeadingDeg(360 - alphaDeg), 'motion')
|
||||
}
|
||||
|
||||
this.motionCallback = callback
|
||||
wx.onDeviceMotionChange(callback)
|
||||
wx.startDeviceMotionListening({
|
||||
interval: 'ui',
|
||||
success: () => {
|
||||
this.motionReady = true
|
||||
this.listening = true
|
||||
this.source = 'motion'
|
||||
},
|
||||
fail: (res) => {
|
||||
this.detachMotionCallback()
|
||||
const motionMessage = res && res.errMsg ? res.errMsg : 'startDeviceMotionListening failed'
|
||||
this.callbacks.onError(`${previousMessage};${motionMessage}`)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
startCompassSource(): void {
|
||||
const callback = (result: WechatMiniprogram.OnCompassChangeCallbackResult) => {
|
||||
if (typeof result.direction !== 'number' || Number.isNaN(result.direction)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.applyAbsoluteHeading(normalizeHeadingDeg(result.direction), 'compass')
|
||||
}
|
||||
|
||||
this.compassCallback = callback
|
||||
wx.onCompassChange(callback)
|
||||
wx.startCompass({
|
||||
success: () => {
|
||||
this.compassReady = true
|
||||
this.listening = true
|
||||
this.source = 'compass'
|
||||
},
|
||||
fail: (res) => {
|
||||
this.detachCompassCallback()
|
||||
this.callbacks.onError(res && res.errMsg ? res.errMsg : 'startCompass failed')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
applyAbsoluteHeading(headingDeg: number, source: 'compass' | 'motion'): void {
|
||||
if (this.absoluteHeadingDeg === null) {
|
||||
this.absoluteHeadingDeg = headingDeg
|
||||
} else {
|
||||
this.absoluteHeadingDeg = interpolateHeadingDeg(this.absoluteHeadingDeg, headingDeg, ABSOLUTE_HEADING_CORRECTION)
|
||||
}
|
||||
|
||||
this.source = source
|
||||
this.callbacks.onHeading(this.absoluteHeadingDeg)
|
||||
}
|
||||
|
||||
detachCallbacks(): void {
|
||||
this.detachMotionCallback()
|
||||
this.detachCompassCallback()
|
||||
}
|
||||
|
||||
detachMotionCallback(): void {
|
||||
if (!this.motionCallback) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof wx.offDeviceMotionChange === 'function') {
|
||||
wx.offDeviceMotionChange(this.motionCallback)
|
||||
}
|
||||
this.motionCallback = null
|
||||
}
|
||||
|
||||
detachCompassCallback(): void {
|
||||
if (!this.compassCallback) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof wx.offCompassChange === 'function') {
|
||||
wx.offCompassChange(this.compassCallback)
|
||||
}
|
||||
this.compassCallback = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user