375 lines
9.1 KiB
TypeScript
375 lines
9.1 KiB
TypeScript
import { MapEngine, type MapEngineStageRect, type MapEngineViewState } from '../../engine/map/mapEngine'
|
|
import { loadRemoteMapConfig } from '../../utils/remoteMapConfig'
|
|
type CompassTickData = {
|
|
angle: number
|
|
long: boolean
|
|
major: boolean
|
|
}
|
|
type CompassLabelData = {
|
|
text: string
|
|
angle: number
|
|
rotateBack: number
|
|
radius: number
|
|
className: string
|
|
}
|
|
type SideButtonMode = 'all' | 'left' | 'right' | 'hidden'
|
|
type MapPageData = MapEngineViewState & {
|
|
showDebugPanel: boolean
|
|
statusBarHeight: number
|
|
topInsetHeight: number
|
|
panelTimerText: string
|
|
panelMileageText: string
|
|
panelDistanceValueText: string
|
|
panelProgressText: string
|
|
panelSpeedValueText: string
|
|
compassTicks: CompassTickData[]
|
|
compassLabels: CompassLabelData[]
|
|
sideButtonMode: SideButtonMode
|
|
showLeftButtonGroup: boolean
|
|
showRightButtonGroups: boolean
|
|
showBottomDebugButton: boolean
|
|
}
|
|
const INTERNAL_BUILD_VERSION = 'map-build-134'
|
|
const REMOTE_GAME_CONFIG_URL = 'https://oss-mbh5.colormaprun.com/wxmini/test/game.json'
|
|
let mapEngine: MapEngine | null = null
|
|
function buildSideButtonVisibility(mode: SideButtonMode) {
|
|
return {
|
|
sideButtonMode: mode,
|
|
showLeftButtonGroup: mode === 'all' || mode === 'left' || mode === 'right',
|
|
showRightButtonGroups: mode === 'all' || mode === 'right',
|
|
showBottomDebugButton: mode !== 'hidden',
|
|
}
|
|
}
|
|
|
|
function getNextSideButtonMode(currentMode: SideButtonMode): SideButtonMode {
|
|
if (currentMode === 'all') {
|
|
return 'left'
|
|
}
|
|
if (currentMode === 'left') {
|
|
return 'right'
|
|
}
|
|
if (currentMode === 'right') {
|
|
return 'hidden'
|
|
}
|
|
return 'left'
|
|
}
|
|
function buildCompassTicks(): CompassTickData[] {
|
|
const ticks: CompassTickData[] = []
|
|
for (let angle = 0; angle < 360; angle += 5) {
|
|
ticks.push({
|
|
angle,
|
|
long: angle % 15 === 0,
|
|
major: angle % 45 === 0,
|
|
})
|
|
}
|
|
return ticks
|
|
}
|
|
function buildCompassLabels(): CompassLabelData[] {
|
|
return [
|
|
{ text: '\u5317', angle: 0, rotateBack: 0, radius: 68, className: 'compass-widget__mark--cardinal compass-widget__mark--north' },
|
|
{ text: '\u4e1c\u5317', angle: 45, rotateBack: 0, radius: 58, className: 'compass-widget__mark--intermediate compass-widget__mark--northeast' },
|
|
{ text: '\u4e1c', angle: 90, rotateBack: 0, radius: 68, className: 'compass-widget__mark--cardinal' },
|
|
{ text: '\u4e1c\u5357', angle: 135, rotateBack: 0, radius: 58, className: 'compass-widget__mark--intermediate' },
|
|
{ text: '\u5357', angle: 180, rotateBack: 0, radius: 68, className: 'compass-widget__mark--cardinal' },
|
|
{ text: '\u897f\u5357', angle: 225, rotateBack: 0, radius: 58, className: 'compass-widget__mark--intermediate' },
|
|
{ text: '\u897f', angle: 270, rotateBack: 0, radius: 68, className: 'compass-widget__mark--cardinal' },
|
|
{ text: '\u897f\u5317', angle: 315, rotateBack: 0, radius: 58, className: 'compass-widget__mark--intermediate compass-widget__mark--northwest' },
|
|
]
|
|
}
|
|
function getFallbackStageRect(): MapEngineStageRect {
|
|
const systemInfo = wx.getSystemInfoSync()
|
|
const width = Math.max(320, systemInfo.windowWidth)
|
|
const height = Math.max(280, systemInfo.windowHeight)
|
|
|
|
return {
|
|
width,
|
|
height,
|
|
left: 0,
|
|
top: 0,
|
|
}
|
|
}
|
|
|
|
Page({
|
|
data: {
|
|
showDebugPanel: false,
|
|
statusBarHeight: 0,
|
|
topInsetHeight: 12,
|
|
panelTimerText: '00:00:00',
|
|
panelMileageText: '0m',
|
|
panelDistanceValueText: '108',
|
|
panelProgressText: '0/14',
|
|
panelSpeedValueText: '0',
|
|
compassTicks: buildCompassTicks(),
|
|
compassLabels: buildCompassLabels(),
|
|
...buildSideButtonVisibility('left'),
|
|
} as MapPageData,
|
|
|
|
onLoad() {
|
|
const systemInfo = wx.getSystemInfoSync()
|
|
const statusBarHeight = systemInfo.statusBarHeight || 0
|
|
const menuButtonRect = wx.getMenuButtonBoundingClientRect()
|
|
const menuButtonBottom = menuButtonRect && typeof menuButtonRect.bottom === 'number' ? menuButtonRect.bottom : statusBarHeight
|
|
|
|
mapEngine = new MapEngine(INTERNAL_BUILD_VERSION, {
|
|
onData: (patch) => {
|
|
this.setData(patch)
|
|
},
|
|
})
|
|
|
|
this.setData({
|
|
...mapEngine.getInitialData(),
|
|
showDebugPanel: false,
|
|
statusBarHeight,
|
|
topInsetHeight: Math.max(statusBarHeight + 12, menuButtonBottom + 20),
|
|
panelTimerText: '00:00:00',
|
|
panelMileageText: '0m',
|
|
panelDistanceValueText: '108',
|
|
panelProgressText: '0/14',
|
|
panelSpeedValueText: '0',
|
|
compassTicks: buildCompassTicks(),
|
|
compassLabels: buildCompassLabels(),
|
|
...buildSideButtonVisibility('left'),
|
|
})
|
|
},
|
|
|
|
onReady() {
|
|
this.measureStageAndCanvas()
|
|
this.loadMapConfigFromRemote()
|
|
},
|
|
|
|
onUnload() {
|
|
if (mapEngine) {
|
|
mapEngine.destroy()
|
|
mapEngine = null
|
|
}
|
|
},
|
|
|
|
loadMapConfigFromRemote() {
|
|
const currentEngine = mapEngine
|
|
if (!currentEngine) {
|
|
return
|
|
}
|
|
|
|
loadRemoteMapConfig(REMOTE_GAME_CONFIG_URL)
|
|
.then((config) => {
|
|
if (mapEngine !== currentEngine) {
|
|
return
|
|
}
|
|
|
|
currentEngine.applyRemoteMapConfig(config)
|
|
})
|
|
.catch((error) => {
|
|
if (mapEngine !== currentEngine) {
|
|
return
|
|
}
|
|
|
|
const errorMessage = error && error.message ? error.message : '鏈煡閿欒'
|
|
this.setData({
|
|
configStatusText: `杞藉叆澶辫触: ${errorMessage}`,
|
|
statusText: `杩滅▼鍦板浘閰嶇疆杞藉叆澶辫触: ${errorMessage} (${INTERNAL_BUILD_VERSION})`,
|
|
})
|
|
})
|
|
},
|
|
|
|
measureStageAndCanvas() {
|
|
const page = this
|
|
const applyStage = (rawRect?: Partial<WechatMiniprogram.BoundingClientRectCallbackResult>) => {
|
|
const fallbackRect = getFallbackStageRect()
|
|
const rect: MapEngineStageRect = {
|
|
width: rawRect && typeof rawRect.width === 'number' ? rawRect.width : fallbackRect.width,
|
|
height: rawRect && typeof rawRect.height === 'number' ? rawRect.height : fallbackRect.height,
|
|
left: rawRect && typeof rawRect.left === 'number' ? rawRect.left : fallbackRect.left,
|
|
top: rawRect && typeof rawRect.top === 'number' ? rawRect.top : fallbackRect.top,
|
|
}
|
|
|
|
const currentEngine = mapEngine
|
|
if (!currentEngine) {
|
|
return
|
|
}
|
|
|
|
currentEngine.setStage(rect)
|
|
|
|
const canvasQuery = wx.createSelectorQuery().in(page)
|
|
canvasQuery.select('#mapCanvas').fields({ node: true, size: true })
|
|
canvasQuery.exec((canvasRes) => {
|
|
const canvasRef = canvasRes[0] as any
|
|
if (!canvasRef || !canvasRef.node) {
|
|
page.setData({
|
|
statusText: `WebGL 寮曟搸鍒濆鍖栧け璐?(${INTERNAL_BUILD_VERSION})`,
|
|
})
|
|
return
|
|
}
|
|
|
|
const dpr = wx.getSystemInfoSync().pixelRatio || 1
|
|
try {
|
|
currentEngine.attachCanvas(canvasRef.node, rect.width, rect.height, dpr)
|
|
} catch (error) {
|
|
page.setData({
|
|
statusText: `WebGL 鍒濆鍖栧け璐?(${INTERNAL_BUILD_VERSION})`,
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
const query = wx.createSelectorQuery().in(page)
|
|
query.select('.map-stage').boundingClientRect()
|
|
query.exec((res) => {
|
|
const rect = res[0] as WechatMiniprogram.BoundingClientRectCallbackResult | undefined
|
|
applyStage(rect)
|
|
})
|
|
},
|
|
|
|
handleTouchStart(event: WechatMiniprogram.TouchEvent) {
|
|
if (mapEngine) {
|
|
mapEngine.handleTouchStart(event)
|
|
}
|
|
},
|
|
|
|
handleTouchMove(event: WechatMiniprogram.TouchEvent) {
|
|
if (mapEngine) {
|
|
mapEngine.handleTouchMove(event)
|
|
}
|
|
},
|
|
|
|
handleTouchEnd(event: WechatMiniprogram.TouchEvent) {
|
|
if (mapEngine) {
|
|
mapEngine.handleTouchEnd(event)
|
|
}
|
|
},
|
|
|
|
handleTouchCancel() {
|
|
if (mapEngine) {
|
|
mapEngine.handleTouchCancel()
|
|
}
|
|
},
|
|
|
|
handleRecenter() {
|
|
if (mapEngine) {
|
|
mapEngine.handleRecenter()
|
|
}
|
|
},
|
|
|
|
handleRotateStep() {
|
|
if (mapEngine) {
|
|
mapEngine.handleRotateStep()
|
|
}
|
|
},
|
|
|
|
handleRotationReset() {
|
|
if (mapEngine) {
|
|
mapEngine.handleRotationReset()
|
|
}
|
|
},
|
|
|
|
handleSetManualMode() {
|
|
if (mapEngine) {
|
|
mapEngine.handleSetManualMode()
|
|
}
|
|
},
|
|
|
|
handleSetNorthUpMode() {
|
|
if (mapEngine) {
|
|
mapEngine.handleSetNorthUpMode()
|
|
}
|
|
},
|
|
|
|
handleSetHeadingUpMode() {
|
|
if (mapEngine) {
|
|
mapEngine.handleSetHeadingUpMode()
|
|
}
|
|
},
|
|
|
|
handleCycleNorthReferenceMode() {
|
|
if (mapEngine) {
|
|
mapEngine.handleCycleNorthReferenceMode()
|
|
}
|
|
},
|
|
|
|
handleAutoRotateCalibrate() {
|
|
if (mapEngine) {
|
|
mapEngine.handleAutoRotateCalibrate()
|
|
}
|
|
},
|
|
|
|
handleToggleGpsTracking() {
|
|
if (mapEngine) {
|
|
mapEngine.handleToggleGpsTracking()
|
|
}
|
|
},
|
|
|
|
handleToggleOsmReference() {
|
|
if (mapEngine) {
|
|
mapEngine.handleToggleOsmReference()
|
|
}
|
|
},
|
|
|
|
handleCycleSideButtons() {
|
|
this.setData(buildSideButtonVisibility(getNextSideButtonMode(this.data.sideButtonMode)))
|
|
},
|
|
handleToggleMapRotateMode() {
|
|
if (!mapEngine) {
|
|
return
|
|
}
|
|
|
|
if (this.data.orientationMode === 'heading-up') {
|
|
mapEngine.handleSetManualMode()
|
|
return
|
|
}
|
|
|
|
mapEngine.handleSetHeadingUpMode()
|
|
},
|
|
handleToggleDebugPanel() {
|
|
this.setData({
|
|
showDebugPanel: !this.data.showDebugPanel,
|
|
})
|
|
},
|
|
|
|
handleCloseDebugPanel() {
|
|
this.setData({
|
|
showDebugPanel: false,
|
|
})
|
|
},
|
|
|
|
handleDebugPanelTap() {},
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|