嘉兴绿城濮院
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

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