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