import * as VPASSDK from "./VPASSDK-1.2.4.js"; import { createScopedThreejs } from "threejs-miniprogram"; import { registerGLTFLoader } from "../../loader/gltfLoader"; var THREE; import { STATES, promptStateMap } from "./index-helper"; import { getMapData, post } from "../../getMapData"; var _canvas; let map; const icons = { left: "/pages/index/left.png", straight: "/pages/index/straight.png", right: "/pages/index/right.png", end: "/pages/index/end.png", escalatorUp: "/pages/index/escalator-up.png", escalatorDown: "/pages/index/escalator-down.png", elevatorUp: "/pages/index/elevator-up.png", elevatorDown: "/pages/index/elevator-down.png", }; let locationOption; let initFloorOrder; Page({ /** * 页面的初始数据 */ data: { inited: false, locX: 0, locY: 0, floors: [], floorOrder: null, floorId: null, floorName: null, windowHeight: 812, states: STATES, state: STATES.selectFloor, promptStateMap, map: null, e: null, lastLoc: null, tab: 1, showTabs: false, shop: null, nextFloor: null, nextNextFloor: null, navIcon: icons.straight, distanceToNextPoint: null, msgTop: "", nextPointType: null, msgBottomLeft: "", msgBottomRight: "", totalDistance: 0, distance: 0, arriveEnd: false, theta: null, flash: "off", parkTop: 0, parkLeft: 0, flash_isFilter: "true", parkWidth: 0, parkHeight: 0, session: null, filteredMallFloors: [], filteredParkFloors: [], selectMall: true, safeTop: 54, frameSize: "medium", leftYaw: true, rightYaw: true, searchType: 0, point: null, resolution: null, poiMap: {}, warningCount: 0, }, setSelectMall() { this.setData({ selectMall: true }); }, setSelectPark() { this.setData({ selectMall: false }); }, /** * 生命周期函数--监听页面加载 */ async onLoad({ e, searchType = 0, floorOrder }) { initFloorOrder = floorOrder; const { config, poiMap } = await getMapData(); this.poiMap = poiMap; this.frameIndex = 0; this.getSystemInfo(); wx.setKeepScreenOn({ keepScreenOn: true, }); const { globalData: { floors }, } = getApp(); const { windowHeight } = wx.getSystemInfoSync(); this.setData({ floors, filteredMallFloors: floors.filter( ({ url, isPark }) => url !== null && !isPark ), filteredParkFloors: floors.filter( ({ url, isPark }) => url !== null && isPark ), windowHeight, e: decodeURIComponent(e), searchType: Number(searchType), }); this.initSDK(config); }, initSDK(config) { console.log(config); this.SDK = new VPASSDK.SDKWrapper(config); wx.createSelectorQuery() .select("#webgl") .node() .exec((res) => { _canvas = res[0].node; // todo 初始化引擎放到我们系统初始化中 // 创建一个与 canvas 绑定的 three.js THREE = createScopedThreejs(_canvas); // SXC registerGLTFLoader(THREE); }); }, requestLocation() { this.ignoreArriveEnd = false; if (!(this.data.inited && this.data.floorOrder !== null)) return; if (!this.sdkInited) { try { this.SDK.initAR( { rgba2JpegCanvas: "#capture", // 压缩jpeg的Canvas,必填 webGLCanvas: "#webgl", // 绘制AR内容canvas,必填 }, THREE, _canvas ); } catch (error) { console.log(error); } } this.sdkInited = true; locationOption = { floor_id: this.data.floorId, onLocateEvent: () => {}, distanceOfNextPoint: () => {}, onVerticalYaw: () => { this.setData({ warningCount: this.data.warningCount + 1 }); }, onLocateEvent: (res) => {}, onSaveViewmatrix: (res) => {}, onSaveFusion_pose: (res) => {}, distanceOfNextPoint: (res) => { // console.log("distanceOfNextPoint", res); }, onFirstSuccess: (res) => { this.firstSuccess(res); this.setData({ totalDistance: 0, lastLoc: [res.locX, res.locY], state: STATES.successPrompt, flash: "off", }); }, onBluetoothAndScanStatus: (res) => { console.log("关于蓝牙和扫描框状态:", res.type); // if (res.type === true) { // if (this.data.state === STATES.bluetoothRequired) { // this.requestLocation(); // } // } else if (res.type === 99) { // this.setState(STATES.bluetoothRequired); // this.finishARNavigation(); // } }, onError: (e) => { const { type } = e; if (type !== 10010) console.log("error:", e); if (type === 10005) return this.setState(STATES.fail5s); if (type === 10007) { this.finishARNavigation(); return this.setState(STATES.fail8s); } if (type === 10008) { return wx.showModal({ title: "提示", content: "断网了,重新链接?", showCancel: false, success: (res) => { if (res.confirm) { console.log("用户点击确定"); // 获取网络信号 wx.getNetworkType({ success: (res) => { locationOption.onNetWork({ type: res.networkType, msg: "获取网络类型", }); if (res.networkType !== "none") { this.SDK.requestVPASLocation(locationOption); } else { locationOption.onError({ type: 10008, msg: "监听网络信号失败", }); } }, fail: (err) => { locationOption.onError({ type: 10008, msg: "监听网络信号失败", }); }, }); } }, }); } if (type === 10009) { return wx.showToast({ icon: "none", title: "车位号无效\n换个试试吧", }); } if (type === 10010) { return wx.showToast({ icon: "none", title: "请以垂直水平角度手持手机", }); } wx.showToast({ icon: "none", title: "定位失败\n错误码:" + type, }); }, onEverySuccess: (res) => { // 跟踪回调 const lastLoc = [res.locX, res.locY]; const { distance, distanceToNextPoint, type: nextPointType, orientation: theta, } = res; if (!this.data.totalDistance) this.setData({ totalDistance: distance }); const remainMinutes = Math.floor(distance / 1.4 / 60); this.setData({ theta, distance, distanceToNextPoint, nextPointType, msgBottomLeft: "剩余" + Math.floor(distance) + "米", msgBottomRight: remainMinutes ? remainMinutes + "分钟" : "< 1 分钟", }); this.setMsgTopAndIcon(); if ( this.data.lastLoc && this.data.lastLoc[0] === lastLoc[0] && this.data.lastLoc[1] === lastLoc[1] ) return; this.setData({ lastLoc, }); }, onNetWork: (status) => { console.log("network", status); }, onArrive: (res) => { // console.log("onArrive", res); if (res.type === 3 || res.type === 4) { this.finishARNavigation(); this.setState(STATES.arriveElevator); } else if (res.type === 5 || res.type === 6) { this.finishARNavigation(); this.setState(STATES.arriveEscalator); } else if (res.type === 8 || res.type === 9) { this.finishARNavigation(); this.setState(res.type === 8 ? STATES.arrivePark : STATES.arriveMall); } else if (res.type === 7) { if (this.ignoreArriveEnd) return; this.setData({ arriveEnd: true }); this.setMsgTopAndIcon(); this.setState(STATES.arriveEnd); this.ignoreArriveEnd = true; } }, onResourceLoaded: (res) => { console.log("AR资源导航加载完成"); }, onStep: (res) => { // console.log(res) }, onYaw: ({ type }) => { this.setData({ leftYaw: type === 1 || type === 2, rightYaw: type === 0 || type === 2, }); }, onPoiEvent: async ({ eventUrl }) => { if (eventUrl.includes("***")) { let [appId, path] = eventUrl.split("***"); wx.navigateToMiniProgram({ appId, path, }); return; } const poi = this.poiMap[eventUrl]; console.log(eventUrl, poi); if (poi && !this.locked) { this.locked = true; setTimeout(() => { this.locked = false; }, 5000); const memberID = getApp().globalData.memberID; if (poi.responseType === "活动" && memberID) { const { msg } = await post("/api/ar/v1/applet/GetUserAward", { memberID, poiCode: poi.code, }); return wx.showModal({ content: msg, }); } if (poi.appId) { return wx.navigateToMiniProgram({ appId: poi.appId, path: poi.path, }); } if (poi.webUrl) { wx.navigateTo({ url: `/pages/detail/index?url=${encodeURIComponent(poi.webUrl)}`, }); } } }, }; console.log(locationOption); this.SDK.requestVPASLocation(locationOption); this.setData({ state: STATES.startScan, arriveEnd: false, showTabs: false, }); }, setMsgTopAndIcon() { const { distanceToNextPoint, nextPointType, arriveEnd, nextFloor, floors, } = this.data; if ( distanceToNextPoint !== null && nextPointType !== null && nextPointType !== -1 ) { const flooredDistance = Math.floor(distanceToNextPoint); const nextFloorName = nextFloor ? nextFloor.name : ""; this.setData({ msgTop: arriveEnd ? "已到达" : distanceToNextPoint > 20 ? `直行${flooredDistance}米` : nextPointType === 7 ? `${flooredDistance}米后 到达终点` : nextPointType === 8 ? `${ distanceToNextPoint < 5 ? "" : `${flooredDistance}米后 ` }到达停车位入口` : nextPointType === 9 ? `${ distanceToNextPoint < 5 ? "" : `${flooredDistance}米后 ` }到达商场入口` : [3, 4, 5, 6].includes(nextPointType) ? `${ distanceToNextPoint < 5 ? "" : `${flooredDistance}米后 ` }乘梯至${nextFloorName}` : [1, 2].includes(nextPointType) ? `${ distanceToNextPoint < 5 ? nextPointType === 1 ? "左转" : "右转" : `${flooredDistance}米后 ${ nextPointType === 1 ? "左转" : "右转" }` }` : distanceToNextPoint < 5 ? `${nextPointType === 1 ? "左转" : "右转"}` : "", navIcon: arriveEnd ? icons.end : distanceToNextPoint > 20 ? icons.straight : { 1: icons.left, 2: icons.right, 3: icons.elevatorUp, 4: icons.elevatorDown, 5: icons.escalatorUp, 6: icons.escalatorDown, 7: icons.end, }[nextPointType], }); } }, setFloor({ currentTarget: { id } }) { const floor = this.data[ this.data.selectMall ? "filteredMallFloors" : "filteredParkFloors" ][id]; this.setData({ floorOrder: floor.floorOrder, point: null, floorId: floor.floorId, floorName: floor.name, }); }, firstSuccess(res) { console.log("firstSuccess---", this.data.e); if (!map) return; let shop = map.shopMap[this.data.e] ? map.shopMap[this.data.e] : map.facilityMap[this.data.e] ? map.facilityMap[this.data.e] : map.pMap[this.data.e]; if (!shop) { const endParamList = this.data.e.split("_"); if (endParamList.length === 3) { let [efloororder, epoint, ename] = endParamList; efloororder = Number(efloororder); epoint = Number(epoint); shop = { isDevice: true, name: ename, navPoint: epoint, yaxis: epoint, floorOrder: efloororder, floorName: map.mall.floors[efloororder][1], }; } } console.log("end", shop); if (!shop) return wx.showToast({ icon: "none", title: `未匹配到该终点:${this.data.e}`, }); this.setData({ shop: { ...shop, logoPath: shop.logoPath ? shop.logoPath.replaceAll("\\", "/") : null, }, }); const { naviData, nextFloorId, nextNextFloorId } = map.requestRoute( [res.locX, res.locY, this.data.floorId], { floorOrder: shop.floorOrder, navPoint: shop.yaxis } ); if (!naviData) return; let nextFloor = this.data.floors.find( ({ floorId }) => nextFloorId == floorId ); let nextNextFloor = this.data.floors.find( ({ floorId }) => nextNextFloorId == floorId ); this.setData({ nextFloor, nextNextFloor }); let final = new THREE.Vector3( naviData[naviData.length - 1].x, naviData[naviData.length - 1].y, 0 ); if (!nextFloor) { naviData.pop(); if (naviData.length === 1) { naviData.push({ ...naviData[0], pointType: 1, x: (naviData[0].x + final.x) / 2, y: (naviData[0].y + final.y) / 2, }); } } console.log("naviData", naviData, "final", final); this.SDK.setNavigationData( naviData, final, res.wasmFunction, locationOption ); this.SDK.startARNavigation(); setTimeout(() => { this.setState(STATES.inNav); this.setData({ showTabs: true, tab: 1, }); }, 1000); }, exit() { wx.redirectTo({ url: "/pages/h5map/index", }); }, handleToMap() { this.setState(STATES.tomap); }, handlePromptBtn({ detail: { btn } }) { const { state } = this.data; if (state === STATES.bluetoothRequired) { if (btn === "3") return this.exit(); } if (state === STATES.fail8s) { if (btn === "1") return this.requestLocation(); if (btn === "2") return this.setState(STATES.selectFloor); if (btn === "3") return this.exit(); } if (state === STATES.wrongLocation) return this.exit(); if (state === STATES.badConnection) return this.requestLocation(); if ( state === STATES.arriveEscalator || state === STATES.arriveElevator || state === STATES.arriveMall || state === STATES.arrivePark ) { const nextFloor = this.data.nextNextFloor ? this.data.nextNextFloor : this.data.nextFloor; if (nextFloor) this.setData({ floorOrder: nextFloor.floorOrder, point: null, floorId: nextFloor.floorId, floorName: nextFloor.name, }); return this.requestLocation(); } if (state === STATES.requestEnd || state === STATES.arriveEnd) { if (btn === "1") return this.exit(); if (btn === "2") return this.setState(STATES.inNav); } if (state === STATES.noCamera) { if (btn === "1") return wx.openSetting({ withSubscriptions: true, success: ({ authSetting }) => { if (authSetting["scope.camera"]) { wx.redirectTo({ url: `/pages/index/index?e=${this.data.e}`, }); } }, }); if (btn === "2") return this.exit(); } if (state === STATES.tomap) { if (btn === "1") return wx.redirectTo({ url: `/pages/h5map/index?e=${this.data.e}`, }); if (btn === "2") return this.setState(STATES.inNav); } }, setState(state) { if ( (this.data.state === STATES.arriveEscalator || this.data.state === STATES.arriveElevator || this.data.state === STATES.arriveMall || this.data.state === STATES.arrivePark) && state === STATES.inNav ) return console.log("到达弹窗出现忽略导航中状态变更触发"); if ( this.data.state === STATES.bluetoothRequired && state !== STATES.startScan ) return console.log("蓝牙弹窗状态只能进入开始定位状态"); this.setData({ state, }); }, handleMap({ detail }) { map = detail; this.setData({ inited: true, }); const { floors } = this.data; const floor = floors[initFloorOrder]; initFloorOrder = undefined; if (floor) { this.setData({ floorOrder: floor.floorOrder, point: null, floorId: floor.floorId, floorName: floor.name, }); this.requestLocation(); } }, handleTabChange({ detail }) { this.setData({ tab: detail, }); if (this.SDK) { this.SDK.updateOnScreenArrowPosition( detail == 0 ? new THREE.Vector3(0, -0.015, -0.25) : new THREE.Vector3(0, -0.06, -0.25) ); } }, handleRelocate() { this.SDK.finishARNavigation(); this.requestLocation(); }, handleNavExit() { this.setState(STATES.requestEnd); }, handleNoCamera() { this.setState(STATES.noCamera); }, flashlightBtn() { if (this.data.flash === "off") { this.setData({ flash: "on", flash_isFilter: "true", }); } else { this.setData({ flash: "off", }); } }, getSystemInfo() { wx.getSystemInfo({ success: (res) => { console.log("设备信息:", res); let parkWidth = 248; let parkHeight = 70; let parkTop = res.windowHeight - parkHeight; let parkLeft = res.windowWidth - parkWidth; this.setData({ parkWidth: parkWidth, parkHeight: parkHeight, parkTop: parkTop / 2, parkLeft: parkLeft / 2, safeTop: res.safeArea.top, frameSize: res.system.includes("iOS") ? "medium" : "small", resolution: res.system.includes("iOS") ? "high" : "small", }); console.log( "宽高左上:", this.data.parkWidth, this.data.parkHeight, this.data.parkTop, this.data.parkLeft ); }, }); }, clickScreen(e) { let detail = e.detail; this.SDK.getScreenCoordinate({ x: detail.x, y: detail.y }); console.log("点击屏幕x, y:", detail.x, detail.y); }, touchMove(event) { this.SDK.getScreenCoordinate(event.touches[0]); }, touchCancel(event) { this.SDK.touchCancel(); }, touchStart() { console.log("touch Start"); this.SDK.touchStart(); }, touchEnd() { console.log("touch End"); this.SDK.touchCancel(); }, /** * 生命周期函数--监听页面显示 */ onShow: function () { this.getSystemInfo(); }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () {}, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { this.finishARNavigation(true); if (this.SDK) this.SDK.releaseRender(); }, finishARNavigation(isUnload = false) { if (this.SDK) this.SDK.finishARNavigation(isUnload); this.setData({ totalDistance: 0 }); }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () {}, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function () {}, /** * 用户点击右上角分享 */ onShareAppMessage({ from }) { const e = from === "button" && this.data.point !== null ? `${this.data.floorOrder}_${this.data.point}_来自分享的位置` : null; return e === null ? { title: "", path: "/pages/h5map/index", imageUrl: "/pages/h5map/share.png", } : { title: "来自分享的位置", path: `/pages/h5map/index?e=${e}`, imageUrl: "/pages/h5map/share.png", }; }, handlePoint({ detail }) { this.setData({ point: detail }); }, });