@ -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> |
|||