You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

758 lines
21 KiB

import * as VPASSDK from "./VPASSDK-1.2.2.js";
import { stopBeaconScan, getLocation } from "ais-h5-location";
import { createScopedThreejs } from "threejs-miniprogram";
import { registerGLTFLoader } from "../../loader/gltfLoader";
var THREE;
import configData from "./config";
import { STATES, promptStateMap } from "./index-helper";
var _canvas;
let map;
let locationOption;
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",
};
Page({
/**
* 页面的初始数据
*/
data: {
inited: false,
isMap: true,
isMeet: true,
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: 0,
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,
},
clickScreen(e) {
let detail = e.detail;
if (this.SDK) this.SDK.getScreenCoordinate({ x: detail.x, y: detail.y });
console.log("点击屏幕x, y:", detail.x, detail.y);
},
touchMove(event) {
if (this.SDK) this.SDK.getScreenCoordinate(event.touches[0]);
},
touchCancel(event) {
if (this.SDK) this.SDK.touchCancel();
},
touchStart() {
console.log("touch Start");
if (this.SDK) this.SDK.touchStart();
},
touchEnd() {
console.log("touch End");
if (this.SDK) this.SDK.touchCancel();
},
setSelectMall() {
this.setData({ selectMall: true });
},
setSelectPark() {
this.setData({ selectMall: false });
},
/**
* 生命周期函数--监听页面加载
*/
async onLoad({ e, searchType = 0 }) {
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();
},
initSDK() {
this.SDK = new VPASSDK.SDKWrapper(configData);
wx.createSelectorQuery()
.select("#webgl")
.node()
.exec((res) => {
_canvas = res[0].node;
// todo 初始化引擎放到我们系统初始化中
// 创建一个与 canvas 绑定的 three.js
THREE = createScopedThreejs(_canvas);
// SXC
registerGLTFLoader(THREE);
});
},
requestLocation() {
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: () => {},
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);
},
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 });
this.setData({
theta,
distance,
distanceToNextPoint,
nextPointType,
msgBottomLeft: "剩余" + Math.floor(distance) + "米",
msgBottomRight: Math.floor(distance / 1.4 / 60) + "分钟",
});
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) {
this.setData({ arriveEnd: true });
this.setMsgTopAndIcon();
this.setState(STATES.arriveEnd);
}
},
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: ({ eventUrl }) => {
console.log(eventUrl);
if (!eventUrl.includes("***")) return;
let [appId, path] = eventUrl.split("***");
wx.navigateToMiniProgram({
appId,
path,
});
},
};
console.log("locationOption:", locationOption);
const floor = this.data.floors.find(
({ floorId }) => locationOption.floor_id == floorId
);
if (floor.isPark) {
this.startBlueTooth(locationOption.floor_id);
} else {
this.stopBlueTooth();
}
console.log(floor);
this.SDK.requestVPASLocation(locationOption);
this.setData({
state: STATES.startScan,
arriveEnd: false,
showTabs: false,
});
},
stopBlueTooth() {
stopBeaconScan();
wx.closeBluetoothAdapter();
},
startBlueTooth(currentFloor) {
const ak = configData.map.find(({ floor_id }) => floor_id == currentFloor)
.ak;
console.log("ak:", ak);
if (!ak) return console.warn("no ak");
wx.openBluetoothAdapter({
success: () => {
getLocation({
ak,
intervalTime: 1000, // 定时器(请求频率时长)
successCb: (result) => {
const { location, floor, indoor } = result.body && result.body[0];
const sameFloor = (floor && floor.toUpperCase()) == currentFloor; // 判断是否为同一楼层(避免获取同临楼层定位信息)
// pointX、pointY格式处理
const splitArray = location && location.split(",");
const pointX = parseFloat(splitArray[0]);
const pointY = parseFloat(splitArray[1]);
// 过滤蓝牙location 无效值
let isValidLocation;
if (splitArray && splitArray.length) {
isValidLocation = pointX > 1 && pointY > 1;
}
/**
* vpas updateBluetoothLocation 触发条件:
* 选择楼层 等于 蓝牙返回楼层时
* indoor = 1(室内)
*/
if (sameFloor && indoor === "1") {
isValidLocation &&
this.SDK.updateBluetoothLocation(pointX, pointY);
}
},
failCb: (err) => {
console.warn("fail-蓝牙位置定位失败", err);
},
});
},
fail: (res) => {
console.warn("蓝牙未开启>>", res);
},
});
},
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);
const openid = getApp().globalData.openid;
if (
[
"oBbmR5c_SWeSyHBQ2YrAnu9W2Zts",
"oBbmR5VLexJ41jtbMsvIKVaiz7vE",
"oBbmR5ecGc_0RmQhR8qbQR1rdpYg",
].includes(openid)
)
this.setData({
session: {
session: res.session,
timestamp: new Date().getTime(),
naviData,
openid,
path: [
{ locX: res.locX, locY: res.locY, timestamp: new Date().getTime() },
],
},
});
this.SDK.setNavigationData(
naviData,
final,
res.wasmFunction,
locationOption
);
this.SDK.startARNavigation();
setTimeout(() => {
this.setState(STATES.inNav);
this.setData({
showTabs: true,
tab: 0,
});
}, 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,
});
},
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
);
},
});
},
/**
* 生命周期函数--监听页面显示
*/
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.stopBlueTooth();
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 });
},
});