You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6623 lines
214 KiB
6623 lines
214 KiB
var Map_QM, elevator, straight, renderFrame, elevatorDown, deviceJSON, man_3d, man_2d, _indexPathFloor = 0, clock = new THREE.Clock();
|
|
var outTime = -1, oTime = -1, language = "cn", deviceShow = false, iconNameShow = false; //deviceShow 设备图标是否显示 iconNameShow--图标名称是否显示
|
|
var isPathPlay = true, basePath = "", graphPath = "", ftPath = "", dtPath = "", facAllArr = []; //basePath 基础路径 graphPath最佳路径 ftPath 扶梯路径 dtPath 电梯路径
|
|
var cameraPerspective, cameraOrtho, aspect, isPathState = false, pathCameraState = "2D"; //isPathState--导航状态
|
|
|
|
|
|
ConfigFun = function () {
|
|
this.shopServerInfo = "./static/offline/JSON/QueryShopList.json";
|
|
this.mapServerInfo = "./static/offline/JSON/GetMapInfo.json";
|
|
this.imgUrl = "http://1000my.com/MallSite";
|
|
this.playSpeed = 10; //动画播放速度
|
|
this.collision = true; //是否支持名称的碰撞检测
|
|
this.selectBuild = 0;
|
|
this.selectFloor = 0;
|
|
this.showModelIcon = false; //电梯扶梯是否显示3D模型 true 模型 false 图标
|
|
this.deviceObj = {}; //angle --- 设备旋转角度 node ---- 设备导航点位 floor --- 设备楼层
|
|
this.startObj = {}; // 导航起点;
|
|
this.overObj = {}; //导航结束点
|
|
this.otherPath = null; //人为干预的路线
|
|
this.distance = 6000; //楼栋间距
|
|
this.mapDistance = { min: 100, max: 1000 }; //限制地图缩放
|
|
this.tubeMaterial = new THREE.MeshPhongMaterial({ color: 0xB47834, transparent: true, opacity: 0.6 }); //路径材质
|
|
this.cameraDist = { x: 0, y: 220, z: 220, state: "3D" }; //相机坐标 state---2D 平面 3D 立体
|
|
this.sceneGap = { x: 0, y: 0, z: 0, scale: 0.1 }; //改变地图位置,大小
|
|
this.cameraZoom = 2; //设置我的方向状态地图放大倍数;
|
|
this.perc_H = "-50%"; //弹窗的偏移百分比17 或者像素
|
|
this.doubleDist = 400; //双叠层状态下楼层的间距
|
|
this.overlap = false; //是否叠层
|
|
this.mapScale = 18; //地图比例尺
|
|
this.angleRadius = 2; //圆角半径 大于2 则店铺box显示圆角
|
|
this.buildHeight = 5;
|
|
this.shopHeight = 50; //店铺高度
|
|
//服务icon 英文配置
|
|
this.iconEn = { "洗手间": "Toilets", "停车场": "Parking", "电梯": "Lift", "扶梯": "Escalator", "母婴室": "Baby care room", "服务台": "service desk" };
|
|
this.modelArr = []; //一直显示不隐藏
|
|
//标签数据 click --是否可点击
|
|
this.labelIconArr = [];
|
|
this.spriteMaterialArr = [];
|
|
this.lineBasicMaterialArr = [];
|
|
this.meshMaterialArr = [];
|
|
this.shopData = []; //店铺数据
|
|
this.allMap = [];
|
|
/*** ------------------------------------------------ 参数 API START ------------------------------------------------- */
|
|
/**
|
|
* @api {方法} setModelState() 模型显示状态
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 设置模型显示状态 默认 3d
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {String} state 传入状态 2d 或 3d
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setModelState("3d");
|
|
*/
|
|
|
|
this.setModelState = function (state = "3d") { //设置模型显示状态 2d 3d
|
|
if (Map_QM) {
|
|
Map_QM.renderer.clear();
|
|
Map_QM.changeIconState(state);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @api {方法} setIconNameShow() 设施名称显隐
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 设置设施名称显示或隐藏
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {boolean} isShow 是否显示 true显示 false隐藏
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {boolean} 请求示例
|
|
*
|
|
* Config.setIconNameShow(true);
|
|
*/
|
|
this.setIconNameShow = function (isShow) {
|
|
iconNameShow = isShow;
|
|
}
|
|
/**
|
|
* @api {方法} setPlaySpeed() 改变导航速度
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 改变导航播放速度,范围 2-20 默认是6
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} speed 播放速度
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setPlaySpeed(8);
|
|
*/
|
|
this.setPlaySpeed = function (sp) {
|
|
this.playSpeed = parseInt(sp);
|
|
}
|
|
//设置弹窗偏离位置 默认 -50% 范围 -100% 100%
|
|
this.setPercH = function (perc = "-50%") {
|
|
this.perc_H = perc;
|
|
}
|
|
/**
|
|
* @api {方法} setDeviceShow() 设备显示状态
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 设置设备的显示状态 默认false
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {boolean} value 是否显示
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {boolean} 请求示例
|
|
*
|
|
* Config.setDeviceShow(true);
|
|
*/
|
|
this.setDeviceShow = function (value) {
|
|
deviceShow = value;
|
|
}
|
|
//
|
|
/**
|
|
* @api {方法} setCollision() 设置碰撞检测
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 设置box名称是否支持碰撞检测 默认支持
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {boolean} value 是否支持
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setCollision(true);
|
|
*/
|
|
this.setCollision = function (value) {
|
|
this.collision = value;
|
|
}
|
|
/**
|
|
* @api {方法} setShowModelIcon() 公共设施模型
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 设置公共设施模型效果 true 3D模型 false icon显示
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {boolean} value 显示状态
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setShowModelIcon(true);
|
|
*/
|
|
this.setShowModelIcon = function (value) {
|
|
this.showModelIcon = value;
|
|
}
|
|
/**
|
|
* @api {方法} setSceneGap() 地图模型展示
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 设置公共设施模型效果 x/y/z 模型中心点位置
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {Number} x 水平方向位置,负数左移,正数右移
|
|
* @apiParam {Number} y 垂直方向位置,负数下移,正数上移
|
|
* @apiParam {Number} z 远近位置,默认为0
|
|
* @apiParam {Number} scale 缩放默认为0.1
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setSceneGap({x:0,y:0,z:0,scale:0.1});
|
|
*/
|
|
this.setSceneGap = function (value) {
|
|
this.sceneGap = value;
|
|
}
|
|
|
|
//设置其它可行路径
|
|
this.setOtherPath = function (value) {
|
|
this.otherPath = value;
|
|
}
|
|
/**
|
|
* @api {方法} setSceneGapInit() 地图初始参数
|
|
* @apiGroup 地图数据
|
|
* @apiDescription 设置地图初始位置、大小
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} x X轴上位移
|
|
* @apiParam {int} y Y轴上位移
|
|
* @apiParam {int} z Z轴上位移
|
|
* @apiParam {Number} scale 地图缩放比例
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setSceneGapInit({x:-100,y:0,z:0,scale:0.1});
|
|
*/
|
|
this.setSceneGapInit = function (value) {
|
|
this.sceneGap = value;
|
|
}
|
|
//
|
|
/**
|
|
* @api {方法} setLabelIconArr() 设置外部标签
|
|
* @apiGroup 地图数据
|
|
* @apiDescription 设置外部标签
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {Array} value 标签数组
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setLabelIconArr(true);
|
|
*/
|
|
this.setLabelIconArr = function (value) {
|
|
this.labelIconArr = value;
|
|
}
|
|
/**
|
|
* @api {方法} setModelArr() 设置外部模型
|
|
* @apiGroup 地图数据
|
|
* @apiDescription 设置外部模型
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {Array} value 模型数组
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.setModelArr({floor:0,url:'./static/img/model/yj.gltf',list:[{site:{x :0, y :0, z :0}, rot:{x :1.5708, y :0, z :0}, size:{x :1, y :1, z :1}} ]});
|
|
*/
|
|
this.setModelArr = function (value) {
|
|
this.modelArr = value;
|
|
}
|
|
/**
|
|
* @api {方法} getInstance() 初始化方法
|
|
* @apiGroup 地图数据
|
|
* @apiDescription 地图数据初始化 (可重复调用)
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {Function} callBack 回调函数
|
|
* @apiParam {int} build 导航起点楼栋编号
|
|
* @apiParam {int} floor 导航起点楼层编号
|
|
* @apiParam {int} navPoint 导航起点点位编号 传 -1 不显示起点
|
|
* @apiParam {int} angle 导航起点初始角度
|
|
* @apiParam {String} mallCode 商场Code (可选)
|
|
* @apiParam {String} _url 云地址 (可选)
|
|
*
|
|
* @apiSampleRequest off
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Config.getInstance(,0,1,1,0,"993f60c6-fef5-4999-9c3e-a4f71eb48364","http://122.112.233.82/mall");
|
|
*
|
|
* @apiSuccess {int} code 状态码 200-正常;404-地图无法显示;500-地图关联数据错误
|
|
* @apiSuccess {String} msg 状态提示信息
|
|
* @apiSuccess {Array} data 返回楼层数据
|
|
* @apiSuccessExample {json} success-example
|
|
* {
|
|
* "code": 200,
|
|
* "msg": "加载成功"
|
|
* "data": []
|
|
* }
|
|
*/
|
|
this.getInstance = function (callBack, build = 0, floor = 0, navPoint = 1, angle = 0, mallCode = "", _url = "http://saas.1000my.com:8013") {
|
|
Config.startObj.build = Config.deviceObj.build = parseInt(build) || 0;
|
|
Config.startObj.floor = Config.deviceObj.floor = parseInt(floor) || 0;
|
|
Config.startObj.node = Config.deviceObj.node = parseInt(navPoint) || 1;
|
|
Config.deviceObj.angle = parseInt(angle) || 0;
|
|
Config.selectFloor = Config.deviceObj.floor;
|
|
Config.selectBuild = Config.deviceObj.build;
|
|
let backObj = { code: 200, msg: "加载成功", data: [] };
|
|
if (mallCode != "") {
|
|
let tim = Config.timeStamp();
|
|
let token = encodeURIComponent(Config.encrypt("/api/CDN/GetMapInfo" + tim));
|
|
Config.requestNoJM({
|
|
method: "POST",
|
|
data: JSON.stringify({ "mallCode": mallCode, "key": "Zeditor" }),
|
|
url: _url + '/api/CDN/GetMapInfo?token=' + token + '&time=' + tim,
|
|
success: (res) => {
|
|
if (res.code == "200" && res.data) {
|
|
try {
|
|
Config.allMap = JSON.parse(LZString.decompressFromBase64(res.data.mapData));
|
|
} catch (e) {
|
|
backObj.code = 404;
|
|
backObj.msg = "地图数据JSON格式错误";
|
|
}
|
|
//console.log(Config.allMap);
|
|
tim = Config.timeStamp();
|
|
token = encodeURIComponent(Config.encrypt("/api/Shop/QueryShopListForMap" + tim));
|
|
let param = Config.encrypt(JSON.stringify({ "mallCode": mallCode, "BuildingOrder": build }));
|
|
Config.request({
|
|
method: "POST",
|
|
data: param,
|
|
url: _url + '/api/Shop/QueryShopListForMap?token=' + token + '&time=' + tim,
|
|
success: (res) => {
|
|
if (res.code == "200") {
|
|
Config.shopData = [];
|
|
if (Array.isArray(res.data)) {
|
|
for (let i = 0; i < res.data.length; i++) {
|
|
for (let n = 0; n < res.data[i].shopList.length; n++) {
|
|
res.data[i].shopList[n].buildingOrder = build;
|
|
Config.shopData.push(res.data[i].shopList[n]);
|
|
}
|
|
}
|
|
//console.log(Config.shopData)
|
|
} else {
|
|
backObj.code = 500;
|
|
backObj.msg = "店铺数据解析失败";
|
|
}
|
|
} else {
|
|
backObj.code = 500;
|
|
backObj.msg = "店铺数据解析失败";
|
|
}
|
|
tim3 = Config.timeStamp();
|
|
token3 = encodeURIComponent(Config.encrypt("/api/CDN/DeviceListForMap" + tim3));
|
|
let param3 = Config.encrypt(JSON.stringify({ "mallCode": mallCode }));
|
|
Config.request({
|
|
method: "POST",
|
|
data: param3,
|
|
url: _url + '/api/CDN/DeviceListForMap?token=' + token3 + '&time=' + tim3,
|
|
success: (res) => {
|
|
if (res.code == "200") {
|
|
deviceJSON = res.data;
|
|
if (deviceJSON.length == 0) {
|
|
backObj.code = 500;
|
|
backObj.msg = "无设备数据";
|
|
}
|
|
} else {
|
|
backObj.code = 500;
|
|
backObj.msg = "设备数据获取失败";
|
|
}
|
|
console.log(deviceJSON);
|
|
try {
|
|
if(!Map_QM){
|
|
Map_QM = new MainMap_QM(callBack, backObj);
|
|
Map_QM.initBuild();
|
|
}else{
|
|
Map_QM.callBackLoadOver = callBack;
|
|
Map_QM.backObj = backObj;
|
|
Map_QM.loaderOver();
|
|
}
|
|
} catch (e) {
|
|
backObj.code = 404;
|
|
backObj.msg = "地图数据解析失败";
|
|
}
|
|
if (backObj.code == 404) {
|
|
callBack(backObj);
|
|
callBack = null;
|
|
}
|
|
},
|
|
fail: () => {
|
|
backObj.code = 500;
|
|
backObj.msg = "设备数据获取失败";
|
|
try {
|
|
if(!Map_QM){
|
|
Map_QM = new MainMap_QM(callBack, backObj);
|
|
Map_QM.initBuild();
|
|
}else{
|
|
Map_QM.callBackLoadOver = callBack;
|
|
Map_QM.backObj = backObj;
|
|
Map_QM.loaderOver();
|
|
}
|
|
} catch (e) {
|
|
backObj.code = 404;
|
|
backObj.msg = "地图数据解析失败";
|
|
}
|
|
if (backObj.code == 404) {
|
|
callBack(backObj);
|
|
callBack = null;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
fail: () => {
|
|
try {
|
|
if(!Map_QM){
|
|
Map_QM = new MainMap_QM(callBack, backObj);
|
|
Map_QM.initBuild();
|
|
}else{
|
|
Map_QM.callBackLoadOver = callBack;
|
|
Map_QM.backObj = backObj;
|
|
Map_QM.loaderOver();
|
|
}
|
|
} catch (e) {
|
|
backObj.code = 404;
|
|
backObj.msg = "地图数据解析失败";
|
|
}
|
|
if (backObj.code == 404) {
|
|
callBack(backObj);
|
|
callBack = null;
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
backObj.code = 404;
|
|
backObj.msg = "地图数据获取失败";
|
|
callBack(backObj)
|
|
callBack = null;
|
|
return;
|
|
}
|
|
},
|
|
fail: () => {
|
|
backObj.code = 404;
|
|
backObj.msg = "地图数据获取失败";
|
|
callBack(backObj)
|
|
callBack = null;
|
|
}
|
|
});
|
|
} else {
|
|
this.readTextFile(Config.mapServerInfo, function (res) {
|
|
try {
|
|
if (res.data.mallKey != "Zeditor") {
|
|
Config.allMap = JSON.parse(res.data.mapData);
|
|
} else {
|
|
Config.allMap = JSON.parse(LZString.decompressFromBase64(res.data.mapData));
|
|
}
|
|
} catch (e) {
|
|
backObj.code = 404;
|
|
backObj.msg = "地图数据JSON格式错误";
|
|
callBack(backObj)
|
|
callBack = null;
|
|
}
|
|
//console.log(Config.allMap);
|
|
Config.getShopData(callBack);
|
|
});
|
|
}
|
|
}
|
|
/*** ----------------------------------------------- 参数 API END ----------------------------------------------- **** */
|
|
this.Point = function (x = 0, y = 0) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
this.WallLine = function (start, end) {
|
|
this.start = start; //起始点位
|
|
this.end = end; //结束点位
|
|
this.leftParLine; //左侧平行线段
|
|
this.rightParLine; //右侧平行线段
|
|
this.leftPoint; //左侧平行线交点
|
|
this.rightPoint; //右侧平行线交点
|
|
}
|
|
|
|
/**
|
|
* 检测点是否在多边形区域内
|
|
*/
|
|
this.checkBoundary = function (p, ptPolygon) {
|
|
// 判断边界方法
|
|
let nCount = ptPolygon.length;
|
|
let nCross = 0;
|
|
for (let i = 0; i < nCount; i++) {
|
|
let p1 = ptPolygon[i]; //当前节点
|
|
let p2 = ptPolygon[(i + 1) % nCount]; //下一个节点
|
|
// 求解 y=p.y 与 p1p2 的交点
|
|
if (p1.y == p2.y) // p1p2 与 y=p0.y平行
|
|
continue;
|
|
if (p.y < Math.min(p1.y, p2.y)) // 交点在p1p2延长线上
|
|
continue;
|
|
if (p.y >= Math.max(p1.y, p2.y)) // 交点在p1p2延长线上
|
|
continue;
|
|
// 从P发射一条水平射线 求交点的 X 坐标 ------原理: ((p2.y-p1.y)/(p2.x-p1.x))=((y-p1.y)/(x-p1.x))
|
|
//直线k值相等 交点y=p.y
|
|
let x = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
|
|
if (x > p.x)
|
|
nCross++; // 只统计单边交点
|
|
}
|
|
// 单边交点为偶数,点在多边形之外 ---
|
|
return (nCross % 2 == 1);
|
|
}
|
|
|
|
this.request = function (params) {
|
|
params.method = params.method || 'GET';
|
|
let xmlhttp = new XMLHttpRequest();
|
|
xmlhttp.onreadystatechange = function () {
|
|
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
|
|
////console.log(xmlhttp.responseText);
|
|
let data = Config.decrypt(xmlhttp.responseText);
|
|
let jsonObject = JSON.parse(data);
|
|
params.success(jsonObject);
|
|
}
|
|
if (xmlhttp.readyState === 4 && (xmlhttp.status === 404 || xmlhttp.status === 405)) {
|
|
params.fail();
|
|
}
|
|
};
|
|
xmlhttp.onerror = function (e) {
|
|
params.fail();
|
|
};
|
|
xmlhttp.open(params.method, params.url, true);
|
|
xmlhttp.setRequestHeader("Access-Control-Allow-Origin", "*");
|
|
xmlhttp.setRequestHeader("Content-type", "application/json");
|
|
xmlhttp.setRequestHeader("Access-Control-Allow-Method", "POST,GET");
|
|
xmlhttp.send(params.data);
|
|
}
|
|
this.requestNoJM = function (params) {
|
|
params.method = params.method || 'GET';
|
|
let xmlhttp = new XMLHttpRequest();
|
|
xmlhttp.onreadystatechange = function () {
|
|
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
|
|
let jsonObject;
|
|
try {
|
|
jsonObject = JSON.parse(xmlhttp.responseText);
|
|
} catch (e) {
|
|
params.fail();
|
|
return;
|
|
}
|
|
params.success(jsonObject);
|
|
}
|
|
if (xmlhttp.readyState === 4 && (xmlhttp.status === 404 || xmlhttp.status === 405)) {
|
|
params.fail();
|
|
}
|
|
};
|
|
xmlhttp.onerror = function (e) {
|
|
params.fail();
|
|
};
|
|
xmlhttp.open(params.method, params.url, true);
|
|
xmlhttp.setRequestHeader("Access-Control-Allow-Origin", "*");
|
|
xmlhttp.setRequestHeader("Content-type", "application/json");
|
|
xmlhttp.setRequestHeader("Access-Control-Allow-Method", "POST,GET");
|
|
xmlhttp.send(params.data);
|
|
}
|
|
|
|
//加密
|
|
this.encrypt = function (word, keyStr) {
|
|
keyStr = keyStr ? keyStr : "0123456789QMSaas";
|
|
var key = CryptoJS.enc.Utf8.parse(keyStr); //Latin1 w8m31+Yy/Nw6thPsMpO5fg==
|
|
var srcs = CryptoJS.enc.Utf8.parse(word);
|
|
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
|
|
mode: CryptoJS.mode.ECB,
|
|
padding: CryptoJS.pad.Pkcs7
|
|
});
|
|
return encrypted.toString();
|
|
}
|
|
//解密
|
|
this.decrypt = function (word, keyStr) {
|
|
keyStr = keyStr ? keyStr : "0123456789QMSaas";
|
|
var key = CryptoJS.enc.Utf8.parse(keyStr); //Latin1 w8m31+Yy/Nw6thPsMpO5fg==
|
|
var decrypt = CryptoJS.AES.decrypt(word, key, {
|
|
mode: CryptoJS.mode.ECB,
|
|
padding: CryptoJS.pad.Pkcs7
|
|
});
|
|
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
|
|
}
|
|
|
|
this.timeStamp = function () {
|
|
return parseInt(new Date().getTime() / 1000);
|
|
}
|
|
|
|
this.readTextFile = function (file, callback) {
|
|
let rawFile = new XMLHttpRequest();
|
|
rawFile.overrideMimeType("application/json");
|
|
rawFile.open("GET", file, true);
|
|
rawFile.onreadystatechange = function () {
|
|
if (rawFile.readyState === 4 && rawFile.status == 200) {
|
|
try {
|
|
let jsonObject = JSON.parse(rawFile.response);
|
|
callback(jsonObject);
|
|
} catch (e) {
|
|
//console.log(e);
|
|
}
|
|
}
|
|
}
|
|
rawFile.onerror = function () {
|
|
callBack(null);
|
|
}
|
|
rawFile.send(null);
|
|
}
|
|
|
|
//判断点是fou顺时针
|
|
this.isClockwise = function (polygon) {
|
|
let len = polygon.length;
|
|
let su = 0, ni = 0;
|
|
for (let i = 0; i < len; i++) {
|
|
let p = polygon[i];
|
|
let p1 = polygon[i == 0 ? len - 1 : i - 1];
|
|
let p2 = polygon[i == len - 1 ? 0 : i + 1];
|
|
let vx1 = p1.x - p.x;
|
|
let vy1 = p1.y - p.y;
|
|
let vx2 = p2.x - p.x;
|
|
let vy2 = p2.y - p.y;
|
|
// 负值多是顺时针,正值多是逆时针
|
|
if (((vx1 * vy2) + (-1 * vy1 * vx2)) < 0) {
|
|
su++;
|
|
} else {
|
|
ni++;
|
|
}
|
|
return su > ni;
|
|
}
|
|
}
|
|
|
|
this.blocked = (dom, checkList, cfloor) => {
|
|
const { top, left, right, bottom } = dom.getBoundingClientRect();
|
|
let corners = [
|
|
[left, top],
|
|
[right, top],
|
|
[left, bottom],
|
|
[right, bottom]
|
|
];
|
|
|
|
for (let i = 0; i < corners.length; i++) {
|
|
const [x, y] = corners[i];
|
|
const raycaster = new THREE.Raycaster();
|
|
const p = new THREE.Vector2();
|
|
let ele = document.getElementById("mapContainer");
|
|
p.x = (x / parseInt(ele.clientWidth)) * 2 - 1;
|
|
p.y = -(y / parseInt(ele.clientHeight)) * 2 + 1;
|
|
|
|
raycaster.setFromCamera(p, Map_QM.camera);
|
|
let intersects = raycaster.intersectObjects(checkList);
|
|
for (let t = 0; t < intersects.length; t++) {
|
|
if (intersects[t].object.userData.order > cfloor) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**碰撞检测
|
|
* 传入A中心点和A的宽、高
|
|
* B的中心点和B的宽、高
|
|
*/
|
|
this.isCollision = function (A, aW, aH, B, bW, bH) {
|
|
let noCol = false;
|
|
if (Math.abs(A.x - B.x) < (aW + bW) / 2 + 20 && Math.abs(A.y - B.y) < (aH + bH) / 2 + 10) {
|
|
noCol = true;
|
|
}
|
|
return noCol;
|
|
}
|
|
this.changeParkToString = function (area) {
|
|
let areaArr = [];
|
|
for (let i = 0; i < area.hasLines.length; i++) {
|
|
let line = area.hasLines[i];
|
|
let array = [];
|
|
array.push(line.startPoint.x, line.startPoint.y, line.endPoint.x, line.endPoint.y);
|
|
areaArr.push(array);
|
|
}
|
|
return areaArr;
|
|
}
|
|
this.changeAreaToString = function (area) {
|
|
let areaArr = [];
|
|
for (let i = 0; i < area.hasLines.length; i++) {
|
|
let line = area.hasLines[i];
|
|
let array = [];
|
|
if (line.isStrLine) {
|
|
array.push(line.startPoint.x, line.startPoint.y, line.endPoint.x, line.endPoint.y);
|
|
} else {
|
|
array.push(line.startPoint.x, line.startPoint.y, line.ctrlPoint1.x, line.ctrlPoint1.y, line.ctrlPoint2.x, line.ctrlPoint2.y, line.endPoint.x, line.endPoint.y);
|
|
}
|
|
areaArr.push(array);
|
|
}
|
|
return areaArr;
|
|
}
|
|
this.changeWallToString = function (area) {
|
|
let areaArr = [];
|
|
let points = Config.getWallPoints(area.pathPoints, area.thick);
|
|
for (let i = 0; i < points.length; i++) {
|
|
let array = [];
|
|
let pend = i == points.length - 1 ? points[0] : points[i + 1];
|
|
array.push(points[i].x, points[i].y, pend.x, pend.y);
|
|
areaArr.push(array);
|
|
}
|
|
return areaArr;
|
|
}
|
|
|
|
|
|
this.QM_Line_Father = function (sPoint, ePoint, ctrlPoint1, ctrlPoint2, isStrLine) {
|
|
this.startPoint = sPoint; //起始点
|
|
this.endPoint = ePoint; //结束点
|
|
this.ctrlPoint1 = ctrlPoint1;
|
|
this.ctrlPoint2 = ctrlPoint2;
|
|
this.isStrLine = isStrLine; //是否是直线
|
|
}
|
|
//根据配置参数转换店铺圆角
|
|
this.changeShopLinesToString = function (area) {
|
|
let areaStr = [];
|
|
let lines = [];
|
|
for (let m = 0; m < area.hasLines.length; m++) {
|
|
let sPoint, ePoint, cPoint1, cPoint2;
|
|
sPoint = new Config.Point(area.hasLines[m].startPoint.x, area.hasLines[m].startPoint.y);
|
|
ePoint = new Config.Point(area.hasLines[m].endPoint.x, area.hasLines[m].endPoint.y);
|
|
if (area.hasLines[m].isStrLine) {
|
|
cPoint1 = null;
|
|
cPoint2 = null;
|
|
} else {
|
|
cPoint1 = new Config.Point(area.hasLines[m].ctrlPoint1.x, area.hasLines[m].ctrlPoint1.y);
|
|
cPoint2 = new Config.Point(area.hasLines[m].ctrlPoint2.x, area.hasLines[m].ctrlPoint2.y);
|
|
}
|
|
let line = new Config.QM_Line_Father(sPoint, ePoint, cPoint1, cPoint2, area.hasLines[m].isStrLine);
|
|
lines.push(line);
|
|
}
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
let line0 = lines[i];
|
|
let line1 = (i < lines.length - 1) ? lines[i + 1] : lines[0];
|
|
if (Config.angleRadius > 2) {
|
|
if (line0.isStrLine && line1.isStrLine && Math.abs(line0.endPoint.x - line0.startPoint.x) + Math.abs(line0.endPoint.y - line0.startPoint.y) > parseInt(Config.angleRadius) * 2) {
|
|
let x1 = line0.endPoint.x;
|
|
let y1 = line0.endPoint.y;
|
|
let x2 = line0.startPoint.x;
|
|
let y2 = line0.startPoint.y;
|
|
let x3 = line1.endPoint.x;
|
|
let y3 = line1.endPoint.y;
|
|
if (Math.abs((x3 - x1) / (x2 - x1) - (y3 - y1) / (y2 - y1)) < 0.1) {
|
|
let yArr = [];
|
|
yArr.push(line0.startPoint.x, line0.startPoint.y, line0.endPoint.x, line0.endPoint.y);
|
|
areaStr.push(yArr);
|
|
continue;
|
|
}
|
|
|
|
let result = Config.getIncircleByLines(x1, y1, x2, y2, x3, y3, Config.angleRadius);
|
|
let bezierResult = Config.getBezier(result.center.x, result.center.y, result.tangencyPoints[0].x, result.tangencyPoints[
|
|
0].y, result.tangencyPoints[1].x, result.tangencyPoints[1].y, x1, y1, Config.angleRadius);
|
|
|
|
if (i > 0) {
|
|
let ctrlPoint1, ctrlPoint2, array = [];
|
|
ctrlPoint1 = ctrlPoint2 = new Config.Point(((bezierResult[0].x - line0.startPoint.x) / 2 + line0.startPoint.x) >> 0, ((
|
|
bezierResult[0].y - line0.startPoint.y) / 2 + line0.startPoint.y) >> 0); //控制点
|
|
array.push(line0.startPoint.x, line0.startPoint.y, ctrlPoint1.x, ctrlPoint1.y, ctrlPoint2.x, ctrlPoint2.y, bezierResult[0].x, bezierResult[0].y);
|
|
areaStr.push(array);
|
|
} else {
|
|
lines[0].endPoint.x = bezierResult[0].x;
|
|
lines[0].endPoint.y = bezierResult[0].y;
|
|
}
|
|
let arr = [];
|
|
arr.push(bezierResult[0].x, bezierResult[0].y, bezierResult[1].x, bezierResult[1].y, bezierResult[2].x, bezierResult[2].y, bezierResult[3].x, bezierResult[3].y);
|
|
areaStr.push(arr);
|
|
line1.startPoint.x = bezierResult[3].x;
|
|
line1.startPoint.y = bezierResult[3].y;
|
|
} else { /////////////////////////////
|
|
if (i != 0) {
|
|
let pArr = [];
|
|
if (line0.isStrLine) {
|
|
pArr.push(line0.startPoint.x, line0.startPoint.y, line0.endPoint.x, line0.endPoint.y);
|
|
} else {
|
|
pArr.push(line0.startPoint.x, line0.startPoint.y, line0.ctrlPoint1.x, line0.ctrlPoint1.y, line0.ctrlPoint2.x, line0.ctrlPoint2.y, line0.endPoint.x, line0.endPoint.y);
|
|
}
|
|
areaStr.push(pArr);
|
|
}
|
|
}
|
|
if (i == lines.length - 1) {
|
|
let ocPoint1, ocPoint2, oArr = [];
|
|
if (line1.isStrLine) {
|
|
oArr.push(line1.startPoint.x, line1.startPoint.y, line1.endPoint.x, line1.endPoint.y);
|
|
} else {
|
|
ocPoint1 = new Config.Point(line1.ctrlPoint1.x, line1.ctrlPoint1.y);
|
|
ocPoint2 = new Config.Point(line1.ctrlPoint2.x, line1.ctrlPoint2.y);
|
|
oArr.push(line1.startPoint.x, line1.startPoint.y, ocPoint1.x, ocPoint1.y, ocPoint2.x, ocPoint2.y, line1.endPoint.x, line1.endPoint.y);
|
|
}
|
|
areaStr.push(oArr);
|
|
}
|
|
} else {
|
|
let yArr = [];
|
|
if (line0.isStrLine) {
|
|
yArr.push(line0.startPoint.x, line0.startPoint.y, line0.endPoint.x, line0.endPoint.y);
|
|
} else {
|
|
yArr.push(line0.startPoint.x, line0.startPoint.y, line0.ctrlPoint1.x, line0.ctrlPoint1.y, line0.ctrlPoint2.x, line0.ctrlPoint2.y, line0.endPoint.x, line0.endPoint.y);
|
|
}
|
|
areaStr.push(yArr);
|
|
}
|
|
}
|
|
return areaStr;
|
|
}
|
|
|
|
//根据圆心、两个切点、切点相交线顶点和半径 计算三次贝塞尔曲线的控制点
|
|
this.getBezier = function (x1, y1, x2, y2, x3, y3, x4, y4, radius) {
|
|
//切线向量A
|
|
var vectorAx = x2 - x1;
|
|
var vectorAy = y2 - y1;
|
|
//切线向量B
|
|
var vectorBx = x3 - x1;
|
|
var vectorBy = y3 - y1;
|
|
|
|
//计算切点和圆形组成相交线的夹角
|
|
var angle = Math.acos((vectorAx * vectorBx + vectorAy * vectorBy) / (Math.sqrt(vectorAx * vectorAx + vectorAy *
|
|
vectorAy) * Math.sqrt(vectorBx * vectorBx + vectorBy * vectorBy)));
|
|
//计算切点到控制点的距离
|
|
var tempDistence = 4 / 3 * radius * Math.tan(angle / 4);
|
|
return [{
|
|
"x": x2,
|
|
"y": y2
|
|
}, Config.getPointFromLine(x2, y2, x4, y4, tempDistence), Config.getPointFromLine(x3, y3, x4, y4, tempDistence), {
|
|
"x": x3,
|
|
"y": y3
|
|
}];
|
|
}
|
|
//根据半径计算两条线段相切圆的圆心和切点坐标
|
|
this.getIncircleByLines = function (x1, y1, x2, y2, x3, y3, radius) {
|
|
//向量夹角
|
|
let angle = Config.getVectorAngle(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
|
|
angle = ((angle > 180) ? 360 - angle : angle) / 2;
|
|
//根据夹角计算侧边切点相对于顶点距离
|
|
let distance = radius / Math.tan(Math.PI * angle / 180);
|
|
//计算侧边相切点具体坐标
|
|
let tangencyPoints = [Config.getPointFromLine(x1, y1, x2, y2, distance), Config.getPointFromLine(x1, y1, x3, y3,
|
|
distance)];
|
|
|
|
let centerX, centerY;
|
|
let areaSize = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);
|
|
//计算圆心坐标
|
|
if (areaSize < 0) {
|
|
centerX = (tangencyPoints[0].x * (1 / Math.tan(Math.PI * angle / 180)) + tangencyPoints[0].y - y1) / (1 / Math.tan(
|
|
Math.PI * angle / 180));
|
|
centerY = (tangencyPoints[0].y * (1 / Math.tan(Math.PI * angle / 180)) + x1 - tangencyPoints[0].x) / (1 / Math.tan(
|
|
Math.PI * angle / 180));
|
|
} else {
|
|
centerX = (tangencyPoints[1].x * (1 / Math.tan(Math.PI * angle / 180)) + tangencyPoints[1].y - y1) / (1 / Math.tan(
|
|
Math.PI * angle / 180));
|
|
centerY = (tangencyPoints[1].y * (1 / Math.tan(Math.PI * angle / 180)) + x1 - tangencyPoints[1].x) / (1 / Math.tan(
|
|
Math.PI * angle / 180));
|
|
}
|
|
return {
|
|
"center": {
|
|
"x": centerX,
|
|
"y": centerY
|
|
},
|
|
"tangencyPoints": tangencyPoints,
|
|
"angle": Math.PI * angle / 90
|
|
};
|
|
}
|
|
|
|
//根据距离计算线段上某一点的具体坐标
|
|
this.getPointFromLine = function (startX, startY, endX, endY, distance) {
|
|
if (startX == endX) return {
|
|
"x": startX,
|
|
"y": startY < endY ? (startY + distance) : (startY - distance)
|
|
};
|
|
|
|
let k = (startY - endY) * 1.0 / (startX - endX);
|
|
let b = startY - k * startX;
|
|
let A = Math.pow(k, 2) + 1;
|
|
let B = 2 * ((b - startY) * k - startX);
|
|
let C = Math.pow(b - startY, 2) + Math.pow(startX, 2) - Math.pow(distance, 2);
|
|
let x1 = (-B + Math.sqrt(Math.pow(B, 2) - 4 * A * C)) / (2 * A);
|
|
let x2 = (-B - Math.sqrt(Math.pow(B, 2) - 4 * A * C)) / (2 * A);
|
|
let x = 0;
|
|
|
|
if (x1 == x2) x = x1;
|
|
else if (startX <= x1 && x1 <= endX || endX <= x1 && x1 <= startX) x = x1;
|
|
else if (startX <= x2 && x2 <= endX || endX <= x2 && x2 <= startX) x = x2;
|
|
|
|
let y = k * x + b;
|
|
return {
|
|
"x": x,
|
|
"y": y
|
|
};
|
|
}
|
|
|
|
//计算两个向量之间的夹角
|
|
this.getVectorAngle = function (x1, y1, x2, y2) {
|
|
let epsilon = 1.0e-6;
|
|
let dist, dot, degree, angle;
|
|
dist = Math.sqrt(x1 * x1 + y1 * y1);
|
|
x1 /= dist;
|
|
y1 /= dist;
|
|
dist = Math.sqrt(x2 * x2 + y2 * y2);
|
|
x2 /= dist;
|
|
y2 /= dist;
|
|
dot = x1 * x2 + y1 * y2;
|
|
if (Math.abs(dot - 1.0) <= epsilon) angle = 0;
|
|
else if (Math.abs(dot + 1.0) <= epsilon) angle = Math.PI;
|
|
else {
|
|
angle = Math.acos(dot);
|
|
let cross = x1 * y2 - x2 * y1;
|
|
if (cross < 0) angle = 2 * Math.PI - angle;
|
|
}
|
|
degree = angle * 180 / Math.PI;
|
|
return degree;
|
|
}
|
|
//检测区域是否在区域内 true (area2包含area)
|
|
this.checkAreaInArea = function (area, area2) {
|
|
let ptPolygon = [];
|
|
for (let i = 0; i < area2.hasLines.length; i++) {
|
|
let line = area2.hasLines[i];
|
|
let pArr;
|
|
if (line.isStrLine) {
|
|
pArr = Config.getPointArrOnLine(line.startPoint, line.endPoint);
|
|
} else {
|
|
pArr = Config.getPointArr(line.startPoint, line.ctrlPoint1, line.ctrlPoint2, line.endPoint, 0.1);
|
|
}
|
|
ptPolygon.push(...pArr);
|
|
}
|
|
for (let f = 0; f < area.hasLines.length; f++) {
|
|
let line2 = area.hasLines[f];
|
|
let sPoint = Config.checkBoundary(new Config.Point(line2.startPoint.x, line2.startPoint.y), ptPolygon);
|
|
let ePoint = Config.checkBoundary(new Config.Point(line2.endPoint.x, line2.endPoint.y), ptPolygon);
|
|
if (!sPoint || !ePoint) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 返回取得点的数组
|
|
* s1--起点 s2 --终点 s3,s4 --控制点
|
|
*/
|
|
this.getPointArr = function (s1, s3, s4, s2, sp = 0.01) {
|
|
let pArr = [];
|
|
let sz = [s1, s3, s4, s2];
|
|
let p = Config.P_BEZ(0, sz);
|
|
for (let j = 0; j < 1; j += sp) {
|
|
p = Config.P_BEZ(j, sz);
|
|
pArr.push(p);
|
|
}
|
|
return pArr;
|
|
}
|
|
|
|
this.P_BEZ = function (t, sz) { //n次
|
|
let x_p = 0;
|
|
let y_p = 0;
|
|
let n = sz.length;
|
|
for (let i = 0; i < sz.length; i++) {
|
|
let son = Config.jie_cheng(n - 1);
|
|
let mother = Config.jie_cheng(i) * Config.jie_cheng(n - 1 - i);
|
|
let b = (son / mother) * Math.pow(t, i) * Math.pow(1 - t, n - 1 - i);
|
|
x_p += sz[i].x * b;
|
|
y_p += sz[i].y * b;
|
|
}
|
|
|
|
x_p = Number(x_p * 1000) / 1000;
|
|
y_p = Number(y_p * 1000) / 1000;
|
|
return (new Config.Point(x_p, y_p));
|
|
}
|
|
|
|
this.jie_cheng = function (i) { //阶乘
|
|
let n = 1;
|
|
for (let j = 1; j <= i; j++) {
|
|
n *= j;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
* 获取线段上的所有点
|
|
*/
|
|
this.getPointArrOnLine = function (s1, s2) {
|
|
let points = [];
|
|
if (s1.x == s2.x) {
|
|
let vy = s1.y < s2.y ? 1 : -1;
|
|
for (let m = 1; m < Math.abs(s1.y - s2.y); m++) {
|
|
let y0 = s1.y + (m * vy);
|
|
let x0 = s1.x;
|
|
points.push(new Config.Point(x0, y0));
|
|
}
|
|
return points;
|
|
}
|
|
let k = (s1.y - s2.y) / (s1.x - s2.x); // 坐标直线斜率k
|
|
let b = s1.y - k * s1.x; // 坐标直线b
|
|
if (Math.abs(s1.x - s2.x) > Math.abs(s1.y - s2.y)) {
|
|
let vx = s1.x < s2.x ? 1 : -1;
|
|
for (let i = 1; i < Math.abs(s1.x - s2.x); i++) {
|
|
let x0 = s1.x + (i * vx);
|
|
let y0 = k * x0 + b;
|
|
points.push(new Config.Point(x0, y0));
|
|
}
|
|
} else {
|
|
let vy = s1.y < s2.y ? 1 : -1;
|
|
for (let n = 1; n < Math.abs(s1.y - s2.y); n++) {
|
|
let y0 = s1.y + (n * vy);
|
|
let x0 = (y0 - b) / k;
|
|
points.push(new Config.Point(x0, y0));
|
|
}
|
|
}
|
|
return points;
|
|
}
|
|
|
|
//转换公共设施type值
|
|
this.getFacType = function (str) {
|
|
let typeObj = {
|
|
ft: 0, mys: 3, xsj: 4, dt: 5, fwt: 7, tcc: 8, cjr: 10, xys: 11, ztg: 17, thg: 18, td: 20, dit: 21, czc: 22, atm: 23, jcfw: 24, sjcd: 25, bc: 26, cjc: 27, jtn: 28, jtv: 29, ksgj: 30, sjxsn: 31,
|
|
sjxsv: 32, tcjf: 33, vip: 34, xsjn: 35, xsjv: 36, yszj: 37, xxt: 38, door: 39, pq: 40, upft: 0, downft: 0, ysp: 50, B1up: 51, B1down: 52, B2up: 53, B2down: 54, B3up: 55, B3down: 56,
|
|
lt: 88, xcgc: 57, tthy: 58, fwt2: 60, syt2: 61, syt1: 62, gwc: 63, fwt1: 64, jrc: 65, qbc: 66, zxc: 67, jws: 68, etxsj: 69, vip_xxq: 70, ab: 71, abjks: 72, bys: 73, cpgys: 74, gzyld: 75, hqgys: 76, jjs: 77,
|
|
jw: 78, ksj: 79, kt: 80, qzgysn: 81, rsggys: 82, swzl: 83, tsgbs1: 84, tsgbs2: 85, tsgbs3: 86, wxc: 87, yhs: 89, yls: 90, ylz: 91, ydygys: 92, ydygysn: 93, ydygysv: 94, zls: 95, zys: 96, zas: 97, xxq: 98, jtxsj: 99, hzs: 100, brs: 101, mtl: 102, dgnxsj: 103, wxbxsj: 104
|
|
};
|
|
return typeObj[str];
|
|
}
|
|
this.getFacName = function (str) {
|
|
let typeObj = {
|
|
ft: '扶梯', mys: '母婴室', xsj: '洗手间', dt: '直梯', fwt: '服务台', tcc: '停车场', cjr: '无障碍洗手间', xys: '吸烟室', dit: '地铁', czc: '出租车', atm: 'ATM', jcfw: '寄存服务', td: '人行通道',
|
|
sjcd: '手机充电', bc: '泊车', cjc: '裁剪处', jtn: '家庭洗手间(男)', jtv: '家庭洗手间(女)', ksgj: '公交', sjxsn: '男伤健人士洗手间', sjxsv: '女伤健人士洗手间', tcjf: '停车缴费', vip: 'VIP',
|
|
xsjn: '男洗手间', xsjv: '女洗手间', yszj: '雨伞租借', xxt: '信息台', door: '出入口', pq: '喷泉', upft: '上扶梯', downft: '下扶梯', ysp: '艺术品', lt: '楼梯', xcgc: '下沉广场', tthy: '天台花园',
|
|
fwt2: '超市服务台', syt2: '超市收银台', syt1: 'mall收银台', gwc: '购物车', fwt1: 'mall服务台', jrc: '自助加热', qbc: '自助取冰', zxc: '自行车停放', jws: '警务室', etxsj: '儿童洗手间',
|
|
vip_xxq: 'vip休息区', ab: '安保', abjks: '安保监控室', bys: '播音室', cpgys: '裁判更衣室', gzyld: '观众医疗点', hqgys: '后勤更衣室', jjs: '急救室', jw: '警卫', ksj: '开水间', kt: '看台', qzgysn: '亲自更衣(男)', rsggys: '热身馆更衣室',
|
|
swzl: '失物招领', tsgbs1: '特殊贵宾室1', tsgbs2: '特殊贵宾室2', tsgbs3: '特殊贵宾室3', wxc: '闻讯处', yhs: '医护室', yls: '医疗室', ylz: '医疗站', ydygys: '运动员更衣室', ydygysn: '运动员男更衣室',
|
|
ydygysv: '运动员女更衣室', zls: '诊疗室', zys: '直饮水', zas: '治安室', xxq: '休息区', jtxsj: '家庭洗手间', hzs: '化妆室', brs: '哺乳室', mtl: '摩天轮', dgnxsj: '多功能洗手间', wxbxsj: '无性别洗手间', ztg: 'L1自提柜', thg: 'B1自提柜'
|
|
};
|
|
return typeObj[str];
|
|
}
|
|
this.parkSort = function (a, b) {
|
|
return a.name < b.name ? -1 : 1;
|
|
}
|
|
//导航点排序
|
|
this.sortNumber = function (a, b) {
|
|
return a.id - b.id;
|
|
}
|
|
//店铺排序
|
|
this.sortShopByFloor = function (a, b) {
|
|
return a.floorOrder < b.floorOrder ? -1 : 1;
|
|
}
|
|
//店铺排序
|
|
this.sortHouseNum = function (a, b) {
|
|
return a.houseNum < b.houseNum ? -1 : 1;
|
|
}
|
|
|
|
this.sortNode = function (a, b) {
|
|
return a.id - b.id
|
|
}
|
|
|
|
/**该方法用来绘制一个圆角矩形
|
|
*@param cxt:canvas的上下文环境
|
|
*@param x:左上角x轴坐标
|
|
*@param y:左上角y轴坐标
|
|
*@param width:矩形的宽度
|
|
*@param height:矩形的高度
|
|
*@param radius:圆的半径
|
|
**/
|
|
this.drawRoundRectPath = function (cxt, width, height, radius) {
|
|
cxt.beginPath(0);
|
|
//从右下角顺时针绘制,弧度从0到1/2PI
|
|
cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
|
|
//矩形下边线
|
|
cxt.lineTo(radius, height);
|
|
//左下角圆弧,弧度从1/2PI到PI
|
|
cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
|
|
//矩形左边线
|
|
cxt.lineTo(0, radius);
|
|
//左上角圆弧,弧度从PI到3/2PI
|
|
cxt.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
|
|
//上边线
|
|
cxt.lineTo(width - radius, 0);
|
|
//右上角圆弧
|
|
cxt.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
|
|
//右边线
|
|
cxt.lineTo(width, height - radius);
|
|
cxt.closePath();
|
|
}
|
|
|
|
this.wordToSreen = function (world_vector) {
|
|
let vector = world_vector.project(Map_QM.camera);
|
|
let halfWidth = window.innerWidth / 2, halfHeight = window.innerHeight / 2;
|
|
return {
|
|
x: Math.round(vector.x * halfWidth + halfWidth),
|
|
y: Math.round(-vector.y * halfHeight + halfHeight)
|
|
};
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
this.getWallPoints = function (points, wallWidth) {
|
|
if (points.length < 2) {
|
|
//console.log("getWallPoints", "points size is letter than 2");
|
|
return new Array();
|
|
}
|
|
//构建线段列表
|
|
let lines = new Array();
|
|
for (let index = 0; index < points.length - 1; index++) {
|
|
let startPoint = points[index];
|
|
let endPoint = points[index + 1];
|
|
let line = (Config.getParallelLine(startPoint, endPoint, wallWidth));
|
|
lines.push(line);
|
|
}
|
|
//生成线段对应的左右两侧平行线
|
|
for (let index = 0; index < lines.length - 1; index++) {
|
|
let start = lines[index];
|
|
let end = lines[index + 1];
|
|
if (start.leftParLine != null && start.rightParLine != null && end.leftParLine != null && end.rightParLine != null) {
|
|
start.leftPoint = Config.getIntersectionByLines(start.leftParLine, end.leftParLine);
|
|
start.rightPoint = Config.getIntersectionByLines(start.rightParLine, end.rightParLine);
|
|
}
|
|
}
|
|
//循环线段列表 获取墙体所有点位 顺序为 左侧起始点->左侧所有交点->左侧结束点->右侧结束点->右侧所有交点->右侧起始点
|
|
let leftPointList = new Array();
|
|
let rightPointList = new Array();
|
|
for (let index = 0; index < lines.length; index++) {
|
|
//第一条线段 记录左右两侧平行线的起点坐标
|
|
if (index == 0) {
|
|
leftPointList.push(lines[index].leftParLine.start);
|
|
rightPointList.push(lines[index].rightParLine.start);
|
|
}
|
|
//最后一条线段 记录左右两侧平行线的终点坐标
|
|
if (index == lines.length - 1) {
|
|
leftPointList.push(lines[index].leftParLine.end);
|
|
rightPointList.push(lines[index].rightParLine.end);
|
|
} else {//记录线段左右平行线交点坐标
|
|
if (!isNaN(lines[index].leftPoint.x) || !isNaN(lines[index].leftPoint.y) || !isNaN(lines[index].rightPoint.x) || !isNaN(lines[index].rightPoint.y)) {
|
|
leftPointList.push(lines[index].leftPoint);
|
|
rightPointList.push(lines[index].rightPoint);
|
|
}
|
|
}
|
|
}
|
|
rightPointList.reverse();
|
|
return leftPointList.concat(rightPointList);
|
|
}
|
|
|
|
//生成线段左右两侧的平行线
|
|
this.getParallelLine = function (start, end, wallWidth) {
|
|
let line = new Config.WallLine(start, end);
|
|
//计算当前线段的斜率
|
|
let gradient = (start.y - end.y) / (start.x - end.x);
|
|
//计算垂直线的斜率
|
|
let perGradient = -1 / gradient;
|
|
//获取垂直线上左右两侧 与当前点位相距一定距离的两个定点
|
|
let startResult = Config.getParallelPoints(perGradient, start, wallWidth);
|
|
let endResult = Config.getParallelPoints(perGradient, end, wallWidth);
|
|
let x1 = startResult[0].x;
|
|
let y1 = startResult[0].y;
|
|
let x2 = endResult[0].x;
|
|
let y2 = endResult[0].y;
|
|
let x3 = end.x;
|
|
let y3 = end.y;
|
|
let x4 = startResult[1].x;
|
|
let y4 = startResult[1].y;
|
|
let x5 = endResult[1].x;
|
|
let y5 = endResult[1].y;
|
|
let s = (x1 - x3) * (y2 - y3) - (y1 - y3) * (x2 - x3);
|
|
//判断点位位于线段的左侧还是右侧
|
|
if (s >= 0) {
|
|
line.leftParLine = new Config.WallLine(new Config.Point(x1, y1), new Config.Point(x2, y2));
|
|
line.rightParLine = new Config.WallLine(new Config.Point(x4, y4), new Config.Point(x5, y5));
|
|
} else {
|
|
line.leftParLine = new Config.WallLine(new Config.Point(x4, y4), new Config.Point(x5, y5));
|
|
line.rightParLine = new Config.WallLine(new Config.Point(x1, y1), new Config.Point(x2, y2));
|
|
}
|
|
return line;
|
|
}
|
|
|
|
// 生成线段起始 和 结束 点位 对应的 两条 与线段垂直的直线 并记录坐标
|
|
this.getParallelPoints = function (gradient, point, wallWidth) {
|
|
let x, y;
|
|
//斜率为无穷大时 计算不了垂直线 指定点位
|
|
if (gradient == Number.NEGATIVE_INFINITY || gradient == Number.POSITIVE_INFINITY) {
|
|
x = point.x;
|
|
y = point.y + 5;
|
|
} else {
|
|
//不是横线时 根据斜率计算点位
|
|
x = point.x + 5;
|
|
y = parseInt(gradient * (x - point.x) + point.y);
|
|
}
|
|
|
|
return Config.pointXY(point, new Config.Point(x, y), wallWidth / 2);
|
|
}
|
|
|
|
// 获取点位在直线上的坐标
|
|
this.pointXY = function (curPoint, nextPoint, length) {
|
|
let result = new Array();
|
|
//x值相等 说明是竖线 只需增减y轴坐标
|
|
if (curPoint.x == nextPoint.x) {
|
|
result.push(new Config.Point(curPoint.x, curPoint.y + length));
|
|
result.push(new Config.Point(curPoint.x, curPoint.y - length));
|
|
return result;
|
|
}
|
|
//根据 斜率 和 距离 计算出对应的两个点位
|
|
let k = (curPoint.y - nextPoint.y) / (curPoint.x - nextPoint.x);
|
|
let b = curPoint.y - k * curPoint.x;
|
|
let A = Math.pow(k, 2) + 1;
|
|
let B = 2 * ((b - curPoint.y) * k - curPoint.x);
|
|
let C = Math.pow(b - curPoint.y, 2) + Math.pow(curPoint.x, 2) - Math.pow(length, 2);
|
|
let x1 = (-B + Math.sqrt(Math.pow(B, 2) - 4 * A * C)) / (2 * A);
|
|
let x2 = (-B - Math.sqrt(Math.pow(B, 2) - 4 * A * C)) / (2 * A);
|
|
|
|
result.push(new Config.Point(parseInt(x1), parseInt(k * x1 + b)));
|
|
result.push(new Config.Point(parseInt(x2), parseInt(k * x2 + b)));
|
|
return result;
|
|
}
|
|
|
|
//计算两条直线的相交点
|
|
this.getIntersectionByLines = function (line1, line2) {
|
|
//直线斜率
|
|
let gradient1 = (line1.end.y - line1.start.y) / (line1.end.x - line1.start.x);
|
|
let gradient2 = (line2.end.y - line2.start.y) / (line2.end.x - line2.start.x);
|
|
//斜率差值小于一定范围 表示两条线近似平行 因为交点太远 可能超出屏幕 直接取线段中点为交点
|
|
if (Math.abs(gradient1 - gradient2) < 0.1) return new Config.Point(line1.end.x, line1.end.y);
|
|
let x1 = line1.start.x;
|
|
let y1 = line1.start.y;
|
|
let x2 = line1.end.x;
|
|
let y2 = line1.end.y;
|
|
let x3 = line2.start.x;
|
|
let y3 = line2.start.y;
|
|
let x4 = line2.end.x;
|
|
let y4 = line2.end.y;
|
|
|
|
//计算交点坐标
|
|
let x = ((x1 - x2) * (x3 * y4 - x4 * y3) - (x3 - x4) * (x1 * y2 - x2 * y1)) / ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4));
|
|
let y = ((y1 - y2) * (x3 * y4 - x4 * y3) - (x1 * y2 - x2 * y1) * (y3 - y4)) / ((y1 - y2) * (x3 - x4) - (x1 - x2) * (y3 - y4));
|
|
return new Config.Point(x, y);
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//计算点到线段的距离
|
|
this.PointToLineDistance = function (xx, yy, x1, y1, x2, y2) {
|
|
let ang1, ang2, ang, m;
|
|
let result = 0;
|
|
// 分别计算三条边的长度
|
|
const a = Math.sqrt((x1 - xx) * (x1 - xx) + (y1 - yy) * (y1 - yy));
|
|
if (a === 0) {
|
|
return [0, { x: x1, y: y1 }];
|
|
}
|
|
const b = Math.sqrt((x2 - xx) * (x2 - xx) + (y2 - yy) * (y2 - yy));
|
|
if (b === 0) {
|
|
return [0, { x: x2, y: y2 }];
|
|
}
|
|
const c = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
|
// 如果线段是一个点则退出函数并返回距离
|
|
if (c === 0) {
|
|
result = a;
|
|
return [result, { x: x1, y: y1 }];
|
|
}
|
|
// 如果点(xx, yy到点x1, y1)这条边短
|
|
if (a < b) {
|
|
// 如果直线段AB是水平线。得到直线段AB的弧度
|
|
if (y1 === y2) {
|
|
if (x1 < x2) {
|
|
ang1 = 0;
|
|
} else {
|
|
ang1 = Math.PI;
|
|
}
|
|
} else {
|
|
m = (x2 - x1) / c;
|
|
if (m - 1 > 0.00001) {
|
|
m = 1;
|
|
}
|
|
ang1 = Math.acos(m);
|
|
if (y1 > y2) {
|
|
ang1 = Math.PI * 2 - ang1;
|
|
}// 直线(x1, y1)-(x2, y2)与折X轴正向夹角的弧度
|
|
}
|
|
m = (xx - x1) / a;
|
|
if (m - 1 > 0.00001) {
|
|
m = 1;
|
|
}
|
|
ang2 = Math.acos(m);
|
|
if (y1 > yy) {
|
|
ang2 = Math.PI * 2 - ang2;
|
|
}// 直线(x1, y1)-(xx, yy)与折X轴正向夹角的弧度
|
|
ang = ang2 - ang1;
|
|
if (ang < 0) {
|
|
ang = -ang;
|
|
}
|
|
if (ang > Math.PI) {
|
|
ang = Math.PI * 2 - ang;
|
|
}
|
|
// 如果是钝角则直接返回距离
|
|
if (ang > Math.PI / 2) {
|
|
return [a, { x: x1, y: y1 }];
|
|
}
|
|
// 返回距离并且求得当前距离所在线段的坐标
|
|
if (x1 === x2) {
|
|
return [b * Math.sin(ang), { x: x1, y: yy }];
|
|
} else if (y1 === y2) {
|
|
return [b * Math.sin(ang), { x: xx, y: y1 }];
|
|
}
|
|
// 直线的斜率存在且不为0的情况下
|
|
let x = 0, y = 0;
|
|
const k1 = ((y2 - y1) / x2 - x1);
|
|
const kk = -1 / k1;
|
|
const bb = yy - xx * kk;
|
|
const b1 = y2 - x2 * k1;
|
|
x = (b1 - bb) / (kk - k1);
|
|
y = kk * x + bb;
|
|
return [a * Math.sin(ang), { x, y }];
|
|
}
|
|
// 如果两个点的纵坐标相同,则直接得到直线斜率的弧度
|
|
if (y1 === y2) {
|
|
if (x1 < x2) {
|
|
ang1 = Math.PI;
|
|
} else {
|
|
ang1 = 0;
|
|
}
|
|
} else {
|
|
m = (x1 - x2) / c;
|
|
if (m - 1 > 0.00001) {
|
|
m = 1;
|
|
}
|
|
ang1 = Math.acos(m);
|
|
if (y2 > y1) {
|
|
ang1 = Math.PI * 2 - ang1;
|
|
}
|
|
}
|
|
m = (xx - x2) / b;
|
|
if (m - 1 > 0.00001) {
|
|
m = 1;
|
|
}
|
|
ang2 = Math.acos(m);// 直线(x2-x1)-(xx, yy)斜率的弧度
|
|
if (y2 > yy) {
|
|
ang2 = Math.PI * 2 - ang2;
|
|
}
|
|
ang = ang2 - ang1;
|
|
if (ang < 0) {
|
|
ang = -ang;
|
|
}
|
|
if (ang > Math.PI) {
|
|
ang = Math.PI * 2 - ang;
|
|
}// 交角的大小
|
|
// 如果是对角则直接返回距离
|
|
if (ang > Math.PI / 2) {
|
|
return [b, { x: x2, y: y2 }];
|
|
}
|
|
// 如果是锐角,返回计算得到的距离,并计算出相应的坐标
|
|
if (x1 === x2) {
|
|
return [b * Math.sin(ang), { x: x1, y: yy }];
|
|
} else if (y1 === y2) {
|
|
return [b * Math.sin(ang), { x: xx, y: y1 }];
|
|
}
|
|
// 直线的斜率存在且不为0的情况下
|
|
let x = 0, y = 0;
|
|
const k1 = ((y2 - y1) / x2 - x1);
|
|
const kk = -1 / k1;
|
|
const bb = yy - xx * kk;
|
|
const b1 = y2 - x2 * k1;
|
|
x = (b1 - bb) / (kk - k1);
|
|
y = kk * x + bb;
|
|
return [b * Math.sin(ang), { x, y }];
|
|
}
|
|
//点到直线距离
|
|
this.PointToLineDis = function (xx, yy, x1, y1, x2, y2) {
|
|
let len;
|
|
if (x1 - x2 == 0) {
|
|
len = Math.abs(xx - x1);
|
|
} else {
|
|
let A = (y1 - y2) / (x1 - x2);
|
|
let B = y1 - A * x1;
|
|
len = Math.abs((A * xx + B - yy) / Math.sqrt(A * A + 1))
|
|
}
|
|
return len;
|
|
}
|
|
|
|
|
|
this.getShopData = function (callBack) {
|
|
this.readTextFile(Config.shopServerInfo, function (res) {
|
|
Config.shopData = res.data;
|
|
//console.log(Config.shopData);
|
|
if (Config.shopData && Array.isArray(Config.shopData)) {
|
|
Config.shopData.sort(Config.sortShopByFloor);
|
|
let backObj = { "code": 200, msg: "加载成功", "data": [] };
|
|
try {
|
|
if(!Map_QM){
|
|
Map_QM = new MainMap_QM(callBack, backObj);
|
|
Map_QM.initBuild();
|
|
}else{
|
|
Map_QM.callBackLoadOver = callBack;
|
|
Map_QM.backObj = backObj;
|
|
Map_QM.loaderOver();
|
|
}
|
|
} catch (e) {
|
|
callBack({ "code": 404, "msg": "地图数据解析失败" })
|
|
callBack = null;
|
|
}
|
|
} else {
|
|
backObj.code = 500;
|
|
backObj.msg = "店铺数据错误";
|
|
}
|
|
if (backObj.code == 404) {
|
|
callBack(backObj)
|
|
}
|
|
});
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////---------------------------end
|
|
/**
|
|
* 根据色值获取材质
|
|
*/
|
|
this.getMeshMaterial = function (color, alphaModle = 0.9) {
|
|
let meshMaterial;
|
|
for (let k = 0; k < Config.meshMaterialArr.length; k++) {
|
|
let color2 = new THREE.Color(color)
|
|
if (Config.meshMaterialArr[k].color.equals(color2) && Config.meshMaterialArr[k].opacity == alphaModle) {
|
|
meshMaterial = Config.meshMaterialArr[k];
|
|
}
|
|
}
|
|
if (!meshMaterial) {
|
|
meshMaterial = new THREE.MeshPhongMaterial({
|
|
color: color,
|
|
emissive: 0x000000,
|
|
specular: 0x000000,
|
|
transparent: true,
|
|
side: THREE.DoubleSide,
|
|
opacity: alphaModle
|
|
});
|
|
Config.meshMaterialArr.push(meshMaterial);
|
|
}
|
|
return meshMaterial;
|
|
}
|
|
this.rotateYZ = function (geometry, ry, rz) {
|
|
let center = new THREE.Vector3();
|
|
geometry.computeBoundingBox();
|
|
geometry.boundingBox.getCenter(center);
|
|
let x = center.x;
|
|
let y = center.y;
|
|
let z = center.z;
|
|
geometry.center();
|
|
geometry.rotateY(ry);
|
|
geometry.rotateX(rz);
|
|
geometry.translate(x, y, z);
|
|
}
|
|
this.rotateTextYZ = function (geometry, rx, ry, rz) {
|
|
let center = new THREE.Vector3();
|
|
geometry.computeBoundingBox();
|
|
geometry.boundingBox.getCenter(center);
|
|
let x = center.x;
|
|
let y = center.y;
|
|
let z = center.z;
|
|
geometry.center();
|
|
geometry.rotateX(rx);
|
|
geometry.rotateY(ry);
|
|
geometry.rotateZ(rz);
|
|
geometry.translate(x, y, z);
|
|
}
|
|
//对象克隆
|
|
this.cloneObject = function (sourceObj) {
|
|
let target = (sourceObj instanceof Array) ? [] : {};
|
|
for (attr in sourceObj) {
|
|
if (!obj.hasOwnProperty(attr)) continue;
|
|
target[attr] = (typeof sourceObj[i] == "object") ? obj[attr].clone() : obj[attr];
|
|
}
|
|
return target;
|
|
}
|
|
}
|
|
var Config = new ConfigFun();
|
|
|
|
//////////////////////////////-------------------------------------------配置 ConfigFun
|
|
/**
|
|
* 地图主类,入口 初始化设备点位
|
|
* @param width,height 勾图的地图宽、高
|
|
* @param floor, 楼层编号从0开始
|
|
* @param navPoint, 导航点位
|
|
* @param angle(-180~180) 设备角度
|
|
*/
|
|
MainMap_QM = function (callBack, backObj) {
|
|
this.callBackLoadOver = callBack;
|
|
this.backObj = backObj;
|
|
let ele = document.getElementById("mapContainer");
|
|
this.w = parseInt(ele.clientWidth) || window.innerWidth;
|
|
this.h = parseInt(ele.clientHeight) || window.innerHeight;
|
|
|
|
this.scene = new THREE.Scene();
|
|
this.scene.name = "scene";
|
|
|
|
aspect = this.w / this.h;
|
|
cameraPerspective = new THREE.PerspectiveCamera(45, aspect, 10, 10000);
|
|
cameraPerspective.position.set(Config.cameraDist.x, Config.cameraDist.y, Config.cameraDist.z); //x 水平 y 垂直旋转 z 展示大小
|
|
cameraPerspective.lookAt(new THREE.Vector3(0, 0, 0));
|
|
|
|
cameraOrtho = new THREE.OrthographicCamera(340 * aspect / - 2, 340 * aspect / 2, 340 / 2, 340 / - 2, 10, 10000);
|
|
cameraOrtho.position.set(0, 200, 0);
|
|
cameraOrtho.lookAt(new THREE.Vector3(0, 0, 0));
|
|
this.camera = Config.cameraDist.state == "2D" ? cameraOrtho : cameraPerspective;
|
|
//
|
|
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); //
|
|
this.renderer.setSize(this.w, this.h);
|
|
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
//this.renderer.outputEncoding = THREE.GammaEncoding;
|
|
ele.appendChild(this.renderer.domElement);
|
|
|
|
this.labelRenderer = new THREE.CSS2DRenderer();
|
|
this.labelRenderer.setSize(this.w, this.h, Config.perc_H);
|
|
this.labelRenderer.domElement.style.position = 'absolute';
|
|
this.labelRenderer.domElement.style.top = 0;
|
|
ele.appendChild(this.labelRenderer.domElement);
|
|
|
|
this.directionalLight1 = new THREE.DirectionalLight(0xffffff, 0.2);
|
|
this.directionalLight1.name = "light";
|
|
this.directionalLight1.position.set(800, 1200, 800);
|
|
this.scene.add(this.directionalLight1);
|
|
let aLight = new THREE.AmbientLight(0xffffff, 0.7);
|
|
this.scene.add(aLight);
|
|
this.directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.2);
|
|
this.directionalLight2.name = "light";
|
|
this.directionalLight2.position.set(-800, 1200, -800);
|
|
this.scene.add(this.directionalLight2);
|
|
|
|
this.buildObj = new THREE.Group();
|
|
this.sceneGap = new THREE.Group();
|
|
this.scene.add(this.sceneGap);
|
|
this.sceneGap.add(this.buildObj);
|
|
this.sceneGap.position.set(Config.sceneGap.x, Config.sceneGap.y, Config.sceneGap.z);
|
|
this.sceneGap.scale.set(Config.sceneGap.scale, Config.sceneGap.scale, Config.sceneGap.scale);
|
|
|
|
this.mixers = [];
|
|
this.controls = new THREE.OrbitControls(this.camera, this.labelRenderer.domElement);
|
|
//鼠标控制
|
|
//this.controls.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
|
|
//this.controls.enabled = true;
|
|
this.controls.minZoom = 0.8;
|
|
this.controls.maxZoom = Config.cameraZoom;
|
|
//设置相机距离原点的最远距离
|
|
this.controls.minDistance = Config.mapDistance.min;
|
|
//设置相机距离原点的最远距离
|
|
this.controls.maxDistance = Config.mapDistance.max;
|
|
this.controls.minPolarAngle = Config.cameraDist.state == "2D" ? 0 : 0.3; // radians
|
|
this.controls.maxPolarAngle = Config.cameraDist.state == "2D" ? 0 : Math.PI / 2 - 0.3; // radians
|
|
this.CSSObject = new THREE.Object3D();
|
|
this.buildObj.add(this.CSSObject);
|
|
|
|
this.controls.addEventListener('change', this.collisionChock, false); //控制器变化
|
|
if (window.PointerEvent) {
|
|
document.getElementById('mapContainer').addEventListener('pointerup', this.onMouseClickBox, false); //地图点击
|
|
} else {
|
|
document.getElementById('mapContainer').addEventListener('click', this.onMouseClickBox, false); //地图点击
|
|
}
|
|
document.addEventListener('rezise', this.changeWindowResize, false); //窗口变化
|
|
this.mapArr = [];
|
|
this.selectShop;
|
|
this.selectEle = null; //当前使用的电梯
|
|
|
|
this.shape = new THREE.Shape();
|
|
this.shape.moveTo(-10, -10);
|
|
this.shape.lineTo(10, -10);
|
|
this.shape.lineTo(10, 10);
|
|
this.shape.lineTo(-10, 10);
|
|
this.dtLineGroup = new THREE.Group();
|
|
this.dtLineGroup.name = "dtLine";
|
|
this.buildObj.add(this.dtLineGroup);
|
|
|
|
if (document.getElementById('moveFloorBG')) {
|
|
this.moveFloorbg = new THREE.CSS2DObject(document.getElementById('moveFloorBG'));
|
|
this.scene.add(this.moveFloorbg);
|
|
}
|
|
this.guide;
|
|
new THREE.GLTFLoader().load("./static/img/runman.gltf", function (obj) {
|
|
man_3d = obj.scene;
|
|
man_3d.scale.x = man_3d.scale.y = man_3d.scale.z = 15;
|
|
man_3d.children[0].children[1].children[0].material.color = new THREE.Color(0xfe9219);
|
|
Map_QM.sceneGap.add(man_3d);
|
|
man_3d.visible = false;
|
|
man_3d.children[0].rotation.x = Math.PI / 2;
|
|
man_3d.children[0].rotation.y = Math.PI;
|
|
// obj作为参数创建一个混合器,解析播放obj及其子对象包含的动画数据
|
|
let mixer = new THREE.AnimationMixer(obj.scene);
|
|
let AnimationAction = mixer.clipAction(obj.animations[0]);
|
|
AnimationAction.timeScale = 2;
|
|
AnimationAction.play();
|
|
Map_QM.mixers.push(mixer);
|
|
Map_QM.guide = man_3d;
|
|
});
|
|
|
|
new THREE.TextureLoader().load("./static/img/guide.png", textu => {
|
|
let planeMaterial = new THREE.MeshPhongMaterial({
|
|
map: textu,
|
|
depthTest: true,
|
|
transparent: true,
|
|
alphaTest: 0.1
|
|
});
|
|
let planeGeometry = new THREE.PlaneGeometry(128, 128);
|
|
man_2d = new THREE.Mesh(planeGeometry, planeMaterial);
|
|
man_2d.center = new THREE.Vector2(0.5, 0.5);
|
|
man_2d.visible = false;
|
|
Map_QM.sceneGap.add(man_2d);
|
|
});
|
|
|
|
|
|
|
|
this.qiModel; //起点
|
|
this.qiIcon; //起点Icon
|
|
this.dirIcon; //我的方向Icon
|
|
this.endIcon; //终点Icon
|
|
this.endModel;
|
|
this.forShopArr = []; //途径数据
|
|
}
|
|
MainMap_QM.prototype = {
|
|
initBuild: function (e) {
|
|
elevator = null;
|
|
straight = null;
|
|
elevatorDown = null;
|
|
if (Config.showModelIcon) {
|
|
let loader = new THREE.GLTFLoader();
|
|
loader.load("./static/img/elevator.gltf", function (collada) {
|
|
collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = 15;
|
|
collada.scene.rotation.x = -90 * Math.PI / -180;
|
|
collada.scene.renderOrder = 300;
|
|
elevator = collada.scene;
|
|
collada.scene.children[0].traverse(function (child) {
|
|
if (child.isMesh && child.name == "boli2") {
|
|
//child.material.color = new THREE.Color(0xffffff);
|
|
child.material.opacity = 0.8;
|
|
}
|
|
if (child.isMesh && child.name == "pidai") {
|
|
//child.material.color = new THREE.Color(0xffffff);
|
|
child.material.opacity = 0.8;
|
|
}
|
|
});
|
|
new THREE.GLTFLoader().load("./static/img/elevatorDown.gltf", function (collada) {
|
|
collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = 15;
|
|
collada.scene.rotation.x = -90 * Math.PI / -180;
|
|
collada.scene.renderOrder = 300;
|
|
elevatorDown = collada.scene;
|
|
collada.scene.children[0].traverse(function (child) {
|
|
if (child.isMesh && child.name == "boli2") {
|
|
//child.material.color = new THREE.Color(0xffffff);
|
|
child.material.opacity = 0.8;
|
|
}
|
|
if (child.isMesh && child.name == "pidai") {
|
|
//child.material.color = new THREE.Color(0xffffff);
|
|
child.material.opacity = 0.8;
|
|
}
|
|
});
|
|
|
|
new THREE.GLTFLoader().load("./static/img/dt.gltf", function (collada) {
|
|
collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = 15;
|
|
collada.scene.rotation.x = -90 * Math.PI / -180;
|
|
collada.scene.renderOrder = 300;
|
|
straight = collada.scene;
|
|
//console.log(straight);
|
|
straight.traverse(function (child) {
|
|
if (child.isMesh && child.name == "zhitiboli") {
|
|
//child.material.color = new THREE.Color(0xffffff);
|
|
child.material.opacity = 0.6;
|
|
child.material.side = 1;
|
|
}
|
|
// if (child.isMesh && child.name == "zhitijiegou") {
|
|
// child.material.color = new THREE.Color(0xffffff);
|
|
// child.material.opacity = 0.8;
|
|
// }
|
|
});
|
|
Map_QM.loaderOver();
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
Map_QM.loaderOver();
|
|
}
|
|
},
|
|
loaderOver: function (e) {
|
|
Map_QM.cancelRender();
|
|
this.controls.reset();
|
|
basePath=null;
|
|
|
|
this.renderer.dispose();
|
|
this.remove_child(this.sceneGap);
|
|
this.scene.remove(this.sceneGap);
|
|
this.sceneGap=new THREE.Group();
|
|
this.sceneGap.position.set(Config.sceneGap.x, Config.sceneGap.y, Config.sceneGap.z);
|
|
this.sceneGap.scale.set(Config.sceneGap.scale, Config.sceneGap.scale, Config.sceneGap.scale);
|
|
this.scene.add(this.sceneGap);
|
|
this.buildObj=new THREE.Group();
|
|
this.sceneGap.add(this.buildObj);
|
|
this.CSSObject = new THREE.Object3D();
|
|
this.buildObj.add(this.CSSObject);
|
|
this.buildObj.add(this.dtLineGroup);
|
|
|
|
Config.mapScale = Config.allMap[Config.selectBuild].scale || 18;
|
|
facAllArr = [];
|
|
this.mapArr.length = 0;
|
|
basePath = "{";
|
|
for (let bd = 0; bd < Config.allMap.length; bd++) {
|
|
for (let i = 0; i < Config.allMap[bd].buildArr.length; i++) {
|
|
this.convertPath(bd, i);
|
|
}
|
|
}
|
|
if (basePath.length > 1) {
|
|
basePath = basePath.substr(0, basePath.length - 1);
|
|
}
|
|
if (Config.otherPath) { //如果多楼栋需要配置楼栋之间通行路径
|
|
basePath += Config.otherPath;
|
|
}
|
|
basePath += "}";
|
|
//初始化基础路径;
|
|
let graphPathObj = JSON.parse(basePath);
|
|
let ftPathObj = JSON.parse(basePath);
|
|
let dtPathObj = JSON.parse(basePath);
|
|
for (let j = 0; j < facAllArr.length; j++) {
|
|
for (let k = 0; k < facAllArr[j].length; k++) {
|
|
let facP = facAllArr[j][k].buildOrder + "_" + facAllArr[j][k].floorOrder + "_" + facAllArr[j][k].navCode;
|
|
for (let h = 0; h < facAllArr[j].length; h++) {
|
|
if (h != k) {
|
|
let nP = facAllArr[j][h].buildOrder + "_" + facAllArr[j][h].floorOrder + "_" + facAllArr[j][h].navCode;
|
|
if (facAllArr[j][h].facCode == "dt") {
|
|
graphPathObj[facP][nP] = 400 + 200 * Math.abs(parseInt(facAllArr[j][h].floorOrder) - parseInt(facAllArr[j][k].floorOrder));
|
|
ftPathObj[facP][nP] = 3000;
|
|
dtPathObj[facP][nP] = 400 + 200 * Math.abs(parseInt(facAllArr[j][h].floorOrder) - parseInt(facAllArr[j][k].floorOrder));
|
|
}else if (facAllArr[j][h].facCode == "lt") {
|
|
graphPathObj[facP][nP] = 400 + 200 * Math.abs(parseInt(facAllArr[j][h].floorOrder) - parseInt(facAllArr[j][k].floorOrder));
|
|
ftPathObj[facP][nP] = 400 + 200 * Math.abs(parseInt(facAllArr[j][h].floorOrder) - parseInt(facAllArr[j][k].floorOrder));
|
|
dtPathObj[facP][nP] = 400 + 200 * Math.abs(parseInt(facAllArr[j][h].floorOrder) - parseInt(facAllArr[j][k].floorOrder));
|
|
} else {
|
|
graphPathObj[facP][nP] = 400 + 200 * Math.abs(parseInt(facAllArr[j][h].floorOrder) - parseInt(facAllArr[j][k].floorOrder));
|
|
ftPathObj[facP][nP] = 400 + 200 * Math.abs(parseInt(facAllArr[j][h].floorOrder) - parseInt(facAllArr[j][k].floorOrder));
|
|
dtPathObj[facP][nP] = 3000;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
graphPath = graphPathObj;
|
|
ftPath = ftPathObj;
|
|
dtPath = dtPathObj;
|
|
var fIndex = 0, bIndex = 0;
|
|
this.mapArr[bIndex] = [];
|
|
intTimer = setInterval(() => {
|
|
let floor = new FloorMap_QM(bIndex, fIndex, Config.allMap[bIndex].buildArr[fIndex].name);
|
|
floor.floorName = Config.allMap[bIndex].buildArr[fIndex].name;
|
|
floor.initDraw();
|
|
floor.allObj.position.set(bIndex * Config.distance, (fIndex - Config.selectFloor) * Config.doubleDist, 0);
|
|
//floor.allObj.renderOrder = 20 - fIndex;
|
|
this.buildObj.add(floor.allObj);
|
|
this.mapArr[bIndex].push(floor);
|
|
fIndex++;
|
|
if (fIndex >= Config.allMap[bIndex].buildArr.length) {
|
|
if (bIndex == Config.allMap.length - 1) {
|
|
clearInterval(intTimer);
|
|
this.controls.minPan = new THREE.Vector3(this.w / -10, 0, this.h / -10);
|
|
this.controls.maxPan = new THREE.Vector3(this.w / 10, 0, this.h / 10);
|
|
let pathData = Config.allMap[Config.selectBuild].buildArr[parseInt(Config.deviceObj.floor)].mapData.path;
|
|
if (parseInt(Config.deviceObj.node) != -1) {
|
|
if (pathData && !Config.deviceObj.xaxis && pathData.nodes.length > parseInt(Config.deviceObj.node)) {
|
|
Config.deviceObj.xaxis = pathData.nodes[parseInt(Config.deviceObj.node)].x;
|
|
Config.deviceObj.yaxis = pathData.nodes[parseInt(Config.deviceObj.node)].y;
|
|
} else {
|
|
console.warn("初始化点位失败");
|
|
}
|
|
Map_QM.mapArr[Config.selectBuild][parseInt(Config.deviceObj.floor)].setStartSite(Config.deviceObj.xaxis, Config.deviceObj.yaxis, parseInt(Config.shopHeight));
|
|
}
|
|
this.initFloor();
|
|
} else {
|
|
bIndex++;
|
|
fIndex = 0;
|
|
this.mapArr[bIndex] = [];
|
|
}
|
|
}
|
|
}, 50);
|
|
},
|
|
|
|
initFloor: function () {
|
|
Map_QM.changeFloorInner();
|
|
Map_QM.startRender();
|
|
Map_QM.controls.saveState();
|
|
},
|
|
|
|
/**
|
|
* 解析路径
|
|
*/
|
|
convertPath: function (buildOrder, floorOrder) {
|
|
let mapData = Config.allMap[buildOrder].buildArr[floorOrder].mapData;
|
|
let pathData = mapData.path;
|
|
if (!pathData) {
|
|
return;
|
|
}
|
|
if (pathData.nodes.length > 0) {
|
|
for (let i = 0; i < pathData.nodes.length; i++) {
|
|
let a = pathData.nodes[i].id;
|
|
basePath += "\"" + buildOrder + "_" + floorOrder + "_" + a + "\":{";
|
|
|
|
for (let n = 0; n < pathData.nodes[i]["list"].length; n++) {
|
|
let b;
|
|
if (pathData.nodes[i]["list"][n].id || pathData.nodes[i]["list"][n].id == "0") {
|
|
b = pathData.nodes[i]["list"][n].id;
|
|
} else {
|
|
b = a == pathData.nodes[i]["list"][n].selfNode.id ? pathData.nodes[i]["list"][n].nextNode.id : pathData.nodes[i]["list"][n].selfNode.id;
|
|
}
|
|
basePath += "\"" + buildOrder + "_" + floorOrder + "_" + b + "\":" + pathData.nodes[i]["list"][n].cost + ",";
|
|
}
|
|
if (pathData.nodes[i]["list"].length > 0) {
|
|
basePath = basePath.substr(0, basePath.length - 1);
|
|
}
|
|
basePath += "},";
|
|
}
|
|
}
|
|
let noHas;
|
|
for (let j = 0; j < mapData.stairs.length; j++) {
|
|
if (mapData.stairs[j].state) { //排除禁用的设施
|
|
noHas = true;
|
|
for (let k = 0; k < facAllArr.length; k++) { //facAllArr 记录遍历结果
|
|
if (facAllArr[k][0].no != "" && facAllArr[k][0].navCode != "" && facAllArr[k][0].no == mapData.stairs[j].no) {
|
|
if (facAllArr[k][0].facCode == mapData.stairs[j].facCode || (facAllArr[k][0].facCode.search("ft") != -1 && mapData.stairs[j].facCode.search("ft") != -1)) {
|
|
noHas = false;
|
|
mapData.stairs[j].floorOrder = floorOrder;
|
|
mapData.stairs[j].buildOrder = buildOrder;
|
|
facAllArr[k].push(mapData.stairs[j]);
|
|
}
|
|
}
|
|
}
|
|
if (noHas) {
|
|
mapData.stairs[j].buildOrder = buildOrder;
|
|
mapData.stairs[j].floorOrder = floorOrder;
|
|
let array = [mapData.stairs[j]];
|
|
facAllArr.push(array);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} changeMapState("3d") 地图状态切换
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 地图展示状态切换
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {string} state 地图状态
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.changeMapState("2d");
|
|
*
|
|
*/
|
|
changeMapState: function (state) {
|
|
if (state === "3d") {
|
|
Map_QM.camera = cameraPerspective;
|
|
Map_QM.controls.maxPolarAngle = Math.PI / 2 - 0.1;
|
|
Map_QM.controls.minPolarAngle = 0.1;
|
|
Map_QM.controls.object = Map_QM.camera;
|
|
Map_QM.camera.updateProjectionMatrix(); //必须update
|
|
Map_QM.camera.position.set(Config.cameraDist.x, Config.cameraDist.y, Config.cameraDist.z);
|
|
Map_QM.changeIconState(state);
|
|
} else {
|
|
Map_QM.camera = cameraOrtho;
|
|
Map_QM.controls.maxPolarAngle = 0;
|
|
Map_QM.controls.minPolarAngle = 0;
|
|
Map_QM.controls.object = Map_QM.camera;
|
|
Map_QM.camera.updateProjectionMatrix(); //必须update
|
|
Map_QM.controls.maxPolarAngle = 0;
|
|
Map_QM.changeIconState(state);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} changeIconState("3d") ICON状态切换
|
|
* @apiGroup 地图交互
|
|
* @apiDescription ICON状态切换
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {string} state 展示状态
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.changeIconState("2d");
|
|
*
|
|
*/
|
|
changeIconState: function (state) {
|
|
if (Map_QM.mapArr[Config.selectBuild][Config.selectFloor]) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].serObj.traverse((obj) => {
|
|
if (obj.userData && obj.userData.use) {
|
|
if (obj.userData.use != "all" && obj.userData.use != state) {
|
|
obj.visible = false;
|
|
} else {
|
|
obj.visible = true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (Map_QM.dirIcon) {
|
|
Map_QM.dirIcon.visible = state == "2d" ? true : false;
|
|
}
|
|
if (Map_QM.qiModel) {
|
|
Map_QM.qiModel.visible = state == "2d" ? false : true;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} changeBuild(0) 楼栋切换
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 楼栋切换 传入楼栋编号
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} index 传入楼栋编号,改变地图显示内容
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {int} 请求示例
|
|
*
|
|
* Map_QM.changeBuild(0);
|
|
*
|
|
*/
|
|
changeBuild: function (fIndex = -1) {
|
|
clearTimeout(outTime);
|
|
Map_QM.forShopArr.length = 0;
|
|
if (Map_QM.selectShop) {
|
|
Map_QM.selectShop.scale.z = 1;
|
|
}
|
|
|
|
if (Map_QM.endModel && Map_QM.endModel.visible) {
|
|
Map_QM.endModel.visible = false;
|
|
}
|
|
if (Map_QM.endIcon && Map_QM.endIcon.visible) {
|
|
Map_QM.endIcon.visible = false;
|
|
}
|
|
Map_QM.clearFloor(Config.selectFloor);
|
|
if (fIndex != -1) {
|
|
Config.selectBuild = fIndex;
|
|
}
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.visible = true;
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].labelObj.traverse((obj) => {
|
|
obj.visible = true;
|
|
});
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].iconLabel.traverse((obj) => {
|
|
obj.visible = true;
|
|
});
|
|
TweenMax.to(Map_QM.buildObj.position, 0.3, {
|
|
x: Config.selectBuild * Config.distance * -1,
|
|
onComplete: function () {
|
|
Map_QM.changeFloorInner(Config.selectFloor); //结束后切换楼层
|
|
}
|
|
});
|
|
},
|
|
/**
|
|
* @api {方法} onShowMeDir() 我的方向
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 我的方向
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.onShowMeDir();
|
|
*
|
|
*/
|
|
onShowMeDir: function (zoom = 0) {
|
|
Config.setModelState("2d");
|
|
Map_QM.camera = cameraOrtho;
|
|
Map_QM.controls.maxPolarAngle = 0;
|
|
Map_QM.controls.minPolarAngle = 0;
|
|
if (isPathState) {
|
|
Map_QM.dirIcon.visible = false;
|
|
Map_QM.qiIcon.visible = true;
|
|
}
|
|
Map_QM.controls.object = Map_QM.camera;
|
|
if (Config.deviceObj.xaxis) {
|
|
Map_QM.controls.object.position.set(Config.deviceObj.xaxis * 0.1, 100, Config.deviceObj.yaxis * 0.1);
|
|
Map_QM.controls.target = new THREE.Vector3(Config.deviceObj.xaxis * 0.1, 0, Config.deviceObj.yaxis * 0.1);
|
|
} else {
|
|
Map_QM.controls.object.position.set(0, 100, 0);
|
|
Map_QM.controls.target = new THREE.Vector3(0, 0, 0);
|
|
}
|
|
zoom = zoom == 0 ? Config.cameraZoom : zoom;
|
|
Map_QM.controls.setZoom(zoom);
|
|
Map_QM.rotationAngle(Config.deviceObj.angle || 0);
|
|
Map_QM.controls.enableRotate = false;
|
|
},
|
|
/**
|
|
* @api {方法} onShowLocalSite(0) 局部显示放大
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 局部显示放大 point 传入放大目标点,zoom放大级别 1-5
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {Object} point 放大的地图位置
|
|
* @apiParam {int} zoom 放大倍数
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {Object} 请求示例
|
|
*
|
|
* Map_QM.onShowLocalSite({point:{x:0,y:0},zoom:5});
|
|
*
|
|
*/
|
|
onShowLocalSite: function (obj) {
|
|
Config.setModelState("3d");
|
|
Map_QM.camera = cameraPerspective;
|
|
Map_QM.controls.object = Map_QM.camera;
|
|
Map_QM.controls.maxPolarAngle = Math.PI / 2 - 0.1;
|
|
Map_QM.controls.minPolarAngle = 0.1;
|
|
Map_QM.controls.reset();
|
|
Map_QM.controls.target = new THREE.Vector3(obj.point.x * Config.sceneGap.scale, 0, obj.point.y * Config.sceneGap.scale);
|
|
let disX = 60 + (5 - parseInt(obj.zoom)) * 300;
|
|
Map_QM.controls.object.position.set(obj.point.x * Config.sceneGap.scale, disX, obj.point.y * Config.sceneGap.scale + disX); // 加 disX 保持地图倾斜角度
|
|
},
|
|
|
|
/**
|
|
* @api {方法} changeLanguage() 切换中英文
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 切换中英文 cn en
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {String} str 显示语言
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.changeLanguage("en");
|
|
*
|
|
*/
|
|
changeLanguage: function (lang = "cn") {
|
|
language = lang;
|
|
for (let t = 0; t < Map_QM.mapArr.length; t++) {
|
|
for (let i = 0; i < Map_QM.mapArr[t].length; i++) {
|
|
Map_QM.mapArr[t][i].labelObj.traverse((obj) => {
|
|
if (obj.element) {
|
|
obj.element.innerText = language == "en" ? obj.element.dataset.nameEn : obj.element.dataset.name;
|
|
}
|
|
});
|
|
Map_QM.mapArr[t][i].iconLabel.traverse((obj) => {
|
|
if (obj.element) {
|
|
obj.element.innerText = language == "en" ? obj.element.dataset.nameEn : obj.element.dataset.name;
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
Map_QM.collisionChock();
|
|
},
|
|
/**
|
|
* @api {方法} onShowDeviceSite() 地图方向复位
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 地图方向复位
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.onShowDeviceSite();
|
|
*
|
|
*/
|
|
onShowDeviceSite: function () {
|
|
Config.setModelState("3d");
|
|
Map_QM.camera = cameraPerspective;
|
|
Map_QM.controls.object = Map_QM.camera;
|
|
Map_QM.controls.maxPolarAngle = Math.PI / 2 - 0.1;
|
|
Map_QM.controls.minPolarAngle = 0.1;
|
|
if (Map_QM.qiModel) {
|
|
Map_QM.qiModel.visible = true;
|
|
}
|
|
if (Map_QM.dirIcon) {
|
|
Map_QM.dirIcon.visible = false;
|
|
}
|
|
Map_QM.controls.enabled=true;
|
|
Map_QM.controls.enableRotate = true;
|
|
Map_QM.controls.reset();
|
|
},
|
|
/**
|
|
* 在2D 状态下平移镜头
|
|
*/
|
|
moveCameraBy2D:function(obj){
|
|
if(pathCameraState == "2D" && Map_QM.camera == cameraOrtho){
|
|
Map_QM.controls.minAzimuthAngle=Config.deviceObj.angle*Math.PI/-180;
|
|
Map_QM.controls.maxAzimuthAngle=Config.deviceObj.angle*Math.PI/-180;
|
|
Map_QM.controls.object.position.set(0, 200, obj.y * Config.sceneGap.scale);
|
|
Map_QM.controls.target = new THREE.Vector3(obj.x * Config.sceneGap.scale, 0, obj.y * Config.sceneGap.scale); //移动
|
|
}
|
|
},
|
|
/**
|
|
* 方向复位
|
|
*/
|
|
resetMeDir: function () {
|
|
Config.setModelState("3d");
|
|
Map_QM.camera = cameraPerspective;
|
|
Map_QM.controls.object = Map_QM.camera;
|
|
Map_QM.controls.maxPolarAngle = Math.PI / 2 - 0.1;
|
|
Map_QM.controls.minPolarAngle = 0.1;
|
|
Map_QM.controls.minAzimuthAngle=-Infinity;
|
|
Map_QM.controls.maxAzimuthAngle=Infinity;
|
|
Map_QM.controls.target = new THREE.Vector3(0, 0, 0);
|
|
Map_QM.dirIcon.visible = false;
|
|
Map_QM.qiIcon.visible = false;
|
|
if (Map_QM.qiModel) {
|
|
Map_QM.qiModel.visible = true;
|
|
}
|
|
Map_QM.controls.reset();
|
|
},
|
|
/**
|
|
* @api {方法} changePathDir(pathState) 切换导航方向
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 切换导航方向
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {String} pathState 地图导航方向 2D/3D
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.changePathDir("2D");
|
|
*
|
|
*/
|
|
changePathDir: function (pathState="3D") {
|
|
if(isPathState){ //导航状态
|
|
let initVis = false;
|
|
if(Map_QM.endModel && Map_QM.endIcon){
|
|
initVis = pathCameraState == "2D" ? Map_QM.endIcon.visible : Map_QM.endModel.visible;
|
|
}
|
|
pathCameraState=pathState;
|
|
if(Map_QM.endModel && Map_QM.endIcon){
|
|
Map_QM.endModel.visible = pathCameraState == "2D" ? false : initVis;
|
|
Map_QM.endIcon.visible = pathCameraState == "2D" ? initVis : false;
|
|
}
|
|
if(pathCameraState == "2D"){ //2D导航
|
|
Map_QM.onShowMeDir(2);
|
|
Map_QM.guide.visible=false;
|
|
let pos = Map_QM.guide.position;
|
|
Map_QM.guide = man_2d;
|
|
Map_QM.guide.position.x = pos.x;
|
|
Map_QM.guide.position.y = pos.y;
|
|
Map_QM.guide.visible=true;
|
|
Map_QM.controls.enabled = false;
|
|
}else{
|
|
Map_QM.resetMeDir();
|
|
Map_QM.controls.enabled = true;
|
|
Map_QM.guide.visible=false;
|
|
let pos = Map_QM.guide.position;
|
|
Map_QM.guide = man_3d;
|
|
Map_QM.guide.position.x = pos.x;
|
|
Map_QM.guide.position.y = pos.y;
|
|
Map_QM.guide.visible=true;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} cancelSelectShop() 取消店铺弹跳
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 取消店铺弹跳效果
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.cancelSelectShop();
|
|
*
|
|
*/
|
|
cancelSelectShop: function () {
|
|
TweenMax.killAll(true);
|
|
if (Map_QM.selectShop) {
|
|
Map_QM.selectShop.scale.z = 1;
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} changeStateShopPro(isShow) 店铺促销标签
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 店铺促销标签展示/隐藏
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {boolean} isShow 店铺促销标签是否显示
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {boolean} 请求示例
|
|
*
|
|
* Map_QM.changeStateShopPro(true);
|
|
*
|
|
*/
|
|
changeStateShopPro: function (isShow = false) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].tagObj.traverse((obj) => {
|
|
obj.visible = isShow;
|
|
});
|
|
},
|
|
/**
|
|
* @api {方法} changeShowTagObjState(isShow) 自定义标签
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 自定义标签展示/隐藏
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {boolean} isShow 自定义标签是否显示
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {boolean} 请求示例
|
|
*
|
|
* Map_QM.changeShowTagObjState(true);
|
|
*
|
|
*/
|
|
changeShowTagObjState: function (isShow = false) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].showTagObj.traverse((obj) => {
|
|
obj.visible = isShow;
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @api {方法} rotationAngle(angle) 改变水平角度
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 改变地图水平角度 angle>-180 && angle<180
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {int} angle 旋转角度
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {int} 请求示例
|
|
*
|
|
* Map_QM.rotationAngle(90);
|
|
*
|
|
*/
|
|
rotationAngle: function (angle) {
|
|
Map_QM.controls.setRotateHorizontal(angle / 180 * Math.PI);
|
|
},
|
|
|
|
/**
|
|
* @api {方法} setCameraDist(cDist) 调整地图大小
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 调整地图大小(值越小地图越大) Config.mapDistance.min ~ Config.mapDistance.max
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {int} cDist 摄像头距离
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {int} 请求示例
|
|
*
|
|
* Map_QM.setCameraDist(150);
|
|
*
|
|
*/
|
|
setCameraDist: function (cDist) {
|
|
clearTimeout(oTime);
|
|
oTime = setTimeout(() => {
|
|
clearTimeout(oTime);
|
|
if (Config.mapDistance.min < parseInt(cDist) && parseInt(cDist) < Config.mapDistance.max) {
|
|
let oldObj = { dis: Map_QM.controls.getDistance() };
|
|
TweenMax.killAll(true);
|
|
TweenMax.to(oldObj, 0.5, {
|
|
dis: cDist,
|
|
onUpdate: function () {
|
|
Map_QM.controls.setDistance(oldObj.dis);
|
|
Map_QM.collisionChock();
|
|
}
|
|
});
|
|
}
|
|
}, 200);
|
|
},
|
|
/**
|
|
* @api {方法} startRender() 启动地图渲染
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 启动地图渲染 与 cancelRender 配合使用可节约资源
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.startRender();
|
|
*
|
|
*/
|
|
startRender: function () {
|
|
Map_QM.cancelRender();
|
|
if (Map_QM.qiModel) {
|
|
Map_QM.qiModel.rotateY(0.05);
|
|
}
|
|
if (Map_QM.endModel) {
|
|
Map_QM.endModel.rotateY(0.05);
|
|
}
|
|
Map_QM.camera.updateProjectionMatrix();
|
|
Map_QM.controls.update();
|
|
Map_QM.renderer.render(Map_QM.scene, Map_QM.camera);
|
|
Map_QM.labelRenderer.render(Map_QM.scene, Map_QM.camera);
|
|
|
|
for (let item of Map_QM.mixers) {
|
|
item.update(clock.getDelta());
|
|
}
|
|
renderFrame = requestAnimationFrame(Map_QM.startRender);
|
|
},
|
|
/**
|
|
* @api {方法} cancelRender() 取消地图渲染
|
|
* @apiGroup 地图显示
|
|
* @apiDescription 取消地图渲染 与 startRender 配合使用可节约资源
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.cancelRender();
|
|
*
|
|
*/
|
|
cancelRender: function () {
|
|
window.cancelAnimationFrame(renderFrame);
|
|
},
|
|
|
|
/**
|
|
* @api {方法} showFloor(floorOrder) 楼层切换
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 楼层切换,传入楼层编号,编号从下到上排序,最下面是0
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {int} floorOrder 楼层编号
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {int} 请求示例
|
|
*
|
|
* Map_QM.showFloor(1);
|
|
*
|
|
*/
|
|
showFloor: function (fIndex = -1) {
|
|
isPathState = false;
|
|
if (Map_QM.qiIcon) {
|
|
Map_QM.qiIcon.visible = false;
|
|
}
|
|
Map_QM.controls.enabled = true;
|
|
Map_QM.controls.enableRotate = true;
|
|
Map_QM.controls.minAzimuthAngle=-Infinity;
|
|
Map_QM.controls.maxAzimuthAngle=Infinity;
|
|
Map_QM.dispatchEvent({
|
|
type: 'changeFloorinit',
|
|
data: Map_QM.selectFloor
|
|
});
|
|
Map_QM.clearFloor(fIndex);
|
|
if (Config.cameraDist.state == "3D") {
|
|
Map_QM.resetMeDir();
|
|
}
|
|
|
|
clearTimeout(outTime);
|
|
Map_QM.forShopArr.length = 0;
|
|
if (fIndex != -1) {
|
|
Map_QM.changeFloorInner(fIndex);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} addElementLabel(divObj,x=0,y=0,type="2d_pop") 地图html标签
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 地图显示Html标签
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {Element} divObj div对象
|
|
* @apiParam {int} x 显示X坐标
|
|
* @apiParam {int} y 显示Y坐标
|
|
* @apiParam {string} type 对象标识
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
* Map_QM.addElementLabel(divObj,0,0);
|
|
*
|
|
*/
|
|
addElementLabel: function (divObj, x = 0, y = 0, type = "2d_pop") {
|
|
let shopInfo = new THREE.CSS2DObject(divObj);
|
|
shopInfo.position.set(x, -1 * y, 50);
|
|
shopInfo.applyMatrix(Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.matrix);
|
|
shopInfo.userData.type = type;
|
|
shopInfo.name="shopInfo";
|
|
Map_QM.CSSObject.add(shopInfo);
|
|
return shopInfo;
|
|
},
|
|
/**
|
|
* @api {方法} elementDestroy(divObj,x=0,y=0,type="2d_pop") 销毁地图标签
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 销毁地图上的html标签
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {string} type 对象标识
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.elementDestroy("2d_pop");
|
|
*
|
|
*/
|
|
elementDestroy: function (type = "2d_pop") {
|
|
for (let i = Map_QM.CSSObject.children.length - 1; i >= 0; i--) {
|
|
if (Map_QM.CSSObject.children[i].userData && Map_QM.CSSObject.children[i].userData.type == type) {
|
|
Map_QM.CSSObject.remove(Map_QM.CSSObject.children[i]);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} initSingleDevice(floorOrder,code) 设置标签背景色
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 设置标签背景色
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floorOrder 标签所在楼层
|
|
* @apiParam {string} code 对象标识
|
|
* @apiParam {string} color 选中颜色 (可选)
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.initSingleDevice(0,"");
|
|
*/
|
|
initSingleDevice: function (floorOrder, code, color = "#5F4E41", build = 0) {
|
|
Map_QM.mapArr[build][floorOrder].showTagObj.traverse((obj) => {
|
|
if (obj.element && obj.userData.code == code) {
|
|
obj.element.style.background = color;
|
|
}
|
|
});
|
|
},
|
|
/**
|
|
* @api {方法} clearDeviceSelectState() 清除标签选中
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 清除标签选中状态
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floorOrder 标签所在楼层
|
|
* @apiParam {string} code 对象标识
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.clearDeviceSelectState();
|
|
*/
|
|
clearDeviceSelectState: function () {
|
|
for (let t = 0; t < Map_QM.mapArr.length; t++) {
|
|
for (let i = 0; i < Map_QM.mapArr[t].length; i++) {
|
|
Map_QM.mapArr[t][i].showTagObj.traverse((obj) => {
|
|
if (obj.element) {
|
|
obj.element.style.background = "#777777";
|
|
}
|
|
});
|
|
}
|
|
}
|
|
},
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* 内部楼层切换
|
|
* @param {int} fIndex 楼层编号
|
|
* @param {int} midIndex 如果是叠层,需要传入 最多三层
|
|
* @param {int} endIndex 如果是叠层,需要传入 最多三层
|
|
*/
|
|
changeFloorInner: function (fIndex = -1, endIndex = -1, midIndex = -1) {
|
|
Map_QM.clearFloor(Config.selectFloor);
|
|
let addFloor = fIndex - Config.selectFloor > 0 ? 1 : -1;
|
|
if (fIndex != -1) {
|
|
Config.selectFloor = fIndex;
|
|
}
|
|
for (let t = 0; t < Map_QM.mapArr.length; t++) {
|
|
for (let i = 0; i < Map_QM.mapArr[t].length; i++) {
|
|
Map_QM.mapArr[t][i].allObj.visible = t == Config.selectBuild ? true : false;
|
|
Map_QM.mapArr[t][i].labelObj.traverse((obj) => {
|
|
obj.visible = false;
|
|
});
|
|
Map_QM.mapArr[t][i].iconLabel.traverse((obj) => {
|
|
obj.visible = false;
|
|
});
|
|
|
|
Map_QM.mapArr[t][i].tagObj.traverse((obj) => {
|
|
obj.visible = false;
|
|
});
|
|
Map_QM.mapArr[t][i].showTagObj.traverse((obj) => {
|
|
obj.visible = false;
|
|
});
|
|
}
|
|
}
|
|
if (Map_QM.mapArr[Config.selectBuild][Config.selectFloor]) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.visible = true;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
for (let i = 0; i < Map_QM.mapArr[Config.selectBuild].length; i++) {
|
|
if (i == Config.selectFloor || (i == midIndex && Config.overlap) || (i == endIndex && Config.overlap)) {
|
|
Map_QM.mapArr[Config.selectBuild][i].allObj.visible = true;
|
|
Map_QM.mapArr[Config.selectBuild][i].labelObj.traverse((obj) => {
|
|
obj.visible = true;
|
|
});
|
|
Map_QM.mapArr[Config.selectBuild][i].iconLabel.traverse((obj) => {
|
|
obj.visible = true;
|
|
});
|
|
|
|
Map_QM.mapArr[Config.selectBuild][i].showTagObj.traverse((obj) => {
|
|
obj.visible = true;
|
|
});
|
|
} else {
|
|
Map_QM.mapArr[Config.selectBuild][i].allObj.visible = false;
|
|
}
|
|
|
|
if (i == Map_QM.mapArr[Config.selectBuild].length - 1) {
|
|
if (Config.overlap) { //叠层
|
|
if (midIndex === -1 && endIndex !== -1) { //两层
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.position.y = Config.selectFloor < endIndex ? -1 * Config.doubleDist : Config.doubleDist;
|
|
Map_QM.mapArr[Config.selectBuild][endIndex].allObj.position.y = Config.selectFloor > endIndex ? -1 * Config.doubleDist : Config.doubleDist;
|
|
} else if (endIndex === -1) { //一层
|
|
TweenMax.fromTo(Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.position, 0.3, { y: addFloor * Config.doubleDist }, { y: 0, ease: Cubic.easeIn });
|
|
//Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.position.y=0;
|
|
} else { //三层
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.position.y = 0;
|
|
Map_QM.mapArr[Config.selectBuild][midIndex].allObj.position.y = 0;
|
|
Map_QM.mapArr[Config.selectBuild][endIndex].allObj.position.y = 0;
|
|
let minF = Math.min(midIndex, Config.selectFloor, endIndex);
|
|
let maxF = Math.max(midIndex, Config.selectFloor, endIndex);
|
|
Map_QM.mapArr[Config.selectBuild][minF].allObj.position.y = -1 * Config.doubleDist;
|
|
Map_QM.mapArr[Config.selectBuild][maxF].allObj.position.y = Config.doubleDist;
|
|
}
|
|
} else {
|
|
//Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.position.y=0;
|
|
TweenMax.fromTo(Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.position, 0.3, { y: addFloor * Config.doubleDist }, { y: 0, ease: Cubic.easeIn });
|
|
}
|
|
Map_QM.timeOutInit();
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param {Object} e
|
|
* 地图BOX点击
|
|
*/
|
|
onMouseClickBox: function (event) {
|
|
clearTimeout(oTime);
|
|
oTime = setTimeout(() => {
|
|
clearTimeout(oTime);
|
|
let mouse = new THREE.Vector2();
|
|
mouse.x = (event.offsetX / Map_QM.w) * 2 - 1;
|
|
mouse.y = -(event.offsetY / Map_QM.h) * 2 + 1;
|
|
Map_QM.onCallTouchORMouse(mouse);
|
|
}, 200);
|
|
},
|
|
onCallTouchORMouse: function (mouse) {
|
|
if (!Map_QM.mapArr[Config.selectBuild][Config.selectFloor] || isPathState) {
|
|
return;
|
|
}
|
|
let raycaster = new THREE.Raycaster();
|
|
raycaster.setFromCamera(mouse, Map_QM.camera);
|
|
let intersects = raycaster.intersectObjects(Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.children, true);
|
|
let clickShop = false;
|
|
for (let i = 0; i < intersects.length; i++) {
|
|
//店铺BOX点击
|
|
if (intersects[i].object.userData && intersects[i].object.userData.type == "shop" && intersects[i].object.name != "shop" && intersects[i].object.name != "") {
|
|
if (Map_QM.endModel && Map_QM.endModel.visible) {
|
|
Map_QM.endModel.visible = false;
|
|
}
|
|
clickShop = true;
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].findPath.clearPath();
|
|
Map_QM.setSelectShopMat(intersects[i].object);
|
|
break;
|
|
}
|
|
}
|
|
Map_QM.dispatchEvent({
|
|
type: 'shop',
|
|
data: clickShop ? (Map_QM.selectShop?.userData) : null
|
|
});
|
|
//图标点击
|
|
for (let i = 0; i < intersects.length; i++) {
|
|
//图标点击
|
|
if (intersects[i].object.userData && intersects[i].object.userData.type == "icon") {
|
|
if (Map_QM.endModel && Map_QM.endModel.visible) {
|
|
Map_QM.endModel.visible = false;
|
|
}
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].findPath.clearPath();
|
|
Map_QM.dispatchEvent({
|
|
type: 'icon',
|
|
data: intersects[i].object.userData
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
//设备点击
|
|
for (let i = 0; i < intersects.length; i++) {
|
|
//图标点击
|
|
if (intersects[i].object.userData && intersects[i].object.userData.type == "device") {
|
|
if (Map_QM.endModel && Map_QM.endModel.visible) {
|
|
Map_QM.endModel.visible = false;
|
|
}
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].findPath.clearPath();
|
|
Map_QM.dispatchEvent({
|
|
type: 'device',
|
|
data: intersects[i].object.userData
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
//改变选中店铺box
|
|
setSelectShopMat: function (selObject, logoW = 0, url = "") {
|
|
TweenMax.killAll(true);
|
|
if (Map_QM.selectShop) {
|
|
Map_QM.selectShop.scale.z = 1;
|
|
}
|
|
Map_QM.selectShop = selObject;
|
|
TweenMax.to(Map_QM.selectShop.scale, 0.5, {
|
|
z: 3, repeat: 4, yoyo: true, ease: Cubic.easeIn,
|
|
onComplete: function () {
|
|
if (Map_QM.selectShop) {
|
|
TweenMax.to(Map_QM.selectShop.scale, 0.5, { z: 1 });
|
|
}
|
|
}
|
|
});
|
|
|
|
},
|
|
/**
|
|
* 初始化后调用
|
|
*/
|
|
timeOutInit: function () {
|
|
if (Map_QM.callBackLoadOver) {
|
|
let floorData = [];
|
|
for (let i = 0; i < Config.allMap.length; i++) {
|
|
let build = [];
|
|
for (let j = 0; j < Config.allMap[i].buildArr.length; j++) {
|
|
if (Config.allMap[i].buildArr[j]) {
|
|
build.push({ order: Config.allMap[i].buildArr[j].order, name: Config.allMap[i].buildArr[j].name });
|
|
}
|
|
}
|
|
floorData.push(build);
|
|
}
|
|
if (Map_QM.backObj) {
|
|
Map_QM.controls.enabled = true;
|
|
Map_QM.backObj.data = floorData;
|
|
}
|
|
Map_QM.callBackLoadOver(Map_QM.backObj); //初始化完成后回调
|
|
Map_QM.callBackLoadOver = null;
|
|
Map_QM.backObj = null;
|
|
}
|
|
Map_QM.dispatchEvent({
|
|
type: 'changeFloorOver',
|
|
data: Map_QM.selectFloor
|
|
});
|
|
Map_QM.collisionChock();
|
|
},
|
|
/**
|
|
* 碰撞检测
|
|
* @param {Object} 传入检测楼层下标
|
|
*/
|
|
collisionChock: function () {
|
|
if (!Config.collision) {
|
|
return;
|
|
}
|
|
Map_QM.dispatchEvent({
|
|
type: 'mapAngleChange',
|
|
data: { "hAngle": Map_QM.controls.getRotateHorizontal(), "vAngle": Map_QM.controls.getRotate() }
|
|
});
|
|
outTime = setTimeout(() => {
|
|
clearTimeout(outTime);
|
|
let checkList = [];
|
|
if (Config.overlap) {
|
|
for (let i = 0; i < Map_QM.mapArr[Config.selectBuild].length; i++) {
|
|
Map_QM.mapArr[Config.selectBuild][i].allObj.traverse((obj) => {
|
|
if (obj.name == "floor" && Map_QM.mapArr[Config.selectBuild][i].allObj.visible) { //
|
|
checkList.push(obj);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (Map_QM.mapArr[Config.selectBuild]) {
|
|
for (let m = 0; m < Map_QM.mapArr[Config.selectBuild].length; m++) {
|
|
if (Map_QM.mapArr[Config.selectBuild][m].allObj.visible) {
|
|
|
|
let IconChilds = Map_QM.mapArr[Config.selectBuild][m].iconLabel.children;
|
|
IconChilds.forEach((item) => {
|
|
item.element.style.visibility = "visible";
|
|
});
|
|
|
|
let childs = Map_QM.mapArr[Config.selectBuild][m].labelObj.children;
|
|
childs.forEach((item) => {
|
|
item.element.style.visibility = "visible";
|
|
});
|
|
let svgChilds = Map_QM.mapArr[Config.selectBuild][m].svgObj.children;
|
|
let rat = Map_QM.controls.getRotateHorizontal();
|
|
svgChilds.forEach((item) => {
|
|
if (rat < -3.1415926 / 2 || rat > 3.14159 / 2) { // <-160 >160
|
|
item.rotation.z = item.userData.rot > 0 ? item.userData.rot - 3.1415926 : item.userData.rot + 3.1415926;
|
|
} else {
|
|
item.rotation.z = item.userData.rot;
|
|
}
|
|
});
|
|
let len = childs.length;
|
|
for (let i = 0; i < len; i++) {
|
|
let obj = childs[i].element;
|
|
if (obj.style.visibility == "visible" && obj.style.transform) {
|
|
let labP = obj.style.transform.split("translate")[2].split(", ");
|
|
for (let j = i + 1; j < len; j++) {
|
|
let pb = childs[j].element.style.transform.split("translate")[2].split(", ");
|
|
let isCol = Config.isCollision(new Config.Point(labP[0].substring(1, labP[0].length - 2), labP[1].substring(0,
|
|
labP[1].length - 3)), obj.clientWidth, obj.clientHeight,
|
|
new Config.Point(pb[0].substring(1, pb[0].length - 2), pb[1].substring(0, pb[1].length - 3)), childs[j].element
|
|
.clientWidth, childs[j].element.clientHeight);
|
|
if (isCol) {
|
|
childs[j].element.style.visibility = "hidden";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let iLen = IconChilds.length;
|
|
for (let ii = 0; ii < iLen; ii++) {
|
|
let objIcon = IconChilds[ii].element;
|
|
if (objIcon.style.visibility == "visible" && objIcon.style.transform) {
|
|
let labPIcon = objIcon.style.transform.split("translate")[2].split(", ");
|
|
for (let jj = ii + 1; jj < iLen; jj++) {
|
|
let pbe = IconChilds[jj].element.style.transform.split("translate")[2].split(", ");
|
|
let isCol2 = Config.isCollision(new Config.Point(labPIcon[0].substring(1, labPIcon[0].length - 2), labPIcon[1].substring(0,
|
|
labPIcon[1].length - 3)), objIcon.clientWidth, objIcon.clientHeight,
|
|
new Config.Point(pbe[0].substring(1, pbe[0].length - 2), pbe[1].substring(0, pbe[1].length - 3)), IconChilds[jj].element
|
|
.clientWidth, IconChilds[jj].element.clientHeight);
|
|
if (isCol2) {
|
|
IconChilds[jj].element.style.visibility = "hidden";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Config.overlap) {
|
|
let renChild = Map_QM.mapArr[Config.selectBuild][m].showTagObj.children;
|
|
renChild.forEach((item) => {
|
|
if (item.element.style.visibility == "visible") {
|
|
let check = Config.blocked(item.element, checkList, m);
|
|
if (check) {
|
|
item.element.style.visibility = "hidden";
|
|
}
|
|
}
|
|
});
|
|
childs.forEach((item) => {
|
|
if (item.element.style.visibility == "visible") {
|
|
let check = Config.blocked(item.element, checkList, m);
|
|
if (check) {
|
|
item.element.style.visibility = "hidden";
|
|
}
|
|
}
|
|
});
|
|
IconChilds.forEach((item) => {
|
|
if (item.element.style.visibility == "visible") {
|
|
let check = Config.blocked(item.element, checkList, m);
|
|
if (check) {
|
|
item.element.style.visibility = "hidden";
|
|
}
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}, 200);
|
|
},
|
|
|
|
/**
|
|
* 寻路----------------------------------------------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @api {方法} bounceIcon({type:"xsj"}) 图标弹跳
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 地图图标弹跳效果
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {String} iconType 设施缩写
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.bounceIcon({type:"xsj"});
|
|
*
|
|
*/
|
|
bounceIcon: function (iconType) {
|
|
let toFloor = parseInt(Config.selectFloor);
|
|
let facs = Map_QM.mapArr[Config.selectBuild][toFloor].serObj.children; //交通图标
|
|
for (let i = 0; i < facs.length; i++) {
|
|
if (facs[i].type == "Sprite") {
|
|
facs[i].reSetSite();
|
|
if (facs[i].facCode == iconType) {
|
|
facs[i].jumpIcon();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} pathIcon({type:"xsj"}) 获取最近设施
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 获取离当前楼层最近的设施
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {JSON} type 设施缩写
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.pathIcon({type:"xsj"});
|
|
*
|
|
* @apiSuccessExample 返回示例
|
|
* {
|
|
* "floor": 楼层编号, "node": 设施导航点,"typeCode":设施编号
|
|
* }
|
|
*
|
|
*/
|
|
pathIcon: function (iconType) {
|
|
console.log(Config.deviceObj)
|
|
let selIcon; //
|
|
let minS = -1;
|
|
for (let i = 0; i < Map_QM.mapArr[Config.selectBuild].length; i++) {
|
|
let sers = Map_QM.mapArr[Config.selectBuild][i].serObj.children; //服务图标
|
|
for (let n = 0; n < sers.length; n++) {
|
|
if (sers[n].facCode == iconType.type) {
|
|
if (!selIcon) {
|
|
selIcon = sers[n];
|
|
minS = Math.abs(sers[n].position.x - Config.deviceObj.xaxis) + Math.abs(-1 * Config.deviceObj.yaxis - sers[n].position.y) + Math.abs(i - Config.deviceObj.floor) * 600;
|
|
} else {
|
|
let s1 = Math.abs(sers[n].position.x - Config.deviceObj.xaxis) + Math.abs(-1 * Config.deviceObj.yaxis - sers[n].position.y) + Math.abs(i - Config.deviceObj.floor) * 600;
|
|
if (s1 < minS) {
|
|
minS = s1;
|
|
selIcon = sers[n];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (selIcon) {
|
|
return { "floor": selIcon.floor, "node": selIcon.navCode, "typeCode": Config.getFacType(iconType.type) };
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} pathByStartAndOver(startObj,toObj,callBackFun) 设置地图点位
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 根据传入的起、终点;直接导航
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floor 楼层编号
|
|
* @apiParam {String} shopNum 店铺编号/车位编号
|
|
* @apiParam {String} type "shop"/"park"
|
|
* @apiParam {Function} callBackFun 回调函数
|
|
*
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.pathByStartAndOver({"floor":3,"shopNum":"L102","type":"shop"},{"floor":4,"shopNum":"L204","type":"shop"});
|
|
*
|
|
*/
|
|
pathByStartAndOver: function (startObj, toObj, callBackFun) {
|
|
try {
|
|
Config.startObj = this.shopNumToNavPoint(startObj, startObj.type);
|
|
let overObj = this.shopNumToNavPoint(toObj, toObj.type);
|
|
this.pathNode(overObj, callBackFun);
|
|
} catch (e) {
|
|
return "传入点位无法导航";
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} changeStartPoint({type:"xsj"}) 设置起始点位
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 设置起始点位
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floor 起点楼层编号
|
|
* @apiParam {String} shopNum 起点店铺编号
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample {String} 请求示例
|
|
*
|
|
* Map_QM.changeStartPoint({"floor":3,"shopNum":"6220"});
|
|
*
|
|
*/
|
|
changeStartPoint: function (toObj) {
|
|
if (toObj) {
|
|
Map_QM.clearFloor();
|
|
Config.startObj = this.shopNumToNavPoint(toObj, "shop");
|
|
} else {
|
|
Map_QM.clearFloor();
|
|
let pathData = Config.allMap[Config.selectBuild].buildArr[parseInt(Config.deviceObj.floor)].mapData.path;
|
|
Config.deviceObj.xaxis = pathData.nodes[parseInt(Config.deviceObj.node)].x;
|
|
Config.deviceObj.yaxis = pathData.nodes[parseInt(Config.deviceObj.node)].y;
|
|
Config.startObj = Config.deviceObj;
|
|
}
|
|
Config.selectBuild = 0;
|
|
},
|
|
|
|
/**
|
|
* @api {方法} changeMapIPState(ipName,color) 改变POI颜色
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 改变POI 颜色
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {string} ipName POI名称
|
|
* @apiParam {string} color 颜色字符串
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.changeMapIPState("L1001","#ffff00");
|
|
*
|
|
*/
|
|
changeMapIPState: function (ipName, color) {
|
|
for (let i = 0; i < Map_QM.mapArr[Config.selectBuild].length; i++) {
|
|
let shopArr = Map_QM.mapArr[Config.selectBuild][i].allObj.children;
|
|
for (let k = 0; k < shopArr.length; k++) {
|
|
if (shopArr[k].name == ipName) {
|
|
shopArr[k].material = Config.getMeshMaterial(color);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} getMapIPData(ipName) 获取POI 基础数据
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 获取POI 基础数据
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {string} ipName POI名称
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.getMapIPData("L1001");
|
|
*
|
|
*
|
|
*/
|
|
getMapIPData: function (ipName) {
|
|
for (let i = 0; i < Map_QM.mapArr[Config.selectBuild].length; i++) {
|
|
let shopArr = Map_QM.mapArr[Config.selectBuild][i].allObj.children;
|
|
for (let k = 0; k < shopArr.length; k++) {
|
|
if (shopArr[k].name == ipName) {
|
|
return shopArr[k].userData;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} pathNode() 地图模拟导航
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 地图路径模拟导航
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floor 楼层编号
|
|
* @apiParam {string} node 路径点位编号
|
|
* @apiParam {function} callBackFun 回调方法
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.pathNode({floor:2,node:"53"},callBackFun);
|
|
*
|
|
*/
|
|
pathNode: function (toObj, callBackFun) {
|
|
Map_QM.clearFloor(-1, true);
|
|
isPathState = true;
|
|
if (!Config.startObj.xaxis && !Config.startObj.yaxis) {
|
|
Map_QM.changeStartPoint(null);
|
|
}
|
|
outTime = setTimeout(() => {
|
|
clearTimeout(outTime);
|
|
Config.overObj = null;
|
|
Config.overObj = { floor: toObj.floor, node: toObj.node };
|
|
if (Config.overObj.node != "") {
|
|
this.onFindPathModel();
|
|
if (callBackFun) {
|
|
callBackFun(Map_QM.forShopArr);
|
|
}
|
|
}
|
|
}, 200);
|
|
},
|
|
|
|
/**
|
|
* @api {方法} getGapByPathNode() 获取实际距离
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 通过点位获取距离
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floor 楼层编号
|
|
* @apiParam {string} node 路径点位编号
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.getGapByPathNode({floor:2,node:"53"});
|
|
*
|
|
* @apiSuccessExample {Object} dist 距离米数 time 步行时间
|
|
* {
|
|
* dis:200,time:4
|
|
* }
|
|
*/
|
|
getGapByPathNode: function (toObj) {
|
|
let startNade = Config.selectBuild + "_" + Config.deviceObj.floor + "_" + Config.deviceObj.node;
|
|
let toNade = Config.selectBuild + "_" + toObj.floor + "_" + toObj.node;
|
|
let path = { "cost": -1 }, minTime = 1;
|
|
try {
|
|
path = dijkstra.find_path(graphPath, startNade, toNade);
|
|
minTime = parseInt(path.cost / Config.mapScale / 50) < 0.5 ? 0.5 : parseInt(path.cost / Config.mapScale / 50);
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
return { dis: parseInt(path.cost / Config.mapScale), time: minTime }
|
|
},
|
|
/**
|
|
* @api {方法} getAllIcon() 获取所有Icon
|
|
* @apiGroup 地图数据
|
|
* @apiDescription 获取所有Icon
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floorOrder 楼层编号(可选) 不传返回所有
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
*/
|
|
getAllIcon: function (floorOrder = -1, buildOrder = -1) {
|
|
let icons = [];
|
|
|
|
if (floorOrder != -1) {
|
|
let sers = Map_QM.mapArr[Config.selectBuild][floorOrder].serObj.children; //服务图标
|
|
for (let n = 0; n < sers.length; n++) {
|
|
if (sers[n].type == "Sprite") {
|
|
let title = sers[n].userData.title;
|
|
let titleEn = Config.iconEn[title];
|
|
let type = sers[n].facCode;
|
|
let imgUrl = sers[n].imgUrl;
|
|
if (sers[n].facCode == "upft" || sers[n].facCode == "downft" || sers[n].facCode == "ft") {
|
|
title = "扶梯";
|
|
titleEn = Config.iconEn[title];
|
|
type = "ft";
|
|
imgUrl = "./static/img/ft.png";
|
|
}
|
|
let icon = { type: type, floor: floorOrder, imgUrl: imgUrl, poid: sers[n].userData.poid, title: title, titleEn: titleEn };
|
|
icons.push(icon);
|
|
}
|
|
}
|
|
return icons;
|
|
}
|
|
|
|
for (let j = 0; j < Map_QM.mapArr.length; j++) {
|
|
let iconBuild = [];
|
|
for (let i = 0; i < Map_QM.mapArr[j].length; i++) {
|
|
let iconArr = [];
|
|
if (Map_QM.mapArr[j][i].serObj) {
|
|
let sers = Map_QM.mapArr[j][i].serObj.children; //服务图标
|
|
for (let n = 0; n < sers.length; n++) {
|
|
if (sers[n].type == "Sprite") {
|
|
let title = sers[n].userData.title;
|
|
let titleEn = Config.iconEn[title];
|
|
let type = sers[n].facCode;
|
|
let imgUrl = sers[n].imgUrl;
|
|
if (sers[n].facCode == "upft" || sers[n].facCode == "downft" || sers[n].facCode == "ft") {
|
|
title = "扶梯";
|
|
titleEn = Config.iconEn[title];
|
|
type = "ft";
|
|
imgUrl = "./static/img/ft.png";
|
|
}
|
|
let icon = { type: type, floor: i, imgUrl: imgUrl, poid: sers[n].userData.poid, title: title, titleEn: titleEn };
|
|
iconArr.push(icon);
|
|
}
|
|
}
|
|
}
|
|
iconBuild.push(iconArr);
|
|
}
|
|
icons.push(iconBuild);
|
|
}
|
|
|
|
return icons;
|
|
},
|
|
/**
|
|
* @api {方法} pathPark() 获取车位点位
|
|
* @apiGroup 地图数据
|
|
* @apiDescription 获取车位导航点
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floor 楼层编号
|
|
* @apiParam {String} shopNum 车位编号
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.pathPark({floor:2,shopNum:"B1002"});
|
|
*
|
|
*/
|
|
pathPark: function (toObj) {
|
|
return this.shopNumToNavPoint(toObj, "park");
|
|
},
|
|
|
|
/**
|
|
* @api {方法} pathShopByName() 获取店铺点位
|
|
* @apiGroup 地图数据
|
|
* @apiDescription 通过店铺名称获取点位
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {String} shopName 店铺名称
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.pathShopByName("金拱门");
|
|
*
|
|
*/
|
|
pathShopByName: function (shopName) {
|
|
for (let item of Config.shopData) {
|
|
if (item.name === shopName) {
|
|
return { "floor": item.floorOrder, "node": item.yaxis }
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} shopNumToNavPoint() 获取导航点位
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 通过店铺编号或车位获取导航点位
|
|
* @apiVersion 1.0.0
|
|
* @apiParam {int} floor 楼层编号
|
|
* @apiParam {int} shopNum 店铺或车位编号
|
|
* @apiParam {String} type 店铺或车位标识 "shop" "park"
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
*/
|
|
shopNumToNavPoint: function (obj, type) {
|
|
let shopArr;
|
|
if (type == "shop") {
|
|
shopArr = Map_QM.mapArr[Config.selectBuild][obj.floor].allObj.children;
|
|
} else if (type == "park") {
|
|
shopArr = Map_QM.mapArr[Config.selectBuild][obj.floor].parkObj.children;
|
|
}
|
|
let reObj = { node: "", xaxis: "", yaxis: "" };
|
|
for (let k = 0; k < shopArr.length; k++) {
|
|
if (shopArr[k].name == obj.shopNum) {
|
|
reObj.node = shopArr[k].node;
|
|
reObj.xaxis = shopArr[k].xaxis;
|
|
reObj.yaxis = shopArr[k].yaxis;
|
|
reObj.floor = obj.floor;
|
|
reObj.shopNum = obj.shopNum;
|
|
break;
|
|
}
|
|
}
|
|
return reObj;
|
|
},
|
|
/**
|
|
* 模拟导航获取路线
|
|
*/
|
|
onFindPathModel: function (usePath = null) {
|
|
Map_QM.forShopArr.length = 0;
|
|
_indexPathFloor = 0;
|
|
isPathPlay = true;
|
|
Map_QM.dispatchEvent({
|
|
type: 'startFindPath',
|
|
data: ""
|
|
});
|
|
if (parseInt(Config.startObj.node) == -1) {
|
|
return;
|
|
}
|
|
if (!Config.startObj.xaxis) {
|
|
let pathData = Config.allMap[Config.selectBuild].buildArr[parseInt(Config.startObj.floor)].mapData.path;
|
|
Config.startObj.xaxis = pathData.nodes[parseInt(Config.startObj.node)].x;
|
|
Config.startObj.yaxis = pathData.nodes[parseInt(Config.startObj.node)].y;
|
|
}
|
|
usePath = usePath ?? graphPath;
|
|
Map_QM.forShopPath(usePath);
|
|
},
|
|
forShopPath: function (usePath) {
|
|
let startNade = Config.selectBuild + "_" + Config.startObj.floor + "_" + Config.startObj.node;
|
|
let toNade = Config.selectBuild + "_" + Config.overObj.floor + "_" + Config.overObj.node;
|
|
let path = dijkstra.find_path(usePath, startNade, toNade);
|
|
let PathPoint = path.nodes;
|
|
let Dir = "前方", index = 0;
|
|
this.forShopArr = [];
|
|
if (PathPoint.length > 1) {
|
|
this.forShopArr.push({ floor: Config.startObj.floor, PathPoint: [] });
|
|
let pathData;
|
|
for (let j = 0; j < PathPoint.length; j++) {
|
|
let array = PathPoint[j].split("_");
|
|
pathData = Config.allMap[Config.selectBuild].buildArr[parseInt(array[1])].mapData.path;
|
|
if (array[1] == this.forShopArr[index].floor) {
|
|
this.forShopArr[index].PathPoint.push(pathData.nodes[parseInt(array[2])]);
|
|
} else {
|
|
if (j > 0) {
|
|
this.forShopArr[index].Facilities = this.getFacilIcon(PathPoint[j - 1].split("_"));
|
|
} else {
|
|
this.forShopArr[index].Facilities = null;
|
|
}
|
|
this.forShopArr.push({ floor: parseInt(array[1]), PathPoint: [] });
|
|
index++;
|
|
this.forShopArr[index].PathPoint.push(pathData.nodes[parseInt(array[2])]);
|
|
}
|
|
}
|
|
let dy = 0, dx = 0, ang = 0;
|
|
|
|
if (this.forShopArr[0].PathPoint.length > 1) {
|
|
if (this.forShopArr[0].PathPoint.length == 2) {
|
|
dy = this.forShopArr[0].PathPoint[1].y - this.forShopArr[0].PathPoint[0].y;
|
|
dx = this.forShopArr[0].PathPoint[1].x - this.forShopArr[0].PathPoint[0].x;
|
|
} else {
|
|
dy = this.forShopArr[0].PathPoint[2].y - this.forShopArr[0].PathPoint[1].y;
|
|
dx = this.forShopArr[0].PathPoint[2].x - this.forShopArr[0].PathPoint[1].x;
|
|
}
|
|
ang = Math.atan2(dy, dx) * 180 / Math.PI - Config.deviceObj.angle;
|
|
|
|
ang = ang > 180 ? ang - 360 : ang;
|
|
ang = ang < -180 ? ang + 360 : ang;
|
|
|
|
if (ang < -50 && ang >= -130) {
|
|
Dir = "向前出发";
|
|
} else if (ang >= -50 && ang < 50) {
|
|
Dir = "向右出发";
|
|
} else if (ang >= 50 && ang < 130) {
|
|
Dir = "向后出发";
|
|
} else {
|
|
Dir = "向左出发";
|
|
}
|
|
}
|
|
}
|
|
let pLen = Map_QM.forShopArr[Map_QM.forShopArr.length - 1].PathPoint.length;
|
|
Config.overObj.xaxis = Map_QM.forShopArr[Map_QM.forShopArr.length - 1].PathPoint[pLen - 1].x;
|
|
Config.overObj.yaxis = Map_QM.forShopArr[Map_QM.forShopArr.length - 1].PathPoint[pLen - 1].y
|
|
|
|
if (Map_QM.forShopArr.length > 0) { // "floor" PathPoint Direction (Facilities)
|
|
Map_QM.forShopArr[0].Direction = Dir;
|
|
|
|
for (let m = 0; m < Map_QM.forShopArr.length; m++) {
|
|
//查找经过店铺
|
|
Map_QM.forShopArr[m].wayShop = Map_QM.foreignShop(Map_QM.forShopArr[m].PathPoint, Map_QM.forShopArr[m].floor, m);
|
|
if (Config.overObj.floor == Map_QM.forShopArr[m].floor) {
|
|
let len = Map_QM.forShopArr[m].wayShop.length;
|
|
if (Map_QM.forShopArr[m].wayShop[len - 1]?.shop.yaxis == Config.overObj.node) {
|
|
Map_QM.forShopArr[m].wayShop.pop();
|
|
}
|
|
}
|
|
}
|
|
Map_QM.dispatchEvent({
|
|
type: 'initPathOver',
|
|
data: Map_QM.forShopArr
|
|
});
|
|
} else {
|
|
console.error('无可行路径,请检查起、终点位');
|
|
return;
|
|
}
|
|
let mint = parseInt(path.cost / Config.mapScale / 55) < 0.5 ? 0.5 : parseInt(path.cost / Config.mapScale / 55);
|
|
//console.log(`距离目的地 ${parseInt(path.cost / Config.mapScale)} 米,预计${mint} 分钟`); // 21 是比例尺
|
|
this.onFindPathToObj();
|
|
},
|
|
/**
|
|
* 途径店铺
|
|
*/
|
|
foreignShop: function (pathArr, cFloor, m) {
|
|
console.log(pathArr)
|
|
let shopList = [];
|
|
let shops = Map_QM.mapArr[Config.selectBuild][parseInt(cFloor)].allObj.children;
|
|
for (let n = 0; n < pathArr.length; n++) {
|
|
for (let i = 0; i < shops.length; i++) {
|
|
if (shops[i].userData && shops[i].userData.type == "shop" && shops[i].userData.navRecommend) {
|
|
if (shops[i].userData.node == pathArr[n].id && shops[i].userData.shopData) {
|
|
let data = { pathArrIn: m, pathIndex: n, shop: shops[i].userData.shopData };
|
|
shopList.push(data);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return shopList;
|
|
},
|
|
getFacilIcon: function (fromFArr) {
|
|
let childs = this.mapArr[Config.selectBuild][fromFArr[1]].serObj.children;
|
|
let selectEle;
|
|
for (let i = 0; i < childs.length; i++) {
|
|
if (childs[i].navCode == fromFArr[2]) {
|
|
selectEle = childs[i];
|
|
break;
|
|
}
|
|
}
|
|
return selectEle;
|
|
},
|
|
|
|
/**
|
|
* 寻路动画方法
|
|
*/
|
|
onFindPathToObj: function () {
|
|
Map_QM.dispatchEvent({ //初始化寻路界面
|
|
type: 'initPathPage',
|
|
data: this.forShopArr
|
|
});
|
|
outTime = -1;
|
|
_indexPathFloor = 0;
|
|
Map_QM.callBackLoadOver = Map_QM.callBackForPathShop; //楼层初始化完成后回调
|
|
|
|
if (Config.overlap) {
|
|
if (Map_QM.forShopArr.length == 2) {
|
|
Map_QM.changeFloorInner(Map_QM.forShopArr[0].floor, Map_QM.forShopArr[1].floor);
|
|
} else if (Map_QM.forShopArr.length == 3) {
|
|
Map_QM.changeFloorInner(Map_QM.forShopArr[0].floor, Map_QM.forShopArr[1].floor, Map_QM.forShopArr[2].floor);
|
|
} else {
|
|
Map_QM.changeFloorInner(Map_QM.forShopArr[_indexPathFloor].floor);
|
|
}
|
|
} else {
|
|
if (pathCameraState == "2D") {
|
|
Map_QM.onShowMeDir(2);
|
|
Map_QM.controls.enabled = false;
|
|
Map_QM.guide = man_2d;
|
|
}
|
|
Map_QM.changeFloorInner(Map_QM.forShopArr[_indexPathFloor].floor);
|
|
}
|
|
},
|
|
/**
|
|
* 播放楼层动画完成后
|
|
*/
|
|
callBackForPathShop: function () {
|
|
Map_QM.callBackLoadOver = null;
|
|
Map_QM.dispatchEvent({ //开始播放寻路动画
|
|
type: 'startPlayPath',
|
|
data: this.forShopArr
|
|
});
|
|
Map_QM.onFindPath();
|
|
},
|
|
/**
|
|
* 寻路方法
|
|
* @param {Object} startN
|
|
* @param {Object} endN
|
|
*/
|
|
onFindPath: function () {
|
|
TweenMax.killAll(true);
|
|
if (Config.overlap) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.overObj.floor].setOverSite(Config.overObj.xaxis, Config.overObj.yaxis, Map_QM.mapArr[Config.selectBuild][Config.overObj.floor].allObj.position.y + parseInt(Config.shopHeight));
|
|
} else {
|
|
if (Config.overObj.floor == Config.selectFloor && Config.overObj.xaxis) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.overObj.floor].setOverSite(Config.overObj.xaxis, Config.overObj.yaxis, Map_QM.mapArr[Config.selectBuild][Config.overObj.floor].allObj.position.y + parseInt(Config.shopHeight));
|
|
}
|
|
}
|
|
|
|
if (Map_QM.forShopArr.length > 0) {
|
|
document.addEventListener("pathOver", Map_QM.onFindPathFloor, true);
|
|
if (Config.overlap && _indexPathFloor==0) {//叠层
|
|
for (let pathObj of Map_QM.forShopArr) {
|
|
Map_QM.mapArr[Config.selectBuild][pathObj.floor].findPath.onFindPathAnimation(pathObj.PathPoint, pathObj.floor); //传入数组
|
|
}
|
|
let extrudeSettings;
|
|
let vects = new THREE.CurvePath();
|
|
let vects2 = new THREE.CurvePath();
|
|
if (Map_QM.forShopArr.length == 2) {
|
|
vects.add(new THREE.LineCurve3(new THREE.Vector3(Map_QM.forShopArr[0].PathPoint[Map_QM.forShopArr[0].PathPoint.length - 1].x, Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[0].floor].allObj.position.y, Map_QM.forShopArr[0].PathPoint[Map_QM.forShopArr[0].PathPoint.length - 1].y),
|
|
new THREE.Vector3(Map_QM.forShopArr[1].PathPoint[0].x, Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[1].floor].allObj.position.y, Map_QM.forShopArr[1].PathPoint[0].y)));
|
|
extrudeSettings = { bevelEnabled: true, steps: 200, bevelSegments: 8, extrudePath: vects };
|
|
let geometry = new THREE.ExtrudeGeometry(Map_QM.shape, extrudeSettings);
|
|
let lineDashed = new THREE.Mesh(geometry, Config.tubeMaterial);
|
|
Map_QM.dtLineGroup.add(lineDashed);
|
|
}
|
|
if (Map_QM.forShopArr.length == 3) {
|
|
vects.add(new THREE.LineCurve3(new THREE.Vector3(Map_QM.forShopArr[0].PathPoint[Map_QM.forShopArr[0].PathPoint.length - 1].x, Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[0].floor].allObj.position.y, Map_QM.forShopArr[0].PathPoint[Map_QM.forShopArr[0].PathPoint.length - 1].y),
|
|
new THREE.Vector3(Map_QM.forShopArr[1].PathPoint[0].x, Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[1].floor].allObj.position.y, Map_QM.forShopArr[1].PathPoint[0].y)));
|
|
|
|
vects2.add(new THREE.LineCurve3(new THREE.Vector3(Map_QM.forShopArr[1].PathPoint[Map_QM.forShopArr[1].PathPoint.length - 1].x, Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[1].floor].allObj.position.y, Map_QM.forShopArr[1].PathPoint[Map_QM.forShopArr[1].PathPoint.length - 1].y),
|
|
new THREE.Vector3(Map_QM.forShopArr[2].PathPoint[0].x, Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[2].floor].allObj.position.y, Map_QM.forShopArr[2].PathPoint[0].y)));
|
|
extrudeSettings = { bevelEnabled: true, steps: 200, bevelSegments: 8, extrudePath: vects };
|
|
extrudeSettings2 = { bevelEnabled: true, steps: 200, bevelSegments: 8, extrudePath: vects2 };
|
|
let geometry = new THREE.ExtrudeGeometry(Map_QM.shape, extrudeSettings);
|
|
let lineDashed = new THREE.Mesh(geometry, Config.tubeMaterial);
|
|
Map_QM.dtLineGroup.add(lineDashed);
|
|
let geometry2 = new THREE.ExtrudeGeometry(Map_QM.shape, extrudeSettings2);
|
|
let lineDashed2 = new THREE.Mesh(geometry2, Config.tubeMaterial);
|
|
Map_QM.dtLineGroup.add(lineDashed2);
|
|
}
|
|
} else {
|
|
Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[_indexPathFloor].floor].findPath.clearPath();
|
|
Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[_indexPathFloor].floor].findPath.onFindPathAnimation(Map_QM.forShopArr[_indexPathFloor].PathPoint); //传入数组
|
|
}
|
|
Map_QM.mapArr[Config.selectBuild][Map_QM.forShopArr[_indexPathFloor].floor].findPath.guidePathPlay(Map_QM.forShopArr[_indexPathFloor]);
|
|
Map_QM.collisionChock();
|
|
}
|
|
},
|
|
/**
|
|
* 显示楼层
|
|
*/
|
|
showNavFloor: function (fromFloor, toFloor) {
|
|
let floorArr = [];
|
|
let min = Math.min(fromFloor, toFloor);
|
|
let max = Math.max(fromFloor, toFloor);
|
|
for (let i = min; i <= max; i++) {
|
|
floorArr.push(Map_QM.mapArr[Config.selectBuild][i].floorName);
|
|
}
|
|
return floorArr;
|
|
},
|
|
|
|
//导航完成事件
|
|
onFindPathFloor: function (event) {
|
|
document.removeEventListener("pathOver", Map_QM.onFindPathFloor);
|
|
if (Map_QM.forShopArr.length <= _indexPathFloor) {
|
|
return;
|
|
}
|
|
Map_QM.dispatchEvent({ //当前层寻路完成
|
|
type: 'floorPlayOver',
|
|
data: Map_QM.forShopArr[_indexPathFloor].floor
|
|
});
|
|
if (_indexPathFloor < Map_QM.forShopArr.length - 1) {
|
|
let pathFloor = Map_QM.forShopArr[_indexPathFloor].floor;
|
|
let x0 = Map_QM.forShopArr[_indexPathFloor].Facilities.position.x + 64;
|
|
let y0 = Map_QM.forShopArr[_indexPathFloor].Facilities.position.y;
|
|
let model = Map_QM.forShopArr[_indexPathFloor].Facilities.userData.model;
|
|
let box;
|
|
if (model && model.userData.name == "dt") {
|
|
model.traverse(function (child) {
|
|
if (child.isMesh && child.name == "zhitibox") {
|
|
box = child;
|
|
}
|
|
});
|
|
}
|
|
let zo = 2, tz = 2;
|
|
_indexPathFloor++;
|
|
let toFloor = parseInt(Map_QM.forShopArr[_indexPathFloor].floor);
|
|
Config.selectFloor = toFloor;
|
|
if (pathFloor < toFloor) {
|
|
tz = ((toFloor - pathFloor) * 48);
|
|
} else {
|
|
zo = ((pathFloor - toFloor) * 48 - 4);
|
|
}
|
|
document.getElementById('moveFloor').style.bottom = zo + "px";
|
|
let floorArr = Map_QM.showNavFloor(pathFloor, toFloor); //电梯旁显示的楼层名称
|
|
Map_QM.moveFloorbg.element.style.visibility = "visible";
|
|
Map_QM.moveFloorbg.element.style.height = (floorArr.length * 48) + "px";
|
|
Map_QM.moveFloorbg.position.set(x0, y0, 80);
|
|
Map_QM.moveFloorbg.applyMatrix(Map_QM.mapArr[Config.selectBuild][pathFloor].allObj.matrix);
|
|
Map_QM.moveFloorbg.applyMatrix(Map_QM.sceneGap.matrix);
|
|
let floorBox = document.getElementById('floorBox');
|
|
while (floorBox.hasChildNodes()) {
|
|
floorBox.removeChild(floorBox.firstChild);
|
|
}
|
|
for (let i = floorArr.length - 1; i >= 0; i--) {
|
|
let span2 = document.createElement("span");
|
|
span2.style.cssText = "width: 48px; height: 48px; line-height: 48px; color: #000000;display: block; text-align: center;";
|
|
span2.innerText = floorArr[i];
|
|
floorBox.appendChild(span2);
|
|
}
|
|
TweenMax.fromTo('#moveFloor', 1.5, { bottom: zo },
|
|
{
|
|
bottom: tz,
|
|
delay: 0.1,
|
|
onComplete: function () {
|
|
if (!Config.overlap) {
|
|
Map_QM.callBackLoadOver = Map_QM.callBackForPathShop; //楼层初始化完成后回调
|
|
Map_QM.changeFloorInner(Map_QM.forShopArr[_indexPathFloor].floor);
|
|
} else {
|
|
if (Map_QM.forShopArr > _indexPathFloor) {
|
|
Config.selectFloor = Map_QM.forShopArr[_indexPathFloor].floor;
|
|
}
|
|
Map_QM.clearFloor(-1, false);
|
|
Map_QM.callBackForPathShop();
|
|
}
|
|
}
|
|
});
|
|
if (box) {
|
|
TweenMax.fromTo(box.position, 1.2, { y: (zo / 3) }, {
|
|
y: (tz / 3), delay: 0.2, onComplete: function () {
|
|
box.position.y = 0;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (pathCameraState == "3D") {
|
|
let xt = Map_QM.guide.position.x + event.detail.dx * 10;
|
|
let yt = Map_QM.guide.position.y + event.detail.dy * 10;
|
|
|
|
let s = Math.sqrt((xt - Map_QM.guide.position.x) * (xt - Map_QM.guide.position.x) + (yt - Map_QM.guide.position.y) * (yt - Map_QM.guide.position.y));
|
|
ang = Math.acos((yt - Map_QM.guide.position.y) / s);
|
|
if (xt < Map_QM.guide.position.x) {
|
|
Map_QM.guide.rotation.z = -1 * ang;//Math.PI-ang;
|
|
} else {
|
|
Map_QM.guide.rotation.z = ang; //Math.PI+ang;
|
|
}
|
|
|
|
if (model && model.userData.name == "upft") {
|
|
Map_QM.guide.visible = true;
|
|
TweenMax.to(Map_QM.guide.position, 1.3, {
|
|
x: xt, y: yt, z: 50, onComplete: function () {
|
|
Map_QM.guide.visible = false;
|
|
}
|
|
});
|
|
}
|
|
if (model && model.userData.name == "downft") {
|
|
Map_QM.guide.visible = true;
|
|
TweenMax.to(Map_QM.guide.position, 1.3, {
|
|
x: xt, y: yt, z: -50, onComplete: function () {
|
|
Map_QM.guide.visible = false;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
Config.startObj = Config.deviceObj;
|
|
//console.log("到达店铺");
|
|
Map_QM.dispatchEvent({ //寻路完成
|
|
type: 'PathPlayOver',
|
|
data: "PathPlayOver"
|
|
});
|
|
}
|
|
},
|
|
/**
|
|
* 楼层状态清理
|
|
*/
|
|
clearFloor: function (fIndex = -1, reSet = true) {
|
|
if (fIndex == -1) {
|
|
fIndex = Config.deviceObj.floor;
|
|
}
|
|
if (Map_QM.selectShop) {
|
|
Map_QM.selectShop.scale.z = 1;
|
|
}
|
|
if (Map_QM.endModel && Map_QM.endModel.visible) {
|
|
Map_QM.endModel.visible = false;
|
|
}
|
|
if (Map_QM.endIcon && Map_QM.endIcon.visible) {
|
|
Map_QM.endIcon.visible = false;
|
|
}
|
|
if (Map_QM.moveFloorbg) {
|
|
Map_QM.moveFloorbg.element.style.visibility = "hidden";
|
|
}
|
|
Map_QM.clearDeviceSelectState();
|
|
if (reSet) { //叠层不处理
|
|
if (Map_QM.mapArr[Config.selectBuild] && Map_QM.mapArr[Config.selectBuild].length > 0) {
|
|
for (let i = 0; i < Map_QM.mapArr[Config.selectBuild].length; i++) {
|
|
let child = Map_QM.mapArr[Config.selectBuild][i].allObj;
|
|
for (let k = child.children.length - 1; k >= 0; k--) {
|
|
if (child.children[k].name == "lineDash") {
|
|
Map_QM.mapArr[Config.selectBuild][i].allObj.remove(child.children[k]);
|
|
}
|
|
}
|
|
Map_QM.mapArr[Config.selectBuild][i].findPath.clearPath();
|
|
}
|
|
}
|
|
Map_QM.remove_child(Map_QM.dtLineGroup);
|
|
}
|
|
TweenMax.killAll(true);
|
|
},
|
|
|
|
remove_child: function (remObj) {
|
|
|
|
if (!remObj) {
|
|
return;
|
|
}
|
|
let child_elem = remObj.children;
|
|
for (let i = child_elem.length - 1; i >= 0; i--) {
|
|
if (child_elem[i].children.length > 0) {
|
|
Map_QM.remove_child(child_elem[i]);
|
|
} else {
|
|
if (child_elem[i] instanceof THREE.Mesh) {
|
|
child_elem[i].geometry.dispose(); // 删除几何体
|
|
if (child_elem[i].material !== undefined) Map_QM.removeMaterial(child_elem.material); // 删除材质
|
|
}
|
|
}
|
|
if (child_elem[i].name != "light" && child_elem[i].name != "shopInfo" && child_elem[i].name != "dtline") {
|
|
remObj.remove(child_elem[i]);
|
|
}
|
|
}
|
|
|
|
},
|
|
removeMaterial: function (material) {
|
|
if (Array.isArray(material)) {
|
|
for (var i = 0, l = material.length; i < l; i++) {
|
|
this.removeMaterialFromRefCounter(material[i]);
|
|
}
|
|
} else {
|
|
this.removeMaterialFromRefCounter(material);
|
|
}
|
|
},
|
|
removeMaterialFromRefCounter: function (material) {
|
|
var materialsRefCounter = this.materialsRefCounter;
|
|
if (materialsRefCounter) {
|
|
var count = materialsRefCounter.get(material);
|
|
count--;
|
|
if (count === 0) {
|
|
materialsRefCounter.delete(material);
|
|
delete this.materials[material.uuid];
|
|
} else {
|
|
materialsRefCounter.set(material, count);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} pathStop() 导航暂停/播放
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 导航动画暂停/播放
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
*/
|
|
pathStop: function () {
|
|
isPathPlay = !isPathPlay;
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].findPath.pathPlay.isPlay = isPathPlay;
|
|
},
|
|
/**
|
|
* @api {方法} pathRePlay() 导航动画重播
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 导航动画重播
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
*/
|
|
pathRePlay: function () {
|
|
if (Config.overObj && Map_QM.forShopArr[0]) {
|
|
clearTimeout(outTime);
|
|
outTime = setTimeout(() => {
|
|
clearTimeout(outTime);
|
|
isPathPlay = true;
|
|
Map_QM.clearFloor();
|
|
Map_QM.onFindPathToObj();
|
|
}, 300);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api {方法} ChangePathByFt() 切换扶梯模式
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 导航切换扶梯模式
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {function} callBack 回调函数
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.ChangePathByFt(function);
|
|
*
|
|
*/
|
|
ChangePathByFt: function (callBack) {
|
|
if (Config.overObj) {
|
|
clearTimeout(outTime);
|
|
outTime = setTimeout(() => {
|
|
clearTimeout(outTime);
|
|
Map_QM.clearFloor();
|
|
Map_QM.onFindPathModel(ftPath);
|
|
if(callBack){
|
|
callBack(Map_QM.forShopArr);
|
|
}
|
|
}, 300);
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} ChangePathByDt() 切换电梯模式
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 导航切换电梯模式
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {function} callBack 回调函数
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.ChangePathByDt(function);
|
|
*
|
|
*/
|
|
ChangePathByDt: function (callBack) {
|
|
if (Config.overObj) {
|
|
clearTimeout(outTime);
|
|
outTime = setTimeout(() => {
|
|
clearTimeout(outTime);
|
|
Map_QM.clearFloor();
|
|
Map_QM.onFindPathModel(dtPath);
|
|
if(callBack){
|
|
callBack(Map_QM.forShopArr);
|
|
}
|
|
}, 300);
|
|
}
|
|
},
|
|
/**
|
|
* @api {方法} ChangePathByGood() 切换最佳模式
|
|
* @apiGroup 地图导航
|
|
* @apiDescription 导航切换最佳模式
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {function} callBack 回调函数
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.ChangePathByGood(function);
|
|
*
|
|
*/
|
|
ChangePathByGood: function (callBack) {
|
|
if (Config.overObj) {
|
|
clearTimeout(outTime);
|
|
outTime = setTimeout(() => {
|
|
clearTimeout(outTime);
|
|
Map_QM.clearFloor();
|
|
Map_QM.onFindPathModel(graphPath);
|
|
callBack(Map_QM.forShopArr);
|
|
}, 300);
|
|
}
|
|
},
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* @api {方法} changeWindowResize() 窗口变化
|
|
* @apiGroup 地图交互
|
|
* @apiDescription 窗口变化
|
|
* @apiVersion 1.0.0
|
|
*
|
|
* @apiParam {int} width 窗口宽
|
|
* @apiParam {int} height 窗口高
|
|
*
|
|
* @apiSampleRequest off
|
|
*
|
|
* @apiParamExample 请求示例
|
|
*
|
|
* Map_QM.changeWindowResize(1280,1080);
|
|
*/
|
|
changeWindowResize: function (width, height, onSet = true) {
|
|
Map_QM.camera.aspect = width / height;
|
|
Map_QM.camera.updateProjectionMatrix();
|
|
Map_QM.renderer.setSize(width, height);
|
|
Map_QM.labelRenderer.setSize(width, height);
|
|
Map_QM.w = width;
|
|
Map_QM.h = height;
|
|
|
|
}
|
|
}
|
|
Object.assign(MainMap_QM.prototype, THREE.EventDispatcher.prototype);
|
|
|
|
//////////////////////////////////////-------------------------------FloorMap
|
|
FloorMap_QM = function (bIndex, fIndex, floorName) {
|
|
this.Model_QM = new MyModel_QM();
|
|
this.facUtil = new Facilities_QM();
|
|
this.findPath = new FindPath_QM();
|
|
this.logoUtil = new ShopLogo_QM();
|
|
this.allObj = new THREE.Group();
|
|
this.allObj.name = floorName;
|
|
this.allObj.rotation.x = Math.PI / -2;
|
|
this.labelObj = new THREE.Group();
|
|
this.labelObj.renderOrder = 100;
|
|
this.iconLabel = new THREE.Group();
|
|
this.iconLabel.renderOrder = 100;
|
|
|
|
this.floorOrder = fIndex;
|
|
this.buildOrder = bIndex
|
|
this.floorName = floorName;
|
|
|
|
//存放设施图标
|
|
this.serObj = new THREE.Object3D();
|
|
//存放车位box
|
|
this.parkObj = new THREE.Group();
|
|
//标签
|
|
this.tagObj = new THREE.Group();
|
|
this.tagObj.renderOrder = 100;
|
|
this.devObj = new THREE.Group();
|
|
//存放设施图标
|
|
this.logoObj = new THREE.Object3D();
|
|
this.allObj.add(this.logoObj);
|
|
this.svgObj = new THREE.Group();
|
|
this.allObj.add(this.svgObj);
|
|
this.allObj.add(this.serObj);
|
|
this.allObj.add(this.devObj);
|
|
this.allObj.add(this.labelObj);
|
|
this.allObj.add(this.iconLabel);
|
|
this.allObj.add(this.tagObj);
|
|
//标签
|
|
this.showTagObj = new THREE.Group();
|
|
this.showTagObj.renderOrder = 100;
|
|
this.allObj.add(this.showTagObj);
|
|
|
|
this.startIcon;
|
|
}
|
|
FloorMap_QM.prototype.initDraw = function () {
|
|
this.initFloor();
|
|
this.initFacilitie();
|
|
this.initDevice(); //初始化设备
|
|
this.initStairs();
|
|
this.initTextArea();
|
|
this.initWall();
|
|
this.initDecos();
|
|
this.initPark();
|
|
this.initModel();
|
|
}
|
|
FloorMap_QM.prototype.initModel = function () {
|
|
let sopce = this;
|
|
if (Config.modelArr) {
|
|
for (let i = 0; i < Config.modelArr.length; i++) {
|
|
if (Config.modelArr[i].floor == this.floorOrder) {
|
|
new THREE.GLTFLoader().load(Config.modelArr[i].url, function (object) {//加载路径fbx文件
|
|
let mod = object.scene;
|
|
mod.children[0].traverse(function (child) {
|
|
if (child.isMesh) {
|
|
child.receiveShadow = true;
|
|
child.castShadow = true;
|
|
}
|
|
});
|
|
for (let t = 0; t < Config.modelArr[i].list.length; t++) {
|
|
let obj = mod.clone();
|
|
obj.position.set(Config.modelArr[i].list[t].site.x, -1 * Config.modelArr[i].list[t].site.y, Config.modelArr[i].list[t].site.z);
|
|
obj.scale.set(Config.modelArr[i].list[t].size.x, Config.modelArr[i].list[t].size.y, Config.modelArr[i].list[t].size.z);
|
|
obj.rotateX(Config.modelArr[i].list[t].rot.x);
|
|
obj.rotateY(Config.modelArr[i].list[t].rot.y);
|
|
obj.rotateZ(Config.modelArr[i].list[t].rot.z);
|
|
sopce.allObj.add(obj);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Config.labelIconArr) {
|
|
for (let i = 0; i < Config.labelIconArr.length; i++) {
|
|
if (Config.labelIconArr[i].floor == this.floorOrder) {
|
|
let SpriteDiv = document.createElement('div');
|
|
SpriteDiv.className = Config.labelIconArr[i].className;
|
|
SpriteDiv.innerHTML = Config.labelIconArr[i].title;
|
|
SpriteDiv.dataset.id = Config.labelIconArr[i].data.id;
|
|
SpriteDiv.dataset.x = Config.labelIconArr[i].site.x;
|
|
SpriteDiv.dataset.y = Config.labelIconArr[i].site.y;
|
|
SpriteDiv.dataset.z = Config.labelIconArr[i].site.z;
|
|
let pointLabel = new THREE.CSS2DObject(SpriteDiv)
|
|
pointLabel.position.set(Config.labelIconArr[i].site.x, -1 * Config.labelIconArr[i].site.y, Config.labelIconArr[i].site.z);
|
|
pointLabel.name = Config.labelIconArr[i].title;
|
|
pointLabel.userData = Config.labelIconArr[i].data;
|
|
pointLabel.userData.site = Config.labelIconArr[i].site;
|
|
if (Config.labelIconArr[i].click) { //可点击
|
|
SpriteDiv.addEventListener("click", (event) => {
|
|
Map_QM.dispatchEvent({
|
|
type: 'labelIcon',
|
|
data: event.target.dataset
|
|
});
|
|
}, false);
|
|
}
|
|
pointLabel.userData.floor = Config.labelIconArr[i].floor;
|
|
sopce.showTagObj.add(pointLabel);
|
|
pointLabel.userData.show = Config.labelIconArr[i].data.show;
|
|
if (Config.labelIconArr[i].data.show != language) {
|
|
pointLabel.element.style.opacity = 0;
|
|
pointLabel.element.style.pointerEvents = "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//初始化单楼层
|
|
FloorMap_QM.prototype.initFloor = function () {
|
|
let floor;
|
|
let mapData = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData;
|
|
let entColor, borderColor;
|
|
if (mapData.floorArea) {
|
|
floor = Config.changeAreaToString(mapData.floorArea);
|
|
}
|
|
let bLen = mapData.buildArea.length;
|
|
let hLen = mapData.hollowArea.length;
|
|
let hows_f = [];
|
|
for (let m = 0; m < hLen; m++) {
|
|
hows_f.push(Config.changeAreaToString(mapData.hollowArea[m]));
|
|
}
|
|
if (floor) {
|
|
entColor = parseInt(mapData.floorArea.entColor.replace("#", "0x"), 16);
|
|
borderColor = parseInt(mapData.floorArea.borderColor.replace("#", "0x"), 16);
|
|
floorH = parseInt(mapData.floorArea.toHeight);
|
|
let mash = this.Model_QM.MyModelShape(floor, hows_f, mapData.floorArea, entColor, borderColor, 10);
|
|
mash.userData = {
|
|
"type": "floor",
|
|
"order": this.floorOrder
|
|
};
|
|
this.allObj.add(mash);
|
|
}
|
|
/////////////////////初始化楼栋
|
|
for (let i = 0; i < bLen; i++) {
|
|
let build = Config.changeAreaToString(mapData.buildArea[i]);
|
|
let hows = [];
|
|
for (let t = 0; t < hLen; t++) {
|
|
let isIn = Config.checkAreaInArea(mapData.hollowArea[t], mapData.buildArea[i]);
|
|
if (isIn) {
|
|
hows.push(Config.changeAreaToString(mapData.hollowArea[t]));
|
|
}
|
|
}
|
|
entColor = parseInt(mapData.buildArea[i].entColor.replace("#", "0x"), 16);
|
|
borderColor = parseInt(mapData.buildArea[i].borderColor.replace("#", "0x"), 16);
|
|
Config.buildHeight = Math.max(parseInt(mapData.buildArea[i].toHeight), Config.buildHeight);
|
|
buildH = parseInt(mapData.buildArea[i].toHeight);
|
|
let mash = this.Model_QM.MyModelShape(build, hows, mapData.buildArea[i], entColor, borderColor, 30);
|
|
mash.userData = {
|
|
"type": "build"
|
|
};
|
|
this.allObj.add(mash);
|
|
}
|
|
//店铺
|
|
let sLen = mapData.shopArea.length;
|
|
for (let i = 0; i < sLen; i++) {
|
|
if (Config.changeAreaToString(mapData.shopArea[i]) != "") {
|
|
let arr = Config.changeShopLinesToString(mapData.shopArea[i]);
|
|
entColor = mapData.shopArea[i].entColor || "#b7b7b7";
|
|
borderColor = mapData.shopArea[i].borderColor || "#b7b7b7";
|
|
let show = showE = mapData.shopArea[i].name;
|
|
let logo = "", navRecommend = false, shopD = {};
|
|
Config.shopHeight = parseInt(mapData.shopArea[i].toHeight);
|
|
let shopData = Config.shopData;
|
|
if (shopData) {
|
|
for (let h = 0; h < shopData.length; h++) {
|
|
if (shopData[h].buildingOrder) {
|
|
if (shopData[h].buildingOrder == this.buildOrder && shopData[h].floorOrder == this.floorOrder) {
|
|
if (shopData[h].houseNum == mapData.shopArea[i].name) {
|
|
show = shopData[h].name;
|
|
showE = shopData[h].nameEn;
|
|
logo = shopData[h].logoPath;
|
|
if (shopData[h].navRecommend == undefined) {
|
|
navRecommend = true;
|
|
} else {
|
|
navRecommend = shopData[h].navRecommend;
|
|
}
|
|
shopD = shopData[h];
|
|
if (shopData[h].isNewStore) { //新店
|
|
mapData.shopArea[i].type = "new-shop";
|
|
this.addTagLabel(mapData.shopArea[i], { "node": mapData.shopArea[i].shopNav, "floor": this.floorOrder, "build": this.buildOrder });
|
|
}
|
|
if (shopData[h].isSpecial) { //促销
|
|
mapData.shopArea[i].type = "promotion";
|
|
this.addTagLabel(mapData.shopArea[i], { "node": mapData.shopArea[i].shopNav, "floor": this.floorOrder, "build": this.buildOrder });
|
|
}
|
|
if (shopData[h].formatColor) {
|
|
entColor = parseInt(shopData[h].formatColor.replace("#", "0x"), 16);
|
|
}
|
|
if (shopData[h].borderColor) {
|
|
borderColor = parseInt(shopData[h].borderColor.replace("#", "0x"), 16);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (shopData[h].floorOrder == this.floorOrder) {
|
|
if (shopData[h].houseNum == mapData.shopArea[i].name) {
|
|
show = shopData[h].name;
|
|
showE = shopData[h].nameEn;
|
|
logo = shopData[h].logoPath;
|
|
if (shopData[h].navRecommend == undefined) {
|
|
navRecommend = true;
|
|
} else {
|
|
navRecommend = shopData[h].navRecommend;
|
|
}
|
|
shopD = shopData[h];
|
|
if (shopData[h].isNewStore) { //新店
|
|
mapData.shopArea[i].type = "new-shop";
|
|
this.addTagLabel(mapData.shopArea[i], { "node": mapData.shopArea[i].shopNav, "floor": this.floorOrder, "build": this.buildOrder });
|
|
}
|
|
if ((shopData[h].shopActList && shopData[h].shopActList.length > 0)) { //促销
|
|
mapData.shopArea[i].type = "promotion";
|
|
this.addTagLabel(mapData.shopArea[i], { "node": mapData.shopArea[i].shopNav, "floor": this.floorOrder, "build": this.buildOrder });
|
|
}
|
|
if (shopData[h].formatColor) {
|
|
entColor = parseInt(shopData[h].formatColor.replace("#", "0x"), 16);
|
|
}
|
|
if (shopData[h].borderColor) {
|
|
borderColor = parseInt(shopData[h].borderColor.replace("#", "0x"), 16);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mapData.shopArea[i].logoUrl && mapData.shopArea[i].isLabel == 0) { //添加logo
|
|
this.logoUtil.renderIcon(mapData.shopArea[i], this, parseInt(mapData.shopArea[i].toHeight) + 1);
|
|
} else { //添加文字
|
|
if (show != "shop" && show != "") {
|
|
let shopDiv = document.createElement('div');
|
|
shopDiv.className = "shopLabel";
|
|
shopDiv.innerText = show;
|
|
shopDiv.dataset.name = show
|
|
shopDiv.dataset.nameEn = showE;
|
|
let shopLabel = new THREE.CSS2DObject(shopDiv);
|
|
shopLabel.position.set(mapData.shopArea[i].xaxis >> 0, -1 * mapData.shopArea[i].yaxis >> 0, parseInt(mapData.shopArea[i].toHeight));
|
|
this.labelObj.add(shopLabel);
|
|
shopLabel.element.style.pointerEvents = "none";
|
|
}
|
|
}
|
|
|
|
let mahc = this.Model_QM.MyModelShape(arr, null, mapData.shopArea[i], entColor, borderColor, 100);
|
|
mahc.node = mapData.shopArea[i].shopNav;
|
|
mahc.userData = {
|
|
"shopData": shopD,
|
|
"xaxis": mapData.shopArea[i].xaxis >> 0,
|
|
"yaxis": mapData.shopArea[i].yaxis >> 0,
|
|
"node": mahc.node,
|
|
"floor": this.floorOrder,
|
|
"navRecommend": navRecommend,
|
|
"type": "shop",
|
|
"entColor": entColor,
|
|
"shopNum": mapData.shopArea[i].name,
|
|
"shopName": show,
|
|
"logo": logo,
|
|
"borderColor": borderColor
|
|
};
|
|
|
|
show = show == "shop" ? "" : show;
|
|
show = show == "floor" ? "" : show;
|
|
show = show == "build" ? "" : show;
|
|
mahc.shopName = show;
|
|
mahc.xaxis = mapData.shopArea[i].xaxis >> 0;
|
|
mahc.yaxis = mapData.shopArea[i].yaxis >> 0;
|
|
this.allObj.add(mahc);
|
|
}
|
|
}
|
|
}
|
|
|
|
FloorMap_QM.prototype.addTagLabel = function (obj, userData) {
|
|
let shopDiv = document.createElement('img');
|
|
shopDiv.src = "./static/img/" + obj.type + ".png";
|
|
shopDiv.style.zIndex = 200;
|
|
let shopLabel = new THREE.CSS2DObject(shopDiv);
|
|
shopLabel.userData = userData;
|
|
shopLabel.position.set(obj.xaxis >> 0, -1 * obj.yaxis >> 0, Config.shopHeight);
|
|
this.tagObj.add(shopLabel);
|
|
}
|
|
|
|
//初始化服务图标
|
|
FloorMap_QM.prototype.initFacilitie = function () {
|
|
let serArr = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData.icons;
|
|
for (let i = 0; i < serArr.length; i++) {
|
|
serArr[i].floorOrder = this.floorOrder;
|
|
this.facUtil.renderIcon(serArr[i], this);
|
|
}
|
|
}
|
|
|
|
//初始化设备图标
|
|
FloorMap_QM.prototype.initDevice = function () {
|
|
let mapData = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData;
|
|
if (deviceShow && deviceJSON && deviceJSON[this.buildOrder]) {
|
|
for (item of deviceJSON[this.buildOrder].floors) {
|
|
if (item.floorOrder == this.floorOrder) {
|
|
let devices = item.devices;
|
|
for (let i = 0; i < devices.length; i++) {
|
|
if (devices[i].yaxis != "" && mapData.path.nodes[parseInt(devices[i].yaxis)]) {
|
|
devices[i].x = mapData.path.nodes[parseInt(devices[i].yaxis)].x;
|
|
devices[i].y = mapData.path.nodes[parseInt(devices[i].yaxis)].y;
|
|
devices[i].node = parseInt(devices[i].yaxis);
|
|
this.facUtil.renderDeviceIcon(devices[i], this);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//初始化电梯图标
|
|
FloorMap_QM.prototype.initStairs = function () {
|
|
let facArr = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData.stairs;
|
|
for (let i = 0; i < facArr.length; i++) {
|
|
if (facArr[i].facCode == "upft") {
|
|
if (elevator) {
|
|
let ex = elevator.clone();
|
|
ex.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site);
|
|
ex.rotation.y = facArr[i].angle * Math.PI / -180;
|
|
ex.userData.type = "icon";
|
|
ex.userData.use = "3d";
|
|
ex.userData.name = "upft";
|
|
this.serObj.add(ex);
|
|
facArr[i].facCode = "ft";
|
|
this.facUtil.renderIcon(facArr[i], this, false, ex);
|
|
} else {
|
|
facArr[i].facCode = "ft";
|
|
this.facUtil.renderIcon(facArr[i], this, true);
|
|
}
|
|
|
|
} else if (facArr[i].facCode == "downft") {
|
|
if (elevatorDown) {
|
|
let ex = elevatorDown.clone();
|
|
ex.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site);
|
|
ex.rotation.y = facArr[i].angle * Math.PI / -180;
|
|
ex.userData.type = "icon";
|
|
ex.userData.use = "3d";
|
|
ex.userData.name = "downft";
|
|
this.serObj.add(ex);
|
|
facArr[i].facCode = "ft";
|
|
this.facUtil.renderIcon(facArr[i], this, false, ex);
|
|
} else {
|
|
facArr[i].facCode = "ft";
|
|
this.facUtil.renderIcon(facArr[i], this, true);
|
|
}
|
|
|
|
} else if (facArr[i].facCode == "dt") {
|
|
if (straight) {
|
|
let stra = straight.clone();
|
|
stra.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site);
|
|
stra.rotation.y = facArr[i].angle * Math.PI / -180;
|
|
stra.userData.type = "icon";
|
|
stra.userData.use = "3d";
|
|
stra.userData.name = "dt";
|
|
this.serObj.add(stra);
|
|
this.facUtil.renderIcon(facArr[i], this, false, stra);
|
|
} else {
|
|
this.facUtil.renderIcon(facArr[i], this, true);
|
|
}
|
|
} else {
|
|
this.facUtil.renderIcon(facArr[i], this, true);
|
|
}
|
|
}
|
|
}
|
|
//初始化装饰图标
|
|
FloorMap_QM.prototype.initDecos = function () {
|
|
let mapData = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData;
|
|
let sLen = mapData.decos.length;
|
|
let entColor, borderColor;
|
|
if (mapData.groupArea) {
|
|
for (let k = 0; k < mapData.groupArea.length; k++) {
|
|
var gp = new THREE.Group();
|
|
gp.rotateX(mapData.groupArea[k].angleX * Math.PI / 180);
|
|
gp.rotateY(mapData.groupArea[k].angleY * Math.PI / 180);
|
|
gp.rotateZ(mapData.groupArea[k].angleZ * Math.PI / 180);
|
|
for (let i = 0; i < sLen; i++) {
|
|
if (mapData.decos[i].gid && mapData.decos[i].gid == mapData.groupArea[k]._name && Config.changeAreaToString(mapData.decos[i]) != "") {
|
|
let arr = Config.changeAreaToString(mapData.decos[i]);
|
|
entColor = parseInt(mapData.decos[i].entColor.replace("#", "0x"), 16);
|
|
borderColor = parseInt(mapData.decos[i].borderColor.replace("#", "0x"), 16);
|
|
let show = mapData.decos[i].name == "deco" ? "" : mapData.decos[i].name;
|
|
let mahc = this.Model_QM.MyModelShape(arr, null, mapData.decos[i], entColor, borderColor, 240);
|
|
mahc.xaxis = mapData.decos[i].xaxis >> 0;
|
|
mahc.yaxis = mapData.decos[i].yaxis >> 0;
|
|
mahc.node = mapData.decos[i].shopNav;
|
|
mahc.userData = {
|
|
"type": "deco"
|
|
};
|
|
if (show != "") {
|
|
let shopDiv = document.createElement('div');
|
|
shopDiv.className = "decoLabel";
|
|
shopDiv.textContent = show;
|
|
let shopLabel = new THREE.CSS2DObject(shopDiv);
|
|
shopLabel.name = mapData.decos[i].name;
|
|
shopLabel.position.set(mapData.decos[i].xaxis >> 0, -1 * mapData.decos[i].yaxis >> 0, parseInt(mapData.decos[i].toHeight) + parseInt(mapData.groupArea[k].site));
|
|
this.labelObj.add(shopLabel);
|
|
}
|
|
gp.add(mahc);
|
|
mahc.position.x = -1 * mapData.groupArea[k].xaxis;
|
|
mahc.position.y = mapData.groupArea[k].yaxis;
|
|
}
|
|
}
|
|
this.allObj.add(gp);
|
|
gp.position.x = mapData.groupArea[k].xaxis;
|
|
gp.position.y = -1 * mapData.groupArea[k].yaxis;
|
|
gp.position.z = mapData.groupArea[k].site;
|
|
gp.scale.set(mapData.groupArea[k].scale, mapData.groupArea[k].scale, mapData.groupArea[k].scale);
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < sLen; i++) {
|
|
if ((!mapData.decos[i].gid || mapData.decos[i].gid == "") && Config.changeAreaToString(mapData.decos[i]) != "") {
|
|
let arr = Config.changeAreaToString(mapData.decos[i]);
|
|
entColor = parseInt(mapData.decos[i].entColor.replace("#", "0x"), 16);
|
|
borderColor = parseInt(mapData.decos[i].borderColor.replace("#", "0x"), 16);
|
|
let show = mapData.decos[i].name == "deco" ? "" : mapData.decos[i].name;
|
|
let mahc = this.Model_QM.MyModelShape(arr, null, mapData.decos[i], entColor, borderColor, 240);
|
|
mahc.xaxis = mapData.decos[i].xaxis >> 0;
|
|
mahc.yaxis = mapData.decos[i].yaxis >> 0;
|
|
mahc.node = mapData.decos[i].shopNav;
|
|
mahc.userData = {
|
|
"type": "deco"
|
|
};
|
|
if (show != "") {
|
|
let shopDiv = document.createElement('div');
|
|
shopDiv.className = "decoLabel";
|
|
shopDiv.textContent = show;
|
|
let shopLabel = new THREE.CSS2DObject(shopDiv);
|
|
shopLabel.name = mapData.decos[i].name;
|
|
shopLabel.position.set(mapData.decos[i].xaxis >> 0, -1 * mapData.decos[i].yaxis >> 0, parseInt(mapData.decos[i].toHeight));
|
|
this.labelObj.add(shopLabel);
|
|
}
|
|
this.allObj.add(mahc);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* 渲染墙体
|
|
*/
|
|
FloorMap_QM.prototype.initWall = function () {
|
|
let mapData = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData;
|
|
//渲染
|
|
if (mapData.wallArea) {
|
|
let sLen = mapData.wallArea.length;
|
|
for (let i = 0; i < sLen; i++) {
|
|
let arr = Config.changeWallToString(mapData.wallArea[i]);
|
|
let mahc = this.Model_QM.MyModelShape(arr, null, mapData.wallArea[i], mapData.wallArea[i].entColor || "#eaeaea", mapData.wallArea[i].borderColor || "#eaeaea", 300);
|
|
mahc.userData = {
|
|
"type": "wall"
|
|
};
|
|
this.allObj.add(mahc);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 渲染文本
|
|
*/
|
|
FloorMap_QM.prototype.initTextArea = function () {
|
|
let mapData = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData;
|
|
//渲染
|
|
if (mapData.svgArea) {
|
|
let sLen = mapData.svgArea.length;
|
|
for (let i = 0; i < sLen; i++) {
|
|
let mahc = this.Model_QM.MyModelText(mapData.svgArea[i]);
|
|
mahc.userData = {
|
|
"type": "svg",
|
|
"rot": mahc.rotation.z,
|
|
"shopNum": mapData.svgArea[i].name
|
|
};
|
|
this.svgObj.add(mahc);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置终点图标
|
|
*/
|
|
FloorMap_QM.prototype.setOverSite = function (shopX, shopY, shopZ) {
|
|
if (Map_QM.endModel) {
|
|
Map_QM.endModel.visible = pathCameraState == "2D" ? false : true;
|
|
Map_QM.endModel.scale.x = Map_QM.endModel.scale.y = Map_QM.endModel.scale.z = 100;
|
|
Map_QM.endModel.position.set(shopX, shopZ, shopY); //x,z,y
|
|
Map_QM.endModel.applyMatrix(Map_QM.sceneGap.matrix);
|
|
if (Map_QM.endIcon) {
|
|
Map_QM.endIcon.visible = pathCameraState == "2D" ? true : false;
|
|
Map_QM.endIcon.scale.x = Map_QM.endIcon.scale.y = Map_QM.endIcon.scale.z = 100;
|
|
Map_QM.endIcon.position.set(shopX, shopZ, shopY); //x,z,y
|
|
Map_QM.endIcon.applyMatrix(Map_QM.sceneGap.matrix);
|
|
}
|
|
} else {
|
|
let loader2 = new THREE.GLTFLoader();
|
|
loader2.load("./static/img/zhong.gltf", function (collada2) {
|
|
collada2.scene.traverse(function (child2) {
|
|
if (child2.name == "object_1" || child2.name == "object_2" || child2.name == "object_3" || child2.name == "object_4" || child2.name == "object_6" || child2.name == "object_11" || child2.name == "object_21" || child2.name == "object_31" || child2.name == "object_41") {
|
|
child2.material = new THREE.MeshBasicMaterial({ color: 0xFF464E, transparent: true });
|
|
}
|
|
if (child2.name == "object_5" || child2.name == "object_51") {
|
|
child2.material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true });
|
|
}
|
|
});
|
|
collada2.scene.scale.x = collada2.scene.scale.y = collada2.scene.scale.z = 100;
|
|
if (shopX != 0 && shopY != 0) {
|
|
collada2.scene.position.set(shopX, shopZ, shopY); //x,z,y
|
|
}
|
|
collada2.scene.applyMatrix(Map_QM.sceneGap.matrix);
|
|
collada2.scene.renderOrder = 200;
|
|
Map_QM.endModel = collada2.scene;
|
|
Map_QM.scene.add(collada2.scene);
|
|
Map_QM.endModel.visible = pathCameraState == "2D" ? false : true;
|
|
});
|
|
|
|
let spriteMap = new THREE.TextureLoader().load("./static/img/Z.png");
|
|
let spriteMaterial = new THREE.SpriteMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放
|
|
map: spriteMap,
|
|
depthTest: true,
|
|
transparent: true,
|
|
});
|
|
Map_QM.endIcon = new MySprite_QM(spriteMaterial);
|
|
Map_QM.endIcon.scale.set(80, 80, 1);
|
|
Map_QM.endIcon.center = new THREE.Vector2(0.5, 0);
|
|
Map_QM.endIcon.position.set(shopX, shopZ, shopY);
|
|
Map_QM.endIcon.applyMatrix(Map_QM.sceneGap.matrix);
|
|
Map_QM.endIcon.renderOrder = 300;
|
|
Map_QM.endIcon.visible = pathCameraState == "2D" ? true : false;
|
|
Map_QM.scene.add(Map_QM.endIcon);
|
|
}
|
|
}
|
|
/**
|
|
* 设置起点图标
|
|
*/
|
|
FloorMap_QM.prototype.setStartSite = function (shopX, shopY, shopZ) {
|
|
let _this = this;
|
|
new THREE.GLTFLoader().load("./static/img/qi.gltf", function (collada) {
|
|
//console.log(collada);
|
|
collada.scene.traverse(function (child) {
|
|
if (child.name == "object_1" || child.name == "object_3" || child.name == "object_4" || child.name == "object_31" || child.name == "object_41") {
|
|
child.material = new THREE.MeshBasicMaterial({ color: 0xFFAE43, transparent: true });
|
|
}
|
|
if (child.name == "object_2" || child.name == "object_21") {
|
|
child.material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true });
|
|
}
|
|
});
|
|
collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = 100;
|
|
collada.scene.rotateX(Math.PI / 2);
|
|
if (shopX != 0 && shopY != 0) {
|
|
collada.scene.position.set(shopX, -1 * shopY, shopZ); //x,z,y
|
|
}
|
|
collada.scene.renderOrder = 200;
|
|
Map_QM.qiModel = collada.scene;
|
|
_this.allObj.add(collada.scene);
|
|
//--------------------------------------------------------------
|
|
let spriteMap = new THREE.TextureLoader().load("./static/img/Q.png");
|
|
let spriteMaterial = new THREE.SpriteMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放
|
|
map: spriteMap,
|
|
depthTest: true,
|
|
transparent: true,
|
|
});
|
|
Map_QM.qiIcon = new MySprite_QM(spriteMaterial);
|
|
Map_QM.qiIcon.scale.set(80, 80, 1);
|
|
Map_QM.qiIcon.center = new THREE.Vector2(0.5, 0);
|
|
Map_QM.qiIcon.position.set(shopX, -1 * shopY, shopZ);
|
|
Map_QM.qiIcon.renderOrder = 300;
|
|
Map_QM.qiIcon.visible = false;
|
|
_this.allObj.add(Map_QM.qiIcon);
|
|
|
|
let spriteMap2 = new THREE.TextureLoader().load("./static/img/site.png");
|
|
let spriteMaterial2 = new THREE.SpriteMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放
|
|
map: spriteMap2,
|
|
depthTest: true,
|
|
transparent: true,
|
|
});
|
|
Map_QM.dirIcon = new MySprite_QM(spriteMaterial2);
|
|
Map_QM.dirIcon.scale.set(80, 80, 1);
|
|
Map_QM.dirIcon.center = new THREE.Vector2(0.5, 0.5);
|
|
Map_QM.dirIcon.position.set(shopX, -1 * shopY, shopZ);
|
|
Map_QM.dirIcon.renderOrder = 300;
|
|
Map_QM.dirIcon.visible = false;
|
|
_this.allObj.add(Map_QM.dirIcon);
|
|
|
|
});
|
|
}
|
|
/**
|
|
* 查找线
|
|
* @param {Object} startNode
|
|
* @param {Object} endNode
|
|
*/
|
|
FloorMap_QM.prototype.isNoFindLine = function (startNode, endNode) {
|
|
let no = false;
|
|
for (let i = 0; i < startNode.lineArr.length; i++) {
|
|
if (startNode.lineArr[i].nextNode.id == endNode.id || startNode.lineArr[i].selfNode.id == endNode.id) {
|
|
no = true;
|
|
break;
|
|
}
|
|
}
|
|
return no;
|
|
}
|
|
|
|
//初始化停车位
|
|
FloorMap_QM.prototype.initPark = function () {
|
|
let mapData = Config.allMap[this.buildOrder].buildArr[this.floorOrder].mapData;
|
|
//渲染车位
|
|
if (mapData.parkArea) {
|
|
let sLen = mapData.parkArea.length;
|
|
if (sLen > 0) {
|
|
this.allObj.add(this.parkObj);
|
|
}
|
|
for (let i = 0; i < sLen; i++) {
|
|
if (Config.changeParkToString(mapData.parkArea[i]) != "") {
|
|
let arr = Config.changeParkToString(mapData.parkArea[i]);
|
|
mapData.parkArea[i].alphaModle = 95;
|
|
let mahc = this.Model_QM.MyModelShape(arr, null, mapData.parkArea[i], mapData.parkArea[i].entColor, mapData.parkArea[i].borderColor, 80);
|
|
this.parkObj.add(mahc);
|
|
mahc.xaxis = mapData.parkArea[i].xaxis >> 0;
|
|
mahc.yaxis = mapData.parkArea[i].yaxis >> 0;
|
|
mahc.node = mapData.parkArea[i].shopNav;
|
|
mahc.userData = {
|
|
"xaxis": mahc.xaxis,
|
|
"yaxis": mahc.yaxis,
|
|
"node": mahc.node,
|
|
"floor": this.floorOrder,
|
|
"shopNum": mahc.name,
|
|
"type": "park"
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 渲染3D模型类
|
|
* 传入区域点list
|
|
* 镂空点 howllowArr
|
|
* 模型对象 options
|
|
*/
|
|
MyModel_QM = function () {
|
|
this.xaxis = 0;
|
|
this.yaxis = 0;
|
|
this.node = 0;
|
|
}
|
|
|
|
MyModel_QM.prototype.MyModelShape = function (areaArr, howllowArr, opObj, entityColor = 0xdadada, lineColor = 0xeeeeee, indexOrder = 1) {
|
|
let len = areaArr.length;
|
|
if (len == 0) {
|
|
return;
|
|
}
|
|
let alphaModle = opObj.alphaModle / 100 || 0;
|
|
// 实例化shape对象
|
|
let shape = new THREE.Shape();
|
|
// 设置开始点的位置
|
|
for (let i = 0; i < areaArr.length; i++) {
|
|
shape.moveTo(areaArr[i][0], -1 * areaArr[i][1]);
|
|
if (areaArr[i].length == 4) {
|
|
shape.lineTo(areaArr[i][2], -1 * areaArr[i][3]);
|
|
} else {
|
|
shape.bezierCurveTo(areaArr[i][2], -1 * areaArr[i][3], areaArr[i][4], -1 * areaArr[i][5], areaArr[i][6], -1 * areaArr[i][7]);
|
|
}
|
|
}
|
|
let material;
|
|
for (let k = 0; k < Config.lineBasicMaterialArr.length; k++) {
|
|
let color2 = new THREE.Color(lineColor)
|
|
if (Config.lineBasicMaterialArr[k].color.equals(color2) && Config.lineBasicMaterialArr[k].opacity == parseInt(Config.lineAlpha) / 100) {
|
|
material = Config.lineBasicMaterialArr[k];
|
|
}
|
|
}
|
|
if (!material) {
|
|
material = new THREE.LineBasicMaterial({
|
|
color: lineColor,
|
|
transparent: true,
|
|
opacity: 0.8
|
|
}); //材质对象lineColor
|
|
Config.lineBasicMaterialArr.push(material);
|
|
}
|
|
if (howllowArr && howllowArr.length > 0) {
|
|
for (let n = 0; n < howllowArr.length; n++) {
|
|
let hole = new THREE.Path(); // 添加孔洞
|
|
for (let k = 0; k < howllowArr[n].length; k++) {
|
|
hole.moveTo(howllowArr[n][k][0], -1 * howllowArr[n][k][1]);
|
|
if (howllowArr[n][k].length == 4) {
|
|
hole.lineTo(howllowArr[n][k][2], -1 * howllowArr[n][k][3]);
|
|
} else {
|
|
hole.bezierCurveTo(howllowArr[n][k][2], -1 * howllowArr[n][k][3], howllowArr[n][k][4], -1 * howllowArr[n][k][5], howllowArr[n][k][6], -1 * howllowArr[n][k][7]);
|
|
}
|
|
}
|
|
shape.holes.push(hole);
|
|
}
|
|
}
|
|
let scanGeometry, meshMaterial, options = {
|
|
depth: parseInt(opObj.toHeight),
|
|
bevelEnabled: false,
|
|
curveSegments: 24
|
|
};
|
|
|
|
scanGeometry = new THREE.ExtrudeGeometry(shape, options);
|
|
for (let e = 0; e < Config.meshMaterialArr.length; e++) {
|
|
let color2 = new THREE.Color(entityColor);
|
|
if (Config.meshMaterialArr[e].color.equals(color2) && Config.meshMaterialArr[e].opacity == alphaModle) {
|
|
meshMaterial = Config.meshMaterialArr[e];
|
|
}
|
|
}
|
|
if (!meshMaterial) {
|
|
meshMaterial = new THREE.MeshPhongMaterial({ //MeshBasicMaterial MeshLambertMaterial MeshPhongMaterial
|
|
color: entityColor,
|
|
transparent: true,
|
|
opacity: alphaModle,
|
|
depthTest: true
|
|
});
|
|
// specular:0xaeaeae,//高光部分的颜色
|
|
// shininess:10,//高光部分的亮度,默认30
|
|
Config.meshMaterialArr.push(meshMaterial);
|
|
}
|
|
if (opObj.angleY || opObj.angleZ) {
|
|
Config.rotateYZ(scanGeometry, opObj.angleY * Math.PI / 180, opObj.angleZ * Math.PI / 180);
|
|
}
|
|
// 创建模型
|
|
let mesh = new THREE.Mesh(scanGeometry, meshMaterial);
|
|
|
|
if (opObj.name != "wall") {
|
|
let cubeEdges = new THREE.EdgesGeometry(scanGeometry, 60);
|
|
let cubeLine = new THREE.LineSegments(cubeEdges, material);
|
|
mesh.add(cubeLine);
|
|
}
|
|
if (opObj.name != "floor") {
|
|
mesh.position.z = opObj.site || 0;
|
|
} else {
|
|
mesh.position.z = -1 * parseInt(opObj.toHeight) - 1;
|
|
}
|
|
mesh.receiveShadow = true;
|
|
mesh.castShadow = true;
|
|
mesh.renderOrder = indexOrder;
|
|
mesh.name = opObj.name || "";
|
|
|
|
return mesh;
|
|
}
|
|
|
|
MyModel_QM.prototype.MyModelText = function (svgArea) {
|
|
|
|
let text = svgArea.data;
|
|
const paths = new THREE.SVGLoader().parse(text).paths;
|
|
const group = new THREE.Group();
|
|
|
|
group.rotateX(parseInt(svgArea.angleZ) * Math.PI / 180);
|
|
group.rotateY(parseInt(svgArea.angleY) * Math.PI / 180);
|
|
group.rotateZ(parseInt(svgArea.angle) * Math.PI / 180);
|
|
group.scale.multiplyScalar(svgArea.scale);
|
|
group.position.x = parseInt(svgArea.xaxis) - svgArea.width / 2;
|
|
group.position.y = -1 * parseInt(svgArea.yaxis) + svgArea.height / 2;
|
|
group.position.z = parseInt(svgArea.site);
|
|
group.scale.y *= - 1;
|
|
|
|
let meshMaterial;
|
|
for (let e = 0; e < Config.meshMaterialArr.length; e++) {
|
|
let color2 = new THREE.Color().setHex(svgArea.entColor);
|
|
if (Config.meshMaterialArr[e].color.equals(color2) && Config.meshMaterialArr[e].opacity == svgArea.alphaModle) {
|
|
meshMaterial = Config.meshMaterialArr[e];
|
|
}
|
|
}
|
|
if (!meshMaterial) {
|
|
meshMaterial = new THREE.MeshStandardMaterial({
|
|
color: svgArea.entColor,
|
|
opacity: parseInt(svgArea.alphaModle) / 100
|
|
});
|
|
Config.meshMaterialArr.push(meshMaterial);
|
|
}
|
|
|
|
for (let i = 0; i < paths.length; i++) {
|
|
const path = paths[i];
|
|
let shapes = path.toShapes(true);
|
|
for (let j = 0; j < shapes.length; j++) {
|
|
const shape = shapes[j];
|
|
const geometry = new THREE.ExtrudeBufferGeometry(shape, {
|
|
depth: svgArea.toHeight,
|
|
bevelEnabled: false,
|
|
curveSegments: 24
|
|
});
|
|
const mesh = new THREE.Mesh(geometry, meshMaterial);
|
|
mesh.renderOrder = 50;
|
|
mesh.name = svgArea.name || "";
|
|
mesh.position.set(-svgArea.width / 2, -svgArea.height / 2, 0);
|
|
group.add(mesh);
|
|
}
|
|
}
|
|
return group;
|
|
}
|
|
|
|
/**
|
|
* 公共设施
|
|
*/
|
|
MySprite_QM = function (spriteMaterial, obj = null) {
|
|
|
|
THREE.Sprite.call(this);
|
|
if (obj) {
|
|
this.navCode = obj.navCode;
|
|
this.no = obj.no;
|
|
this.facCode = obj.facCode;
|
|
this.floor = obj.floorOrder;
|
|
this.site = parseInt(obj.site) || (Config.shopHeight + 32);
|
|
}
|
|
this.imgUrl;
|
|
this.material = (spriteMaterial !== undefined) ? spriteMaterial : new SpriteMaterial();
|
|
//图标跳动
|
|
this.jumpIcon = function () {
|
|
let oldZ = this.site;
|
|
let self = this;
|
|
TweenMax.fromTo(self.position, 0.5, { z: oldZ }, {
|
|
z: oldZ + 20, repeat: 1,
|
|
onComplete: function () {
|
|
TweenMax.to(self.position, 0.2, { z: oldZ });
|
|
}
|
|
});
|
|
}
|
|
this.reSetSite = function () { //重置位置
|
|
this.position.z = this.site;
|
|
}
|
|
};
|
|
|
|
MySprite_QM.prototype = Object.create(THREE.Sprite.prototype);
|
|
MySprite_QM.prototype.constructor = MySprite_QM;
|
|
|
|
/**
|
|
* 渲染公共设施
|
|
*/
|
|
Facilities_QM = function () { }
|
|
|
|
Facilities_QM.prototype.renderIcon = function (obj, _this, isShow = true, ele = null) {
|
|
if (obj) {
|
|
let spriteMaterial;
|
|
let url = "./static/img/" + obj.facCode + ".png";
|
|
for (let m = 0; m < Config.spriteMaterialArr.length; m++) {
|
|
if (Config.spriteMaterialArr[m].name == obj.facCode) {
|
|
spriteMaterial = Config.spriteMaterialArr[m];
|
|
}
|
|
}
|
|
if (!spriteMaterial) {
|
|
let spriteMap = new THREE.TextureLoader().load(url);
|
|
spriteMaterial = new THREE.SpriteMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放
|
|
map: spriteMap,
|
|
depthTest: true,
|
|
transparent: true,
|
|
});
|
|
spriteMaterial.name = obj.facCode;
|
|
Config.spriteMaterialArr.push(spriteMaterial);
|
|
}
|
|
|
|
let sprite = new MySprite_QM(spriteMaterial, obj);
|
|
sprite.scale.set(64, 64, 1);
|
|
sprite.imgUrl = url;
|
|
sprite.center = new THREE.Vector2(0.5, 0);
|
|
sprite.userData = obj;
|
|
sprite.userData.type = "icon";
|
|
sprite.userData.use = ele ? "2d" : "all";
|
|
sprite.userData.model = ele;
|
|
sprite.position.set(obj.x, -1 * obj.y, 60);
|
|
sprite.renderOrder = 300;
|
|
sprite.visible = isShow;
|
|
_this.serObj.add(sprite);
|
|
if (iconNameShow) {
|
|
let shopDiv = document.createElement('div');
|
|
shopDiv.className = "shopLabel";
|
|
shopDiv.style.fontSize="12px";
|
|
shopDiv.style.height="14px";
|
|
shopDiv.innerText = obj.title;
|
|
shopDiv.dataset.name = obj.title;
|
|
shopDiv.dataset.nameEn = Config.iconEn[obj.title];
|
|
let shopLabel = new THREE.CSS2DObject(shopDiv);
|
|
shopLabel.position.set(obj.x, -1 * obj.y, 30);
|
|
_this.iconLabel.add(shopLabel);
|
|
shopLabel.element.style.pointerEvents = "none";
|
|
}
|
|
}
|
|
}
|
|
Facilities_QM.prototype.renderDeviceIcon = function (obj, _this) {
|
|
if (obj) {
|
|
let spriteMaterial;
|
|
let url = "./static/img/deviceDir.png";
|
|
for (let m = 0; m < Config.spriteMaterialArr.length; m++) {
|
|
if (Config.spriteMaterialArr[m].name == "deviceDir") {
|
|
spriteMaterial = Config.spriteMaterialArr[m];
|
|
}
|
|
}
|
|
if (!spriteMaterial) {
|
|
let spriteMap = new THREE.TextureLoader().load(url);
|
|
spriteMaterial = new THREE.MeshPhongMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放
|
|
map: spriteMap,
|
|
depthTest: false,
|
|
transparent: true,
|
|
});
|
|
spriteMaterial.name = "deviceDir";
|
|
Config.spriteMaterialArr.push(spriteMaterial);
|
|
}
|
|
let planeGeometry = new THREE.PlaneGeometry(100, 100);
|
|
let plane = new THREE.Mesh(planeGeometry, spriteMaterial);
|
|
plane.center = new THREE.Vector2(0, 0);
|
|
plane.userData = JSON.parse(JSON.stringify(obj));
|
|
plane.userData.type = "device";
|
|
plane.position.set(obj.x, -1 * obj.y, 20);
|
|
plane.rotateZ(parseInt(obj.angle) * Math.PI / 180);
|
|
plane.renderOrder = 410;
|
|
_this.devObj.add(plane);
|
|
|
|
let SpriteDiv = document.createElement('div');
|
|
SpriteDiv.className = "other-pop";
|
|
SpriteDiv.style.background = "#777777";
|
|
SpriteDiv.innerText = obj.devNum;
|
|
let pointLabel = new THREE.CSS2DObject(SpriteDiv)
|
|
pointLabel.position.set(obj.x, -1 * obj.y, 0);
|
|
pointLabel.element.style.pointerEvents = "none";
|
|
pointLabel.userData.type = "dev_IP";
|
|
pointLabel.userData.code = obj.code;
|
|
pointLabel.userData.name = obj.devNum;
|
|
_this.showTagObj.add(pointLabel);
|
|
pointLabel.element.style.pointerEvents = "none";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 店铺LOGO地图展示类
|
|
*/
|
|
ShopLogo_QM = function () {
|
|
this.renderIcon = function (obj, _this) {
|
|
if (obj) {
|
|
let x = obj.xaxis >> 0;
|
|
let y = -1 * obj.yaxis >> 0;
|
|
let z = parseInt(Config.shopHeight) + 0.1;
|
|
let imgW = obj.imgW >> 0;
|
|
let imgH = obj.imgH >> 0;
|
|
|
|
new THREE.TextureLoader().load(obj.logoUrl, textu => {
|
|
let planeMaterial = new THREE.MeshPhongMaterial({
|
|
map: textu,
|
|
depthTest: false,
|
|
transparent: true
|
|
});
|
|
let planeGeometry = new THREE.PlaneGeometry(imgW, imgH);
|
|
let plane = new THREE.Mesh(planeGeometry, planeMaterial);
|
|
plane.center = new THREE.Vector2(0, 0);
|
|
plane.position.set(x, y, z);
|
|
plane.renderOrder = 70;
|
|
_this.logoObj.add(plane);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
MySprite_QM.prototype.constructor = MySprite_QM;
|
|
|
|
var _selfFindPath;
|
|
FindPath_QM = function () {
|
|
this.pathArr = [];
|
|
this.lineDashed;
|
|
//路线指引箭头皮肤
|
|
this.planeGeometry = new THREE.PlaneGeometry(128, 128);
|
|
|
|
this.stop = null;
|
|
this._index = 0; //寻路用
|
|
this.pathState = "init";
|
|
this.pathPlay = {
|
|
_isPlay: false,
|
|
get isPlay() {
|
|
return this._isPlay;
|
|
},
|
|
set isPlay(val) {
|
|
this._isPlay = val;
|
|
if (_selfFindPath && _selfFindPath.stop) {
|
|
window.cancelAnimationFrame(_selfFindPath.stop);
|
|
_selfFindPath.stop = null;
|
|
}
|
|
if (_selfFindPath && _selfFindPath.pathState == "isPlay" && _selfFindPath._index < _selfFindPath.pathArr.length) {
|
|
_selfFindPath.playMoveGuide();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FindPath_QM.prototype.clearPath = function () {
|
|
this.pathArr = [];
|
|
if (this.lineDashed) {
|
|
if (Map_QM.mapArr[Config.selectBuild][Config.selectFloor]) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.remove(this.lineDashed);
|
|
}
|
|
this.lineDashed.destroy();
|
|
this.lineDashed = null;
|
|
}
|
|
if (Map_QM.guide) {
|
|
Map_QM.guide.visible = false;
|
|
if (Map_QM.mapArr[Config.selectBuild][Config.selectFloor]) {
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.remove(man_2d);
|
|
Map_QM.mapArr[Config.selectBuild][Config.selectFloor].allObj.remove(man_3d);
|
|
}
|
|
}
|
|
|
|
if (_selfFindPath && _selfFindPath.stop) {
|
|
window.cancelAnimationFrame(_selfFindPath.stop);
|
|
}
|
|
this._index = 0;
|
|
this.pathState = "init";
|
|
}
|
|
/**
|
|
* @param {Object} startNade
|
|
* @param {Object} toNade
|
|
* @param {Object} callBack 回调函数
|
|
*/
|
|
FindPath_QM.prototype.onFindPathAnimation = function (pathArray, floorOrder = -1) {
|
|
if (pathArray && pathArray.length > 0) {
|
|
this.pathArr = [];
|
|
for (let j = 0; j < pathArray.length; j++) {
|
|
this.pathArr.push(pathArray[j]);
|
|
}
|
|
this.pathState = "isPlay";
|
|
this._index = 0;
|
|
if (floorOrder === -1) {
|
|
floorOrder = Config.selectFloor;
|
|
}
|
|
this.drawPath(floorOrder);
|
|
}
|
|
}
|
|
/**
|
|
*
|
|
*/
|
|
FindPath_QM.prototype.drawPath = function (floorOrder) {
|
|
let linePath = [];
|
|
for (let i = 0; i < this.pathArr.length; i++) {
|
|
if (i < this.pathArr.length) {
|
|
linePath.push([this.pathArr[i].x, -1 * this.pathArr[i].y]);
|
|
}
|
|
}
|
|
this.lineDashed = new PathLine(12, linePath, parseInt(Config.buildHeight) + 1);
|
|
this.lineDashed.name = "lineDash";
|
|
this.lineDashed.renderOrder = 128;
|
|
Map_QM.mapArr[Config.selectBuild][floorOrder].allObj.add(this.lineDashed);
|
|
////////////////////////////////////////////////////////
|
|
}
|
|
FindPath_QM.prototype.guidePathPlay = function (paths) {
|
|
if (Map_QM.guide) {
|
|
Map_QM.guide.renderOrder = 99;
|
|
if (paths.PathPoint) {
|
|
Map_QM.guide.position.x = paths.PathPoint[0].x;
|
|
Map_QM.guide.position.y = -1 * paths.PathPoint[0].y;
|
|
Map_QM.moveCameraBy2D(paths.PathPoint[0]);
|
|
man_2d.position.z = Config.shopHeight + 2;
|
|
man_3d.position.z = Config.buildHeight + 2;
|
|
Map_QM.guide.visible = true;
|
|
Map_QM.mapArr[Config.selectBuild][paths.floor].allObj.add(man_2d);
|
|
Map_QM.mapArr[Config.selectBuild][paths.floor].allObj.add(man_3d);
|
|
}
|
|
}
|
|
this.pathArr = paths.PathPoint;
|
|
_selfFindPath = this;
|
|
if (isPathPlay) {
|
|
this.pathPlay.isPlay = true;
|
|
}
|
|
}
|
|
/**
|
|
* 播放图标指引动画
|
|
*/
|
|
FindPath_QM.prototype.playMoveGuide = function () {
|
|
if (!Map_QM.guide) {
|
|
return;
|
|
}
|
|
let px = Map_QM.guide.position.x;
|
|
let py = Map_QM.guide.position.y;
|
|
let targetX = _selfFindPath.pathArr[_selfFindPath._index].x - px;
|
|
let targetY = -1 * _selfFindPath.pathArr[_selfFindPath._index].y - py;
|
|
let dist = Math.sqrt(targetX * targetX + targetY * targetY);
|
|
let df = Math.ceil(dist / Config.playSpeed);
|
|
let dx = (_selfFindPath.pathArr[_selfFindPath._index].x - px) / df;
|
|
let dy = ((-1 * _selfFindPath.pathArr[_selfFindPath._index].y) - py) / df;
|
|
let ang = 0;
|
|
if (df < 2) {
|
|
Map_QM.guide.position.x = _selfFindPath.pathArr[_selfFindPath._index].x;
|
|
Map_QM.guide.position.y = -1 * _selfFindPath.pathArr[_selfFindPath._index].y;
|
|
Map_QM.moveCameraBy2D({x:_selfFindPath.pathArr[_selfFindPath._index].x,y:_selfFindPath.pathArr[_selfFindPath._index].y});
|
|
man_3d.rotation.z = man_2d.rotation.z = 0;//180;
|
|
_selfFindPath._index++;
|
|
if (_selfFindPath._index > 0 && _selfFindPath._index < _selfFindPath.pathArr.length) {
|
|
let s = Math.sqrt((_selfFindPath.pathArr[_selfFindPath._index].x - _selfFindPath.pathArr[_selfFindPath._index - 1].x) * (_selfFindPath.pathArr[_selfFindPath._index].x - _selfFindPath.pathArr[_selfFindPath._index - 1].x) + (
|
|
_selfFindPath.pathArr[_selfFindPath._index].y - _selfFindPath.pathArr[_selfFindPath._index - 1].y) * (_selfFindPath.pathArr[_selfFindPath._index].y - _selfFindPath.pathArr[_selfFindPath._index - 1].y));
|
|
ang = Math.acos((_selfFindPath.pathArr[_selfFindPath._index].y - _selfFindPath.pathArr[_selfFindPath._index - 1].y) / s);
|
|
if (_selfFindPath.pathArr[_selfFindPath._index].x < _selfFindPath.pathArr[_selfFindPath._index - 1].x) {
|
|
man_3d.rotation.z = man_2d.rotation.z = Math.PI - ang;
|
|
} else {
|
|
man_3d.rotation.z = man_2d.rotation.z = Math.PI + ang;
|
|
}
|
|
}
|
|
for (let t = 0; t < Map_QM.forShopArr[_indexPathFloor].wayShop.length; t++) {
|
|
if (Map_QM.forShopArr[_indexPathFloor].wayShop[t].pathIndex == _selfFindPath._index) {
|
|
Map_QM.dispatchEvent({ //寻路中返回小人当前所在点位
|
|
type: 'PathPlaying',
|
|
data: { "pathArrIn": _indexPathFloor, "pathIndex": _selfFindPath._index }
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
px += dx;
|
|
py += dy;
|
|
Map_QM.guide.position.x = px;
|
|
Map_QM.guide.position.y = py;
|
|
Map_QM.moveCameraBy2D({x:px, y:-1*py});
|
|
}
|
|
|
|
if (_selfFindPath.pathPlay.isPlay && Map_QM.guide) {
|
|
if (_selfFindPath._index < _selfFindPath.pathArr.length) {
|
|
_selfFindPath.stop = requestAnimationFrame(_selfFindPath.playMoveGuide);
|
|
} else {
|
|
if (_selfFindPath && _selfFindPath.stop) {
|
|
window.cancelAnimationFrame(_selfFindPath.stop);
|
|
_selfFindPath.stop = null;
|
|
}
|
|
_selfFindPath._index = 0;
|
|
if (Map_QM.guide) {
|
|
Map_QM.guide.visible = false;
|
|
}
|
|
let myEvent = new CustomEvent('pathOver', {
|
|
detail: { dx: dx, dy: dy },
|
|
});
|
|
document.dispatchEvent(myEvent); //触发导航完成事件
|
|
_selfFindPath.pathState = "pathOver";
|
|
}
|
|
}
|
|
}
|
|
|
|
var getProportionPoint2 = (point, segment, length, dx, dy) => {
|
|
let factor = segment / length;
|
|
return { x: point.x - dx * factor, y: point.y - dy * factor };
|
|
};
|
|
|
|
var getRoundCornerBy3Points2 = ({ angularPoint, p1, p2, radius }) => {
|
|
let dx1 = angularPoint.x - p1.x;
|
|
let dy1 = angularPoint.y - p1.y;
|
|
let dx2 = angularPoint.x - p2.x;
|
|
let dy2 = angularPoint.y - p2.y;
|
|
|
|
let angle = (Math.atan2(dy1, dx1) - Math.atan2(dy2, dx2)) / 2;
|
|
let tan = Math.abs(Math.tan(angle));
|
|
let segment = radius / tan;
|
|
|
|
let length1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
let length2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
|
|
|
|
let length = Math.min(length1, length2);
|
|
|
|
if (segment > length) {
|
|
segment = length;
|
|
radius = length * tan;
|
|
}
|
|
let p1Cross = getProportionPoint2(angularPoint, segment, length1, dx1, dy1);
|
|
let p2Cross = getProportionPoint2(angularPoint, segment, length2, dx2, dy2);
|
|
|
|
let dx = angularPoint.x * 2 - p1Cross.x - p2Cross.x;
|
|
let dy = angularPoint.y * 2 - p1Cross.y - p2Cross.y;
|
|
|
|
let L = Math.sqrt(dx * dx + dy * dy);
|
|
let d = Math.sqrt(segment * segment + radius * radius);
|
|
|
|
let circlePoint = getProportionPoint2(angularPoint, d, L, dx, dy);
|
|
|
|
let startAngle = Math.atan2(
|
|
p1Cross.y - circlePoint.y,
|
|
p1Cross.x - circlePoint.x
|
|
);
|
|
let endAngle = Math.atan2(
|
|
p2Cross.y - circlePoint.y,
|
|
p2Cross.x - circlePoint.x
|
|
);
|
|
|
|
let sweepAngle = endAngle - startAngle;
|
|
|
|
if (sweepAngle < 0) {
|
|
startAngle = endAngle;
|
|
sweepAngle = -sweepAngle;
|
|
}
|
|
|
|
endAngle = startAngle + sweepAngle;
|
|
return { p1Cross, p2Cross, startAngle, endAngle, circlePoint };
|
|
};
|
|
|
|
var POINT = function (x, y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.equals = function (p) {
|
|
return this.x === p.x && this.y === p.y;
|
|
}
|
|
this.rotate = function (center, a, clockWise) {
|
|
let { x, y } = this;
|
|
if (clockWise) a = -a;
|
|
let rx0 = center.x;
|
|
let ry0 = center.y;
|
|
this.x = (x - rx0) * Math.cos(a) - (y - ry0) * Math.sin(a) + rx0;
|
|
this.y = (x - rx0) * Math.sin(a) + (y - ry0) * Math.cos(a) + ry0;
|
|
}
|
|
}
|
|
|
|
var LINE = function (k, b) {
|
|
this.k = k;
|
|
this.b = b;
|
|
this.kSign = this.k > 0 ? 1 : -1;
|
|
|
|
this.a = Math.atan(this.k);
|
|
|
|
this.bDiff = function (offset) {
|
|
return Math.abs(offset / Math.cos(this.a));
|
|
}
|
|
this.crossPoint = function (line) {
|
|
const x = (line.b - this.b) / (this.k - line.k);
|
|
const y = this.k * x + this.b;
|
|
return new POINT(x, y);
|
|
}
|
|
this.verticalCrossPoint = function (x, y) {
|
|
let k1 = -1 / this.k;
|
|
let b1 = y - k1 * x;
|
|
let k2 = this.k;
|
|
let b2 = this.b;
|
|
let x1 = (b2 - b1) / (k1 - k2);
|
|
let y1 = k2 * x1 + b2;
|
|
return { x: x1, y: y1 };
|
|
}
|
|
}
|
|
var LINESEGMENT = function (p1, p2) {
|
|
const x1 = p1.x;
|
|
const x2 = p2.x;
|
|
const y1 = p1.y;
|
|
const y2 = p2.y;
|
|
const k = (y2 - y1) / (x2 - x1);
|
|
const b = y1 - k * x1;
|
|
LINE.call(this, k, b)
|
|
Object.assign(this, {
|
|
x1,
|
|
x2,
|
|
y1,
|
|
y2,
|
|
p1,
|
|
p2,
|
|
});
|
|
this.isUp = this.y2 >= this.y1 ? 1 : -1;
|
|
|
|
this.sign = this.kSign * this.isUp;
|
|
|
|
this.xDiff = Math.abs(this.x1 - this.x2);
|
|
|
|
this.yDiff = Math.abs(this.y1 - this.y2);
|
|
|
|
this.length = Math.sqrt(this.xDiff * this.xDiff + this.yDiff * this.yDiff);
|
|
|
|
this.distanceTo = function (x, y) {
|
|
return Math.abs(this.k * x - y + this.b) / Math.sqrt(1 + this.k * this.k);
|
|
}
|
|
|
|
this.mirrow = function (x, y) {
|
|
const { x: midX, y: midY } = this.verticalCrossPoint(x, y);
|
|
return { x: midX * 2 - x, y: midY * 2 - y };
|
|
}
|
|
this.rightLine = function (offset) {
|
|
return new LINE(this.k, this.b - this.sign * this.bDiff(offset));
|
|
}
|
|
this.leftLine = function (offset) {
|
|
return new LINE(this.k, this.b + this.sign * this.bDiff(offset));
|
|
}
|
|
this.leftP1 = function (offset) {
|
|
return new POINT(
|
|
this.p1.x - this.sign * offset * Math.sin(this.a),
|
|
this.p1.y + this.sign * offset * Math.cos(this.a)
|
|
);
|
|
}
|
|
this.rightP1 = function (offset) {
|
|
return new POINT(
|
|
this.p1.x + this.sign * offset * Math.sin(this.a),
|
|
this.p1.y - this.sign * offset * Math.cos(this.a)
|
|
);
|
|
}
|
|
this.leftP2 = function (offset) {
|
|
return new POINT(
|
|
this.p2.x - this.sign * offset * Math.sin(this.a),
|
|
this.p2.y + this.sign * offset * Math.cos(this.a)
|
|
);
|
|
}
|
|
this.rightP2 = function (offset) {
|
|
return new POINT(
|
|
this.p2.x + this.sign * offset * Math.sin(this.a),
|
|
this.p2.y - this.sign * offset * Math.cos(this.a)
|
|
);
|
|
}
|
|
}
|
|
|
|
var interVal = -1, vIndex = 1;
|
|
var mainColor = "rgb(180,120,52)";
|
|
var borderColor = "rgb(216,156,86)";
|
|
var arrowColor = "rgb(255,255,255)";
|
|
|
|
var PathLine = function (radius, linePath, floorHeight) {
|
|
THREE.Group.call(this);
|
|
|
|
const roundCornoredPath = new THREE.Geometry();
|
|
const rings = new THREE.Geometry();
|
|
const arrowGeo1 = new THREE.Geometry();
|
|
const arrowGeo2 = new THREE.Geometry();
|
|
const arrowGeo3 = new THREE.Geometry();
|
|
const factor = radius / 20;
|
|
const innerBorderRatio = (20 - 10) / 20;
|
|
const innerRadius = radius * innerBorderRatio;
|
|
const turnRadius = factor * 40;
|
|
const centerRadius = turnRadius - radius;
|
|
const roundFragments = (1 / 180) * Math.PI;
|
|
const ringInnerRadius = (radius / 26) * 30;
|
|
const ringOuterRadius = (radius / 26) * 56;
|
|
const ringMiddleRadius = ringOuterRadius - factor * 10;
|
|
const avgArrow = 40 * factor;
|
|
let lineSegments = [];
|
|
const h1 = floorHeight + floorHeight / 100;
|
|
const h2 = floorHeight + floorHeight / 50;
|
|
const addFace = (geometry, p1, p2, theta, clockWise) => {
|
|
// left
|
|
// a---b
|
|
// | \ |
|
|
// c---d
|
|
// |\ |
|
|
// bottom---p1--p2-->top
|
|
// | \|
|
|
// e---f
|
|
// | \ |
|
|
// g---h
|
|
// right
|
|
const index = {
|
|
a: 0,
|
|
b: 1,
|
|
c: 2,
|
|
d: 3,
|
|
e: 4,
|
|
f: 5,
|
|
g: 6,
|
|
h: 7,
|
|
};
|
|
const faces = [
|
|
["a", "b", "d", borderColor],
|
|
["a", "c", "d", borderColor],
|
|
["c", "d", "f", mainColor],
|
|
["c", "e", "f", mainColor],
|
|
["e", "f", "h", borderColor],
|
|
["e", "g", "h", borderColor],
|
|
];
|
|
let length = geometry.vertices.length;
|
|
let lineSegment = new LINESEGMENT(p1, p2);
|
|
let a = lineSegment.leftP1(radius);
|
|
let b = lineSegment.leftP2(radius);
|
|
let c = lineSegment.leftP1(innerRadius);
|
|
let d = lineSegment.leftP2(innerRadius);
|
|
let e = lineSegment.rightP1(innerRadius);
|
|
let f = lineSegment.rightP2(innerRadius);
|
|
let g = lineSegment.rightP1(radius);
|
|
let h = lineSegment.rightP2(radius);
|
|
if (clockWise !== undefined) {
|
|
a.rotate(p1, theta, !clockWise);
|
|
b.rotate(p2, theta, clockWise);
|
|
c.rotate(p1, theta, !clockWise);
|
|
d.rotate(p2, theta, clockWise);
|
|
e.rotate(p1, theta, !clockWise);
|
|
f.rotate(p2, theta, clockWise);
|
|
g.rotate(p1, theta, !clockWise);
|
|
h.rotate(p2, theta, clockWise);
|
|
}
|
|
let points = [a, b, c, d, e, f, g, h];
|
|
geometry.vertices.push(
|
|
...points.map((point) => new THREE.Vector3(point.x, point.y, h1))
|
|
);
|
|
faces.forEach(([a, b, c, color]) => {
|
|
const face = new THREE.Face3(
|
|
length + index[a],
|
|
length + index[b],
|
|
length + index[c]
|
|
);
|
|
face.color = new THREE.Color(color);
|
|
geometry.faces.push(face);
|
|
});
|
|
};
|
|
const addSectorFace = (geometry, { x, y }, pathAngle) => {
|
|
const offsetAngle = Math.asin(innerRadius / ringMiddleRadius);
|
|
const sweepAngle = Math.PI * 2 - 2 * offsetAngle;
|
|
// *out*
|
|
// a-----------b
|
|
// \ \ /
|
|
// c-------d
|
|
// \ \ /
|
|
// e---f
|
|
// \ /
|
|
// g
|
|
// *in*
|
|
const index = {
|
|
a: 0,
|
|
b: 1,
|
|
c: 2,
|
|
d: 3,
|
|
e: 4,
|
|
f: 5,
|
|
g: 6,
|
|
};
|
|
const faces = [
|
|
["a", "b", "d", borderColor, true],
|
|
["a", "c", "d", borderColor, true],
|
|
["c", "d", "f", mainColor, false],
|
|
["c", "e", "f", mainColor, false],
|
|
["e", "f", "g", arrowColor, false],
|
|
];
|
|
const angles = Math.ceil((Math.PI * 2) / roundFragments);
|
|
let avg = (Math.PI * 2) / angles;
|
|
const getPoint = (angle, r) => ({
|
|
x: x + r * Math.cos(angle),
|
|
y: y + r * Math.sin(angle),
|
|
});
|
|
const getACEG = (angle) => ({
|
|
a: getPoint(angle, ringOuterRadius),
|
|
c: getPoint(angle, ringMiddleRadius),
|
|
e: getPoint(angle, ringInnerRadius),
|
|
g: { x, y },
|
|
});
|
|
const startAngle = pathAngle + offsetAngle;
|
|
let lastACEG = getACEG(startAngle);
|
|
let drawBorder = true;
|
|
for (let j = 1; j <= angles; j++) {
|
|
let length = geometry.vertices.length;
|
|
const { a, c, e, g } = lastACEG;
|
|
let angle = startAngle + j * avg;
|
|
if (angle > sweepAngle + startAngle) drawBorder = false;
|
|
const { a: b, c: d, e: f } = getACEG(angle);
|
|
let points = [a, b, c, d, e, f, g];
|
|
geometry.vertices.push(
|
|
...points.map((point) => new THREE.Vector3(point.x, point.y, h2))
|
|
);
|
|
faces.forEach(([a, b, c, color, isBorder]) => {
|
|
if (isBorder && !drawBorder) return;
|
|
const face = new THREE.Face3(
|
|
length + index[a],
|
|
length + index[b],
|
|
length + index[c]
|
|
);
|
|
face.color = new THREE.Color(color);
|
|
geometry.faces.push(face);
|
|
});
|
|
lastACEG = { a: b, c: d, e: f, g };
|
|
}
|
|
};
|
|
var vercts = [];
|
|
var arrowVs = [
|
|
[0, 0],
|
|
[-15, -12],
|
|
[-15, 4],
|
|
[0, 20],
|
|
[15, 4],
|
|
[15, -12]
|
|
];
|
|
const addArrowFace = (geometry, { x: x0, y: y0, angle }) => {
|
|
// d
|
|
// /|\
|
|
// c | e
|
|
// |\a/|
|
|
// |/ \|
|
|
// b f
|
|
|
|
let length = geometry.vertices.length;
|
|
const index = {
|
|
a: 0,
|
|
b: 1,
|
|
c: 2,
|
|
d: 3,
|
|
e: 4,
|
|
f: 5,
|
|
};
|
|
let n = angle - Math.PI / 2;
|
|
let points = arrowVs.map(([x, y]) => {
|
|
const x1 = x * factor;
|
|
const y1 = y * factor;
|
|
return {
|
|
x: x0 + x1 * Math.cos(n) - y1 * Math.sin(n),
|
|
y: y0 + y1 * Math.cos(n) + x1 * Math.sin(n),
|
|
};
|
|
});
|
|
const faces = ["abc", "acd", "ade", "aef"];
|
|
|
|
points.forEach((obj) =>
|
|
vercts.push(new THREE.Vector3(obj.x, obj.y, h2))
|
|
);
|
|
points.forEach((obj) =>
|
|
geometry.vertices.push(new THREE.Vector3(obj.x, obj.y, h2))
|
|
);
|
|
faces.forEach((string) => {
|
|
const face = new THREE.Face3(
|
|
...string.split("").map((c) => length + index[c])
|
|
);
|
|
face.color = new THREE.Color(arrowColor);
|
|
geometry.faces.push(face);
|
|
});
|
|
};
|
|
//避免两个点的路径画不出来
|
|
if (linePath.length == 2) {
|
|
let pointAdd = [];
|
|
pointAdd.push((parseInt(linePath[0][0]) + parseInt(linePath[1][0])) / 2);
|
|
pointAdd.push((parseInt(linePath[0][1]) + parseInt(linePath[1][1])) / 2);
|
|
linePath.splice(1, 0, pointAdd);
|
|
}
|
|
for (let i = 0; i < linePath.length - 1; i++) {
|
|
const lineSegment = new LINESEGMENT(
|
|
new POINT(...linePath[i]),
|
|
new POINT(...linePath[i + 1])
|
|
);
|
|
lineSegments.push(lineSegment);
|
|
}
|
|
|
|
// ring
|
|
if (lineSegments.length) {
|
|
let startLine = lineSegments[0];
|
|
let endLine = lineSegments[lineSegments.length - 1];
|
|
let startPathAngle = Math.atan2(
|
|
startLine.y2 - startLine.y1,
|
|
startLine.x2 - startLine.x1
|
|
);
|
|
let endPathAngle = Math.atan2(
|
|
endLine.y1 - endLine.y2,
|
|
endLine.x1 - endLine.x2
|
|
);
|
|
addSectorFace(rings, startLine.p1, startPathAngle);
|
|
addSectorFace(rings, endLine.p2, endPathAngle);
|
|
}
|
|
|
|
let totalLength = avgArrow / -2;
|
|
let lastTotals = [];
|
|
let cutStraightLines = [];
|
|
// path
|
|
let lastP2Cross = null;
|
|
for (let i = 0; i < lineSegments.length - 1; i++) {
|
|
let lineA = lineSegments[i];
|
|
let lineB = lineSegments[i + 1];
|
|
let {
|
|
p1Cross,
|
|
p2Cross,
|
|
startAngle,
|
|
endAngle,
|
|
circlePoint,
|
|
} = getRoundCornerBy3Points2({
|
|
angularPoint: lineA.p2,
|
|
p1: lineA.p1,
|
|
p2: lineB.p2,
|
|
radius: centerRadius,
|
|
});
|
|
|
|
let angleDiff = endAngle - startAngle;
|
|
const clockWise = angleDiff > Math.PI;
|
|
if (clockWise) angleDiff = Math.PI * 2 - angleDiff;
|
|
const angles = Math.ceil(angleDiff / roundFragments);
|
|
let avg = angleDiff / angles;
|
|
|
|
let s = lastP2Cross ? lastP2Cross : lineA.p1;
|
|
let e = p1Cross;
|
|
let lineSegment = new LINESEGMENT(s, e);
|
|
cutStraightLines.push(lineSegment);
|
|
lastTotals.push(totalLength);
|
|
totalLength += lineSegment.length;
|
|
addFace(roundCornoredPath, s, e);
|
|
lastP2Cross = p2Cross;
|
|
|
|
const getFragPointByAngle = (angle) => ({
|
|
x: circlePoint.x + centerRadius * Math.cos(angle),
|
|
y: circlePoint.y + centerRadius * Math.sin(angle),
|
|
});
|
|
let lastFragment = getFragPointByAngle(startAngle);
|
|
for (let j = 1; j <= angles; j++) {
|
|
let angle = startAngle + (clockWise ? -1 : 1) * j * avg;
|
|
let tmp = getFragPointByAngle(angle);
|
|
addFace(roundCornoredPath, lastFragment, tmp, avg / 2, clockWise);
|
|
lastFragment = tmp;
|
|
}
|
|
if (i === lineSegments.length - 2) {
|
|
s = p2Cross;
|
|
e = lineB.p2;
|
|
lineSegment = new LINESEGMENT(s, e);
|
|
cutStraightLines.push(lineSegment);
|
|
lastTotals.push(totalLength);
|
|
totalLength += lineSegment.length;
|
|
addFace(roundCornoredPath, s, e);
|
|
}
|
|
}
|
|
|
|
// arrow
|
|
const num = Math.floor(totalLength / avgArrow) < 0 ? 0 : Math.floor(totalLength / avgArrow);
|
|
|
|
new Array(num).fill(0)
|
|
.map((_, i) => i * avgArrow + avgArrow / 2)
|
|
.map((length) => {
|
|
for (let i = 0; i < lastTotals.length; i++) {
|
|
if (
|
|
lastTotals[i] <= length &&
|
|
lastTotals[i] + cutStraightLines[i].length > length
|
|
)
|
|
return [i, (length - lastTotals[i]) / cutStraightLines[i].length];
|
|
}
|
|
return [lastTotals.length - 1, 1];
|
|
})
|
|
.map(([i, percent]) => {
|
|
let line = cutStraightLines[i];
|
|
return {
|
|
x: (line.x2 - line.x1) * percent + line.x1,
|
|
y: (line.y2 - line.y1) * percent + line.y1,
|
|
angle: Math.atan2(line.y2 - line.y1, line.x2 - line.x1),
|
|
};
|
|
})
|
|
.forEach((point, index) => {
|
|
if (index % 3 == 0) {
|
|
addArrowFace(arrowGeo1, point);
|
|
} else if (index % 3 == 1) {
|
|
addArrowFace(arrowGeo2, point);
|
|
} else {
|
|
addArrowFace(arrowGeo3, point);
|
|
}
|
|
});
|
|
|
|
const material = new THREE.MeshBasicMaterial({
|
|
side: THREE.DoubleSide,
|
|
vertexColors: THREE.FaceColors,
|
|
// depthFunc: THREE.AlwaysDepth
|
|
// depthTest: false
|
|
});
|
|
const pathMesh = new THREE.Mesh(roundCornoredPath, material);
|
|
const ringsMesh = new THREE.Mesh(rings, material);
|
|
const arrowMesh1 = new THREE.Mesh(arrowGeo1, material);
|
|
const arrowMesh2 = new THREE.Mesh(arrowGeo2, material);
|
|
const arrowMesh3 = new THREE.Mesh(arrowGeo3, material);
|
|
this.add(pathMesh);
|
|
this.add(ringsMesh);
|
|
this.add(arrowMesh1);
|
|
arrowMesh2.visible = false;
|
|
this.add(arrowMesh2);
|
|
arrowMesh3.visible = false;
|
|
this.add(arrowMesh3);
|
|
this.name = "meshline";
|
|
if (!Config.overlap) {
|
|
interVal = setInterval(() => {
|
|
arrowMesh1.visible = false;
|
|
arrowMesh2.visible = false;
|
|
arrowMesh3.visible = false;
|
|
if (vIndex == 1) {
|
|
arrowMesh1.visible = true;
|
|
} else if (vIndex == 2) {
|
|
arrowMesh2.visible = true;
|
|
} else {
|
|
arrowMesh3.visible = true;
|
|
vIndex = 0;
|
|
}
|
|
vIndex++;
|
|
}, 200);
|
|
}
|
|
}
|
|
|
|
PathLine.prototype = Object.create(THREE.Group.prototype);
|
|
PathLine.prototype.constructor = PathLine;
|
|
|
|
PathLine.prototype.destroy = function () {
|
|
clearInterval(interVal);
|
|
const clearCache = (item) => {
|
|
item.geometry.dispose();
|
|
item.material.dispose();
|
|
};
|
|
const removeObj = (obj) => {
|
|
let arr = obj.children.filter((x) => x);
|
|
arr.forEach((item) => {
|
|
if (item.children.length) {
|
|
removeObj(item);
|
|
} else {
|
|
clearCache(item);
|
|
item.clear();
|
|
}
|
|
});
|
|
obj.clear();
|
|
arr = null;
|
|
};
|
|
removeObj(this);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Created 2008-08-19.
|
|
* 路径判断类
|
|
*****************************************************************************/
|
|
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": predecessors, "costs": costs };
|
|
},
|
|
|
|
extract_shortest_path_from_predecessor_list: function (pred, d) {
|
|
var nodes = [];
|
|
var u = d;
|
|
var predecessor;
|
|
while (u) {
|
|
nodes.push(u);
|
|
predecessor = pred.predecessors[u];
|
|
u = pred.predecessors[u];
|
|
}
|
|
nodes.reverse();
|
|
return { "cost": pred.costs[d], "nodes": 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;
|
|
}
|
|
|
|
//
|
|
///////////////////////////////////--------------------压缩类-------------------
|
|
var LZString = (function () {
|
|
|
|
// private property
|
|
var f = String.fromCharCode;
|
|
var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
|
|
var baseReverseDic = {};
|
|
|
|
function getBaseValue(alphabet, character) {
|
|
if (!baseReverseDic[alphabet]) {
|
|
baseReverseDic[alphabet] = {};
|
|
for (var i = 0; i < alphabet.length; i++) {
|
|
baseReverseDic[alphabet][alphabet.charAt(i)] = i;
|
|
}
|
|
}
|
|
return baseReverseDic[alphabet][character];
|
|
}
|
|
|
|
var LZString = {
|
|
compressToBase64: function (input) {
|
|
if (input == null) return "";
|
|
var res = LZString._compress(input, 6, function (a) { return keyStrBase64.charAt(a); });
|
|
switch (res.length % 4) { // To produce valid Base64
|
|
default: // When could this happen ?
|
|
case 0: return res;
|
|
case 1: return res + "===";
|
|
case 2: return res + "==";
|
|
case 3: return res + "=";
|
|
}
|
|
},
|
|
|
|
decompressFromBase64: function (input) {
|
|
if (input == null) return "";
|
|
if (input == "") return null;
|
|
return LZString._decompress(input.length, 32, function (index) { return getBaseValue(keyStrBase64, input.charAt(index)); });
|
|
},
|
|
|
|
compressToUTF16: function (input) {
|
|
if (input == null) return "";
|
|
return LZString._compress(input, 15, function (a) { return f(a + 32); }) + " ";
|
|
},
|
|
|
|
decompressFromUTF16: function (compressed) {
|
|
if (compressed == null) return "";
|
|
if (compressed == "") return null;
|
|
return LZString._decompress(compressed.length, 16384, function (index) { return compressed.charCodeAt(index) - 32; });
|
|
},
|
|
|
|
//compress into uint8array (UCS-2 big endian format)
|
|
compressToUint8Array: function (uncompressed) {
|
|
var compressed = LZString.compress(uncompressed);
|
|
var buf = new Uint8Array(compressed.length * 2); // 2 bytes per character
|
|
|
|
for (var i = 0, TotalLen = compressed.length; i < TotalLen; i++) {
|
|
var current_value = compressed.charCodeAt(i);
|
|
buf[i * 2] = current_value >>> 8;
|
|
buf[i * 2 + 1] = current_value % 256;
|
|
}
|
|
return buf;
|
|
},
|
|
|
|
//decompress from uint8array (UCS-2 big endian format)
|
|
decompressFromUint8Array: function (compressed) {
|
|
if (compressed === null || compressed === undefined) {
|
|
return LZString.decompress(compressed);
|
|
} else {
|
|
var buf = new Array(compressed.length / 2); // 2 bytes per character
|
|
for (var i = 0, TotalLen = buf.length; i < TotalLen; i++) {
|
|
buf[i] = compressed[i * 2] * 256 + compressed[i * 2 + 1];
|
|
}
|
|
|
|
var result = [];
|
|
buf.forEach(function (c) {
|
|
result.push(f(c));
|
|
});
|
|
return LZString.decompress(result.join(''));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
//compress into a string that is already URI encoded
|
|
compressToEncodedURIComponent: function (input) {
|
|
if (input == null) return "";
|
|
return LZString._compress(input, 6, function (a) { return keyStrUriSafe.charAt(a); });
|
|
},
|
|
|
|
//decompress from an output of compressToEncodedURIComponent
|
|
decompressFromEncodedURIComponent: function (input) {
|
|
if (input == null) return "";
|
|
if (input == "") return null;
|
|
input = input.replace(/ /g, "+");
|
|
return LZString._decompress(input.length, 32, function (index) { return getBaseValue(keyStrUriSafe, input.charAt(index)); });
|
|
},
|
|
|
|
compress: function (uncompressed) {
|
|
return LZString._compress(uncompressed, 16, function (a) { return f(a); });
|
|
},
|
|
_compress: function (uncompressed, bitsPerChar, getCharFromInt) {
|
|
if (uncompressed == null) return "";
|
|
var i, value,
|
|
context_dictionary = {},
|
|
context_dictionaryToCreate = {},
|
|
context_c = "",
|
|
context_wc = "",
|
|
context_w = "",
|
|
context_enlargeIn = 2, // Compensate for the first entry which should not count
|
|
context_dictSize = 3,
|
|
context_numBits = 2,
|
|
context_data = [],
|
|
context_data_val = 0,
|
|
context_data_position = 0,
|
|
ii;
|
|
|
|
for (ii = 0; ii < uncompressed.length; ii += 1) {
|
|
context_c = uncompressed.charAt(ii);
|
|
if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
|
|
context_dictionary[context_c] = context_dictSize++;
|
|
context_dictionaryToCreate[context_c] = true;
|
|
}
|
|
|
|
context_wc = context_w + context_c;
|
|
if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
|
|
context_w = context_wc;
|
|
} else {
|
|
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
|
|
if (context_w.charCodeAt(0) < 256) {
|
|
for (i = 0; i < context_numBits; i++) {
|
|
context_data_val = (context_data_val << 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
}
|
|
value = context_w.charCodeAt(0);
|
|
for (i = 0; i < 8; i++) {
|
|
context_data_val = (context_data_val << 1) | (value & 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = value >> 1;
|
|
}
|
|
} else {
|
|
value = 1;
|
|
for (i = 0; i < context_numBits; i++) {
|
|
context_data_val = (context_data_val << 1) | value;
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = 0;
|
|
}
|
|
value = context_w.charCodeAt(0);
|
|
for (i = 0; i < 16; i++) {
|
|
context_data_val = (context_data_val << 1) | (value & 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = value >> 1;
|
|
}
|
|
}
|
|
context_enlargeIn--;
|
|
if (context_enlargeIn == 0) {
|
|
context_enlargeIn = Math.pow(2, context_numBits);
|
|
context_numBits++;
|
|
}
|
|
delete context_dictionaryToCreate[context_w];
|
|
} else {
|
|
value = context_dictionary[context_w];
|
|
for (i = 0; i < context_numBits; i++) {
|
|
context_data_val = (context_data_val << 1) | (value & 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = value >> 1;
|
|
}
|
|
|
|
|
|
}
|
|
context_enlargeIn--;
|
|
if (context_enlargeIn == 0) {
|
|
context_enlargeIn = Math.pow(2, context_numBits);
|
|
context_numBits++;
|
|
}
|
|
// Add wc to the dictionary.
|
|
context_dictionary[context_wc] = context_dictSize++;
|
|
context_w = String(context_c);
|
|
}
|
|
}
|
|
|
|
// Output the code for w.
|
|
if (context_w !== "") {
|
|
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
|
|
if (context_w.charCodeAt(0) < 256) {
|
|
for (i = 0; i < context_numBits; i++) {
|
|
context_data_val = (context_data_val << 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
}
|
|
value = context_w.charCodeAt(0);
|
|
for (i = 0; i < 8; i++) {
|
|
context_data_val = (context_data_val << 1) | (value & 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = value >> 1;
|
|
}
|
|
} else {
|
|
value = 1;
|
|
for (i = 0; i < context_numBits; i++) {
|
|
context_data_val = (context_data_val << 1) | value;
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = 0;
|
|
}
|
|
value = context_w.charCodeAt(0);
|
|
for (i = 0; i < 16; i++) {
|
|
context_data_val = (context_data_val << 1) | (value & 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = value >> 1;
|
|
}
|
|
}
|
|
context_enlargeIn--;
|
|
if (context_enlargeIn == 0) {
|
|
context_enlargeIn = Math.pow(2, context_numBits);
|
|
context_numBits++;
|
|
}
|
|
delete context_dictionaryToCreate[context_w];
|
|
} else {
|
|
value = context_dictionary[context_w];
|
|
for (i = 0; i < context_numBits; i++) {
|
|
context_data_val = (context_data_val << 1) | (value & 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = value >> 1;
|
|
}
|
|
|
|
|
|
}
|
|
context_enlargeIn--;
|
|
if (context_enlargeIn == 0) {
|
|
context_enlargeIn = Math.pow(2, context_numBits);
|
|
context_numBits++;
|
|
}
|
|
}
|
|
|
|
// Mark the end of the stream
|
|
value = 2;
|
|
for (i = 0; i < context_numBits; i++) {
|
|
context_data_val = (context_data_val << 1) | (value & 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data_position = 0;
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
context_data_val = 0;
|
|
} else {
|
|
context_data_position++;
|
|
}
|
|
value = value >> 1;
|
|
}
|
|
|
|
// Flush the last char
|
|
while (true) {
|
|
context_data_val = (context_data_val << 1);
|
|
if (context_data_position == bitsPerChar - 1) {
|
|
context_data.push(getCharFromInt(context_data_val));
|
|
break;
|
|
}
|
|
else context_data_position++;
|
|
}
|
|
return context_data.join('');
|
|
},
|
|
|
|
decompress: function (compressed) {
|
|
if (compressed == null) return "";
|
|
if (compressed == "") return null;
|
|
return LZString._decompress(compressed.length, 32768, function (index) { return compressed.charCodeAt(index); });
|
|
},
|
|
|
|
_decompress: function (length, resetValue, getNextValue) {
|
|
var dictionary = [],
|
|
next,
|
|
enlargeIn = 4,
|
|
dictSize = 4,
|
|
numBits = 3,
|
|
entry = "",
|
|
result = [],
|
|
i,
|
|
w,
|
|
bits, resb, maxpower, power,
|
|
c,
|
|
data = { val: getNextValue(0), position: resetValue, index: 1 };
|
|
|
|
for (i = 0; i < 3; i += 1) {
|
|
dictionary[i] = i;
|
|
}
|
|
|
|
bits = 0;
|
|
maxpower = Math.pow(2, 2);
|
|
power = 1;
|
|
while (power != maxpower) {
|
|
resb = data.val & data.position;
|
|
data.position >>= 1;
|
|
if (data.position == 0) {
|
|
data.position = resetValue;
|
|
data.val = getNextValue(data.index++);
|
|
}
|
|
bits |= (resb > 0 ? 1 : 0) * power;
|
|
power <<= 1;
|
|
}
|
|
|
|
switch (next = bits) {
|
|
case 0:
|
|
bits = 0;
|
|
maxpower = Math.pow(2, 8);
|
|
power = 1;
|
|
while (power != maxpower) {
|
|
resb = data.val & data.position;
|
|
data.position >>= 1;
|
|
if (data.position == 0) {
|
|
data.position = resetValue;
|
|
data.val = getNextValue(data.index++);
|
|
}
|
|
bits |= (resb > 0 ? 1 : 0) * power;
|
|
power <<= 1;
|
|
}
|
|
c = f(bits);
|
|
break;
|
|
case 1:
|
|
bits = 0;
|
|
maxpower = Math.pow(2, 16);
|
|
power = 1;
|
|
while (power != maxpower) {
|
|
resb = data.val & data.position;
|
|
data.position >>= 1;
|
|
if (data.position == 0) {
|
|
data.position = resetValue;
|
|
data.val = getNextValue(data.index++);
|
|
}
|
|
bits |= (resb > 0 ? 1 : 0) * power;
|
|
power <<= 1;
|
|
}
|
|
c = f(bits);
|
|
break;
|
|
case 2:
|
|
return "";
|
|
}
|
|
dictionary[3] = c;
|
|
w = c;
|
|
result.push(c);
|
|
while (true) {
|
|
if (data.index > length) {
|
|
return "";
|
|
}
|
|
|
|
bits = 0;
|
|
maxpower = Math.pow(2, numBits);
|
|
power = 1;
|
|
while (power != maxpower) {
|
|
resb = data.val & data.position;
|
|
data.position >>= 1;
|
|
if (data.position == 0) {
|
|
data.position = resetValue;
|
|
data.val = getNextValue(data.index++);
|
|
}
|
|
bits |= (resb > 0 ? 1 : 0) * power;
|
|
power <<= 1;
|
|
}
|
|
|
|
switch (c = bits) {
|
|
case 0:
|
|
bits = 0;
|
|
maxpower = Math.pow(2, 8);
|
|
power = 1;
|
|
while (power != maxpower) {
|
|
resb = data.val & data.position;
|
|
data.position >>= 1;
|
|
if (data.position == 0) {
|
|
data.position = resetValue;
|
|
data.val = getNextValue(data.index++);
|
|
}
|
|
bits |= (resb > 0 ? 1 : 0) * power;
|
|
power <<= 1;
|
|
}
|
|
|
|
dictionary[dictSize++] = f(bits);
|
|
c = dictSize - 1;
|
|
enlargeIn--;
|
|
break;
|
|
case 1:
|
|
bits = 0;
|
|
maxpower = Math.pow(2, 16);
|
|
power = 1;
|
|
while (power != maxpower) {
|
|
resb = data.val & data.position;
|
|
data.position >>= 1;
|
|
if (data.position == 0) {
|
|
data.position = resetValue;
|
|
data.val = getNextValue(data.index++);
|
|
}
|
|
bits |= (resb > 0 ? 1 : 0) * power;
|
|
power <<= 1;
|
|
}
|
|
dictionary[dictSize++] = f(bits);
|
|
c = dictSize - 1;
|
|
enlargeIn--;
|
|
break;
|
|
case 2:
|
|
return result.join('');
|
|
}
|
|
|
|
if (enlargeIn == 0) {
|
|
enlargeIn = Math.pow(2, numBits);
|
|
numBits++;
|
|
}
|
|
|
|
if (dictionary[c]) {
|
|
entry = dictionary[c];
|
|
} else {
|
|
if (c === dictSize) {
|
|
entry = w + w.charAt(0);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
result.push(entry);
|
|
|
|
// Add w+entry[0] to the dictionary.
|
|
dictionary[dictSize++] = w + entry.charAt(0);
|
|
enlargeIn--;
|
|
|
|
w = entry;
|
|
|
|
if (enlargeIn == 0) {
|
|
enlargeIn = Math.pow(2, numBits);
|
|
numBits++;
|
|
}
|
|
|
|
}
|
|
}
|
|
};
|
|
return LZString;
|
|
})();
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
define(function () { return LZString; });
|
|
} else if (typeof module !== 'undefined' && module != null) {
|
|
module.exports = LZString
|
|
} else if (typeof angular !== 'undefined' && angular != null) {
|
|
angular.module('LZString', [])
|
|
.factory('LZString', function () {
|
|
return LZString;
|
|
});
|
|
}
|
|
|
|
///////////////////////////////////--------------------加解密-------------------
|
|
! function (t, n) {
|
|
"object" == typeof exports ? module.exports = exports = n() : "function" == typeof define && define.amd ? define([], n) : t.CryptoJS = n()
|
|
}(this, function () {
|
|
var t = t || function (t, n) {
|
|
var i = Object.create || function () {
|
|
function t() { }
|
|
return function (n) {
|
|
var i;
|
|
return t.prototype = n, i = new t, t.prototype = null, i
|
|
}
|
|
}(),
|
|
e = {},
|
|
r = e.lib = {},
|
|
o = r.Base = function () {
|
|
return {
|
|
extend: function (t) {
|
|
var n = i(this);
|
|
return t && n.mixIn(t), n.hasOwnProperty("init") && this.init !== n.init || (n.init = function () {
|
|
n.$super.init.apply(this, arguments)
|
|
}), n.init.prototype = n, n.$super = this, n
|
|
},
|
|
create: function () {
|
|
var t = this.extend();
|
|
return t.init.apply(t, arguments), t
|
|
},
|
|
init: function () { },
|
|
mixIn: function (t) {
|
|
for (var n in t) t.hasOwnProperty(n) && (this[n] = t[n]);
|
|
t.hasOwnProperty("toString") && (this.toString = t.toString)
|
|
},
|
|
clone: function () {
|
|
return this.init.prototype.extend(this)
|
|
}
|
|
}
|
|
}(),
|
|
s = r.WordArray = o.extend({
|
|
init: function (t, i) {
|
|
t = this.words = t || [], i != n ? this.sigBytes = i : this.sigBytes = 4 * t.length
|
|
},
|
|
toString: function (t) {
|
|
return (t || c).stringify(this)
|
|
},
|
|
concat: function (t) {
|
|
var n = this.words,
|
|
i = t.words,
|
|
e = this.sigBytes,
|
|
r = t.sigBytes;
|
|
if (this.clamp(), e % 4)
|
|
for (var o = 0; o < r; o++) {
|
|
var s = i[o >>> 2] >>> 24 - o % 4 * 8 & 255;
|
|
n[e + o >>> 2] |= s << 24 - (e + o) % 4 * 8
|
|
} else
|
|
for (var o = 0; o < r; o += 4) n[e + o >>> 2] = i[o >>> 2];
|
|
return this.sigBytes += r, this
|
|
},
|
|
clamp: function () {
|
|
var n = this.words,
|
|
i = this.sigBytes;
|
|
n[i >>> 2] &= 4294967295 << 32 - i % 4 * 8, n.length = t.ceil(i / 4)
|
|
},
|
|
clone: function () {
|
|
var t = o.clone.call(this);
|
|
return t.words = this.words.slice(0), t
|
|
},
|
|
random: function (n) {
|
|
for (var i, e = [], r = function (n) {
|
|
var n = n,
|
|
i = 987654321,
|
|
e = 4294967295;
|
|
return function () {
|
|
i = 36969 * (65535 & i) + (i >> 16) & e, n = 18e3 * (65535 & n) + (n >> 16) & e;
|
|
var r = (i << 16) + n & e;
|
|
return r /= 4294967296, r += .5, r * (t.random() > .5 ? 1 : -1)
|
|
}
|
|
}, o = 0; o < n; o += 4) {
|
|
var a = r(4294967296 * (i || t.random()));
|
|
i = 987654071 * a(), e.push(4294967296 * a() | 0)
|
|
}
|
|
return new s.init(e, n)
|
|
}
|
|
}),
|
|
a = e.enc = {},
|
|
c = a.Hex = {
|
|
stringify: function (t) {
|
|
for (var n = t.words, i = t.sigBytes, e = [], r = 0; r < i; r++) {
|
|
var o = n[r >>> 2] >>> 24 - r % 4 * 8 & 255;
|
|
e.push((o >>> 4).toString(16)), e.push((15 & o).toString(16))
|
|
}
|
|
return e.join("")
|
|
},
|
|
parse: function (t) {
|
|
for (var n = t.length, i = [], e = 0; e < n; e += 2) i[e >>> 3] |= parseInt(t.substr(e, 2), 16) << 24 - e % 8 * 4;
|
|
return new s.init(i, n / 2)
|
|
}
|
|
},
|
|
u = a.Latin1 = {
|
|
stringify: function (t) {
|
|
for (var n = t.words, i = t.sigBytes, e = [], r = 0; r < i; r++) {
|
|
var o = n[r >>> 2] >>> 24 - r % 4 * 8 & 255;
|
|
e.push(String.fromCharCode(o))
|
|
}
|
|
return e.join("")
|
|
},
|
|
parse: function (t) {
|
|
for (var n = t.length, i = [], e = 0; e < n; e++) i[e >>> 2] |= (255 & t.charCodeAt(e)) << 24 - e % 4 * 8;
|
|
return new s.init(i, n)
|
|
}
|
|
},
|
|
f = a.Utf8 = {
|
|
stringify: function (t) {
|
|
try {
|
|
return decodeURIComponent(escape(u.stringify(t)))
|
|
} catch (t) {
|
|
throw new Error("Malformed UTF-8 data")
|
|
}
|
|
},
|
|
parse: function (t) {
|
|
return u.parse(unescape(encodeURIComponent(t)))
|
|
}
|
|
},
|
|
h = r.BufferedBlockAlgorithm = o.extend({
|
|
reset: function () {
|
|
this._data = new s.init, this._nDataBytes = 0
|
|
},
|
|
_append: function (t) {
|
|
"string" == typeof t && (t = f.parse(t)), this._data.concat(t), this._nDataBytes += t.sigBytes
|
|
},
|
|
_process: function (n) {
|
|
var i = this._data,
|
|
e = i.words,
|
|
r = i.sigBytes,
|
|
o = this.blockSize,
|
|
a = 4 * o,
|
|
c = r / a;
|
|
c = n ? t.ceil(c) : t.max((0 | c) - this._minBufferSize, 0);
|
|
var u = c * o,
|
|
f = t.min(4 * u, r);
|
|
if (u) {
|
|
for (var h = 0; h < u; h += o) this._doProcessBlock(e, h);
|
|
var p = e.splice(0, u);
|
|
i.sigBytes -= f
|
|
}
|
|
return new s.init(p, f)
|
|
},
|
|
clone: function () {
|
|
var t = o.clone.call(this);
|
|
return t._data = this._data.clone(), t
|
|
},
|
|
_minBufferSize: 0
|
|
}),
|
|
p = (r.Hasher = h.extend({
|
|
cfg: o.extend(),
|
|
init: function (t) {
|
|
this.cfg = this.cfg.extend(t), this.reset()
|
|
},
|
|
reset: function () {
|
|
h.reset.call(this), this._doReset()
|
|
},
|
|
update: function (t) {
|
|
return this._append(t), this._process(), this
|
|
},
|
|
finalize: function (t) {
|
|
t && this._append(t);
|
|
var n = this._doFinalize();
|
|
return n
|
|
},
|
|
blockSize: 16,
|
|
_createHelper: function (t) {
|
|
return function (n, i) {
|
|
return new t.init(i).finalize(n)
|
|
}
|
|
},
|
|
_createHmacHelper: function (t) {
|
|
return function (n, i) {
|
|
return new p.HMAC.init(t, i).finalize(n)
|
|
}
|
|
}
|
|
}), e.algo = {});
|
|
return e
|
|
}(Math);
|
|
return t
|
|
});
|
|
//# sourceMappingURL=core.min.js.map
|
|
! function (e, t, i) {
|
|
"object" == typeof exports ? module.exports = exports = t(require("./core.min"), require("./sha1.min"), require("./hmac.min")) : "function" == typeof define && define.amd ? define(["./core.min", "./sha1.min", "./hmac.min"], t) : t(e.CryptoJS)
|
|
}(this, function (e) {
|
|
return function () {
|
|
var t = e,
|
|
i = t.lib,
|
|
r = i.Base,
|
|
n = i.WordArray,
|
|
o = t.algo,
|
|
a = o.MD5,
|
|
c = o.EvpKDF = r.extend({
|
|
cfg: r.extend({
|
|
keySize: 4,
|
|
hasher: a,
|
|
iterations: 1
|
|
}),
|
|
init: function (e) {
|
|
this.cfg = this.cfg.extend(e)
|
|
},
|
|
compute: function (e, t) {
|
|
for (var i = this.cfg, r = i.hasher.create(), o = n.create(), a = o.words, c = i.keySize, f = i.iterations; a.length < c;) {
|
|
s && r.update(s);
|
|
var s = r.update(e).finalize(t);
|
|
r.reset();
|
|
for (var u = 1; u < f; u++) s = r.finalize(s), r.reset();
|
|
o.concat(s)
|
|
}
|
|
return o.sigBytes = 4 * c, o
|
|
}
|
|
});
|
|
t.EvpKDF = function (e, t, i) {
|
|
return c.create(i).compute(e, t)
|
|
}
|
|
}(), e.EvpKDF
|
|
});
|
|
//# sourceMappingURL=evpkdf.min.js.map
|
|
! function (r, e) {
|
|
"object" == typeof exports ? module.exports = exports = e(require("./core.min")) : "function" == typeof define && define.amd ? define(["./core.min"], e) : e(r.CryptoJS)
|
|
}(this, function (r) {
|
|
return function () {
|
|
function e(r, e, t) {
|
|
for (var n = [], i = 0, o = 0; o < e; o++)
|
|
if (o % 4) {
|
|
var f = t[r.charCodeAt(o - 1)] << o % 4 * 2,
|
|
c = t[r.charCodeAt(o)] >>> 6 - o % 4 * 2;
|
|
n[i >>> 2] |= (f | c) << 24 - i % 4 * 8, i++
|
|
} return a.create(n, i)
|
|
}
|
|
var t = r,
|
|
n = t.lib,
|
|
a = n.WordArray,
|
|
i = t.enc;
|
|
i.Base64 = {
|
|
stringify: function (r) {
|
|
var e = r.words,
|
|
t = r.sigBytes,
|
|
n = this._map;
|
|
r.clamp();
|
|
for (var a = [], i = 0; i < t; i += 3)
|
|
for (var o = e[i >>> 2] >>> 24 - i % 4 * 8 & 255, f = e[i + 1 >>> 2] >>> 24 - (i + 1) % 4 * 8 & 255, c = e[i + 2 >>> 2] >>> 24 - (i + 2) % 4 * 8 & 255, s = o << 16 | f << 8 | c, h = 0; h < 4 && i + .75 * h < t; h++) a.push(n.charAt(s >>> 6 * (3 - h) & 63));
|
|
var p = n.charAt(64);
|
|
if (p)
|
|
for (; a.length % 4;) a.push(p);
|
|
return a.join("")
|
|
},
|
|
parse: function (r) {
|
|
var t = r.length,
|
|
n = this._map,
|
|
a = this._reverseMap;
|
|
if (!a) {
|
|
a = this._reverseMap = [];
|
|
for (var i = 0; i < n.length; i++) a[n.charCodeAt(i)] = i
|
|
}
|
|
var o = n.charAt(64);
|
|
if (o) {
|
|
var f = r.indexOf(o);
|
|
f !== -1 && (t = f)
|
|
}
|
|
return e(r, t, a)
|
|
},
|
|
_map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
|
}
|
|
}(), r.enc.Base64
|
|
});
|
|
//# sourceMappingURL=enc-base64.min.js.map
|
|
! function (e, t, r) {
|
|
"object" == typeof exports ? module.exports = exports = t(require("./core.min"), require("./evpkdf.min")) : "function" == typeof define && define.amd ? define(["./core.min", "./evpkdf.min"], t) : t(e.CryptoJS)
|
|
}(this, function (e) {
|
|
e.lib.Cipher || function (t) {
|
|
var r = e,
|
|
i = r.lib,
|
|
n = i.Base,
|
|
c = i.WordArray,
|
|
o = i.BufferedBlockAlgorithm,
|
|
s = r.enc,
|
|
a = (s.Utf8, s.Base64),
|
|
f = r.algo,
|
|
p = f.EvpKDF,
|
|
d = i.Cipher = o.extend({
|
|
cfg: n.extend(),
|
|
createEncryptor: function (e, t) {
|
|
return this.create(this._ENC_XFORM_MODE, e, t)
|
|
},
|
|
createDecryptor: function (e, t) {
|
|
return this.create(this._DEC_XFORM_MODE, e, t)
|
|
},
|
|
init: function (e, t, r) {
|
|
this.cfg = this.cfg.extend(r), this._xformMode = e, this._key = t, this.reset()
|
|
},
|
|
reset: function () {
|
|
o.reset.call(this), this._doReset()
|
|
},
|
|
process: function (e) {
|
|
return this._append(e), this._process()
|
|
},
|
|
finalize: function (e) {
|
|
e && this._append(e);
|
|
var t = this._doFinalize();
|
|
return t
|
|
},
|
|
keySize: 4,
|
|
ivSize: 4,
|
|
_ENC_XFORM_MODE: 1,
|
|
_DEC_XFORM_MODE: 2,
|
|
_createHelper: function () {
|
|
function e(e) {
|
|
return "string" == typeof e ? B : x
|
|
}
|
|
return function (t) {
|
|
return {
|
|
encrypt: function (r, i, n) {
|
|
return e(i).encrypt(t, r, i, n)
|
|
},
|
|
decrypt: function (r, i, n) {
|
|
return e(i).decrypt(t, r, i, n)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}),
|
|
h = (i.StreamCipher = d.extend({
|
|
_doFinalize: function () {
|
|
var e = this._process(!0);
|
|
return e
|
|
},
|
|
blockSize: 1
|
|
}), r.mode = {}),
|
|
u = i.BlockCipherMode = n.extend({
|
|
createEncryptor: function (e, t) {
|
|
return this.Encryptor.create(e, t)
|
|
},
|
|
createDecryptor: function (e, t) {
|
|
return this.Decryptor.create(e, t)
|
|
},
|
|
init: function (e, t) {
|
|
this._cipher = e, this._iv = t
|
|
}
|
|
}),
|
|
l = h.CBC = function () {
|
|
function e(e, r, i) {
|
|
var n = this._iv;
|
|
if (n) {
|
|
var c = n;
|
|
this._iv = t
|
|
} else var c = this._prevBlock;
|
|
for (var o = 0; o < i; o++) e[r + o] ^= c[o]
|
|
}
|
|
var r = u.extend();
|
|
return r.Encryptor = r.extend({
|
|
processBlock: function (t, r) {
|
|
var i = this._cipher,
|
|
n = i.blockSize;
|
|
e.call(this, t, r, n), i.encryptBlock(t, r), this._prevBlock = t.slice(r, r + n)
|
|
}
|
|
}), r.Decryptor = r.extend({
|
|
processBlock: function (t, r) {
|
|
var i = this._cipher,
|
|
n = i.blockSize,
|
|
c = t.slice(r, r + n);
|
|
i.decryptBlock(t, r), e.call(this, t, r, n), this._prevBlock = c
|
|
}
|
|
}), r
|
|
}(),
|
|
_ = r.pad = {},
|
|
v = _.Pkcs7 = {
|
|
pad: function (e, t) {
|
|
for (var r = 4 * t, i = r - e.sigBytes % r, n = i << 24 | i << 16 | i << 8 | i, o = [], s = 0; s < i; s += 4) o.push(n);
|
|
var a = c.create(o, i);
|
|
e.concat(a)
|
|
},
|
|
unpad: function (e) {
|
|
var t = 255 & e.words[e.sigBytes - 1 >>> 2];
|
|
e.sigBytes -= t
|
|
}
|
|
},
|
|
y = (i.BlockCipher = d.extend({
|
|
cfg: d.cfg.extend({
|
|
mode: l,
|
|
padding: v
|
|
}),
|
|
reset: function () {
|
|
d.reset.call(this);
|
|
var e = this.cfg,
|
|
t = e.iv,
|
|
r = e.mode;
|
|
if (this._xformMode == this._ENC_XFORM_MODE) var i = r.createEncryptor;
|
|
else {
|
|
var i = r.createDecryptor;
|
|
this._minBufferSize = 1
|
|
}
|
|
this._mode && this._mode.__creator == i ? this._mode.init(this, t && t.words) : (this._mode = i.call(r, this, t && t.words), this._mode.__creator = i)
|
|
},
|
|
_doProcessBlock: function (e, t) {
|
|
this._mode.processBlock(e, t)
|
|
},
|
|
_doFinalize: function () {
|
|
var e = this.cfg.padding;
|
|
if (this._xformMode == this._ENC_XFORM_MODE) {
|
|
e.pad(this._data, this.blockSize);
|
|
var t = this._process(!0)
|
|
} else {
|
|
var t = this._process(!0);
|
|
e.unpad(t)
|
|
}
|
|
return t
|
|
},
|
|
blockSize: 4
|
|
}), i.CipherParams = n.extend({
|
|
init: function (e) {
|
|
this.mixIn(e)
|
|
},
|
|
toString: function (e) {
|
|
return (e || this.formatter).stringify(this)
|
|
}
|
|
})),
|
|
m = r.format = {},
|
|
k = m.OpenSSL = {
|
|
stringify: function (e) {
|
|
var t = e.ciphertext,
|
|
r = e.salt;
|
|
if (r) var i = c.create([1398893684, 1701076831]).concat(r).concat(t);
|
|
else var i = t;
|
|
return i.toString(a)
|
|
},
|
|
parse: function (e) {
|
|
var t = a.parse(e),
|
|
r = t.words;
|
|
if (1398893684 == r[0] && 1701076831 == r[1]) {
|
|
var i = c.create(r.slice(2, 4));
|
|
r.splice(0, 4), t.sigBytes -= 16
|
|
}
|
|
return y.create({
|
|
ciphertext: t,
|
|
salt: i
|
|
})
|
|
}
|
|
},
|
|
x = i.SerializableCipher = n.extend({
|
|
cfg: n.extend({
|
|
format: k
|
|
}),
|
|
encrypt: function (e, t, r, i) {
|
|
i = this.cfg.extend(i);
|
|
var n = e.createEncryptor(r, i),
|
|
c = n.finalize(t),
|
|
o = n.cfg;
|
|
return y.create({
|
|
ciphertext: c,
|
|
key: r,
|
|
iv: o.iv,
|
|
algorithm: e,
|
|
mode: o.mode,
|
|
padding: o.padding,
|
|
blockSize: e.blockSize,
|
|
formatter: i.format
|
|
})
|
|
},
|
|
decrypt: function (e, t, r, i) {
|
|
i = this.cfg.extend(i), t = this._parse(t, i.format);
|
|
var n = e.createDecryptor(r, i).finalize(t.ciphertext);
|
|
return n
|
|
},
|
|
_parse: function (e, t) {
|
|
return "string" == typeof e ? t.parse(e, this) : e
|
|
}
|
|
}),
|
|
g = r.kdf = {},
|
|
S = g.OpenSSL = {
|
|
execute: function (e, t, r, i) {
|
|
i || (i = c.random(8));
|
|
var n = p.create({
|
|
keySize: t + r
|
|
}).compute(e, i),
|
|
o = c.create(n.words.slice(t), 4 * r);
|
|
return n.sigBytes = 4 * t, y.create({
|
|
key: n,
|
|
iv: o,
|
|
salt: i
|
|
})
|
|
}
|
|
},
|
|
B = i.PasswordBasedCipher = x.extend({
|
|
cfg: x.cfg.extend({
|
|
kdf: S
|
|
}),
|
|
encrypt: function (e, t, r, i) {
|
|
i = this.cfg.extend(i);
|
|
var n = i.kdf.execute(r, e.keySize, e.ivSize);
|
|
i.iv = n.iv;
|
|
var c = x.encrypt.call(this, e, t, n.key, i);
|
|
return c.mixIn(n), c
|
|
},
|
|
decrypt: function (e, t, r, i) {
|
|
i = this.cfg.extend(i), t = this._parse(t, i.format);
|
|
var n = i.kdf.execute(r, e.keySize, e.ivSize, t.salt);
|
|
i.iv = n.iv;
|
|
var c = x.decrypt.call(this, e, t, n.key, i);
|
|
return c
|
|
}
|
|
})
|
|
}()
|
|
});
|
|
//# sourceMappingURL=cipher-core.min.js.map
|
|
! function (e, i) {
|
|
"object" == typeof exports ? module.exports = exports = i(require("./core.min")) : "function" == typeof define && define.amd ? define(["./core.min"], i) : i(e.CryptoJS)
|
|
}(this, function (e) {
|
|
! function () {
|
|
var i = e,
|
|
t = i.lib,
|
|
n = t.Base,
|
|
s = i.enc,
|
|
r = s.Utf8,
|
|
o = i.algo;
|
|
o.HMAC = n.extend({
|
|
init: function (e, i) {
|
|
e = this._hasher = new e.init, "string" == typeof i && (i = r.parse(i));
|
|
var t = e.blockSize,
|
|
n = 4 * t;
|
|
i.sigBytes > n && (i = e.finalize(i)), i.clamp();
|
|
for (var s = this._oKey = i.clone(), o = this._iKey = i.clone(), a = s.words, f = o.words, c = 0; c < t; c++) a[c] ^= 1549556828, f[c] ^= 909522486;
|
|
s.sigBytes = o.sigBytes = n, this.reset()
|
|
},
|
|
reset: function () {
|
|
var e = this._hasher;
|
|
e.reset(), e.update(this._iKey)
|
|
},
|
|
update: function (e) {
|
|
return this._hasher.update(e), this
|
|
},
|
|
finalize: function (e) {
|
|
var i = this._hasher,
|
|
t = i.finalize(e);
|
|
i.reset();
|
|
var n = i.finalize(this._oKey.clone().concat(t));
|
|
return n
|
|
}
|
|
})
|
|
}()
|
|
});
|
|
//# sourceMappingURL=hmac.min.js.map
|
|
! function (e, o, r) {
|
|
"object" == typeof exports ? module.exports = exports = o(require("./core.min"), require("./cipher-core.min")) : "function" == typeof define && define.amd ? define(["./core.min", "./cipher-core.min"], o) : o(e.CryptoJS)
|
|
}(this, function (e) {
|
|
return e.mode.ECB = function () {
|
|
var o = e.lib.BlockCipherMode.extend();
|
|
return o.Encryptor = o.extend({
|
|
processBlock: function (e, o) {
|
|
this._cipher.encryptBlock(e, o)
|
|
}
|
|
}), o.Decryptor = o.extend({
|
|
processBlock: function (e, o) {
|
|
this._cipher.decryptBlock(e, o)
|
|
}
|
|
}), o
|
|
}(), e.mode.ECB
|
|
});
|
|
//# sourceMappingURL=mode-ecb.min.js.map
|
|
! function (e, r, i) {
|
|
"object" == typeof exports ? module.exports = exports = r(require("./core.min"), require("./cipher-core.min")) : "function" == typeof define && define.amd ? define(["./core.min", "./cipher-core.min"], r) : r(e.CryptoJS)
|
|
}(this, function (e) {
|
|
return e.pad.Pkcs7
|
|
});
|
|
//# sourceMappingURL=pad-pkcs7.min.js.map
|
|
! function (e, r, i) {
|
|
"object" == typeof exports ? module.exports = exports = r(require("./core.min"), require("./enc-base64.min"), require("./md5.min"), require("./evpkdf.min"), require("./cipher-core.min")) : "function" == typeof define && define.amd ? define(["./core.min", "./enc-base64.min", "./md5.min", "./evpkdf.min", "./cipher-core.min"], r) : r(e.CryptoJS)
|
|
}(this, function (e) {
|
|
return function () {
|
|
var r = e,
|
|
i = r.lib,
|
|
n = i.BlockCipher,
|
|
o = r.algo,
|
|
t = [],
|
|
c = [],
|
|
s = [],
|
|
f = [],
|
|
a = [],
|
|
d = [],
|
|
u = [],
|
|
v = [],
|
|
h = [],
|
|
y = [];
|
|
! function () {
|
|
for (var e = [], r = 0; r < 256; r++) r < 128 ? e[r] = r << 1 : e[r] = r << 1 ^ 283;
|
|
for (var i = 0, n = 0, r = 0; r < 256; r++) {
|
|
var o = n ^ n << 1 ^ n << 2 ^ n << 3 ^ n << 4;
|
|
o = o >>> 8 ^ 255 & o ^ 99, t[i] = o, c[o] = i;
|
|
var p = e[i],
|
|
l = e[p],
|
|
_ = e[l],
|
|
k = 257 * e[o] ^ 16843008 * o;
|
|
s[i] = k << 24 | k >>> 8, f[i] = k << 16 | k >>> 16, a[i] = k << 8 | k >>> 24, d[i] = k;
|
|
var k = 16843009 * _ ^ 65537 * l ^ 257 * p ^ 16843008 * i;
|
|
u[o] = k << 24 | k >>> 8, v[o] = k << 16 | k >>> 16, h[o] = k << 8 | k >>> 24, y[o] = k, i ? (i = p ^ e[e[e[_ ^ p]]], n ^= e[e[n]]) : i = n = 1
|
|
}
|
|
}();
|
|
var p = [0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54],
|
|
l = o.AES = n.extend({
|
|
_doReset: function () {
|
|
if (!this._nRounds || this._keyPriorReset !== this._key) {
|
|
for (var e = this._keyPriorReset = this._key, r = e.words, i = e.sigBytes / 4, n = this._nRounds = i + 6, o = 4 * (n + 1), c = this._keySchedule = [], s = 0; s < o; s++)
|
|
if (s < i) c[s] = r[s];
|
|
else {
|
|
var f = c[s - 1];
|
|
s % i ? i > 6 && s % i == 4 && (f = t[f >>> 24] << 24 | t[f >>> 16 & 255] << 16 | t[f >>> 8 & 255] << 8 | t[255 & f]) : (f = f << 8 | f >>> 24, f = t[f >>> 24] << 24 | t[f >>> 16 & 255] << 16 | t[f >>> 8 & 255] << 8 | t[255 & f], f ^= p[s / i | 0] << 24), c[s] = c[s - i] ^ f
|
|
} for (var a = this._invKeySchedule = [], d = 0; d < o; d++) {
|
|
var s = o - d;
|
|
if (d % 4) var f = c[s];
|
|
else var f = c[s - 4];
|
|
d < 4 || s <= 4 ? a[d] = f : a[d] = u[t[f >>> 24]] ^ v[t[f >>> 16 & 255]] ^ h[t[f >>> 8 & 255]] ^ y[t[255 & f]]
|
|
}
|
|
}
|
|
},
|
|
encryptBlock: function (e, r) {
|
|
this._doCryptBlock(e, r, this._keySchedule, s, f, a, d, t)
|
|
},
|
|
decryptBlock: function (e, r) {
|
|
var i = e[r + 1];
|
|
e[r + 1] = e[r + 3], e[r + 3] = i, this._doCryptBlock(e, r, this._invKeySchedule, u, v, h, y, c);
|
|
var i = e[r + 1];
|
|
e[r + 1] = e[r + 3], e[r + 3] = i
|
|
},
|
|
_doCryptBlock: function (e, r, i, n, o, t, c, s) {
|
|
for (var f = this._nRounds, a = e[r] ^ i[0], d = e[r + 1] ^ i[1], u = e[r + 2] ^ i[2], v = e[r + 3] ^ i[3], h = 4, y = 1; y < f; y++) {
|
|
var p = n[a >>> 24] ^ o[d >>> 16 & 255] ^ t[u >>> 8 & 255] ^ c[255 & v] ^ i[h++],
|
|
l = n[d >>> 24] ^ o[u >>> 16 & 255] ^ t[v >>> 8 & 255] ^ c[255 & a] ^ i[h++],
|
|
_ = n[u >>> 24] ^ o[v >>> 16 & 255] ^ t[a >>> 8 & 255] ^ c[255 & d] ^ i[h++],
|
|
k = n[v >>> 24] ^ o[a >>> 16 & 255] ^ t[d >>> 8 & 255] ^ c[255 & u] ^ i[h++];
|
|
a = p, d = l, u = _, v = k
|
|
}
|
|
var p = (s[a >>> 24] << 24 | s[d >>> 16 & 255] << 16 | s[u >>> 8 & 255] << 8 | s[255 & v]) ^ i[h++],
|
|
l = (s[d >>> 24] << 24 | s[u >>> 16 & 255] << 16 | s[v >>> 8 & 255] << 8 | s[255 & a]) ^ i[h++],
|
|
_ = (s[u >>> 24] << 24 | s[v >>> 16 & 255] << 16 | s[a >>> 8 & 255] << 8 | s[255 & d]) ^ i[h++],
|
|
k = (s[v >>> 24] << 24 | s[a >>> 16 & 255] << 16 | s[d >>> 8 & 255] << 8 | s[255 & u]) ^ i[h++];
|
|
e[r] = p, e[r + 1] = l, e[r + 2] = _, e[r + 3] = k
|
|
},
|
|
keySize: 8
|
|
});
|
|
r.AES = n._createHelper(l)
|
|
}(), e.AES
|
|
});
|
|
//# sourceMappingURL=aes.min.js.map
|
|
! function (e, n) {
|
|
"object" == typeof exports ? module.exports = exports = n(require("./core.min")) : "function" == typeof define && define.amd ? define(["./core.min"], n) : n(e.CryptoJS)
|
|
}(this, function (e) {
|
|
return e.enc.Utf8
|
|
});
|
|
//# sourceMappingURL=enc-utf8.min.js.map
|
|
|