@ -0,0 +1,2 @@ |
|||||
|
/node_modules |
||||
|
./package-lock.json |
||||
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"editor.formatOnSave": true |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
import { getMapData,post, code } from "./getMapData"; |
||||
|
|
||||
|
|
||||
|
|
||||
|
const floors = [ |
||||
|
{ |
||||
|
name: "L1", |
||||
|
floorOrder: 0, |
||||
|
url: null, |
||||
|
floorId: "0", |
||||
|
isPark: false, |
||||
|
}, |
||||
|
{ |
||||
|
name: "L2", |
||||
|
floorOrder: 1, |
||||
|
url: true, |
||||
|
floorId: "F2", |
||||
|
isPark: false, |
||||
|
}, |
||||
|
]; |
||||
|
App({ |
||||
|
async onLaunch() { |
||||
|
// 展示本地存储能力
|
||||
|
getMapData(); |
||||
|
const { code } = await new Promise((resolve, reject) => { |
||||
|
wx.login({ |
||||
|
success: resolve, |
||||
|
fail: reject, |
||||
|
}); |
||||
|
}); |
||||
|
const { data } = await post("/api/ar/v1/applet/MemberLogin", { |
||||
|
code, |
||||
|
}); |
||||
|
this.globalData.openid = data.openid; |
||||
|
this.globalData.memberID = data.memberID; |
||||
|
this.globalData.isShopMember = data.isShopMember; |
||||
|
this.openidCbs.forEach((cb) => cb(data.openid)); |
||||
|
}, |
||||
|
onOpenid(cb) { |
||||
|
this.openidCbs.push(cb); |
||||
|
}, |
||||
|
openidCbs: [], |
||||
|
globalData: { |
||||
|
floors, |
||||
|
floorIdFloorOrderMap: floors.reduce( |
||||
|
(acc, nxt) => ({ ...acc, [nxt.floorId]: nxt.floorOrder }), |
||||
|
{} |
||||
|
), |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,22 @@ |
|||||
|
{ |
||||
|
"pages": [ |
||||
|
"pages/h5map/index", |
||||
|
"pages/index/index", |
||||
|
"pages/login/index", |
||||
|
"pages/privacy/index", |
||||
|
"pages/detail/index" |
||||
|
], |
||||
|
"window": { |
||||
|
"navigationStyle": "custom", |
||||
|
"navigationBarBackgroundColor": "#F0F0F0", |
||||
|
"navigationBarTitleText": "", |
||||
|
"navigationBarTextStyle": "black" |
||||
|
}, |
||||
|
"style": "v2", |
||||
|
"sitemapLocation": "sitemap.json", |
||||
|
"permission": { |
||||
|
"scope.userLocation": { |
||||
|
"desc": "你的位置信息将用于小程序位置接口的效果展示" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
/**app.wxss**/ |
||||
|
.container { |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
padding: 200rpx 0; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
view, |
||||
|
input, |
||||
|
scroll-view { |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
@ -0,0 +1,357 @@ |
|||||
|
const FacilityCodeMap = { |
||||
|
ft: 0, |
||||
|
upft: 0, |
||||
|
downft: 0, |
||||
|
mys: 3, |
||||
|
xsj: 4, |
||||
|
fwt: 7, |
||||
|
dt: 5, |
||||
|
lt: 88, |
||||
|
dit: 89, |
||||
|
cjr: 10, |
||||
|
tcc: 8, |
||||
|
xsjn: 12, |
||||
|
xsjv: 13, |
||||
|
xxt: 14, |
||||
|
tczl: 8, |
||||
|
fcjcg: 7, |
||||
|
door: 39, |
||||
|
czc: 500, |
||||
|
vip: 34, |
||||
|
pq: 40, |
||||
|
ksgj: 30, |
||||
|
xcgc: 57, |
||||
|
tthy: 58, |
||||
|
bc: 26, |
||||
|
etxsj: 69, |
||||
|
}; |
||||
|
|
||||
|
export const attachGraphSingle = ({ graph, key, value }) => { |
||||
|
graph[key] = { |
||||
|
...graph[key], |
||||
|
...value, |
||||
|
}; |
||||
|
}; |
||||
|
export const attachGraph = ({ |
||||
|
graph, |
||||
|
leftKey, |
||||
|
rightKey, |
||||
|
leftValue, |
||||
|
rightValue, |
||||
|
}) => { |
||||
|
graph[leftKey] = { |
||||
|
...graph[leftKey], |
||||
|
...leftValue, |
||||
|
}; |
||||
|
graph[rightKey] = { |
||||
|
...graph[rightKey], |
||||
|
...rightValue, |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export const getDataNew = async (map) => { |
||||
|
const { |
||||
|
mall: { shopInfo, mapData }, |
||||
|
} = map; |
||||
|
return { |
||||
|
serverShopInfo: shopInfo, |
||||
|
mapData, |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export const handleData = ( |
||||
|
shopInfo, |
||||
|
mapData, |
||||
|
ftData, |
||||
|
excludeNodes, |
||||
|
extraCosts, |
||||
|
portals, |
||||
|
mall, |
||||
|
facilityTypeMap, |
||||
|
facilityCodeMap |
||||
|
) => { |
||||
|
Object.assign(FacilityCodeMap, facilityCodeMap); |
||||
|
const { floors } = mall; |
||||
|
let shopMap = {}; |
||||
|
let shopNavSet = new Set(); |
||||
|
const parkingSpaceByFloor = []; |
||||
|
const excludeSet = excludeNodes |
||||
|
? excludeNodes.reduce((acc, nxt) => { |
||||
|
acc.add(nxt); |
||||
|
return acc; |
||||
|
}, new Set()) |
||||
|
: new Set(); |
||||
|
shopInfo.forEach(({ shopList }, floorOrder) => { |
||||
|
shopList.forEach((shop) => { |
||||
|
shopMap[shop.houseNum] = shop; |
||||
|
shopNavSet.add(floorOrder + "_" + shop.yaxis); |
||||
|
}); |
||||
|
}); |
||||
|
const noUpMap = {}; |
||||
|
const noDownMap = {}; |
||||
|
const list = mapData.buildArr |
||||
|
.map(({ mapData }) => mapData) |
||||
|
.map(({ icons, path, stairs, shopArea, floorArea, parkArea }, i) => { |
||||
|
const nodes = path ? path.nodes : []; |
||||
|
let points = []; |
||||
|
let routes = []; |
||||
|
let height = Number(floorArea ? floorArea.toHeight : 0); |
||||
|
nodes.forEach(({ id, list, x, y }) => { |
||||
|
points[id] = { |
||||
|
name: id, |
||||
|
position: [x, height + 0.1, y], |
||||
|
}; |
||||
|
list.forEach((node) => { |
||||
|
const needIncrease = extraCosts[`${i}_${id}_${node.id}`]; |
||||
|
routes.push({ |
||||
|
src: id, |
||||
|
des: node.id, |
||||
|
cost: needIncrease ? 1000 : node.cost, |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
let facilities = []; |
||||
|
icons.forEach(({ navCode, facCode, Type }) => { |
||||
|
if (points[Number(navCode)]) |
||||
|
facilities.push({ |
||||
|
Escalator: 0, |
||||
|
NavPoint: Number(navCode), |
||||
|
Type: FacilityCodeMap[facCode], |
||||
|
Images: facCode, |
||||
|
point: points[Number(navCode)].position, |
||||
|
}); |
||||
|
}); |
||||
|
stairs.forEach(({ navCode, facCode, no, downState, upState }) => { |
||||
|
if (points[Number(navCode)]) { |
||||
|
const NavPoint = Number(navCode); |
||||
|
const key = `${i}_${NavPoint}`; |
||||
|
const value = ftData[key]; |
||||
|
if (downState) noDownMap[key] = true; |
||||
|
if (upState) noUpMap[key] = true; |
||||
|
facilities.push({ |
||||
|
Escalator: Number(no), |
||||
|
NavPoint: NavPoint, |
||||
|
Type: FacilityCodeMap[facCode], |
||||
|
Images: facCode, |
||||
|
point: points[Number(navCode)].position, |
||||
|
entrances: value ? Object.keys(value) : [], |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
shopArea.forEach(({ name, shopNav, xaxis, yaxis }) => { |
||||
|
if (shopMap[name]) { |
||||
|
shopMap[name].yaxis = shopNav; |
||||
|
shopMap[name].xaxis = [xaxis, height, yaxis]; |
||||
|
} |
||||
|
}); |
||||
|
parkingSpaceByFloor[i] = parkArea; |
||||
|
return { |
||||
|
facilities, |
||||
|
points, |
||||
|
routes, |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
const facilities = list.map(({ facilities }) => facilities); |
||||
|
facilities.forEach((facilitiesOnSameFloor, floorOrder) => { |
||||
|
facilitiesOnSameFloor.forEach((facility) => { |
||||
|
facility.floorOrder = floorOrder; |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
const flatFacilities = facilities.reduce((acc, nxt) => acc.concat(nxt), []); |
||||
|
flatFacilities.forEach((fac) => { |
||||
|
fac.isFac = true; |
||||
|
fac.floorName = floors[fac.floorOrder][1]; |
||||
|
fac.name = fac.floorName + facilityTypeMap[fac.Type]; |
||||
|
fac.xaxis = fac.point; |
||||
|
fac.yaxis = Number(fac.NavPoint); |
||||
|
fac.id = `${fac.floorOrder}_${fac.Type}_${fac.NavPoint}`; |
||||
|
}); |
||||
|
|
||||
|
const facilityLiftMap = flatFacilities.reduce( |
||||
|
(acc, nxt) => |
||||
|
!(nxt.Type === 0 || nxt.Type === 5) |
||||
|
? acc |
||||
|
: { |
||||
|
...acc, |
||||
|
[`${nxt.floorOrder}_${nxt.NavPoint}`]: nxt, |
||||
|
}, |
||||
|
{} |
||||
|
); |
||||
|
const facilityMap = flatFacilities.reduce( |
||||
|
(acc, nxt) => ({ |
||||
|
...acc, |
||||
|
[nxt.id]: nxt, |
||||
|
}), |
||||
|
{} |
||||
|
); |
||||
|
const routes = list.map(({ routes }) => routes); |
||||
|
const points = list.map(({ points }) => points); |
||||
|
const graph = {}; |
||||
|
routes.forEach((route, floorOrder) => { |
||||
|
route.forEach(({ src, des, cost }) => { |
||||
|
const srcId = floorOrder + "_" + src; |
||||
|
const desId = floorOrder + "_" + des; |
||||
|
if (excludeSet.has(srcId) || excludeSet.has(desId)) return; |
||||
|
graph[srcId] = { |
||||
|
...graph[srcId], |
||||
|
[desId]: cost, |
||||
|
}; |
||||
|
graph[desId] = { |
||||
|
...graph[desId], |
||||
|
[srcId]: cost, |
||||
|
}; |
||||
|
}); |
||||
|
}); |
||||
|
const graphDt = JSON.parse(JSON.stringify(graph)); |
||||
|
const graphFt = JSON.parse(JSON.stringify(graph)); |
||||
|
let escalatorMap = flatFacilities.reduce( |
||||
|
(acc, { NavPoint, Escalator, Type, floorOrder }) => { |
||||
|
if (NavPoint !== undefined && (Type === 0 || Type === 5)) { |
||||
|
if (acc[`${Type}_${Escalator}`]) |
||||
|
acc[`${Type}_${Escalator}`].push({ |
||||
|
NavPoint, |
||||
|
floorOrder, |
||||
|
Type, |
||||
|
}); |
||||
|
else |
||||
|
acc[`${Type}_${Escalator}`] = [ |
||||
|
{ |
||||
|
NavPoint, |
||||
|
floorOrder, |
||||
|
Type, |
||||
|
}, |
||||
|
]; |
||||
|
acc[`${Type}_${Escalator}`].isEscalator = Type === 0; |
||||
|
} |
||||
|
return acc; |
||||
|
}, |
||||
|
{} |
||||
|
); |
||||
|
|
||||
|
Object.values(ftData).forEach((value) => { |
||||
|
Object.entries(value).forEach(([key, dsts]) => { |
||||
|
dsts.forEach((dst) => { |
||||
|
const value = { |
||||
|
[dst]: 6000, |
||||
|
}; |
||||
|
attachGraphSingle({ |
||||
|
graph, |
||||
|
key, |
||||
|
value, |
||||
|
}); |
||||
|
attachGraphSingle({ |
||||
|
graph: graphFt, |
||||
|
key, |
||||
|
value, |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
Object.values(escalatorMap).forEach((list) => { |
||||
|
for (let i = 0; i < list.length - 1; i++) { |
||||
|
for (let j = i + 1; j < list.length; j++) { |
||||
|
const { floorOrder: floorOrderI, NavPoint: src } = list[i]; |
||||
|
const { floorOrder: floorOrderJ, NavPoint: des } = list[j]; |
||||
|
const leftKey = floorOrderI + "_" + src; |
||||
|
const rightKey = floorOrderJ + "_" + des; |
||||
|
const floorDiff = Math.abs(floorOrderI - floorOrderJ); |
||||
|
const isUp = Number(floorOrderJ) > Number(floorOrderI); |
||||
|
if (ftData[leftKey]) return; |
||||
|
if (ftData[rightKey]) return; |
||||
|
const leftValue = { |
||||
|
[rightKey]: |
||||
|
(isUp && noUpMap[leftKey]) || (!isUp && noDownMap[leftKey]) |
||||
|
? Infinity |
||||
|
: list.isEscalator |
||||
|
? 7000 * floorDiff |
||||
|
: 10000 + floorDiff * 1000, |
||||
|
}; |
||||
|
const rightValue = { |
||||
|
[leftKey]: |
||||
|
(!isUp && noUpMap[rightKey]) || (isUp && noDownMap[rightKey]) |
||||
|
? Infinity |
||||
|
: list.isEscalator |
||||
|
? 7000 * floorDiff |
||||
|
: 10000 + floorDiff * 1000, |
||||
|
}; |
||||
|
attachGraph({ |
||||
|
graph, |
||||
|
leftKey, |
||||
|
rightKey, |
||||
|
leftValue, |
||||
|
rightValue, |
||||
|
}); |
||||
|
if (list.isEscalator) |
||||
|
attachGraph({ |
||||
|
graph: graphFt, |
||||
|
leftKey, |
||||
|
rightKey, |
||||
|
leftValue, |
||||
|
rightValue, |
||||
|
}); |
||||
|
else |
||||
|
attachGraph({ |
||||
|
graph: graphDt, |
||||
|
leftKey, |
||||
|
rightKey, |
||||
|
leftValue, |
||||
|
rightValue, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
const grahps = [graph, graphDt, graphFt]; |
||||
|
portals.forEach(({ leftKey, rightKey, leftValue, rightValue }) => |
||||
|
grahps.forEach((graph) => |
||||
|
attachGraph({ |
||||
|
graph, |
||||
|
leftKey, |
||||
|
rightKey, |
||||
|
leftValue, |
||||
|
rightValue, |
||||
|
}) |
||||
|
) |
||||
|
); |
||||
|
return { |
||||
|
points, |
||||
|
routes, |
||||
|
graph, |
||||
|
graphDt, |
||||
|
graphFt, |
||||
|
facilities, |
||||
|
flatFacilities, |
||||
|
excludeSet, |
||||
|
parkingSpaceByFloor, |
||||
|
facilityLiftMap, |
||||
|
facilityMap, |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
const dataHelper = async (map) => { |
||||
|
const { |
||||
|
ftData = {}, |
||||
|
excludeNodes, |
||||
|
extraCosts = {}, |
||||
|
portals = [], |
||||
|
serverShopInfo, |
||||
|
mapData, |
||||
|
mall, |
||||
|
facilityTypeMap, |
||||
|
facilityCodeMap, |
||||
|
} = map; |
||||
|
|
||||
|
return handleData( |
||||
|
serverShopInfo, |
||||
|
mapData, |
||||
|
ftData, |
||||
|
excludeNodes, |
||||
|
extraCosts, |
||||
|
portals, |
||||
|
mall, |
||||
|
facilityTypeMap, |
||||
|
facilityCodeMap |
||||
|
); |
||||
|
}; |
||||
|
export default dataHelper; |
||||
@ -0,0 +1,164 @@ |
|||||
|
import { get } from "./pages/map2d/util"; |
||||
|
import dataHelper from "./data-helper"; |
||||
|
const baseUrl = "https://iot-dev.123.1000my.com"; |
||||
|
export const cdnUrl = "https://test-598d.1000my.com"; |
||||
|
export const code = "project-k5chc3vt0vkodjbmhl8rua"; |
||||
|
export const post = (url, data) => |
||||
|
new Promise((resolve) => { |
||||
|
wx.request({ |
||||
|
url: baseUrl + url, |
||||
|
method: "POST", |
||||
|
header: { projectCode: code }, |
||||
|
data: { ...data }, |
||||
|
success({ data, statusCode }) { |
||||
|
if (statusCode !== 200) return reject(); |
||||
|
resolve(data); |
||||
|
}, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
let mapDataAndShop = null; |
||||
|
|
||||
|
export const mall = { |
||||
|
isNew: true, |
||||
|
baseUrl, |
||||
|
cdnUrl, |
||||
|
code, |
||||
|
floors: [ |
||||
|
[true, "L1"], |
||||
|
[true, "L2"], |
||||
|
], |
||||
|
}; |
||||
|
const config = { |
||||
|
mapDataUrl: `${baseUrl}/api/guide/v1/web/getMallMapData/${code}/Aeditor`, |
||||
|
shopInfoUrl: `${baseUrl}/api/guide/v1/web/getMapInfo?projectCode=${code}`, |
||||
|
}; |
||||
|
export const getMapData = async () => { |
||||
|
if (mapDataAndShop) return mapDataAndShop; |
||||
|
// try {
|
||||
|
// const { mapUrl, shopUrl } = await get(
|
||||
|
// `${cdnUrl}/test-projects/${code}/config.json?t=${new Date().getTime()}`
|
||||
|
// );
|
||||
|
// if (mapUrl) config.mapDataUrl = mapUrl;
|
||||
|
// if (shopUrl) config.shopInfoUrl = shopUrl;
|
||||
|
// } catch (error) {
|
||||
|
// console.log("获取config失败");
|
||||
|
// }
|
||||
|
let [ |
||||
|
{ |
||||
|
data: { mapData }, |
||||
|
}, |
||||
|
{ |
||||
|
data: { buildingList, shopList: serverShopInfo }, |
||||
|
}, |
||||
|
{ data: facs }, |
||||
|
{ data: sdkMapList }, |
||||
|
{ |
||||
|
data: { projectConfig: sdkConfig }, |
||||
|
}, |
||||
|
{ data: pois }, |
||||
|
...rest |
||||
|
] = await Promise.all([ |
||||
|
get(config.mapDataUrl), |
||||
|
get(config.shopInfoUrl), |
||||
|
get( |
||||
|
`${baseUrl}/api/guide/v1/web/getProjectUsedIconList?projectCode=${code}` |
||||
|
), |
||||
|
post(`/api/ar/v1/applet/GetSdkConfigList`, { mallCode: code }), |
||||
|
post(`/api/ar/v1/applet/ProjectConfig`, { mallCode: code }), |
||||
|
post(`/api/ar/v1/applet/GetPoiList`, { mallCode: code }), |
||||
|
...mall.floors.map((_, i) => |
||||
|
get(`${baseUrl}/api/guide/v1/web/getMallMapData/${code}/${i}`) |
||||
|
), |
||||
|
]); |
||||
|
const poiMap = pois.reduce((acc, nxt) => ({ ...acc, [nxt.code]: nxt }), {}); |
||||
|
const sdkMap = sdkMapList.map( |
||||
|
({ |
||||
|
poiid: poi_id, |
||||
|
floorid: floor_id, |
||||
|
isPark: is_park, |
||||
|
appid: app_id, |
||||
|
mapid: map_id, |
||||
|
caseid: case_id, |
||||
|
transMatrix: transform_matrix, |
||||
|
scale, |
||||
|
}) => ({ |
||||
|
app_id, |
||||
|
map_id, |
||||
|
poi_id, |
||||
|
floor_id, |
||||
|
transform_matrix, |
||||
|
scale, |
||||
|
case_id, |
||||
|
is_park, |
||||
|
}) |
||||
|
); |
||||
|
const map2dData = rest |
||||
|
.map((res) => (res.data && res.data.mapData ? res.data.mapData : null)) |
||||
|
.map((mapData) => (mapData ? JSON.parse(mapData) : null)); |
||||
|
mall.floors.forEach((floor, i) => { |
||||
|
floor[2] = map2dData[i]; |
||||
|
}); |
||||
|
serverShopInfo = serverShopInfo |
||||
|
.filter(({ buildingOrder }) => buildingOrder === 0) |
||||
|
.map((iot) => ({ |
||||
|
...iot, |
||||
|
name: iot.shopName, |
||||
|
houseNum: iot.houseNumber, |
||||
|
nameEn: iot.shopNameEn, |
||||
|
logoPath: cdnUrl + iot.logoUrl, |
||||
|
shopFormat: iot.industryFatherName, |
||||
|
intro: true, |
||||
|
})) |
||||
|
.reduce((acc, nxt) => { |
||||
|
if (!acc[nxt.floorOrder]) acc[nxt.floorOrder] = [nxt]; |
||||
|
else acc[nxt.floorOrder] = [...acc[nxt.floorOrder], nxt]; |
||||
|
return acc; |
||||
|
}, []) |
||||
|
.map((shopList, floorOrder) => ({ floorOrder, shopList })); |
||||
|
mapData = JSON.parse(mapData)[0]; |
||||
|
const facilityTypeMap = facs.reduce( |
||||
|
(acc, nxt) => ({ |
||||
|
...acc, |
||||
|
[nxt.node]: nxt.customFacilityName || nxt.name, |
||||
|
}), |
||||
|
{} |
||||
|
); |
||||
|
const facilityCodeMap = facs.reduce( |
||||
|
(acc, nxt) => ({ |
||||
|
...acc, |
||||
|
[nxt.abbreviation]: Number(nxt.objCode), |
||||
|
}), |
||||
|
{} |
||||
|
); |
||||
|
const floors = mall.floors; |
||||
|
let shopMap = {}; |
||||
|
serverShopInfo.forEach(({ shopList }) => { |
||||
|
shopList.forEach((shop) => { |
||||
|
shop.floorName = floors[shop.floorOrder] |
||||
|
? floors[shop.floorOrder][1] |
||||
|
: ""; |
||||
|
shopMap[shop.houseNum] = shop; |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
const dataHelperResponse = await dataHelper({ |
||||
|
serverShopInfo, |
||||
|
mapData, |
||||
|
mall, |
||||
|
facilityTypeMap, |
||||
|
facilityCodeMap, |
||||
|
}); |
||||
|
const pMap = {}; |
||||
|
mapDataAndShop = { |
||||
|
...dataHelperResponse, |
||||
|
serverShopInfo, |
||||
|
mapData, |
||||
|
mall, |
||||
|
shopMap, |
||||
|
pMap, |
||||
|
poiMap, |
||||
|
config: { ...sdkConfig, map: sdkMap }, |
||||
|
}; |
||||
|
return mapDataAndShop; |
||||
|
}; |
||||
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,178 @@ |
|||||
|
module.exports = (function() { |
||||
|
var __MODS__ = {}; |
||||
|
var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; }; |
||||
|
var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; }; |
||||
|
var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } }; |
||||
|
var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; }; |
||||
|
__DEFINE__(1629248775416, function(require, module, exports) { |
||||
|
|
||||
|
|
||||
|
/****************************************************************************** |
||||
|
* Created 2008-08-19. |
||||
|
* |
||||
|
* Dijkstra path-finding functions. Adapted from the Dijkstar Python project. |
||||
|
* |
||||
|
* Copyright (C) 2008 |
||||
|
* Wyatt Baldwin <self@wyattbaldwin.com> |
||||
|
* All rights reserved |
||||
|
* |
||||
|
* Licensed under the MIT license. |
||||
|
* |
||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
|
* THE SOFTWARE. |
||||
|
*****************************************************************************/ |
||||
|
var dijkstra = { |
||||
|
single_source_shortest_paths: function(graph, s, d) { |
||||
|
// Predecessor map for each node that has been encountered.
|
||||
|
// node ID => predecessor node ID
|
||||
|
var predecessors = {}; |
||||
|
|
||||
|
// Costs of shortest paths from s to all nodes encountered.
|
||||
|
// node ID => cost
|
||||
|
var costs = {}; |
||||
|
costs[s] = 0; |
||||
|
|
||||
|
// Costs of shortest paths from s to all nodes encountered; differs from
|
||||
|
// `costs` in that it provides easy access to the node that currently has
|
||||
|
// the known shortest path from s.
|
||||
|
// XXX: Do we actually need both `costs` and `open`?
|
||||
|
var open = dijkstra.PriorityQueue.make(); |
||||
|
open.push(s, 0); |
||||
|
|
||||
|
var closest, |
||||
|
u, v, |
||||
|
cost_of_s_to_u, |
||||
|
adjacent_nodes, |
||||
|
cost_of_e, |
||||
|
cost_of_s_to_u_plus_cost_of_e, |
||||
|
cost_of_s_to_v, |
||||
|
first_visit; |
||||
|
while (!open.empty()) { |
||||
|
// In the nodes remaining in graph that have a known cost from s,
|
||||
|
// find the node, u, that currently has the shortest path from s.
|
||||
|
closest = open.pop(); |
||||
|
u = closest.value; |
||||
|
cost_of_s_to_u = closest.cost; |
||||
|
|
||||
|
// Get nodes adjacent to u...
|
||||
|
adjacent_nodes = graph[u] || {}; |
||||
|
|
||||
|
// ...and explore the edges that connect u to those nodes, updating
|
||||
|
// the cost of the shortest paths to any or all of those nodes as
|
||||
|
// necessary. v is the node across the current edge from u.
|
||||
|
for (v in adjacent_nodes) { |
||||
|
if (adjacent_nodes.hasOwnProperty(v)) { |
||||
|
// Get the cost of the edge running from u to v.
|
||||
|
cost_of_e = adjacent_nodes[v]; |
||||
|
|
||||
|
// Cost of s to u plus the cost of u to v across e--this is *a*
|
||||
|
// cost from s to v that may or may not be less than the current
|
||||
|
// known cost to v.
|
||||
|
cost_of_s_to_u_plus_cost_of_e = cost_of_s_to_u + cost_of_e; |
||||
|
|
||||
|
// If we haven't visited v yet OR if the current known cost from s to
|
||||
|
// v is greater than the new cost we just found (cost of s to u plus
|
||||
|
// cost of u to v across e), update v's cost in the cost list and
|
||||
|
// update v's predecessor in the predecessor list (it's now u).
|
||||
|
cost_of_s_to_v = costs[v]; |
||||
|
first_visit = (typeof costs[v] === 'undefined'); |
||||
|
if (first_visit || cost_of_s_to_v > cost_of_s_to_u_plus_cost_of_e) { |
||||
|
costs[v] = cost_of_s_to_u_plus_cost_of_e; |
||||
|
open.push(v, cost_of_s_to_u_plus_cost_of_e); |
||||
|
predecessors[v] = u; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (typeof d !== 'undefined' && typeof costs[d] === 'undefined') { |
||||
|
var msg = ['Could not find a path from ', s, ' to ', d, '.'].join(''); |
||||
|
throw new Error(msg); |
||||
|
} |
||||
|
|
||||
|
return predecessors; |
||||
|
}, |
||||
|
|
||||
|
extract_shortest_path_from_predecessor_list: function(predecessors, d) { |
||||
|
var nodes = []; |
||||
|
var u = d; |
||||
|
var predecessor; |
||||
|
while (u) { |
||||
|
nodes.push(u); |
||||
|
predecessor = predecessors[u]; |
||||
|
u = predecessors[u]; |
||||
|
} |
||||
|
nodes.reverse(); |
||||
|
return nodes; |
||||
|
}, |
||||
|
|
||||
|
find_path: function(graph, s, d) { |
||||
|
var predecessors = dijkstra.single_source_shortest_paths(graph, s, d); |
||||
|
return dijkstra.extract_shortest_path_from_predecessor_list( |
||||
|
predecessors, d); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* A very naive priority queue implementation. |
||||
|
*/ |
||||
|
PriorityQueue: { |
||||
|
make: function (opts) { |
||||
|
var T = dijkstra.PriorityQueue, |
||||
|
t = {}, |
||||
|
key; |
||||
|
opts = opts || {}; |
||||
|
for (key in T) { |
||||
|
if (T.hasOwnProperty(key)) { |
||||
|
t[key] = T[key]; |
||||
|
} |
||||
|
} |
||||
|
t.queue = []; |
||||
|
t.sorter = opts.sorter || T.default_sorter; |
||||
|
return t; |
||||
|
}, |
||||
|
|
||||
|
default_sorter: function (a, b) { |
||||
|
return a.cost - b.cost; |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Add a new item to the queue and ensure the highest priority element |
||||
|
* is at the front of the queue. |
||||
|
*/ |
||||
|
push: function (value, cost) { |
||||
|
var item = {value: value, cost: cost}; |
||||
|
this.queue.push(item); |
||||
|
this.queue.sort(this.sorter); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Return the highest priority element in the queue. |
||||
|
*/ |
||||
|
pop: function () { |
||||
|
return this.queue.shift(); |
||||
|
}, |
||||
|
|
||||
|
empty: function () { |
||||
|
return this.queue.length === 0; |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// node.js module exports
|
||||
|
if (typeof module !== 'undefined') { |
||||
|
module.exports = dijkstra; |
||||
|
} |
||||
|
|
||||
|
}, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); }) |
||||
|
return __REQUIRE__(1629248775416); |
||||
|
})() |
||||
|
//miniprogram-npm-outsideDeps=[]
|
||||
|
//# sourceMappingURL=index.js.map
|
||||
@ -0,0 +1,50 @@ |
|||||
|
type BaseRendererConfig = { |
||||
|
imagePreserveAspectRatio?: string; |
||||
|
className?: string; |
||||
|
}; |
||||
|
|
||||
|
type CanvasRendererConfig = BaseRendererConfig & { |
||||
|
clearCanvas?: boolean; |
||||
|
context: CanvasRenderingContext2D; |
||||
|
progressiveLoad?: boolean; |
||||
|
preserveAspectRatio?: string; |
||||
|
}; |
||||
|
|
||||
|
interface LoadAnimationParameter { |
||||
|
renderer?: 'canvas'; |
||||
|
loop?: boolean | number; |
||||
|
autoplay?: boolean; |
||||
|
name?: string; |
||||
|
rendererSettings?: CanvasRendererConfig; |
||||
|
animationData?: any; |
||||
|
path?: string; |
||||
|
} |
||||
|
|
||||
|
type AnimationDirection = 1 | -1; |
||||
|
type AnimationSegment = [number, number]; |
||||
|
type AnimationEventName = 'enterFrame' | 'loopComplete' | 'complete' | 'segmentStart' | 'destroy'; |
||||
|
type AnimationEventCallback<T = any> = (args: T) => void; |
||||
|
|
||||
|
interface LoadAnimationReturnType { |
||||
|
play(): void; |
||||
|
stop(): void; |
||||
|
pause(): void; |
||||
|
setSpeed(speed: number): void; |
||||
|
goToAndPlay(value: number, isFrame?: boolean): void; |
||||
|
goToAndStop(value: number, isFrame?: boolean): void; |
||||
|
setDirection(direction: AnimationDirection): void; |
||||
|
playSegments(segments: AnimationSegment | AnimationSegment[], forceFlag?: boolean): void; |
||||
|
setSubframe(useSubFrames: boolean): void; |
||||
|
destroy(): void; |
||||
|
getDuration(inFrames?: boolean): number; |
||||
|
triggerEvent<T = any>(name: AnimationEventName, args: T): void; |
||||
|
addEventListener<T = any>(name: AnimationEventName, callback: AnimationEventCallback<T>): void; |
||||
|
removeEventListener<T = any>(name: AnimationEventName, callback: AnimationEventCallback<T>): void; |
||||
|
} |
||||
|
|
||||
|
declare module lottie { |
||||
|
var loadAnimation: (options: LoadAnimationParameter) => LoadAnimationReturnType; |
||||
|
var setup: (node: any) => void; |
||||
|
} |
||||
|
|
||||
|
export default lottie; |
||||
@ -0,0 +1,35 @@ |
|||||
|
{ |
||||
|
"name": "webpack-demo", |
||||
|
"version": "1.0.0", |
||||
|
"description": "", |
||||
|
"private": true, |
||||
|
"scripts": { |
||||
|
"test": "echo \"Error: no test specified\" && exit 1", |
||||
|
"build": "webpack", |
||||
|
"lint": "eslint --ext .js src", |
||||
|
"lint-fix": "eslint --fix --ext .js src" |
||||
|
}, |
||||
|
"keywords": [], |
||||
|
"author": "", |
||||
|
"license": "ISC", |
||||
|
"devDependencies": { |
||||
|
"@babel/eslint-parser": "^7.14.7", |
||||
|
"@babel/eslint-plugin": "^7.14.5", |
||||
|
"@ecomfe/eslint-config": "^7.1.0", |
||||
|
"@purtuga/esm-webpack-plugin": "^1.5.0", |
||||
|
"babel-eslint": "^11.0.0-beta.2", |
||||
|
"eslint-plugin-babel": "^5.3.1", |
||||
|
"eslint-plugin-vue": "^7.14.0", |
||||
|
"vue-eslint-parser": "^7.9.0", |
||||
|
"webpack": "^4.46.0", |
||||
|
"webpack-cli": "^4.7.2" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@babel/core": "^7.14.8", |
||||
|
"dijkstrajs": "^1.0.2", |
||||
|
"eslint": "^6.8.0", |
||||
|
"lottie-miniprogram": "^1.0.12", |
||||
|
"rbush": "^3.0.1", |
||||
|
"threejs-miniprogram": "^0.0.8" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
// pages/agreement/index.js
|
||||
|
Page({ |
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
stage: "first", |
||||
|
q: "", |
||||
|
e: "", |
||||
|
s: "", |
||||
|
}, |
||||
|
toStage2() { |
||||
|
this.setData({ stage: "second" }); |
||||
|
}, |
||||
|
async agree() { |
||||
|
wx.showLoading(); |
||||
|
const app = getApp(); |
||||
|
const openid = app.globalData.openid; |
||||
|
const db = wx.cloud.database(); |
||||
|
try { |
||||
|
await db.collection("agreement").add({ data: { _id: openid } }); |
||||
|
wx.hideLoading(); |
||||
|
app.globalData.agreed = true; |
||||
|
const { q, e, s } = this.data; |
||||
|
wx.redirectTo({ |
||||
|
url: `/pages/h5map/index?q=${q}&e=${e}&s=${s}`, |
||||
|
}); |
||||
|
} catch (error) { |
||||
|
console.log(error); |
||||
|
wx.hideLoading(); |
||||
|
} |
||||
|
}, |
||||
|
exit() { |
||||
|
wx.exitMiniProgram(); |
||||
|
}, |
||||
|
toPrivacy() { |
||||
|
wx.navigateTo({ |
||||
|
url: "/pages/privacy/index", |
||||
|
}); |
||||
|
}, |
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad({ q, e, s }) { |
||||
|
q && this.setData({ q }); |
||||
|
e && this.setData({ e }); |
||||
|
s && this.setData({ s }); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage: function () {}, |
||||
|
}); |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"usingComponents": {}, |
||||
|
"navigationStyle": "default", |
||||
|
"navigationBarTitleText": "武汉荟聚实景导航", |
||||
|
"navigationBarBackgroundColor": "#FFFFFF" |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
<view class="ag"> |
||||
|
<image class="logo" src="./logo.png"></image> |
||||
|
<view class="name">武汉荟聚</view> |
||||
|
<view class="desc"> |
||||
|
<view class="title">荟聚隐私政策提示</view> |
||||
|
<view wx:if="{{stage==='first'}}" class="p">欢迎您使用武汉荟聚实景导航小程序,为更好地保护您的个人信息安全,请您仔细阅读并理解<text class="og" |
||||
|
bindtap="toPrivacy">《隐私政策》</text>。</view> |
||||
|
<view wx:if="{{stage==='first'}}" class="p">我们将严格按照您同意的<text class="og" |
||||
|
bindtap="toPrivacy">《隐私政策》</text>中的各项条款使用和保护您的个人信息。</view> |
||||
|
<view wx:if="{{stage==='second'}}" class="p">为继续使用我们的产品或服务,请您阅读并同意<text class="og" |
||||
|
bindtap="toPrivacy">《隐私政策》</text>内容。</view> |
||||
|
</view> |
||||
|
<view class="btns" wx:if="{{stage==='first'}}"> |
||||
|
<view class="btn1" bindtap="toStage2">不同意</view> |
||||
|
<view class="btn2" bindtap="agree">同意</view> |
||||
|
</view> |
||||
|
<view class="btns" wx:if="{{stage==='second'}}"> |
||||
|
<view class="btn1" bindtap="exit">不同意并退出</view> |
||||
|
<view class="btn2" bindtap="agree">同意并继续</view> |
||||
|
</view> |
||||
|
</view> |
||||
@ -0,0 +1,91 @@ |
|||||
|
.ag { |
||||
|
display: inline-flex; |
||||
|
flex-direction: column; |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.logo { |
||||
|
width: 86px; |
||||
|
height: 86px; |
||||
|
margin-top: 40px; |
||||
|
} |
||||
|
.name { |
||||
|
font-family: Noto IKEA Simplified Chinese; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 14px; |
||||
|
line-height: 21px; |
||||
|
height: 23px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
text-align: center; |
||||
|
|
||||
|
/* Font color/深灰 */ |
||||
|
|
||||
|
color: #6a6665; |
||||
|
margin-top: 8px; |
||||
|
} |
||||
|
.desc { |
||||
|
margin-top: 70px; |
||||
|
width: calc(100vw - 102px); |
||||
|
height: 198px; |
||||
|
text-align: left; |
||||
|
} |
||||
|
.title { |
||||
|
font-family: Noto IKEA Simplified Chinese; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 14px; |
||||
|
line-height: 21px; |
||||
|
color: #474747; |
||||
|
} |
||||
|
.p { |
||||
|
font-family: Noto IKEA Simplified Chinese; |
||||
|
font-style: normal; |
||||
|
font-weight: normal; |
||||
|
font-size: 14px; |
||||
|
line-height: 21px; |
||||
|
color: #474747; |
||||
|
margin-top: 16px; |
||||
|
text-indent: 2em; |
||||
|
} |
||||
|
.og { |
||||
|
color: #ef9617; |
||||
|
} |
||||
|
.btns { |
||||
|
width: calc(100vw - 70px); |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
.btn1 { |
||||
|
width: 140px; |
||||
|
height: 50px; |
||||
|
font-family: Noto IKEA Simplified Chinese; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 16px; |
||||
|
line-height: 50px; |
||||
|
text-align: center; |
||||
|
color: #767571; |
||||
|
border: 1px solid #b3aea7; |
||||
|
box-sizing: border-box; |
||||
|
border-radius: 100px; |
||||
|
} |
||||
|
|
||||
|
.btn2 { |
||||
|
width: 140px; |
||||
|
height: 50px; |
||||
|
font-family: Noto IKEA Simplified Chinese; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 16px; |
||||
|
line-height: 50px; |
||||
|
text-align: center; |
||||
|
color: #474747; |
||||
|
border: 1px solid #ffdb00; |
||||
|
box-sizing: border-box; |
||||
|
background: #ffdb00; |
||||
|
box-shadow: 0px 4px 20px rgba(215, 148, 87, 0.33); |
||||
|
border-radius: 30px; |
||||
|
} |
||||
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 596 B |
@ -0,0 +1,23 @@ |
|||||
|
// pages/destination/destination.js
|
||||
|
Component({ |
||||
|
/** |
||||
|
* 组件的属性列表 |
||||
|
*/ |
||||
|
properties: { |
||||
|
shop: Object, |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 组件的初始数据 |
||||
|
*/ |
||||
|
data: {}, |
||||
|
|
||||
|
/** |
||||
|
* 组件的方法列表 |
||||
|
*/ |
||||
|
methods: { |
||||
|
handleTap() { |
||||
|
this.triggerEvent("exit"); |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,4 @@ |
|||||
|
{ |
||||
|
"component": true, |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
<view class="destination"> |
||||
|
<image wx:if="{{shop.logoPath}}" class="logo" mode="aspectFit" src="{{shop.logoPath}}"></image> |
||||
|
<view class="name {{!shop.logoPath?'noicon':''}}">{{shop.name}}</view> |
||||
|
<view class="meta {{!shop.logoPath?'noicon':''}}"> |
||||
|
<view> {{shop.floorName}}</view> |
||||
|
<view> {{shop.shopFormat}}</view> |
||||
|
</view> |
||||
|
<view class="border"></view> |
||||
|
<image class="exit" src="./close.png" bindtap="handleTap"></image> |
||||
|
</view> |
||||
@ -0,0 +1,70 @@ |
|||||
|
.destination { |
||||
|
position: fixed; |
||||
|
height: 110px; |
||||
|
left: 10px; |
||||
|
right: 10px; |
||||
|
bottom: 116px; |
||||
|
background: #ffffff; |
||||
|
z-index: 12 !important; |
||||
|
border-radius: 18px 18px 0 0; |
||||
|
} |
||||
|
.destination > .logo { |
||||
|
position: absolute; |
||||
|
top: 14px; |
||||
|
left: 14px; |
||||
|
width: 80px; |
||||
|
height: 80px; |
||||
|
background: #ffffff; |
||||
|
border-radius: 6px; |
||||
|
padding: 8px; |
||||
|
box-sizing: border-box; |
||||
|
box-shadow: 0px 8px 16px rgba(104, 110, 127, 0.08); |
||||
|
} |
||||
|
.destination > .name { |
||||
|
position: absolute; |
||||
|
top: 24px; |
||||
|
left: 108px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 600; |
||||
|
font-size: 24px; |
||||
|
line-height: 34px; |
||||
|
|
||||
|
color: #323337; |
||||
|
} |
||||
|
.destination > .name.noicon { |
||||
|
left: 14px; |
||||
|
} |
||||
|
.destination > .meta { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
position: absolute; |
||||
|
top: 68px; |
||||
|
left: 108px; |
||||
|
right: 20px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
color: #a1a5b3; |
||||
|
} |
||||
|
.destination > .meta.noicon { |
||||
|
left: 14px; |
||||
|
} |
||||
|
.destination > .border { |
||||
|
position: absolute; |
||||
|
left: 20px; |
||||
|
right: 20px; |
||||
|
bottom: 0; |
||||
|
border-top: 1px dashed #edeff3; |
||||
|
} |
||||
|
.destination > .exit { |
||||
|
position: absolute; |
||||
|
top: 16px; |
||||
|
left: auto; |
||||
|
right: 16px; |
||||
|
width: 24px; |
||||
|
height: 24px; |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
// pages/detail/index.js
|
||||
|
Page({ |
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
url: "", |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad({ url }) { |
||||
|
this.setData({ url: decodeURIComponent(url) }); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload() {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh() {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom() {}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage() {}, |
||||
|
}); |
||||
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
<web-view src="{{url}}"> |
||||
|
></web-view> |
||||
@ -0,0 +1 @@ |
|||||
|
/* pages/detail/index.wxss */ |
||||
@ -0,0 +1,17 @@ |
|||||
|
Component({ |
||||
|
options: { |
||||
|
addGlobalClass: true, |
||||
|
multipleSlots: true, |
||||
|
}, |
||||
|
properties: { |
||||
|
propagation: { |
||||
|
type: Boolean, |
||||
|
value: true, |
||||
|
}, |
||||
|
requireFailure: { |
||||
|
type: Boolean, |
||||
|
value: true, |
||||
|
}, |
||||
|
}, |
||||
|
methods: {} |
||||
|
}) |
||||
@ -0,0 +1,5 @@ |
|||||
|
|
||||
|
{ |
||||
|
"component": true, |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<wxs module="gesture" src="./gesture.wxs"></wxs> |
||||
|
<view |
||||
|
bindtouchstart="{{gesture.start}}" |
||||
|
bindtouchmove="{{gesture.move}}" |
||||
|
bindtouchend="{{gesture.end}}" |
||||
|
bindtouchcancel="{{gesture.cancel}}" |
||||
|
|
||||
|
data-propagation="{{propagation}}" |
||||
|
data-requirefailure="{{requireFailure}}" |
||||
|
> |
||||
|
<slot></slot> |
||||
|
</view> |
||||
@ -0,0 +1,263 @@ |
|||||
|
|
||||
|
/* eslint-disable */ |
||||
|
// @ts-ignore |
||||
|
function getLen(v) { |
||||
|
return Math.sqrt(v.x * v.x + v.y * v.y) |
||||
|
} |
||||
|
function dot(v1, v2) { |
||||
|
return v1.x * v2.x + v1.y * v2.y |
||||
|
} |
||||
|
function getAngle(v1, v2) { |
||||
|
var mr = getLen(v1) * getLen(v2) |
||||
|
if (mr === 0) return 0 |
||||
|
var r = dot(v1, v2) / mr |
||||
|
if (r > 1) r = 1 |
||||
|
return Math.acos(r) |
||||
|
} |
||||
|
function cross(v1, v2) { |
||||
|
return v1.x * v2.y - v2.x * v1.y |
||||
|
} |
||||
|
function getRotateAngle(v1, v2) { |
||||
|
var angle = getAngle(v1, v2) |
||||
|
if (cross(v1, v2) > 0) { |
||||
|
angle *= -1 |
||||
|
} |
||||
|
return angle * 180 / Math.PI |
||||
|
} |
||||
|
function _swipeDirection(x1, x2, y1, y2) { |
||||
|
if (Math.abs(x1 - x2) >= Math.abs(y1 - y2)) { |
||||
|
return x1 - x2 > 0 ? 'Left' : 'Right' |
||||
|
} else { |
||||
|
return y1 - y2 > 0 ? 'Up' : 'Down' |
||||
|
} |
||||
|
} |
||||
|
// 实现setTimeout功能 |
||||
|
var setTimeout = function(callback, interval, instance) { |
||||
|
var now = Date.now |
||||
|
var stime = now() |
||||
|
var loop = function() { |
||||
|
if (now() - stime >= interval) { |
||||
|
callback() |
||||
|
} else { |
||||
|
instance.requestAnimationFrame(loop) |
||||
|
} |
||||
|
} |
||||
|
instance.requestAnimationFrame(loop) |
||||
|
} |
||||
|
var start = function(event, ownerInstance) { |
||||
|
var instance = event.instance; |
||||
|
var State = instance.getState() |
||||
|
if(!State._init) { |
||||
|
State.preV = {x: null, y: null} |
||||
|
State.pinchStartLen = null |
||||
|
State.zoom = 1 |
||||
|
State.isDoubleTap = false |
||||
|
State.delta = null |
||||
|
State.last = null |
||||
|
State.now = null |
||||
|
State.x1 = State.x2 = State.y1 = State.y2 = null |
||||
|
State.preTapPosition = {x: null, y: null} |
||||
|
// 控制定时器 |
||||
|
State._cancelLongTap = function() { |
||||
|
State.longTapTimeout = false |
||||
|
} |
||||
|
State._cancelSingleTap = function() { |
||||
|
State.singleTapTimeout = false |
||||
|
} |
||||
|
State._tapTimeout = function() { |
||||
|
State.tapTimeout = false |
||||
|
} |
||||
|
State._swipeTimeout = function() { |
||||
|
State.swipeTimeout = false |
||||
|
} |
||||
|
State._init = true // 表示已经初始化完成 |
||||
|
} |
||||
|
State.tapTimeout = true |
||||
|
State.singleTapTimeout = true |
||||
|
State.longTapTimeout = true |
||||
|
State.swipeTimeout = true |
||||
|
State.now = Date.now() |
||||
|
State.x1 = event.touches[0].pageX |
||||
|
State.y1 = event.touches[0].pageY |
||||
|
State.delta = State.now - (State.last || State.now) |
||||
|
// 触发 touchStart 事件 |
||||
|
ownerInstance.triggerEvent('touchStart', event) |
||||
|
if (State.preTapPosition.x !== null) { |
||||
|
State.isDoubleTap = (State.delta > 0 && |
||||
|
State.delta <= 250 && |
||||
|
Math.abs(State.preTapPosition.x - State.x1) < 30 && |
||||
|
Math.abs(State.preTapPosition.y - State.y1) < 30) |
||||
|
if (State.isDoubleTap) { |
||||
|
State._cancelSingleTap() |
||||
|
} |
||||
|
} |
||||
|
State.preTapPosition.x = State.x1 |
||||
|
State.preTapPosition.y = State.y1 |
||||
|
State.last = State.now |
||||
|
var preV = State.preV |
||||
|
var len = event.touches.length |
||||
|
if (len > 1) { |
||||
|
State._cancelLongTap() |
||||
|
State._cancelSingleTap() |
||||
|
var v = {x: event.touches[1].pageX - State.x1, y: event.touches[1].pageY - State.y1} |
||||
|
preV.x = v.x |
||||
|
preV.y = v.y |
||||
|
State.pinchStartLen = getLen(preV) |
||||
|
// 触发 multipointStart 多指点按 事件 |
||||
|
ownerInstance.triggerEvent('multipointStart', event) |
||||
|
} |
||||
|
State._preventTap = false |
||||
|
setTimeout(function () { |
||||
|
// 触发 longTap(长按) 事件 |
||||
|
if(State.longTapTimeout) { |
||||
|
ownerInstance.triggerEvent('longTap', event) |
||||
|
State._preventTap = true |
||||
|
State.longTapTimeout = true |
||||
|
} |
||||
|
}, 750, instance) |
||||
|
|
||||
|
if (!instance.getDataset()['propagation']) return false |
||||
|
} |
||||
|
var move = function(event, ownerInstance) { |
||||
|
var instance = event.instance; |
||||
|
var State = instance.getState() |
||||
|
var preV = State.preV |
||||
|
var len = event.touches.length |
||||
|
var currentX = event.touches[0].pageX |
||||
|
var currentY = event.touches[0].pageY |
||||
|
State.isDoubleTap = false |
||||
|
if (len > 1) { |
||||
|
var sCurrentX = event.touches[1].pageX |
||||
|
var sCurrentY = event.touches[1].pageY |
||||
|
var v = {x: event.touches[1].pageX - currentX, y: event.touches[1].pageY - currentY} |
||||
|
if (preV.x !== null) { |
||||
|
if (State.pinchStartLen > 0) { |
||||
|
event.zoom = getLen(v) / State.pinchStartLen |
||||
|
// 触发 pinch 事件 |
||||
|
ownerInstance.triggerEvent('pinch', event) |
||||
|
} |
||||
|
event.angle = getRotateAngle(v, preV) |
||||
|
// 触发 rotate 事件 |
||||
|
ownerInstance.triggerEvent('rotate', event) |
||||
|
} |
||||
|
preV.x = v.x |
||||
|
preV.y = v.y |
||||
|
if (State.x2 !== null && State.sx2 !== null) { |
||||
|
event.deltaX = (currentX - State.x2 + sCurrentX - State.sx2) / 2 |
||||
|
event.deltaY = (currentY - State.y2 + sCurrentY - State.sy2) / 2 |
||||
|
} else { |
||||
|
event.deltaX = 0 |
||||
|
event.deltaY = 0 |
||||
|
} |
||||
|
// 触发 twoFingerPressMove 事件 |
||||
|
ownerInstance.triggerEvent('twoFingerPressMove', event) |
||||
|
State.sx2 = sCurrentX |
||||
|
State.sy2 = sCurrentY |
||||
|
} else { |
||||
|
if (State.x2 !== null) { |
||||
|
event.deltaX = currentX - State.x2 |
||||
|
event.deltaY = currentY - State.y2 |
||||
|
// move事件中添加对当前触摸点到初始触摸点的判断, |
||||
|
// 如果曾经大于过某个距离(比如10),就认为是移动到某个地方又移回来,应该不再触发tap事件才对。 |
||||
|
var movedX = Math.abs(State.x1 - State.x2) |
||||
|
var movedY = Math.abs(State.y1 - State.y2) |
||||
|
if (movedX > 10 || movedY > 10) { |
||||
|
State._preventTap = true |
||||
|
} |
||||
|
} else { |
||||
|
event.deltaX = 0 |
||||
|
event.deltaY = 0 |
||||
|
} |
||||
|
// 触发 pressMove 单指点按移动 事件 |
||||
|
ownerInstance.triggerEvent('pressMove', event) |
||||
|
} |
||||
|
// 触发 touchMove 移动事件 |
||||
|
ownerInstance.triggerEvent('touchMove', event) |
||||
|
State._cancelLongTap() |
||||
|
State.x2 = currentX |
||||
|
State.y2 = currentY |
||||
|
// if (len > 1) { |
||||
|
// // event.preventDefault() |
||||
|
// } |
||||
|
if (!instance.getDataset()['propagation']) return false |
||||
|
} |
||||
|
var end = function(event, ownerInstance) { |
||||
|
var instance = event.instance; |
||||
|
var State = instance.getState() |
||||
|
State._cancelLongTap() |
||||
|
if (event.touches.length < 2) { |
||||
|
// 触发 multipointEnd 多指点按结束 事件 |
||||
|
ownerInstance.triggerEvent('multipointEnd', event) |
||||
|
State.sx2 = State.sy2 = null |
||||
|
} |
||||
|
// swipe |
||||
|
if ((State.x2 && Math.abs(State.x1 - State.x2) > 30) || |
||||
|
(State.y2 && Math.abs(State.y1 - State.y2) > 30)) { |
||||
|
event.direction = _swipeDirection(State.x1, State.x2, State.y1, State.y2) |
||||
|
setTimeout(function () { |
||||
|
if(State.swipeTimeout) { |
||||
|
// 触发 swipe 滑动 上下左右 事件 |
||||
|
ownerInstance.triggerEvent('swipe', event) |
||||
|
State.swipeTimeout = true |
||||
|
} |
||||
|
}, 0, instance) |
||||
|
} else { |
||||
|
setTimeout(function () { |
||||
|
if(State.tapTimeout) { |
||||
|
if (!State._preventTap) { |
||||
|
// 触发 tap 事件 |
||||
|
ownerInstance.triggerEvent('tap', event) |
||||
|
} |
||||
|
// trigger double tap immediately |
||||
|
if (State.isDoubleTap) { |
||||
|
// 触发 doubleTap 事件 |
||||
|
ownerInstance.triggerEvent('doubleTap', event) |
||||
|
State.isDoubleTap = false |
||||
|
} |
||||
|
State.tapTimeout = true |
||||
|
} |
||||
|
}, 0, instance) |
||||
|
if (!State.isDoubleTap) { |
||||
|
if (instance.getDataset()['requirefailure']) { // requireFailure |
||||
|
setTimeout(function () { |
||||
|
if(State.singleTapTimeout) { |
||||
|
// 触发 singleTap 事件 |
||||
|
ownerInstance.triggerEvent('singleTap', event) |
||||
|
State.singleTapTimeout = true |
||||
|
} |
||||
|
}, 250, instance) |
||||
|
} else { |
||||
|
ownerInstance.triggerEvent('singleTap', event) |
||||
|
State.singleTapTimeout = true |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// 触发 touchEnd 事件 |
||||
|
ownerInstance.triggerEvent('touchEnd', event) |
||||
|
State.preV.x = 0 |
||||
|
State.preV.y = 0 |
||||
|
State.zoom = 1 |
||||
|
State.pinchStartLen = null |
||||
|
State.x1 = State.x2 = null |
||||
|
State.y1 = State.y2 = null |
||||
|
|
||||
|
if (!instance.getDataset()['propagation']) return false |
||||
|
} |
||||
|
var cancel = function(event, ownerInstance) { |
||||
|
var instance = event.instance; |
||||
|
var State = instance.getState() |
||||
|
State._cancelLongTap() |
||||
|
State._cancelSingleTap() |
||||
|
State._tapTimeout() |
||||
|
State._swipeTimeout() |
||||
|
// 触发 touchCancel 事件 |
||||
|
ownerInstance.triggerEvent('touchCancel', event) |
||||
|
|
||||
|
if (!instance.getDataset()['propagation']) return false |
||||
|
} |
||||
|
module.exports = { |
||||
|
start: start, |
||||
|
move: move, |
||||
|
end: end, |
||||
|
cancel: cancel |
||||
|
} |
||||
@ -0,0 +1,120 @@ |
|||||
|
import { cdnUrl, code } from "../../getMapData"; |
||||
|
const baseUrl = `${cdnUrl}/test-projects/${code}/index.html`; |
||||
|
|
||||
|
Page({ |
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
url: "", |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
async onLoad({ q = "", e = "", s = "", plate = "" } = {}) { |
||||
|
if (q) { |
||||
|
q = decodeURIComponent(q); |
||||
|
const kvs = q |
||||
|
.split("?") |
||||
|
.pop() |
||||
|
.split("&") |
||||
|
.map((kv) => kv.split("=")); |
||||
|
s = kvs.find(([k]) => k === "s") ? kvs.find(([k]) => k === "s")[1] : ""; |
||||
|
e = kvs.find(([k]) => k === "e") ? kvs.find(([k]) => k === "e")[1] : ""; |
||||
|
} |
||||
|
const app = getApp(); |
||||
|
const openid = app.globalData.openid |
||||
|
? app.globalData.openid |
||||
|
: await new Promise((resolve) => app.onOpenid(resolve)); |
||||
|
const { memberID, isShopMember } = app.globalData; |
||||
|
if (memberID) { |
||||
|
return this.setData({ |
||||
|
url: `${baseUrl}?t=${new Date().getTime()}#/?openid=${openid}&memberID=${memberID}${ |
||||
|
isShopMember ? "&isShop=true" : "" |
||||
|
}${e ? "&e=" + e : ""}${e && s ? "&s=" + s : ""}${ |
||||
|
plate ? "&plate=" + plate : "" |
||||
|
}`,
|
||||
|
}); |
||||
|
} |
||||
|
if (!openid) { |
||||
|
console.warn("获取openid失败"); |
||||
|
app.globalData.userDeny = true; |
||||
|
} |
||||
|
if (app.globalData.userDeny) { |
||||
|
return this.setData({ |
||||
|
url: `${baseUrl}?t=${new Date().getTime()}#/?openid=${openid}${ |
||||
|
e ? "&e=" + e : "" |
||||
|
}${e && s ? "&s=" + s : ""}${plate ? "&plate=" + plate : ""}`,
|
||||
|
}); |
||||
|
} |
||||
|
return wx.redirectTo({ |
||||
|
url: "/pages/login/index", |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom: function () {}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage({ webViewUrl: q }) { |
||||
|
let e; |
||||
|
let name; |
||||
|
if (q) { |
||||
|
q = decodeURIComponent(q); |
||||
|
const kvs = q |
||||
|
.split("?") |
||||
|
.pop() |
||||
|
.split("&") |
||||
|
.map((kv) => kv.split("=")); |
||||
|
console.log(kvs); |
||||
|
if (kvs.find(([k]) => k === "e")) { |
||||
|
e = kvs.find(([k]) => k === "e")[1]; |
||||
|
} |
||||
|
if (kvs.find(([k]) => k === "name")) { |
||||
|
name = kvs.find(([k]) => k === "name")[1]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return name |
||||
|
? { |
||||
|
title: name, |
||||
|
path: `/pages/h5map/index?e=${e}`, |
||||
|
imageUrl: "/pages/h5map/share.png", |
||||
|
} |
||||
|
: { |
||||
|
title: "", |
||||
|
path: "/pages/h5map/index", |
||||
|
imageUrl: "/pages/h5map/share.png", |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
<web-view src="{{url}}"> |
||||
|
></web-view> |
||||
@ -0,0 +1 @@ |
|||||
|
/* pages/h5map/index.wxss */ |
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 596 B |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 127 KiB |
@ -0,0 +1,112 @@ |
|||||
|
export const STATES = { |
||||
|
selectFloor: "selectFloor", |
||||
|
startScan: "startScan", |
||||
|
fail5s: "fail5s", |
||||
|
fail8s: "fail8s", |
||||
|
successPrompt: "successPrompt", |
||||
|
wrongLocation: "wrongLocation", |
||||
|
badConnection: "badConnection", |
||||
|
arriveEscalator: "arriveEscalator", |
||||
|
arriveElevator: "arriveElevator", |
||||
|
arriveMall: "arriveMall", |
||||
|
arrivePark: "arrivePark", |
||||
|
requestEnd: "requestEnd", |
||||
|
inNav: "inNav", |
||||
|
noCamera: "noCamera", |
||||
|
tomap: "tomap", |
||||
|
arriveEnd: "arriveEnd", |
||||
|
bluetoothRequired: "bluetoothRequired", |
||||
|
}; |
||||
|
export const promptIcons = { |
||||
|
info: "info", |
||||
|
escalator: "escalator", |
||||
|
elevator: "elevator", |
||||
|
question: "question", |
||||
|
tomap: "tomap", |
||||
|
mall: "mall", |
||||
|
park: "park", |
||||
|
end: "end", |
||||
|
bluetooth: "bluetooth", |
||||
|
}; |
||||
|
export const promptStateMap = { |
||||
|
bluetoothRequired: { |
||||
|
icon: promptIcons.bluetooth, |
||||
|
title: "开启蓝牙 精准导航", |
||||
|
meta: "请在系统设置打开蓝牙", |
||||
|
btn3: "退出导航", |
||||
|
}, |
||||
|
noCamera: { |
||||
|
icon: promptIcons.info, |
||||
|
title: "相机未授权", |
||||
|
meta: "AR导航需要相机权限", |
||||
|
btn1: "打开设置", |
||||
|
btn2: "退出导航", |
||||
|
}, |
||||
|
fail8s: { |
||||
|
icon: promptIcons.info, |
||||
|
title: "定位失败", |
||||
|
meta: "请确认您是否在正确楼层", |
||||
|
btn1: "重新定位", |
||||
|
btn2: "选择楼层", |
||||
|
btn3: "退出导航", |
||||
|
}, |
||||
|
wrongLocation: { |
||||
|
icon: promptIcons.info, |
||||
|
title: "当前位置无法导航", |
||||
|
meta: "请前往导航有效区域", |
||||
|
btn1: "退出导航", |
||||
|
}, |
||||
|
badConnection: { |
||||
|
icon: promptIcons.info, |
||||
|
title: "网络信号差", |
||||
|
meta: "请检查网络连接是否正常", |
||||
|
btn1: "重新定位", |
||||
|
}, |
||||
|
arriveEscalator: { |
||||
|
icon: promptIcons.escalator, |
||||
|
title: "", |
||||
|
meta: "请注意乘梯安全", |
||||
|
btn1: "已到达目标楼层", |
||||
|
btn1Meta: "到达目标楼层后,请点击上方按钮再次定位", |
||||
|
}, |
||||
|
arriveElevator: { |
||||
|
icon: promptIcons.elevator, |
||||
|
title: "", |
||||
|
meta: "请注意乘梯安全", |
||||
|
btn1: "已到达目标楼层", |
||||
|
btn1Meta: "到达目标楼层后,请点击上方按钮再次定位", |
||||
|
}, |
||||
|
arriveMall: { |
||||
|
icon: promptIcons.mall, |
||||
|
title: "请步行至商场区域", |
||||
|
meta: "请注意安全", |
||||
|
btn1: "已到达目标商场", |
||||
|
}, |
||||
|
arrivePark: { |
||||
|
icon: promptIcons.park, |
||||
|
title: "请步行至停车场", |
||||
|
meta: "请注意安全", |
||||
|
btn1: "已到达目标停车场", |
||||
|
}, |
||||
|
requestEnd: { |
||||
|
icon: promptIcons.question, |
||||
|
title: "是否退出导航?", |
||||
|
meta: "退出导航后 将返回首页", |
||||
|
btn1: "确定", |
||||
|
btn2: "取消", |
||||
|
}, |
||||
|
tomap: { |
||||
|
icon: promptIcons.tomap, |
||||
|
title: `即将离开AR导航`, |
||||
|
meta: "是否要继续?", |
||||
|
btn1: "确定", |
||||
|
btn2: "取消", |
||||
|
}, |
||||
|
arriveEnd: { |
||||
|
icon: promptIcons.end, |
||||
|
title: `已到达终点,是否退出导航`, |
||||
|
meta: "退出导航后将返回首页", |
||||
|
btn1: "确定", |
||||
|
btn2: "取消", |
||||
|
}, |
||||
|
}; |
||||
@ -0,0 +1,752 @@ |
|||||
|
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 }); |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,10 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"prompt": "../prompt/prompt", |
||||
|
"map2d": "../map2d/map2d", |
||||
|
"tabs": "../tabs/tabs", |
||||
|
"destination": "../destination/destination", |
||||
|
"nav": "../nav/nav", |
||||
|
"scan": "../scan/scan" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
<view> |
||||
|
<camera wx:if="{{resolution}}" mode="scanCode" device-position="back" flash="{{flash}}" frame-size="{{frameSize}}" style="z-index:0;position:fixed;top:0;width:100%;height:100%;" binderror="handleNoCamera" resolution="{{resolution}}"></camera> |
||||
|
<canvas bindtap="clickScreen" style="z-index:1;position:fixed;top:0;width:100%;height:100%;" type="webgl" id="webgl" canvas-id="webgl"></canvas> |
||||
|
</view> |
||||
|
|
||||
|
<view> |
||||
|
<canvas type="2d" id="capture" style="width: 1px; height: 1px;"> |
||||
|
</canvas> |
||||
|
</view> |
||||
|
<view wx:if="{{state===states.selectFloor||state===states.startScan||state===states.fail5s||state===states.inNav}}" style="top:{{safeTop + 9}}px;color: {{state===states.inNav?'#000':'#fff'}}" class="title">导航助手</view> |
||||
|
<view wx:if="{{showTabs}}" class="floorname" style="top:{{safeTop + 60}}px"> |
||||
|
<image class="loc" src="./loc.png"></image> |
||||
|
<view class="sep"></view> |
||||
|
{{floorName}} |
||||
|
</view> |
||||
|
<!-- <button wx:if="{{state!==states.successPrompt&&!promptStateMap[state]&&point!==null}}" open-type="share" class="share" style="top:{{safeTop + 60}}px;"> |
||||
|
</button> |
||||
|
<image wx:if="{{state!==states.successPrompt&&!promptStateMap[state]&&point!==null}}" src="/pages/index/share.png" style="top:{{safeTop + 60}}px;" class="share-img"></image> --> |
||||
|
<view wx:if="{{state===states.selectFloor}}" class="floor-modal"> |
||||
|
<view class="content"> |
||||
|
<image class="close" src="./close.png" mode="widthFix" bindtap="exit"></image> |
||||
|
<image class="bg" src="./floor-bg.png" mode="widthFix"></image> |
||||
|
<view class="meta1">为了更精确定位 </view> |
||||
|
<view class="meta2"> 请选择您当前所在楼层</view> |
||||
|
<scroll-view class="list" scroll-x> |
||||
|
<view class="list-container"> |
||||
|
<view class="item {{item.floorId===floorId?'active':''}}" id="{{index}}" wx:for="{{selectMall? filteredMallFloors:filteredParkFloors}}" wx:key="floorId" bindtap="setFloor"> |
||||
|
<text>{{item.name}}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
<view class="tip"></view> |
||||
|
<button bindtap="requestLocation" loading="{{!inited}}" class="btn {{(inited && floorOrder!==null)? '' : 'disabled'}}">开始导航</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view wx:if="{{false&&(floorId==='B3'||floorId==='B2'||floorId==='B1')&&(state===states.startScan||state===states.fail5s)}}" class="zzcImg"> |
||||
|
<image src="/pages/index/mask.png" class="zzcimg_ys"></image> |
||||
|
<cover-view wx:if="{{flash_isFilter}}" class="scan_lo_tow" style="width:{{parkWidth}}px;height:{{parkHeight-10}}px;top:{{parkTop}}px;left:{{parkLeft}}px;"> |
||||
|
<cover-image class="scan_img trans-y" src="https://ar-fm.cdn.bcebos.com/lktools/880c9ef27944354288b11f2abed8fba7cb82d559"></cover-image> |
||||
|
</cover-view> |
||||
|
|
||||
|
<view class="scanning_textnl" style="top:{{safeTop + 94}}px;"> |
||||
|
<view> {{state===states.startScan?'开始定位':'努力定位中'}}</view> |
||||
|
<view> {{state===states.startScan?'请摆正手机扫描临近车位号':'再试试扫描其他车位号'}} </view> |
||||
|
</view> |
||||
|
<view class="scanning_tip" style="top:{{safeTop + 170}}px;"> |
||||
|
示例 |
||||
|
<image src='./scanning-tip.png'></image> |
||||
|
</view> |
||||
|
<view class="scanning_text" style="width:100%;top:{{parkTop +80}}px;left:0;right:0;"> |
||||
|
您身边的车位号置于此区域,并对齐扫描边缘 |
||||
|
</view> |
||||
|
<view class="flashlightBtn" bindtap="flashlightBtn"> |
||||
|
<image src="{{flash == 'on'? '/pages/index/flashon.png':'/pages/index/flashoff.png'}}" class="on_img"></image> |
||||
|
</view> |
||||
|
</view> |
||||
|
<scan wx:if="{{(state===states.startScan||state===states.fail5s)}}" fail5s="{{state===states.fail5s}}"></scan> |
||||
|
<prompt wx:if="{{!!promptStateMap[state]}}" icon="{{state===states.arriveEnd&&shop&& (shop.floorName==='5F'||shop.floorName==='6F')?promptStateMap[states.arriveElevator].icon:promptStateMap[state].icon}}" title="{{state===states.arriveEnd&&shop&& (shop.floorName==='5F'||shop.floorName==='6F')? '请乘坐直梯至目的地楼层':state ===states.arriveElevator?'请乘坐电梯至'+nextFloor.name:state ===states.arriveEscalator?'请乘坐扶梯至'+nextFloor.name :promptStateMap[state].title}}" meta="{{state===states.arriveEnd&&shop&&(shop.floorName==='5F'||shop.floorName==='6F')?'本次导航已结束':promptStateMap[state].meta}}" btn1="{{promptStateMap[state].btn1}}" btn1Meta="{{promptStateMap[state].btn1Meta}}" btn2="{{promptStateMap[state].btn2}}" btn3="{{promptStateMap[state].btn3}}" bindbtn="handlePromptBtn"></prompt> |
||||
|
<view wx:if="{{state===states.successPrompt}}" class="success-prompt"> |
||||
|
<image src="./success.png"></image> |
||||
|
<view class="title"> 定位成功 </view> |
||||
|
<view class="meta"> 请跟随路线指示行走 </view> |
||||
|
</view> |
||||
|
<nav wx:if="{{showTabs&&tab===1}}" end="{{arriveEnd}}" icon="{{navIcon}}" t1="{{msgTop}}" t2="{{msgBottomLeft}} {{msgBottomRight}}" bindexit="handleNavExit"> |
||||
|
</nav> |
||||
|
<image wx:if="{{state===states.inNav&&leftYaw===false&&rightYaw===true}}" class="leftyaw" src="./leftyaw.png"></image> |
||||
|
<image wx:if="{{state===states.inNav&&leftYaw===true&&rightYaw===false}}" class="rightyaw" src="./rightyaw.png"></image> |
||||
|
<map2d hidden="{{!(showTabs&&tab===0)}}" floororder="{{floorOrder}}" loc="{{lastLoc}}" searchType="{{searchType}}" bindmap="handleMap" bindpoint="handlePoint" bindexit="handleNavExit"></map2d> |
||||
|
<destination wx:if="{{showTabs&&tab===2&&shop}}" shop="{{shop}}" bindexit="handleNavExit"></destination> |
||||
|
<tabs wx:if="{{showTabs}}" progress="{{(totalDistance-distance)/totalDistance}}" end="{{arriveEnd}}" floor="{{floorName}}" tab="{{tab}}" bindrelocate="handleRelocate" bindchange="handleTabChange" bindtomap="handleToMap" warningCount="{{warningCount}}"></tabs> |
||||
@ -0,0 +1,406 @@ |
|||||
|
#map { |
||||
|
/* z-index: 10000 !important; */ |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
#loc { |
||||
|
width: 50rpx; |
||||
|
height: 50rpx; |
||||
|
position: absolute; |
||||
|
/* bottom: 90px; |
||||
|
right: 80px; */ |
||||
|
z-index: 1000000000 !important; |
||||
|
} |
||||
|
|
||||
|
.floor-modal { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
background: rgba(0, 0, 0, 0.4); |
||||
|
z-index: 10 !important; |
||||
|
} |
||||
|
|
||||
|
.floor-modal > .content { |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
height: 560px; |
||||
|
bottom: 0; |
||||
|
background: linear-gradient( |
||||
|
180deg, |
||||
|
#9fcdff 0%, |
||||
|
#e1f4ff 29.17%, |
||||
|
#ffffff 51.56%, |
||||
|
#ffffff 100% |
||||
|
); |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 20px; |
||||
|
line-height: 28px; |
||||
|
text-align: center; |
||||
|
letter-spacing: 1px; |
||||
|
color: #554936; |
||||
|
padding-top: 245px; |
||||
|
text-align: left; |
||||
|
} |
||||
|
.floor-modal > .content > .bg { |
||||
|
position: absolute; |
||||
|
top: 28px; |
||||
|
|
||||
|
left: 22px; |
||||
|
right: 22px; |
||||
|
|
||||
|
z-index: 1; |
||||
|
} |
||||
|
.floor-modal > .content > .meta1 { |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: normal; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
letter-spacing: 1px; |
||||
|
padding-left: 28px; |
||||
|
color: #474a56; |
||||
|
} |
||||
|
.floor-modal > .content > .meta2 { |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 600; |
||||
|
font-size: 22px; |
||||
|
line-height: 31px; |
||||
|
letter-spacing: 1px; |
||||
|
padding-left: 28px; |
||||
|
color: #323337; |
||||
|
} |
||||
|
|
||||
|
.content > .list { |
||||
|
width: 100vw; |
||||
|
height: 100px; |
||||
|
margin-top: 32px; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
.content > .list .item { |
||||
|
display: inline-flex; |
||||
|
width: 64px; |
||||
|
height: 100px; |
||||
|
background: #f3f4f8; |
||||
|
border-radius: 8px; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
margin-left: 28px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 600; |
||||
|
font-size: 18px; |
||||
|
line-height: 25px; |
||||
|
text-align: center; |
||||
|
letter-spacing: 1px; |
||||
|
color: #323337; |
||||
|
} |
||||
|
.content > .list .item + .item { |
||||
|
margin-left: 8px; |
||||
|
} |
||||
|
.content > .list .item.active { |
||||
|
border: 2px solid #437af7; |
||||
|
} |
||||
|
.list .list-container { |
||||
|
display: inline-flex; |
||||
|
padding-right: 28px; |
||||
|
} |
||||
|
.content > .tip { |
||||
|
margin-top: 10px; |
||||
|
margin-bottom: 9px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 12px; |
||||
|
line-height: 17px; |
||||
|
text-align: center; |
||||
|
color: #7a7e8d; |
||||
|
} |
||||
|
.content > .btn { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
width: calc(100vw - 28px - 28px); |
||||
|
margin-left: 28px; |
||||
|
height: 48px; |
||||
|
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%); |
||||
|
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2); |
||||
|
border-radius: 10px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 600; |
||||
|
font-size: 16px; |
||||
|
text-align: center; |
||||
|
color: #ffffff; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.content > .btn.disabled { |
||||
|
color: #fff; |
||||
|
box-shadow: none; |
||||
|
background: #a1a5b3; |
||||
|
} |
||||
|
|
||||
|
.content > .close { |
||||
|
position: absolute; |
||||
|
width: 24px; |
||||
|
height: 24px; |
||||
|
top: 16px; |
||||
|
right: 16px; |
||||
|
} |
||||
|
.success-prompt { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
background: rgba(0, 0, 0, 80%); |
||||
|
z-index: 10 !important; |
||||
|
} |
||||
|
|
||||
|
.success-prompt > image { |
||||
|
position: absolute; |
||||
|
width: 128px; |
||||
|
height: 128px; |
||||
|
top: 221px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
margin: auto; |
||||
|
} |
||||
|
|
||||
|
.success-prompt > .title { |
||||
|
position: absolute; |
||||
|
top: 429px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 28px; |
||||
|
line-height: 39px; |
||||
|
text-align: center; |
||||
|
letter-spacing: 1px; |
||||
|
color: #ffffff; |
||||
|
} |
||||
|
|
||||
|
.success-prompt > .meta { |
||||
|
position: absolute; |
||||
|
top: 476px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: normal; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
text-align: center; |
||||
|
letter-spacing: 1px; |
||||
|
color: #c9cbd1; |
||||
|
} |
||||
|
.zzcImg { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
/* border: 1px solid red; */ |
||||
|
z-index: 10; |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
} |
||||
|
.zzcimg_ys { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
.scan_lo_tow { |
||||
|
width: 90%; |
||||
|
z-index: 1000000000000 !important; |
||||
|
position: absolute; |
||||
|
left: 5%; |
||||
|
top: 510rpx; |
||||
|
height: 72.4; |
||||
|
} |
||||
|
.trans-y { |
||||
|
animation: site-transy 2s infinite ease-in-out; |
||||
|
} |
||||
|
@keyframes site-transy { |
||||
|
0% { |
||||
|
transform: translateY(-410px); |
||||
|
} |
||||
|
|
||||
|
100% { |
||||
|
transform: translateY(300px); |
||||
|
} |
||||
|
} |
||||
|
.scanning_textnl { |
||||
|
z-index: 1000000000000 !important; |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 20px; |
||||
|
line-height: 28px; |
||||
|
color: #eee9de; |
||||
|
} |
||||
|
.scanning_tip { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: normal; |
||||
|
font-size: 14px; |
||||
|
line-height: 21px; |
||||
|
text-align: center; |
||||
|
color: #fdd02f; |
||||
|
} |
||||
|
.scanning_tip > image { |
||||
|
display: flex; |
||||
|
width: 180px; |
||||
|
height: 50px; |
||||
|
margin: auto; |
||||
|
margin-top: 8px; |
||||
|
} |
||||
|
.scanning_text { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
width: 100%; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 12px; |
||||
|
line-height: 17px; |
||||
|
text-align: center; |
||||
|
letter-spacing: 1px; |
||||
|
color: rgba(238, 233, 222, 0.5); |
||||
|
} |
||||
|
.flashlightBtn { |
||||
|
position: fixed; |
||||
|
top: 1086rpx; |
||||
|
left: 50%; |
||||
|
transform: translate(-50rpx); |
||||
|
color: red; |
||||
|
z-index: 1000000000000 !important; |
||||
|
} |
||||
|
.on_img { |
||||
|
width: 112rpx; |
||||
|
height: 96rpx; |
||||
|
} |
||||
|
.logo { |
||||
|
position: fixed; |
||||
|
z-index: 11; |
||||
|
left: 16px; |
||||
|
width: 24px; |
||||
|
height: 24px; |
||||
|
} |
||||
|
.title { |
||||
|
position: fixed; |
||||
|
z-index: 11; |
||||
|
height: 27px; |
||||
|
left: 16px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: bold; |
||||
|
font-size: 20px; |
||||
|
line-height: 28px; |
||||
|
|
||||
|
color: #000000; |
||||
|
} |
||||
|
.floorname { |
||||
|
position: fixed; |
||||
|
display: inline-flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
z-index: 16; |
||||
|
height: 40px; |
||||
|
left: 8px; |
||||
|
padding-left: 8px; |
||||
|
padding-right: 12px; |
||||
|
background: #ffffff; |
||||
|
border-radius: 20px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
color: #323337; |
||||
|
} |
||||
|
.floorname > .loc { |
||||
|
width: 16px; |
||||
|
height: 16px; |
||||
|
} |
||||
|
.floorname > .sep { |
||||
|
width: 1px; |
||||
|
height: 10px; |
||||
|
background: #c9cbd1; |
||||
|
margin: 0 8px; |
||||
|
} |
||||
|
@keyframes pointleft { |
||||
|
from { |
||||
|
left: 8px; |
||||
|
} |
||||
|
50% { |
||||
|
left: 0; |
||||
|
} |
||||
|
to { |
||||
|
left: 8px; |
||||
|
} |
||||
|
} |
||||
|
@keyframes pointright { |
||||
|
from { |
||||
|
right: 8px; |
||||
|
} |
||||
|
50% { |
||||
|
right: 0; |
||||
|
} |
||||
|
to { |
||||
|
right: 8px; |
||||
|
} |
||||
|
} |
||||
|
.leftyaw { |
||||
|
position: fixed; |
||||
|
width: 98px; |
||||
|
height: 40px; |
||||
|
top: 0; |
||||
|
bottom: 0; |
||||
|
z-index: 11; |
||||
|
left: 8px; |
||||
|
margin: auto; |
||||
|
animation: pointleft 0.5s infinite ease; |
||||
|
} |
||||
|
.rightyaw { |
||||
|
position: fixed; |
||||
|
width: 98px; |
||||
|
height: 40px; |
||||
|
top: 0; |
||||
|
bottom: 0; |
||||
|
z-index: 11; |
||||
|
right: 8px; |
||||
|
margin: auto; |
||||
|
animation: pointright 0.5s infinite ease; |
||||
|
} |
||||
|
.share { |
||||
|
position: fixed; |
||||
|
z-index: 11; |
||||
|
right: 8px; |
||||
|
width: 40px !important; |
||||
|
height: 54px; |
||||
|
background: none; |
||||
|
} |
||||
|
.share-img { |
||||
|
position: fixed; |
||||
|
z-index: 12; |
||||
|
right: 8px; |
||||
|
width: 40px; |
||||
|
height: 54px; |
||||
|
pointer-events: none; |
||||
|
} |
||||
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 977 B |
|
After Width: | Height: | Size: 975 B |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 544 B |
|
After Width: | Height: | Size: 239 B |
|
After Width: | Height: | Size: 176 B |
@ -0,0 +1,57 @@ |
|||||
|
import { post } from "../../getMapData"; |
||||
|
|
||||
|
Page({ |
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
agreed: true, |
||||
|
}, |
||||
|
toPrivacy() { |
||||
|
wx.navigateTo({ |
||||
|
url: "/pages/privacy/index", |
||||
|
}); |
||||
|
}, |
||||
|
toggleAgreed() { |
||||
|
this.setData({ agreed: !this.data.agreed }); |
||||
|
}, |
||||
|
toMainPage() { |
||||
|
const app = getApp(); |
||||
|
app.globalData.userDeny = true; |
||||
|
return wx.redirectTo({ |
||||
|
url: "/pages/h5map/index", |
||||
|
}); |
||||
|
}, |
||||
|
async ongetphonenumber(e) { |
||||
|
if (!e.detail.code) { |
||||
|
return this.toMainPage(); |
||||
|
} |
||||
|
try { |
||||
|
wx.showLoading(); |
||||
|
const app = getApp(); |
||||
|
const { openid } = app.globalData; |
||||
|
const { |
||||
|
code: resCode, |
||||
|
data: { isShopMember, memberID }, |
||||
|
} = await post("/api/ar/v1/applet/MemberRegister", { |
||||
|
code: e.detail.code, |
||||
|
wechatID: openid, |
||||
|
}); |
||||
|
|
||||
|
if (resCode === "200") { |
||||
|
app.globalData.memberID = memberID; |
||||
|
app.globalData.isShopMember = isShopMember; |
||||
|
wx.reLaunch({ |
||||
|
url: "/pages/h5map/index", |
||||
|
}); |
||||
|
} else { |
||||
|
this.toMainPage(); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
this.toMainPage(); |
||||
|
console.log(error); |
||||
|
} finally { |
||||
|
wx.hideLoading(); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
<view class="login"> |
||||
|
<image class="back" src="./back.svg" bindtap="toMainPage"></image> |
||||
|
<image class="logo" src="./logo.png"></image> |
||||
|
<view class="title">南京千目</view> |
||||
|
<button disabled="{{!agreed}}" class="login-btn" open-type="getPhoneNumber" bindgetphonenumber="ongetphonenumber" binderror="onerror">微信快捷登陆</button> |
||||
|
<view class="privacy"> |
||||
|
<image bindtap="toggleAgreed" src="./checkbox.svg" wx:if="{{agreed}}"></image> |
||||
|
<image bindtap="toggleAgreed" wx:else src="./emptycheckbox.svg"></image> 我已阅读并同意<text class="bold" bindtap="toPrivacy">《集团隐私政策声明》</text> |
||||
|
</view> |
||||
|
</view> |
||||
@ -0,0 +1,75 @@ |
|||||
|
.login { |
||||
|
position: relative; |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
background: #e5e5e5; |
||||
|
} |
||||
|
.back { |
||||
|
position: absolute; |
||||
|
width: 60px; |
||||
|
height: 60px; |
||||
|
left: 10px; |
||||
|
top: 104px; |
||||
|
} |
||||
|
.logo { |
||||
|
position: absolute; |
||||
|
width: 80px; |
||||
|
height: 80px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
top: 172px; |
||||
|
margin: auto; |
||||
|
} |
||||
|
.title { |
||||
|
position: absolute; |
||||
|
top: 288px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
text-align: center; |
||||
|
font-family: "PingFang SC"; |
||||
|
font-style: normal; |
||||
|
font-weight: 600; |
||||
|
font-size: 18px; |
||||
|
line-height: 25px; |
||||
|
color: #474a56; |
||||
|
} |
||||
|
.login-btn { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
position: absolute; |
||||
|
top: 399px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
margin: auto; |
||||
|
width: 220px; |
||||
|
height: 60px; |
||||
|
background: #56b23a; |
||||
|
border-radius: 10px; |
||||
|
font-style: normal; |
||||
|
font-weight: 600; |
||||
|
font-size: 16px; |
||||
|
line-height: 22px; |
||||
|
color: #ffffff; |
||||
|
} |
||||
|
.privacy { |
||||
|
position: absolute; |
||||
|
top: 483px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
display: flex; |
||||
|
font-weight: 400; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
color: #7a7e8d; |
||||
|
} |
||||
|
.privacy image { |
||||
|
width: 14px; |
||||
|
height: 14px; |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
.privacy > .bold { |
||||
|
color: #000; |
||||
|
} |
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
After Width: | Height: | Size: 201 KiB |
@ -0,0 +1,454 @@ |
|||||
|
import { getCrossPoint } from "./util"; |
||||
|
import Events from "./events"; |
||||
|
|
||||
|
import dijkstra from "dijkstrajs"; |
||||
|
import { getMapData, mall } from "../../getMapData"; |
||||
|
|
||||
|
const getDistance = (a, b) => |
||||
|
Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.z - b.z) * (a.z - b.z)); |
||||
|
export const minScale = 0.3; |
||||
|
export const maxScale = 1; |
||||
|
|
||||
|
export default class MAPAPP { |
||||
|
events = new Events(); |
||||
|
mall = mall; |
||||
|
groups = []; |
||||
|
x = null; |
||||
|
y = null; |
||||
|
intervals = []; |
||||
|
shown = false; |
||||
|
scale = minScale; |
||||
|
constructor(query, component) { |
||||
|
this.searchType = component.data.searchType; |
||||
|
const canvas = query.node; |
||||
|
const ctx = canvas.getContext("2d"); |
||||
|
const dpr = wx.getSystemInfoSync().pixelRatio; |
||||
|
canvas.width = query.width * dpr; |
||||
|
canvas.height = query.height * dpr; |
||||
|
const start = canvas.createImage(); |
||||
|
start.src = "/pages/map2d/start.png"; |
||||
|
const end = canvas.createImage(); |
||||
|
end.src = "/pages/map2d/end.png"; |
||||
|
const arrow = canvas.createImage(); |
||||
|
arrow.src = "/pages/map2d/arrow.png"; |
||||
|
ctx.scale(dpr, dpr); |
||||
|
Object.assign(this, { |
||||
|
canvas, |
||||
|
ctx, |
||||
|
start, |
||||
|
end, |
||||
|
arrow, |
||||
|
width: query.width, |
||||
|
height: query.height, |
||||
|
}); |
||||
|
this.init(); |
||||
|
} |
||||
|
|
||||
|
on(event, cb) { |
||||
|
return this.events.on(event, cb); |
||||
|
} |
||||
|
once(event, cb) { |
||||
|
return this.events.once(event, cb); |
||||
|
} |
||||
|
off(event, cb) { |
||||
|
return this.events.off(event, cb); |
||||
|
} |
||||
|
dispose() { |
||||
|
console.log("map interval disposed"); |
||||
|
this.intervals && this.intervals.forEach(clearInterval); |
||||
|
this.intervals = []; |
||||
|
} |
||||
|
|
||||
|
async init() { |
||||
|
const data = await getMapData(); |
||||
|
Object.assign(this, data); |
||||
|
const { floors } = this.mall; |
||||
|
const { canvas } = this; |
||||
|
const groups = floors.map(([_, name, map2dData]) => { |
||||
|
const floor = canvas.createImage(); |
||||
|
if (map2dData) floor.src = map2dData.data; |
||||
|
return floor; |
||||
|
}); |
||||
|
this.groups = groups; |
||||
|
this.events.dispatch("loaded", this); |
||||
|
this.intervals.push( |
||||
|
setInterval(() => { |
||||
|
this.animate(); |
||||
|
}, 1000 / 30) |
||||
|
); |
||||
|
} |
||||
|
get shops() { |
||||
|
return !this.serverShopInfo |
||||
|
? [] |
||||
|
: this.serverShopInfo[this.floorOrder].shopList; |
||||
|
} |
||||
|
get currentFloorObject() { |
||||
|
return this.groups[this.floorOrder]; |
||||
|
} |
||||
|
setXY(x, y) { |
||||
|
this.x = x; |
||||
|
this.y = y; |
||||
|
} |
||||
|
scaleX(number) { |
||||
|
const { x, width, scale } = this; |
||||
|
return (number - x) * scale + width / 2; |
||||
|
} |
||||
|
scaleY(number) { |
||||
|
const { y, height, scale } = this; |
||||
|
return (number - y) * scale + height / 2; |
||||
|
} |
||||
|
scaleLen(number) { |
||||
|
const { scale } = this; |
||||
|
return number * scale; |
||||
|
} |
||||
|
animate() { |
||||
|
const { shown, ctx, x, y, width, height } = this; |
||||
|
if (!shown) return; |
||||
|
ctx.clearRect(0, 0, width, height); |
||||
|
ctx.save(); |
||||
|
// ctx.translate(this.scaleX(-x) + width / 2, this.scaleY(-y) + height / 2);
|
||||
|
this.drawFloor(); |
||||
|
this.drawLines(); |
||||
|
ctx.restore(); |
||||
|
this.drawArrow(); |
||||
|
} |
||||
|
drawArrow() { |
||||
|
const { ctx, arrow, width, height } = this; |
||||
|
ctx.save(); |
||||
|
ctx.translate(width / 2, height / 2); |
||||
|
ctx.drawImage(arrow, -16, -16, 32, 32); |
||||
|
ctx.restore(); |
||||
|
} |
||||
|
drawPath() { |
||||
|
const { linePath, ctx } = this; |
||||
|
const start = linePath[0]; |
||||
|
const end = linePath[linePath.length - 1]; |
||||
|
ctx.fillStyle = "#518cf7"; |
||||
|
ctx.beginPath(); |
||||
|
ctx.arc( |
||||
|
this.scaleX(start[0]), |
||||
|
this.scaleY(start[1]), |
||||
|
// this.scaleLen(10),
|
||||
|
10, |
||||
|
0, |
||||
|
2 * Math.PI |
||||
|
); |
||||
|
ctx.fill(); |
||||
|
ctx.beginPath(); |
||||
|
ctx.arc( |
||||
|
this.scaleX(end[0]), |
||||
|
this.scaleY(end[1]), |
||||
|
// this.scaleLen(10),
|
||||
|
10, |
||||
|
0, |
||||
|
2 * Math.PI |
||||
|
); |
||||
|
ctx.fill(); |
||||
|
|
||||
|
ctx.beginPath(); |
||||
|
linePath.forEach(([x, y], i) => { |
||||
|
if (i === 0) { |
||||
|
ctx.moveTo(this.scaleX(x), this.scaleY(y)); |
||||
|
} else { |
||||
|
ctx.lineTo(this.scaleX(x), this.scaleY(y)); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
drawLines() { |
||||
|
const { linePath, ctx } = this; |
||||
|
if (!linePath || !linePath.length) return; |
||||
|
this.drawPath(); |
||||
|
ctx.lineCap = "round"; |
||||
|
ctx.lineJoin = "round"; |
||||
|
// ctx.lineWidth = this.scaleLen(11);
|
||||
|
ctx.lineWidth = 11; |
||||
|
ctx.strokeStyle = "#518cf7"; |
||||
|
ctx.stroke(); |
||||
|
for (let i = 9; i >= 1; i -= 1) { |
||||
|
ctx.lineCap = "butt"; |
||||
|
ctx.lineJoin = "butt"; |
||||
|
// ctx.lineWidth = this.scaleLen(i);
|
||||
|
ctx.lineWidth = i; |
||||
|
ctx.strokeStyle = "#fff"; |
||||
|
// ctx.setLineDash([this.scaleLen(4), this.scaleLen(13)]);
|
||||
|
ctx.setLineDash([4, 13]); |
||||
|
// ctx.lineDashOffset = this.scaleLen(i - 9);
|
||||
|
ctx.lineDashOffset = i - 9; |
||||
|
ctx.stroke(); |
||||
|
ctx.strokeStyle = "#437af7"; |
||||
|
// ctx.setLineDash([0, this.scaleLen(4), this.scaleLen(13), 0]);
|
||||
|
ctx.setLineDash([0, 4, 13, 0]); |
||||
|
// ctx.lineDashOffset = this.scaleLen(i - 9);
|
||||
|
ctx.lineDashOffset = i - 9; |
||||
|
ctx.stroke(); |
||||
|
} |
||||
|
const start = linePath[0]; |
||||
|
const end = linePath[linePath.length - 1]; |
||||
|
ctx.fillStyle = "#437af7"; |
||||
|
// ctx.lineWidth = this.scaleLen(1);
|
||||
|
ctx.lineWidth = 1; |
||||
|
ctx.beginPath(); |
||||
|
ctx.arc( |
||||
|
this.scaleX(start[0]), |
||||
|
this.scaleY(start[1]), |
||||
|
// this.scaleLen(9),
|
||||
|
9, |
||||
|
0, |
||||
|
2 * Math.PI |
||||
|
); |
||||
|
ctx.fill(); |
||||
|
ctx.beginPath(); |
||||
|
ctx.arc( |
||||
|
this.scaleX(end[0]), |
||||
|
this.scaleY(end[1]), |
||||
|
// this.scaleLen(9),
|
||||
|
9, |
||||
|
0, |
||||
|
2 * Math.PI |
||||
|
); |
||||
|
ctx.fill(); |
||||
|
ctx.fillStyle = "#fff"; |
||||
|
ctx.beginPath(); |
||||
|
ctx.arc( |
||||
|
this.scaleX(start[0]), |
||||
|
this.scaleY(start[1]), |
||||
|
// this.scaleLen(4.5),
|
||||
|
4.5, |
||||
|
0, |
||||
|
2 * Math.PI |
||||
|
); |
||||
|
ctx.fill(); |
||||
|
ctx.beginPath(); |
||||
|
ctx.arc( |
||||
|
this.scaleX(end[0]), |
||||
|
this.scaleY(end[1]), |
||||
|
// this.scaleLen(4.5),
|
||||
|
4.5, |
||||
|
0, |
||||
|
2 * Math.PI |
||||
|
); |
||||
|
ctx.fill(); |
||||
|
} |
||||
|
|
||||
|
drawFloor() { |
||||
|
const { floorOrder, groups, ctx } = this; |
||||
|
const floor = groups[floorOrder]; |
||||
|
ctx.save(); |
||||
|
ctx.drawImage( |
||||
|
floor, |
||||
|
this.scaleX(-floor.width / 2), |
||||
|
this.scaleY(-floor.height / 2), |
||||
|
this.scaleLen(floor.width), |
||||
|
this.scaleLen(floor.height) |
||||
|
); |
||||
|
ctx.restore(); |
||||
|
} |
||||
|
|
||||
|
async changeFloor(num) { |
||||
|
this.floorOrder = num; |
||||
|
this.x = null; |
||||
|
this.y = null; |
||||
|
this.events.dispatch("floorchange", Number(num)); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
cross({ x, y }) { |
||||
|
const point = { x, y }; |
||||
|
const { positions } = this; |
||||
|
if (!(positions && positions.length)) return point; |
||||
|
let minDisance = Infinity; |
||||
|
let crossPoint = null; |
||||
|
let index = 1; |
||||
|
for (let k = 1; k < positions.length; k++) { |
||||
|
let point1 = positions[k - 1]; |
||||
|
let point2 = positions[k]; |
||||
|
let cross = getCrossPoint(point, point1, point2); |
||||
|
let d = Math.sqrt( |
||||
|
(point.x - cross.x) * (point.x - cross.x) + |
||||
|
(point.y - cross.y) * (point.y - cross.y) |
||||
|
); |
||||
|
|
||||
|
if (d < minDisance) { |
||||
|
minDisance = d; |
||||
|
crossPoint = cross; |
||||
|
index = k; |
||||
|
if (d < 0.5) break; |
||||
|
} |
||||
|
} |
||||
|
return crossPoint; |
||||
|
} |
||||
|
requestRoute(start, end, draw = true) { |
||||
|
if (!(start && end)) return; |
||||
|
const startFloorId = start[2]; |
||||
|
const startFloorOrder = getApp().globalData.floorIdFloorOrderMap[ |
||||
|
startFloorId |
||||
|
]; |
||||
|
const { name: sname } = this.getNearestPoint({ |
||||
|
x: start[0], |
||||
|
z: start[1], |
||||
|
floorOrder: startFloorOrder, |
||||
|
}); |
||||
|
const startFloor = startFloorOrder; |
||||
|
const startPoint = Number(sname); |
||||
|
|
||||
|
const endFloor = end.floorOrder; |
||||
|
const endPoint = end.navPoint; |
||||
|
|
||||
|
let path = this.shortestPath( |
||||
|
{ |
||||
|
floorOrder: startFloor, |
||||
|
NavPoint: startPoint, |
||||
|
}, |
||||
|
{ |
||||
|
floorOrder: endFloor, |
||||
|
NavPoint: endPoint, |
||||
|
} |
||||
|
); |
||||
|
if (!path) { |
||||
|
console.log("寻路失败", "start", start, "end", end); |
||||
|
return { naviData: null, nextFloorId: null }; |
||||
|
} |
||||
|
let floorIdPoints = path.map((str) => str.split("_")); |
||||
|
const byFirstDiffFloor = ([floorId], i) => |
||||
|
i === 0 ? false : floorIdPoints[i - 1][0] !== floorId; |
||||
|
const index = floorIdPoints.findIndex(byFirstDiffFloor); |
||||
|
console.log("index", index); |
||||
|
|
||||
|
const isFloorChange = |
||||
|
index !== -1 && getApp().globalData.floors[path[index].split("_")[0]]; |
||||
|
const currentFloorOrder = Number(floorIdPoints[0][0]); |
||||
|
const nextFloorOrder = !isFloorChange |
||||
|
? null |
||||
|
: Number(floorIdPoints[index][0]); |
||||
|
const fac = !isFloorChange ? null : this.facilityLiftMap[path[index - 1]]; |
||||
|
let naviData = floorIdPoints.slice(0, index === -1 ? undefined : index); |
||||
|
naviData = naviData.reduce((acc, [floorOrder, point]) => { |
||||
|
const last = acc[acc.length - 1]; |
||||
|
const x = this.points[floorOrder][point].position[0]; |
||||
|
const y = this.points[floorOrder][point].position[2]; |
||||
|
const floorId = startFloorId; |
||||
|
if (last && Math.abs(last.y - y) <= 3 && Math.abs(last.x - x) <= 3) |
||||
|
return acc; |
||||
|
else return [...acc, { x, y, floorId }]; |
||||
|
}, []); |
||||
|
|
||||
|
if (naviData.length === 1) { |
||||
|
naviData.unshift({ |
||||
|
x: start[0], |
||||
|
y: start[1], |
||||
|
flooorId: naviData[0].flooorId, |
||||
|
}); |
||||
|
} |
||||
|
naviData.forEach((data, i) => { |
||||
|
data.pointType = |
||||
|
i === 0 |
||||
|
? 0 |
||||
|
: i !== naviData.length - 1 |
||||
|
? 1 |
||||
|
: !isFloorChange |
||||
|
? 6 |
||||
|
: nextFloorOrder > currentFloorOrder |
||||
|
? fac.Type == 5 |
||||
|
? 2 |
||||
|
: 4 |
||||
|
: fac.Type == 5 |
||||
|
? 3 |
||||
|
: 5; |
||||
|
}); |
||||
|
this.positions = naviData; |
||||
|
console.log("originalNaviData", naviData); |
||||
|
if (draw && naviData.length) { |
||||
|
this.linePath = naviData.map(({ x, y }) => [x, y]); |
||||
|
} |
||||
|
const nextFloorId = !isFloorChange |
||||
|
? null |
||||
|
: getApp().globalData.floors[path[index].split("_")[0]].floorId; |
||||
|
console.log("nextFloorId", nextFloorId); |
||||
|
return { |
||||
|
naviData, |
||||
|
nextFloorId, |
||||
|
}; |
||||
|
} |
||||
|
shortestPath( |
||||
|
{ floorOrder: floorOrder1, NavPoint: NavPoint1 }, |
||||
|
{ floorOrder: floorOrder2, NavPoint: NavPoint2 }, |
||||
|
searchType |
||||
|
) { |
||||
|
const { graph, graphDt, graphFt } = this; |
||||
|
searchType = [0, 1, 2].includes(searchType) ? searchType : this.searchType; |
||||
|
try { |
||||
|
let currentGraph = |
||||
|
searchType === 0 ? graph : searchType === 1 ? graphFt : graphDt; |
||||
|
const s = floorOrder1 + "_" + NavPoint1; |
||||
|
const d = floorOrder2 + "_" + NavPoint2; |
||||
|
if (currentGraph && currentGraph[s] && currentGraph[d]) { |
||||
|
let path = dijkstra.find_path(currentGraph, s, d); |
||||
|
return path; |
||||
|
} else return null; |
||||
|
} catch (e) { |
||||
|
console.log(e); |
||||
|
return this.shortestPath( |
||||
|
{ floorOrder: floorOrder1, NavPoint: NavPoint1 }, |
||||
|
{ floorOrder: floorOrder2, NavPoint: NavPoint2 }, |
||||
|
0 |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
getNearestPoint({ x, z, floorOrder }) { |
||||
|
const { points } = this; |
||||
|
const [nearest] = points[floorOrder].reduce( |
||||
|
([last, min], nxt) => { |
||||
|
if (last === null) { |
||||
|
return [ |
||||
|
nxt, |
||||
|
getDistance( |
||||
|
{ |
||||
|
x, |
||||
|
z, |
||||
|
}, |
||||
|
{ |
||||
|
x: nxt.position[0], |
||||
|
z: nxt.position[2], |
||||
|
} |
||||
|
), |
||||
|
]; |
||||
|
} |
||||
|
const dis = getDistance( |
||||
|
{ |
||||
|
x, |
||||
|
z, |
||||
|
}, |
||||
|
{ |
||||
|
x: nxt.position[0], |
||||
|
z: nxt.position[2], |
||||
|
} |
||||
|
); |
||||
|
if (dis < min) return [nxt, dis]; |
||||
|
else return [last, min]; |
||||
|
}, |
||||
|
[null, Infinity] |
||||
|
); |
||||
|
return nearest; |
||||
|
} |
||||
|
getFloorHeightByFloorOrder(floorOrder) { |
||||
|
const { config, groups } = this; |
||||
|
const floor = groups[floorOrder]; |
||||
|
const { floorHeights } = config; |
||||
|
return floorOrder in floorHeights |
||||
|
? floorHeights[floorOrder] |
||||
|
: floor.floorHeight; |
||||
|
} |
||||
|
getBoxHeightByFloorOrder(floorOrder) { |
||||
|
const { groups } = this; |
||||
|
const floor = groups[floorOrder]; |
||||
|
return floor.boxHeight; |
||||
|
} |
||||
|
getNavIconY(floorOrder) { |
||||
|
const { groups } = this; |
||||
|
const floor = groups[floorOrder]; |
||||
|
if (!floor) return this.getNavIconY(this.floorOrder); |
||||
|
const boxHeight = this.getBoxHeightByFloorOrder(floorOrder); |
||||
|
const radius = PathLine.getPathLineRadius(this, floor); |
||||
|
return boxHeight + radius * 5; |
||||
|
} |
||||
|
} |
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 596 B |
|
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,64 @@ |
|||||
|
/* |
||||
|
@ author: leeenx |
||||
|
@ 事件封装 |
||||
|
@ object.on(event, fn) // 监听一个事件
|
||||
|
@ object.off(event, fn) // 取消监听
|
||||
|
@ object.once(event, fn) // 只监听一次事件
|
||||
|
@ object.dispacth(event, arg) // 触发一个事件
|
||||
|
*/ |
||||
|
|
||||
|
export default class Events { |
||||
|
constructor() { |
||||
|
// 定义的事件与回调
|
||||
|
this.defineEvent = {}; |
||||
|
} |
||||
|
// 注册事件
|
||||
|
register(event, cb) { |
||||
|
if (!this.defineEvent[event]) { |
||||
|
this.defineEvent[event] = [cb]; |
||||
|
} else { |
||||
|
this.defineEvent[event].push(cb); |
||||
|
} |
||||
|
} |
||||
|
// 派遣事件
|
||||
|
dispatch(event, arg) { |
||||
|
if (this.defineEvent[event]) { |
||||
|
{ |
||||
|
for (let i = 0, len = this.defineEvent[event].length; i < len; ++i) { |
||||
|
this.defineEvent[event][i] && this.defineEvent[event][i](arg); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// on 监听
|
||||
|
on(event, cb) { |
||||
|
return this.register(event, cb); |
||||
|
} |
||||
|
// off 方法
|
||||
|
off(event, cb) { |
||||
|
if (this.defineEvent[event]) { |
||||
|
if (typeof cb == "undefined") { |
||||
|
delete this.defineEvent[event]; // 表示全部删除
|
||||
|
} else { |
||||
|
// 遍历查找
|
||||
|
for (let i = 0, len = this.defineEvent[event].length; i < len; ++i) { |
||||
|
if (cb == this.defineEvent[event][i]) { |
||||
|
this.defineEvent[event][i] = null; // 标记为空 - 防止dispath 长度变化
|
||||
|
// 延时删除对应事件
|
||||
|
setTimeout(() => this.defineEvent[event].splice(i, 1), 0); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// once 方法,监听一次
|
||||
|
once(event, cb) { |
||||
|
let onceCb = () => { |
||||
|
cb && cb(); |
||||
|
this.off(event, onceCb); |
||||
|
}; |
||||
|
this.register(event, onceCb); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,112 @@ |
|||||
|
import MAPAPP, { minScale, maxScale } from "./MAPAPP"; |
||||
|
let map = null; |
||||
|
let initScale = 1; |
||||
|
Component({ |
||||
|
/** |
||||
|
* 组件的属性列表 |
||||
|
*/ |
||||
|
properties: { |
||||
|
floororder: Number, |
||||
|
hidden: Boolean, |
||||
|
loc: Array, |
||||
|
searchType: Number, |
||||
|
}, |
||||
|
data: { |
||||
|
loaded: false, |
||||
|
dpr: wx.getSystemInfoSync().pixelRatio, |
||||
|
shops: [], |
||||
|
floors: [], |
||||
|
pageHidden: false, |
||||
|
sliderValue: 0, |
||||
|
}, |
||||
|
observers: { |
||||
|
hidden(val) { |
||||
|
if (val) { |
||||
|
wx.stopCompass({ fail: console.log }); |
||||
|
if (map) { |
||||
|
map.shown = false; |
||||
|
} |
||||
|
} else { |
||||
|
wx.startCompass({ fail: console.log }); |
||||
|
if (map) { |
||||
|
map.shown = true; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
floororder(num) { |
||||
|
if (map && num !== null && num !== undefined && this.data.loaded) |
||||
|
map.changeFloor(num); |
||||
|
}, |
||||
|
loc([x, y]) { |
||||
|
if (map) { |
||||
|
const crossPoint = map.cross({ x, y }); |
||||
|
map.setXY(crossPoint.x, crossPoint.y); |
||||
|
try { |
||||
|
const { name } = map.getNearestPoint({ |
||||
|
x, |
||||
|
z: y, |
||||
|
floorOrder: this.data.floororder, |
||||
|
}); |
||||
|
this.triggerEvent("point", name); |
||||
|
} catch (error) { |
||||
|
console.log(error); |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
lifetimes: { |
||||
|
attached() {}, |
||||
|
detached() { |
||||
|
console.log("map2d detached"); |
||||
|
map.dispose(); |
||||
|
map = null; |
||||
|
}, |
||||
|
ready() { |
||||
|
this.createSelectorQuery() |
||||
|
.select(".map2d") |
||||
|
.fields({ |
||||
|
node: true, |
||||
|
size: true, |
||||
|
}) |
||||
|
.exec((res) => { |
||||
|
map = new MAPAPP(res[0], this); |
||||
|
initScale = map.scale; |
||||
|
this.setData({ |
||||
|
floors: map.mall.floors, |
||||
|
sceneIndex: map.mall.groundFloorIndex, |
||||
|
}); |
||||
|
map.on("loaded", (map) => { |
||||
|
this.setData({ loaded: true }); |
||||
|
if (typeof this.data.floororder === "number") |
||||
|
map.changeFloor(this.data.floororder); |
||||
|
this.triggerEvent("map", map); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
moved: function () {}, |
||||
|
}, |
||||
|
pageLifetimes: { |
||||
|
hide() { |
||||
|
this.setData({ pageHidden: true }); |
||||
|
}, |
||||
|
show() { |
||||
|
this.setData({ pageHidden: false }); |
||||
|
}, |
||||
|
}, |
||||
|
methods: { |
||||
|
handlePinch(e) { |
||||
|
if (map) { |
||||
|
let newScale = initScale * e.detail.zoom; |
||||
|
newScale = Math.max(minScale, newScale); |
||||
|
newScale = Math.min(maxScale, newScale); |
||||
|
map.scale = newScale; |
||||
|
} |
||||
|
}, |
||||
|
handleMultitouchstart() { |
||||
|
initScale = map.scale; |
||||
|
}, |
||||
|
handleTap() { |
||||
|
this.triggerEvent("exit"); |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"component": true, |
||||
|
"usingComponents": { |
||||
|
"gesture": "/pages/gesture/gesture" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
<view class="map2d-wrapper {{hidden?'hidden':''}}"> |
||||
|
<gesture bindpinch="handlePinch" propagation="{{false}}" bindmultipointStart="handleMultitouchstart"> |
||||
|
<canvas id="map2d" class="map2d" type="2d"></canvas> |
||||
|
</gesture> |
||||
|
<image class="exit" src="./close.png" bindtap="handleTap"></image> |
||||
|
</view> |
||||
@ -0,0 +1,35 @@ |
|||||
|
.map2d-wrapper { |
||||
|
position: fixed; |
||||
|
bottom: 116px; |
||||
|
left: 10px; |
||||
|
right: 10px; |
||||
|
height: 210px; |
||||
|
border-radius: 18px 18px 0 0; |
||||
|
overflow: hidden; |
||||
|
background: #fff; |
||||
|
z-index: 12 !important; |
||||
|
} |
||||
|
|
||||
|
.map2d-wrapper.hidden { |
||||
|
bottom: -99999999px; |
||||
|
} |
||||
|
|
||||
|
.map2d { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
width: calc(100vw - 20px); |
||||
|
height: 210px; |
||||
|
z-index: 1; |
||||
|
} |
||||
|
.map2d-wrapper > .exit { |
||||
|
z-index: 2; |
||||
|
position: absolute; |
||||
|
top: 16px; |
||||
|
left: auto; |
||||
|
right: 16px; |
||||
|
width: 24px; |
||||
|
height: 24px; |
||||
|
} |
||||
|
After Width: | Height: | Size: 2.8 KiB |
@ -0,0 +1,31 @@ |
|||||
|
export const get = (url) => |
||||
|
new Promise((resolve) => { |
||||
|
wx.request({ |
||||
|
url, |
||||
|
success({ data }) { |
||||
|
resolve(data); |
||||
|
}, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
export const getCrossPoint = (point, point1, point2) => { |
||||
|
const cross = |
||||
|
(point2.x - point1.x) * (point.x - point1.x) + |
||||
|
(point2.y - point1.y) * (point.y - point1.y); |
||||
|
|
||||
|
if (cross <= 0) return point1; |
||||
|
|
||||
|
const d2 = |
||||
|
(point2.x - point1.x) * (point2.x - point1.x) + |
||||
|
(point2.y - point1.y) * (point2.y - point1.y); |
||||
|
|
||||
|
if (cross >= d2) return point2; |
||||
|
|
||||
|
const r = cross / d2; |
||||
|
|
||||
|
const px = point1.x + (point2.x - point1.x) * r; |
||||
|
const py = point1.y + (point2.y - point1.y) * r; |
||||
|
|
||||
|
return { x: px, y: py }; |
||||
|
}; |
||||
|
After Width: | Height: | Size: 865 B |
|
After Width: | Height: | Size: 596 B |
@ -0,0 +1,14 @@ |
|||||
|
Component({ |
||||
|
properties: { |
||||
|
icon: String, |
||||
|
t1: String, |
||||
|
t2: String, |
||||
|
end: Boolean, |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
handleTap() { |
||||
|
this.triggerEvent("exit"); |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
@ -0,0 +1,4 @@ |
|||||
|
{ |
||||
|
"component": true, |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
<view class="nav"> |
||||
|
<image mode="aspectFit" src="{{icon}}"></image> |
||||
|
<view class="t1">{{end?'已到达': t1}}</view> |
||||
|
<text class="t2">{{end?'': t2}}</text> |
||||
|
<image class="exit" src="./close.png" bindtap="handleTap"></image> |
||||
|
</view> |
||||
@ -0,0 +1,123 @@ |
|||||
|
.nav { |
||||
|
position: fixed; |
||||
|
height: 110px; |
||||
|
left: 10px; |
||||
|
right: 10px; |
||||
|
bottom: 116px; |
||||
|
background: #ffffff; |
||||
|
z-index: 12 !important; |
||||
|
border-radius: 18px 18px 0 0; |
||||
|
} |
||||
|
.nav > image { |
||||
|
position: absolute; |
||||
|
top: 14px; |
||||
|
left: 14px; |
||||
|
width: 80px; |
||||
|
height: 80px; |
||||
|
padding: 4px; |
||||
|
} |
||||
|
.nav > .t1 { |
||||
|
position: absolute; |
||||
|
top: 20px; |
||||
|
left: 108px; |
||||
|
right: 40px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 600; |
||||
|
font-size: 24px; |
||||
|
line-height: 34px; |
||||
|
color: #323337; |
||||
|
white-space: nowrap; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
} |
||||
|
.nav > .t2 { |
||||
|
position: absolute; |
||||
|
top: 65px; |
||||
|
left: 108px; |
||||
|
right: 10px; |
||||
|
font-family: PingFang SC; |
||||
|
font-style: normal; |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
color: #a1a5b3; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.nav > .t2 > .val { |
||||
|
font-family: DINPro; |
||||
|
font-style: normal; |
||||
|
font-weight: normal; |
||||
|
font-size: 18px; |
||||
|
line-height: 23px; |
||||
|
color: #7a7e8d; |
||||
|
margin: 0 4px; |
||||
|
} |
||||
|
.nav > .exit { |
||||
|
position: absolute; |
||||
|
top: 16px; |
||||
|
left: auto; |
||||
|
right: 16px; |
||||
|
width: 24px; |
||||
|
height: 24px; |
||||
|
} |
||||
|
.progress { |
||||
|
position: absolute; |
||||
|
left: 20px; |
||||
|
right: 20px; |
||||
|
bottom: 10px; |
||||
|
height: 2px; |
||||
|
background: #eee9de; |
||||
|
border-radius: 5px; |
||||
|
z-index: 1; |
||||
|
} |
||||
|
.bar { |
||||
|
position: absolute; |
||||
|
left: 20px; |
||||
|
right: 20px; |
||||
|
bottom: 10px; |
||||
|
height: 2px; |
||||
|
background: #ffdb00; |
||||
|
border-radius: 5px; |
||||
|
z-index: 2; |
||||
|
} |
||||
|
.thumb { |
||||
|
position: absolute; |
||||
|
width: 12px; |
||||
|
height: 12px; |
||||
|
bottom: 5px; |
||||
|
border-radius: 50%; |
||||
|
border: 2px solid rgba(239, 150, 23, 0.5); |
||||
|
background: #fff; |
||||
|
z-index: 3; |
||||
|
transform: translate(-50%, 0); |
||||
|
} |
||||
|
.bubble { |
||||
|
position: absolute; |
||||
|
width: 34px; |
||||
|
height: 14px; |
||||
|
bottom: 18px; |
||||
|
transform: translate(-50%, 0); |
||||
|
} |
||||
|
.bubble image { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
width: 34px; |
||||
|
height: 14px; |
||||
|
z-index: 0; |
||||
|
} |
||||
|
.bubble view { |
||||
|
position: absolute; |
||||
|
top: 1px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
z-index: 1; |
||||
|
text-align: center; |
||||
|
font-style: normal; |
||||
|
font-weight: 900; |
||||
|
font-size: 8px; |
||||
|
line-height: 11px; |
||||
|
color: #6a6665; |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
// pages/privacy/index.js
|
||||
|
Page({ |
||||
|
|
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad(options) { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady() { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow() { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide() { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload() { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh() { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom() { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage() { |
||||
|
|
||||
|
} |
||||
|
}) |
||||
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
<text class="content" user-select>隐私政策 |
||||
|
</text> |
||||