var Map_QM, renderFrame = -1, renderCount = 0, pathCameraState, mapState = "mall", iconState = "3d", heatmapInstance, isShowElement = true, isJUZ = false, allJU = true, hasLine = false, startRotate = false, intTimer, shopTime, allTime, language = "zh"; //basePath 基础路径 graphPath最佳路径 ftPath 扶梯路径 dtPath 电梯路径 var css_LR = 'color:#000000;font-size: 14px; z-index: 90; text-shadow: 1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff; pointer-events:none;' var typeObj = [ { ft: 0, type: 0, code: "ft", name: "扶梯" }, { upft: 1, type: 1, code: "upft", name: "上扶梯" }, { downft: 2, type: 2, code: "downft", name: "下扶梯" }, { mys: 3, type: 3, code: "mys", name: "母婴室" }, { xsj: 4, type: 4, code: "xsj", name: "洗手间" }, { dt: 5, type: 5, code: "dt", name: "直梯" }, { hxkj: 6, type: 6, code: "hxkj", name: "焕醒空间" }, { fwt: 7, type: 7, code: "fwt", name: "服务台" }, { tcc: 8, type: 8, code: "tcc", name: "停车场" }, { hhkj: 9, type: 9, code: "hhkj", name: "焕活空间" }, { cjr: 10, type: 10, code: "cjr", name: "无障碍洗手间" }, { xys: 11, type: 11, code: "xys", name: "吸烟室" }, { upft: 12, type: 12, code: "upft", name: "上扶梯" }, { downft: 13, type: 13, code: "downft", name: "下扶梯" }, { dkbc: 14, type: 14, code: "dkbc", name: "代客泊车" }, { tczj: 15, type: 15, code: "tczj", name: "童车租借" }, { ysc: 16, type: 16, code: "ysc", name: "饮水处" }, { ztg: 17, type: 17, code: "ztg", name: "L1自提柜" }, { thg: 18, type: 18, code: "thg", name: "B1自提柜" }, { cwysd: 19, type: 19, code: "cwysd", name: "宠物饮水点" }, { td: 20, type: 20, code: "td", name: "人行通道" }, { dit: 21, type: 21, code: "dit", name: "地铁" }, { czc: 22, type: 22, code: "czc", name: "出租车" }, { atm: 23, type: 23, code: "atm", name: "ATM" }, { jcfw: 24, type: 24, code: "jcfw", name: "寄存服务" }, { sjcd: 25, type: 25, code: "sjcd", name: "手机充电" }, { bc: 26, type: 26, code: "bc", name: "泊车" }, { cjc: 27, type: 27, code: "cjc", name: "裁剪处" }, { jtn: 28, type: 28, code: "jtn", name: "家庭洗手间(男)" }, { jtv: 29, type: 29, code: "jtv", name: "家庭洗手间(女)" }, { ksgj: 30, type: 30, code: "ksgj", name: "公交" }, { sjxsn: 31, type: 31, code: "sjxsn", name: "无障碍洗手间男" }, { sjxsv: 32, type: 32, code: "sjxsv", name: "无障碍洗手间女" }, { tcjf: 33, type: 33, code: "tcjf", name: "停车缴费" }, { vip: 34, type: 34, code: "vip", name: "VIP" }, { xsjn: 35, type: 35, code: "xsjn", name: "男洗手间" }, { xsjv: 36, type: 36, code: "xsjv", name: "女洗手间" }, { yszj: 37, type: 37, code: "yszj", name: "雨伞租借" }, { dyj: 38, type: 38, code: "dyj", name: "打印机" }, { door: 39, type: 39, code: "door", name: "出入口" }, { pq: 40, type: 40, code: "pq", name: "喷泉" }, { d1k: 41, type: 41, code: "d1k", name: "1号出入口" }, { d2k: 42, type: 42, code: "d2k", name: "2号出入口" }, { d3k: 43, type: 43, code: "d3k", name: "3号出入口" }, { d4k: 44, type: 44, code: "d4k", name: "4号出入口" }, { mjzyf: 45, type: 45, code: "mjzyf", name: "门急诊药房" }, { cryc: 46, type: 46, code: "cryc", name: "出入院处" }, { rggh: 47, type: 47, code: "rggh", name: "人工挂号收费处" }, { zzyl: 48, type: 48, code: "zzyl", name: "自动饮料贩卖机" }, { gxly: 49, type: 49, code: "gxly", name: "共享轮椅" }, { ysp: 50, type: 50, code: "ysp", name: "艺术品" }, { B1up: 51, type: 51, code: "B1up", name: "" }, { B1down: 52, type: 52, code: "B1down", name: "" }, { B2up: 53, type: 53, code: "B2up", name: "" }, { B2down: 54, type: 54, code: "B2down", name: "" }, { B3up: 55, type: 55, code: "B3up", name: "" }, { B3down: 56, type: 56, code: "B3down", name: "" }, { xcgc: 57, type: 57, code: "xcgc", name: "下沉广场" }, { tthy: 58, type: 58, code: "tthy", name: "天台花园" }, { ybck: 59, type: 59, code: "ybck", name: "医保窗口" }, { zzfw: 60, type: 60, code: "zzfw", name: "自助服务" }, { gjj: 61, type: 61, code: "gjj", name: "工具间" }, { syt1: 62, type: 62, code: "syt1", name: "mall收银台" }, { gwc: 63, type: 63, code: "gwc", name: "购物车" }, { ht: 64, type: 64, code: "ht", name: "花坛" }, { jrc: 65, type: 65, code: "jrc", name: "自助加热" }, { qbc: 66, type: 66, code: "qbc", name: "自助取冰" }, { zxc: 67, type: 67, code: "zxc", name: "自行车停放" }, { jws: 68, type: 68, code: "jws", name: "警务室" }, { etxsj: 69, type: 69, code: "etxsj", name: "儿童洗手间" }, { vip_xxq: 70, type: 70, code: "vip_xxq", name: "vip休息区" }, { ab: 71, type: 71, code: "ab", name: "安保" }, { abjks: 72, type: 72, code: "abjks", name: "安保监控室" }, { bys: 73, type: 73, code: "bys", name: "播音室" }, { cpgys: 74, type: 74, code: "cpgys", name: "裁判更衣室" }, { gzyld: 75, type: 75, code: "gzyld", name: "观众医疗点" }, { hqgys: 76, type: 76, code: "hqgys", name: "后勤更衣室" }, { jjs: 77, type: 77, code: "jjs", name: "急救室" }, { jw: 78, type: 78, code: "jw", name: "警卫" }, { ksj: 79, type: 79, code: "ksj", name: "开水间" }, { kt: 80, type: 80, code: "kt", name: "看台" }, { qzgysn: 81, type: 81, code: "qzgysn", name: "亲自更衣(男)" }, { rsggys: 82, type: 82, code: "rsggys", name: "热身馆更衣室" }, { swzl: 83, type: 83, code: "swzl", name: "失物招领" }, { tsgbs1: 84, type: 84, code: "tsgbs1", name: "特殊贵宾室1" }, { tsgbs2: 85, type: 85, code: "tsgbs2", name: "特殊贵宾室2" }, { tsgbs3: 86, type: 86, code: "tsgbs3", name: "特殊贵宾室3" }, { wxc: 87, type: 87, code: "wxc", name: "闻讯处" }, { lt: 88, type: 88, code: "lt", name: "楼梯" }, { yhs: 89, type: 89, code: "yhs", name: "医护室" }, { yls: 90, type: 90, code: "yls", name: "医疗室" }, { ylz: 91, type: 91, code: "ylz", name: "医疗站" }, { ydygys: 92, type: 92, code: "ydygys", name: "运动员更衣室" }, { ydygysn: 93, type: 93, code: "ydygysn", name: "运动员男更衣室" }, { ydygysv: 94, type: 94, code: "ydygysv", name: "运动员女更衣室" }, { zls: 95, type: 95, code: "zls", name: "诊疗室" }, { zys: 96, type: 96, code: "zys", name: "直饮水" }, { zas: 97, type: 97, code: "zas", name: "治安室" }, { xxq: 98, type: 98, code: "xxq", name: "休息区" }, { jtxsj: 99, type: 99, code: "jtxsj", name: "家庭洗手间" }, { hzs: 100, type: 100, code: "hzs", name: "化妆室" }, { brs: 101, type: 101, code: "brs", name: "哺乳室" }, { mtl: 102, type: 102, code: "mtl", name: "摩天轮" }, { dgnxsj: 103, type: 103, code: "dgnxsj", name: "多功能洗手间" }, { wxbxsj: 104, type: 104, code: "wxbxsj", name: "无性别洗手间" }, { sjzx: 105, type: 105, code: "sjzx", name: "设计中心" }, { dxp: 106, type: 106, code: "dxp", name: "导向牌" }, { gydh: 107, type: 107, code: "gydh", name: "公用电话" }, { sgq: 108, type: 108, code: "sgq", name: "石拱桥" }, { wxw: 109, type: 109, code: "wxw", name: "无线网" }, { xmb: 110, type: 110, code: "xmb", name: "小卖部" }, { zyzfwz: 111, type: 111, code: "zyzfwz", name: "志愿者服务站" }, { ykzx: 112, type: 112, code: "ykzx", name: "服务中心" }, { zjyy: 113, type: 113, code: "zjyy", name: "专家预约处" }, { yjt: 114, type: 114, code: "yjt", name: "预检台" }, { mzjd: 115, type: 115, code: "mzjd", name: "门诊综合接待室" }, { hd: 116, type: 116, code: "hd", name: "活动点" }, { bsl: 117, type: 117, code: "bsl", name: "白石龙" }, { xzl: 118, type: 118, code: "xzl", name: "写字楼" }, { axzj: 119, type: 119, code: "axzj", name: "爱心租借" }, { cdz: 120, type: 120, code: "cdz", name: "充电桩" }, { hjcq: 121, type: 121, code: "hjcq", name: "黑金车区" }, { yjjj: 122, type: 122, code: "yjjj", name: "宜家家居" }, ]; var QMUtil = function () { this.shopServerInfo = "static/offline/JSON/QueryShopList.json"; this.mapServerInfo = "static/offline/JSON/GetMapInfo.json"; this.beforPath = "./"; //https://qianmu-iot.1000my.com/QMAPSDK/ this.tomUrl = "https://qianmu-iot.1000my.com"; this.options = { playSpeed: 8, //动画播放速度 speedMult: 1, //动画播放倍数 collision: true, //是否支持名称的碰撞检测 modelIcon: true, //是否使用模型 true 模型 false 图标 otherPath: [], //人为干预的路线 [{f:"0_5_10",s:"1_5_47",d:500},{f:"1_5_47",s:"0_5_10",d:500}]; bSpace: 5000, fSpace: 500, //双叠层状态下楼层的间距 maxDis: 700, minDis: 40, shadow: true, //是否显示阴影 navColor: 0xee6a50, //途径店铺颜色 aRadius: 2, //圆角半径 大于2 则店铺box显示圆角 iconName: false, //图标名称是否显示 mapScale: 18, //地图比例尺 pathColor: "#6e95fe", // pathColor2: "#6e7dfe", //'rgb(110,125,254)' pathBgColor: "#a9b5d3", //'rgb(169,181,211)' pathBgColor2: "#bdc0cb", //'rgb(189, 192, 203)', pathStyle: "3D", shopStyle: "shopName", //设置box显示名称shopName或编号shopNum inArea: false, //点击后是否聚焦到店铺 boxShop: [], //设置box上显示的文字(过滤指),可点击触发onlyShop deviceAng: false, //地图初始化方向是否使用设备角度 northShow: false, //指南针显示 facSize: 20, //设施大小 }; this.lightOptions = { d_col: "#ffffff", d_int: 0.2, s_col: "#fffffa", g_col: "#ffffff", a_int: 0.85, }; this.m_zoom = 1.2; //2D地图缩放大小 this._clock = new THREE.Clock(); this._indexPathFloor = 0; // 遍历途径数据 this.changeDist = { inner: 300, outner: 900 }; /** * isPathState 寻路状态 */ this.pathStateObj = { isPathState: false, isPathPlay: true, basePath: "", graphPath: "", ftPath: "", dtPath: "", facAllArr: [], forShopArr: {}, elevator: null, straight: null, elevatorDown: null, seldtFacNo: { type: "", no: "" }, }; this.timeObj = { collTime: -1, pathTime: -1 }; this.sceneGap = { cameraX: 0, cameraY: 220, cameraZ: 220, x: 0, y: 0, z: 0, scale: 0.08 }; //改变地图位置,大小 this.isMorePath = false; //多节点寻路模式 this.selectBuild = 0; this.selectFloor = 0; this.deviceObj = {}; //angle --- 设备旋转角度 node ---- 设备导航点位 floor --- 设备楼层 this.startObj = {}; // 导航起点; this.overObj = {}; //导航结束点 this.buildHeight = 5; this.shopHeight = 30; //店铺高度 控制店铺相关的其它第三方组件高度 //添加平铺logo {floor:5, logoUrl:"./static/img/ss.png", imgW:395, imgH:376, xaxis:1550, yaxis:-860, site:30} this.logos = []; /** * 外立面 * Map_QM.util.initModelArr=[{url:"./static/img/out/yong.glb",type:"out", scale:1, rot:{x:0,y:0,z:0}, site:{x:0,y:0,z:0}, colorModel:"gama" }]; */ this.initModelArr = []; // /** * 一直显示不隐藏, 在楼层内显示 * {floor:6, url:"static/img/out/skp.glb", list:[{size:{x:12.5,y:12.5,z:12.5}, rot:{x:1.5708,y:0,z:0}, site:{x:0,y:0,z:0}}]} */ this.modelArr = []; this.modelStr = [ //种树 {key: "tree", url: "static/img/model/tree.gltf", colorModel: "line", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 1, y: 1, z: 1 }, load: false }, {key: "tree2", url: "static/img/model/tree2.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "tree3", url: "static/img/model/tree3.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "grass", url: "static/img/model/grass.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "flower1", url: "static/img/model/flower1.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 },load: false}, {key: "flower2", url: "static/img/model/flower2.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "huatan1", url: "static/img/model/huatan1.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "huatan2", url: "static/img/model/huatan2.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "penquan2", url: "static/img/model/penquan2.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche1", url: "static/img/model/qiche1.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche2", url: "static/img/model/qiche2.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche3", url: "static/img/model/qiche3.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche4", url: "static/img/model/qiche4.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche5", url: "static/img/model/qiche5.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche6", url: "static/img/model/qiche6.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche7", url: "static/img/model/qiche7.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche8", url: "static/img/model/qiche8.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "qiche9", url: "static/img/model/qiche9.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "jt_up", url: "static/img/model/jt_up.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "jt_left", url: "static/img/model/jt_left.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "jt_left_up", url: "static/img/model/jt_left_up.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "jt_right", url: "static/img/model/jt_right.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "jt_right_up", url: "static/img/model/jt_right_up.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "jt_turn", url: "static/img/model/jt_turn.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "ludeng", url: "static/img/model/ludeng.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "taiyangsan", url: "static/img/model/taiyangsan.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "honglvdeng", url: "static/img/model/honglvdeng.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "park_paly", url: "static/img/model/park_paly.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 80, y: 80, z: 80 }, load: false }, {key: "chongdianzhuang", url: "static/img/model/chongdianzhuang.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "IDS_H", url: "static/img/model/IDS_H.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "IDS_V", url: "static/img/model/IDS_V.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "officeTV", url: "static/img/model/officeTV.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "xiaofangshuan", url: "static/img/model/xiaofangshuan.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "tingchechang", url: "static/img/model/tingchechang.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "chechanglangan", url: "static/img/model/chechanglangan.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "bangongyi", url: "static/img/model/bangongyi.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "lvzhi", url: "static/img/model/lvzhi.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "ren1", url: "static/img/model/ren1.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "ren2", url: "static/img/model/ren2.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "ren3", url: "static/img/model/ren3.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "ren4", url: "static/img/model/ren4.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "ren5", url: "static/img/model/ren5.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "ren6", url: "static/img/model/ren6.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "table", url: "static/img/model/table.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "yizi1", url: "static/img/model/yizi1.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, {key: "gjz1", url: "static/img/model/gjz1.glb", colorModel: "gama", rot: { x: 1.5708, y: 0, z: 0 }, size: { x: 20, y: 20, z: 20 }, load: false }, ]; this.fbxModels = []; //精灵模型 /** * 模型弹窗 * { htmlUrl: "

进入商场

", x: 55, y: 12, z: 3, show:"zh", type: "out" } */ this.tipArr = []; //模型标签 periphery /** * 室内地图标签 * Map_QM.util.labelIconArr([{floor:0,title:'', click:false, site:{x:0,y:1870,z:10},data:{type:"labelIcon",id:"1",show:"cn"}}]); */ this.labelIconArr = []; this.spriteMaterialArr = []; this.lineBasicMaterialArr = []; this.meshMaterialArr = []; this.parkMaterialArr = []; this.shopData = []; //店铺数据 this.iconUrl = []; this.allMap = []; /*** ------------------------------------------------ 参数 API START ------------------------------------------------- */ this.exportImg = function () { let tempSrc = Map_QM.renderer.domElement.toDataURL("image/png"); let a = document.createElement("a"); a.href = tempSrc; a.setAttribute("download", "floor.png"); a.click(); }; /** * @api {方法} changePlaySpeed(speedMult) 改变导航速度倍数 * @apiGroup 地图导航 * @apiDescription 改变导航播放速度倍数 * @apiVersion 4.0.0 * * @apiParam {int} speedMult 播放速度倍数(默认 1) * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.util.changePlaySpeed() * */ this.changePlaySpeed = function (speedMult = 1) { Map_QM.util.options.speedMult = speedMult; }; /*** ----------------------------------------------- 参数 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.assignUVs = function (geometry) { geometry.computeBoundingBox(); let max = geometry.boundingBox.max, min = geometry.boundingBox.min; let offset = new THREE.Vector2(0 - min.x, 0 - min.y); let range = new THREE.Vector2(max.x - min.x, max.y - min.y); let addX = 1, addY = 1; range.x / range.y < 1 ? (addX = range.x / range.y) : (addY = range.y / range.x); geometry.faceVertexUvs[0] = []; for (let face of geometry.faces) { let v1 = geometry.vertices[face.a], v2 = geometry.vertices[face.b], v3 = geometry.vertices[face.c]; if (face.normal.z == 0) { //侧面 if (range.x / range.y >= 1) { let repY = range.y / 256 >= 2 ? 256 : range.y; face.materialIndex = Math.abs(face.normal.x) < 0.7 ? 2 : 1; geometry.faceVertexUvs[0].push( face.materialIndex == 1 ? [ new THREE.Vector2((v1.y + offset.y) / repY, v1.z / 512), new THREE.Vector2((v2.y + offset.y) / repY, v2.z / 512), new THREE.Vector2((v3.y + offset.y) / repY, v3.z / 512), ] : [ new THREE.Vector2((v1.x + offset.x) / range.x, v1.z / 64), new THREE.Vector2((v2.x + offset.x) / range.x, v2.z / 64), new THREE.Vector2((v3.x + offset.x) / range.x, v3.z / 64), ] ); } else { face.materialIndex = Math.abs(face.normal.x) < 0.7 ? 1 : 2; geometry.faceVertexUvs[0].push( face.materialIndex == 1 ? [ new THREE.Vector2((v1.x + offset.x) / range.x, v1.z / 512), new THREE.Vector2((v2.x + offset.x) / range.x, v2.z / 512), new THREE.Vector2((v3.x + offset.x) / range.x, v3.z / 512), ] : [ new THREE.Vector2((v1.y + offset.y) / range.y, v1.z / 64), new THREE.Vector2((v2.y + offset.y) / range.y, v2.z / 64), new THREE.Vector2((v3.y + offset.y) / range.y, v3.z / 64), ] ); } } else { //顶面和底面 face.materialIndex = 0; geometry.faceVertexUvs[0].push([ new THREE.Vector2( ((v1.x + offset.x) / range.x) * addX, ((v1.y + offset.y) / range.y) * addY ), new THREE.Vector2( ((v2.x + offset.x) / range.x) * addX, ((v2.y + offset.y) / range.y) * addY ), new THREE.Vector2( ((v3.x + offset.x) / range.x) * addX, ((v3.y + offset.y) / range.y) * addY ), ]); } } geometry.uvsNeedUpdate = true; }; this.packUv = function (geometry) { geometry.computeBoundingBox(); let max = geometry.boundingBox.max, min = geometry.boundingBox.min; let offset = new THREE.Vector2(0 - min.x, 0 - min.y); let range = new THREE.Vector2(max.x - min.x, max.y - min.y); geometry.faceVertexUvs[0] = []; let allReag = 0; for (let i = 0; i < geometry.faces.length; i += 2) { let v1 = geometry.vertices[geometry.faces[i].a], v2 = geometry.vertices[geometry.faces[i].b]; if (geometry.faces[i].normal.z == 0) { //侧面 if (Math.abs(geometry.faces[i].normal.x) < 0.7) { //左右 allReag += Math.abs(v2.x - v1.x); } else { allReag += Math.abs(v2.y - v1.y); } } } for (let face of geometry.faces) { let v1 = geometry.vertices[face.a], v2 = geometry.vertices[face.b], v3 = geometry.vertices[face.c]; if (face.normal.z == 0) { //侧面 face.materialIndex = 1; if (Math.abs(face.normal.x) < 0.7) { //前后 geometry.faceVertexUvs[0].push([ new THREE.Vector2((v1.x + offset.x) / allReag, v1.z / 512), new THREE.Vector2((v2.x + offset.x) / allReag, v2.z / 512), new THREE.Vector2((v3.x + offset.x) / allReag, v3.z / 512), ]); } else { geometry.faceVertexUvs[0].push([ new THREE.Vector2((v1.y + offset.y) / allReag, v1.z / 512), new THREE.Vector2((v2.y + offset.y) / allReag, v2.z / 512), new THREE.Vector2((v3.y + offset.y) / allReag, v3.z / 512), ]); } } else { //顶面和底面 face.materialIndex = 0; geometry.faceVertexUvs[0].push([ new THREE.Vector2( (v1.x + offset.x) / range.x, (v1.y + offset.y) / range.y ), new THREE.Vector2( (v2.x + offset.x) / range.x, (v2.y + offset.y) / range.y ), new THREE.Vector2( (v3.x + offset.x) / range.x, (v3.y + offset.y) / range.y ), ]); } } }; /** * 检测点是否在多边形区域内 */ 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.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) { window.captureException && window.captureException(e); params.fail(); return; } params.success(jsonObject); } if ( xmlhttp.readyState === 4 && (xmlhttp.status === 404 || xmlhttp.status === 405) ) { params.fail(); } }; xmlhttp.onerror = function () { params.fail(); }; xmlhttp.open(params.method, params.url, true); //xmlhttp.setRequestHeader("Access-Control-Allow-Origin", "*"); xmlhttp.setRequestHeader("Content-type", "application/json"); xmlhttp.send(params.data); }; //解密 this.decrypt = function (word, keyStr) { keyStr = keyStr ? keyStr : "cqmyg#hdhxt!saas"; 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) { window.captureException && window.captureException(e); } } }; rawFile.onerror = function () { callback(null); }; rawFile.send(null); }; /**碰撞检测 * 传入A中心点和A的宽、高 * B的中心点和B的宽、高 */ this.isCollision = function (A, B) { return ( A.x < B.x + B.width && A.x + A.width > B.x && A.y < B.y + B.height && A.y + A.height > B.y ); }; 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 = Map_QM.util.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 Map_QM.util.Point( area.hasLines[m].startPoint.x, area.hasLines[m].startPoint.y ); ePoint = new Map_QM.util.Point( area.hasLines[m].endPoint.x, area.hasLines[m].endPoint.y ); if (area.hasLines[m].isStrLine) { cPoint1 = null; cPoint2 = null; } else { cPoint1 = new Map_QM.util.Point( area.hasLines[m].ctrlPoint1.x, area.hasLines[m].ctrlPoint1.y ); cPoint2 = new Map_QM.util.Point( area.hasLines[m].ctrlPoint2.x, area.hasLines[m].ctrlPoint2.y ); } let line = new Map_QM.util.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 (Map_QM.util.options.aRadius > 2) { if (line0.isStrLine &&line1.isStrLine &&Math.abs(line0.endPoint.x - line0.startPoint.x) + Math.abs(line0.endPoint.y - line0.startPoint.y) > parseInt(Map_QM.util.options.aRadius) * 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 = Map_QM.util.getIncircleByLines(x1,y1,x2,y2,x3,y3,Map_QM.util.options.aRadius); let bezierResult = Map_QM.util.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, Map_QM.util.options.aRadius); if (i > 0) { let ctrlPoint1, ctrlPoint2, array = []; ctrlPoint1 = ctrlPoint2 = new Map_QM.util.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 Map_QM.util.Point(line1.ctrlPoint1.x,line1.ctrlPoint1.y); ocPoint2 = new Map_QM.util.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, }, Map_QM.util.getPointFromLine(x2, y2, x4, y4, tempDistence), Map_QM.util.getPointFromLine(x3, y3, x4, y4, tempDistence), { x: x3, y: y3, }, ]; }; //根据半径计算两条线段相切圆的圆心和切点坐标 this.getIncircleByLines = function (x1, y1, x2, y2, x3, y3, radius) { //向量夹角 let angle = Map_QM.util.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 = [ Map_QM.util.getPointFromLine(x1, y1, x2, y2, distance), Map_QM.util.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) { if (!area2.hasLines || !area.hasLines) { return false; } let ptPolygon = []; for (let i = 0; i < area2.hasLines.length; i++) { let line = area2.hasLines[i]; let pArr; if (line.isStrLine) { pArr = Map_QM.util.getPointArrOnLine(line.startPoint, line.endPoint); } else { pArr = Map_QM.util.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 = Map_QM.util.checkBoundary(new Map_QM.util.Point(line2.startPoint.x, line2.startPoint.y),ptPolygon); let ePoint = Map_QM.util.checkBoundary(new Map_QM.util.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; for (let j = 0; j < 1; j += sp) { p = Map_QM.util.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 = Map_QM.util.jie_cheng(n - 1); let mother = Map_QM.util.jie_cheng(i) * Map_QM.util.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 Map_QM.util.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 Map_QM.util.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 Map_QM.util.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 Map_QM.util.Point(x0, y0)); } } return points; }; //转换公共设施type值 this.getFacType = function (str) { for (let i = 0; i < typeObj.length; i++) { if (typeObj[i].code && typeObj[i].code == str) { return typeObj[i].type; } } }; this.getFacName = function (str) { for (let i = 0; i < typeObj.length; i++) { if (typeObj[i].code && typeObj[i].code == str) { return typeObj[i].name; } } }; //店铺排序 this.sortShopByFloor = function (a, b) { return a.floorOrder < b.floorOrder ? -1 : 1; }; this.sortNode = function (a, b) { return a.id - b.id; }; //////////////////////////////////////////////////////////////////////////////////////////// this.getWallPoints = function (points, wallWidth) { if (points.length < 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 = Map_QM.util.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 = Map_QM.util.getIntersectionByLines( start.leftParLine, end.leftParLine ); start.rightPoint = Map_QM.util.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 Map_QM.util.WallLine(start, end); //计算当前线段的斜率 let gradient = (start.y - end.y) / (start.x - end.x); //计算垂直线的斜率 let perGradient = -1 / gradient; //获取垂直线上左右两侧 与当前点位相距一定距离的两个定点 let startResult = Map_QM.util.getParallelPoints( perGradient, start, wallWidth); let endResult = Map_QM.util.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 Map_QM.util.WallLine(new Map_QM.util.Point(x1, y1), new Map_QM.util.Point(x2, y2)); line.rightParLine = new Map_QM.util.WallLine(new Map_QM.util.Point(x4, y4), new Map_QM.util.Point(x5, y5)); } else { line.leftParLine = new Map_QM.util.WallLine(new Map_QM.util.Point(x4, y4), new Map_QM.util.Point(x5, y5)); line.rightParLine = new Map_QM.util.WallLine(new Map_QM.util.Point(x1, y1), new Map_QM.util.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 = gradient * (x - point.x) + point.y; } return Map_QM.util.pointXY( point, new Map_QM.util.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 Map_QM.util.Point(curPoint.x, curPoint.y + length)); result.push(new Map_QM.util.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 Map_QM.util.Point(x1, k * x1 + b)); result.push(new Map_QM.util.Point(x2, 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 Map_QM.util.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 Map_QM.util.Point(x, y); }; /** * 根据色值获取材质 */ this.getMeshMaterial = function (color, alphaModle = 0.9) { let meshMaterial; for (let k = 0; k < Map_QM.util.meshMaterialArr.length; k++) { let color2 = new THREE.Color(color); if ( Map_QM.util.meshMaterialArr[k].color && Map_QM.util.meshMaterialArr[k].color.equals(color2) && Map_QM.util.meshMaterialArr[k].opacity == alphaModle ) { meshMaterial = Map_QM.util.meshMaterialArr[k]; } } if (!meshMaterial) { meshMaterial = new THREE.MeshPhongMaterial({ color: color, emissive: 0x000000, specular: 0x000000, transparent: true, side: THREE.DoubleSide, opacity: alphaModle, }); Map_QM.util.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); }; //用于生成uuid this.guid = function () { function S4() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); } return S4() + S4() + S4(); }; this.getTextMesh = function (text, position) { const sprite = new SpriteText(text, 32, "#000000"); sprite.padding = 2; sprite.fontSize = 32; sprite.strokeWidth = 2; sprite.renderOrder = 100; sprite.fontWeight = "500"; sprite.material.transparent = true; sprite.material.alphaTest = 0.1; sprite.material.sizeAttenuation = false; sprite.position.set(position.x, position.y, position.z + 24); return sprite; }; }; //////////////////////////////-------------------------------------------配置 UtilFun /** * 地图主类,入口 初始化设备点位 */ var MainMap_QM = function (callBack, options) { this.util = new QMUtil(); this.callBackLoadOver = callBack; this.ele = document.getElementById(options.containerId || "mapContainer"); this.w = parseInt(this.ele.clientWidth) || parseInt(window.getComputedStyle(this.ele, null).getPropertyValue("width")); this.h = parseInt(this.ele.clientHeight) ||parseInt(window.getComputedStyle(this.ele, null).getPropertyValue("height")); this.backObj = { code: 200, msg: "加载成功", data: [] }; this.scene = new THREE.Scene(); this.scene.name = "scene"; //this.scene.fog = new THREE.Fog(0xe5e5e5,this.util.options.maxDis,this.util.options.maxDis + 500); this.aspect = this.w / this.h; this.cameraPerspective = new THREE.PerspectiveCamera(45,this.aspect,10,10000); this.cameraPerspective.position.set(this.util.sceneGap.cameraX,this.util.sceneGap.cameraY,this.util.sceneGap.cameraZ); //x 水平 y 垂直旋转 z 展示大小 this.cameraPerspective.lookAt(new THREE.Vector3(0, 0, 0)); this.cameraOrtho = new THREE.OrthographicCamera(-150 * this.aspect, 150 * this.aspect, 150, -150, 10, 10000) this.cameraOrtho.position.set(this.util.sceneGap.cameraX, this.util.sceneGap.cameraY, this.util.sceneGap.cameraZ) this.cameraOrtho.lookAt(new THREE.Vector3(0, 0, 0)); this.camera = this.cameraPerspective; // this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); // preserveDrawingBuffer 是否可以截图 //this.renderer.outputEncoding = THREE.sRGBEncoding; this.renderer.setSize(this.w, this.h); this.renderer.setPixelRatio(window.devicePixelRatio); this.renderer.shadowMap.enabled = false; // 阴影类型 this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; this.ele.appendChild(this.renderer.domElement); this.labelRenderer = new THREE.CSS2DRenderer(); //弹窗的偏移百分比 或者像素 this.labelRenderer.setSize(this.w, this.h, options.perc_H || "-50%"); this.labelRenderer.domElement.style.position = "absolute"; this.labelRenderer.domElement.style.top = 0; this.ele.appendChild(this.labelRenderer.domElement); let light = new THREE.AmbientLight(0xffffff, 0.4); light.name = "light"; this.scene.add(light); this.hemiLight = new THREE.HemisphereLight(this.util.lightOptions.s_col,this.util.lightOptions.g_col,this.util.lightOptions.a_int); this.hemiLight.name = "light"; this.hemiLight.position.set(0, 1, 0); this.scene.add(this.hemiLight); this.shawLight = new THREE.DirectionalLight(this.util.lightOptions.d_col,this.util.lightOptions.d_int); this.shawLight.name = "light"; this.shawLight.position.set(280, 400, -300); this.scene.add(this.shawLight); this.controls = new THREE.OrbitControls(this.camera, this.ele); this.controls.minZoom = 0.8; this.controls.maxZoom = 2; //设置相机距离原点的最远距离 this.controls.minDistance = this.util.options.minDis; //设置相机距离原点的最远距离 this.controls.maxDistance = this.util.options.maxDis; this.controls.minPolarAngle = 0; // 0是为了兼容2D模式 this.controls.maxPolarAngle = Math.PI / 2 - 0.2; // radians this.ele.addEventListener("click", this.onMouseClickBox); //地图点击 document.addEventListener("resize", this.changeDocmentResize); //窗口变化 this.mapArr = []; this.selectShop; this.selectEle = null; //当前使用的电梯 this.overShop; //终点店铺 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"; if (document.getElementById("moveFloorBG")) { document.getElementById("moveFloorBG").style.zIndex = 500; this.moveFloorbg = new THREE.CSS2DObject( document.getElementById("moveFloorBG") ); this.moveFloorbg.userData.isShow = false; } this.mixers = []; this.man_3d = null; this.man_2d = null; this.guide = null; this.devModel = null; this.sceneGap = new THREE.Group(); this.outModelGap = new THREE.Group(); //全局外立面模型 this.scene.add(this.outModelGap); this.peripheryGap = new THREE.Group(); //周边模型 this.scene.add(this.peripheryGap); this.outObject = new THREE.Object3D(); this.outObject.userData.type = "moveFloor"; this.perObject = new THREE.Object3D(); this.perObject.userData.type = "moveFloor"; this.buildObj = new THREE.Group(); this.qiModel = null; //起点 this.qiIcon = null; //起点Icon this.endIcon = null; //终点Icon this.endModel = null; this.forShopArr = []; //途径数据 this.getInstance(options); if (this.util.options.northShow) { this.util.img = document.createElement("img"); this.util.img.src = "./static/img/noth.png"; this.util.img.classList.add("north"); this.ele.appendChild(this.util.img); } }; MainMap_QM.prototype = { resetModel: function () { if (mapState == "mall") { Map_QM.buildObj.visible = true; Map_QM.controls.reset(); startRotate = false; Map_QM.controls.setDistance(Map_QM.util.changeDist.inner - 25); } else if (mapState == "out") { Map_QM.controls.reset(); Map_QM.controls.setDistance(Map_QM.util.changeDist.inner + 30); Map_QM.outModelGap.rotateY(-1 * Map_QM.outModelGap.rotation.y); startRotate = true; } else { Map_QM.controls.reset(); Map_QM.controls.setDistance(Map_QM.util.changeDist.outner + 25); startRotate = false; } Map_QM.controls.update(); renderCount = 0; }, /** * @api {方法} getPointByNode() 获取导航点位的坐标 * @apiGroup 地图交互 * @apiDescription 获取导航点位的坐标 * @apiVersion 4.0.0 * @apiParam {String} str 导航点位 * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * Map_QM.getPointByNode("0_0_1"); */ getPointByNode: function (str) { let nodes = str.split("_"); if (nodes.length > 2 && !isNaN(parseInt(nodes[2])) && parseInt(nodes[2])>=0) { Map_QM.util.allMap[nodes[0]].buildArr[nodes[1]].mapData.path.nodes.sort(Map_QM.util.sortNode); return Map_QM.util.allMap[nodes[0]].buildArr[nodes[1]].mapData.path.nodes[nodes[2]]; }else{ return {x:-5000,y:-5000,msg:"未打点"}; } }, getInstance: function (options) { this.util.startObj.build = this.util.deviceObj.build = parseInt(options.build) || 0; this.util.startObj.node = this.util.deviceObj.node = parseInt(options.navPoint) || 1; this.util.deviceObj.angle = parseInt(options.angle) || 0; this.util.selectBuild = this.util.deviceObj.build; let _space = this; if (options.mallCode) { let tim = this.util.timeStamp(); this.util.requestNoJM({ method: "GET", url: options.url + "/api/info/v1/web/getUploadUrl", success: (res) => { let resText = res.data; if (typeof resText === "string" &&resText.search("https://") === -1) { resText = JSON.parse(_space.util.decrypt(res.data)); } _space.tomUrl = resText; this.util.requestNoJM({ method: "GET", url: _space.tomUrl + "/ar/" + options.mallCode +"/config.json?a=" +tim, success: (res) => { _space.util.shopServerInfo = res.shopUrl; _space.util.mapServerInfo = res.mapUrl; _space.initLoadMapFile(options); }, fail: () => { _space.backObj.code = 404; _space.backObj.msg = "地图数据获取失败"; _space.callBackLoadOver(_space.backObj); _space.callBackLoadOver = null; }, }); }, fail: () => { this.util.requestNoJM({ method: "GET", url: _space.tomUrl +"/ar/" +options.mallCode +"/config.json?a=" +tim, success: (res) => { _space.util.shopServerInfo = res.shopUrl; _space.util.mapServerInfo = res.mapUrl; _space.initLoadMapFile(options); }, fail: () => { _space.backObj.code = 404; _space.backObj.msg = "地图数据获取失败"; _space.callBackLoadOver(_space.backObj); _space.callBackLoadOver = null; }, }); }, }); } else { if (options.mapData) { try { _space.util.allMap = JSON.parse(options.mapData.mapData); console.log("地图数据更新时间: " + options.mapData.updateTime); } catch (e) { window.captureException && window.captureException(e); console.log(e); _space.backObj.code = 404; _space.backObj.msg = "地图数据JSON格式错误"; _space.callBackLoadOver(_space.backObj); return; } _space.util.shopData = options.shopData; _space.initOptions(options); } else { _space.initLoadMapFile(options); } } }, initLoadMapFile: function (options) { let _space = this; _space.util.readTextFile(_space.util.mapServerInfo, function (res) { if (res) { try { if (Array.isArray(res.data)) { for (let map of res.data) { _space.util.allMap = JSON.parse(map.mapData); } } else { _space.util.allMap = JSON.parse(res.data.mapData); console.log("地图数据更新时间: " + res.data.updateTime); } } catch (e) { window.captureException && window.captureException(e); console.log(e); _space.backObj.code = 404; _space.backObj.msg = "地图数据JSON格式错误"; _space.callBackLoadOver(_space.backObj); _space.callBackLoadOver = null; return; } _space.util.readTextFile(_space.util.shopServerInfo, function (res) { _space.util.shopData = []; if (res) { console.log("shopData: ",res.data); res.data.forEach((item) => { for (let shop of item) { _space.util.shopData.push(...shop.shopList); } }); } _space.initOptions(options); }); } else { _space.backObj.code = 404; _space.backObj.msg = "地图数据JSON格式错误"; _space.callBackLoadOver(_space.backObj); _space.callBackLoadOver = null; return; } }); }, initOptions: function (options) { //初始化参数 if (this.util.allMap[this.util.selectBuild].playSpeed) { this.util.allMap[this.util.selectBuild].hasOwnProperty("scale") && (this.util.options.mapScale = parseInt(this.util.allMap[this.util.selectBuild].scale)); this.util.allMap[this.util.selectBuild].hasOwnProperty("playSpeed") && (this.util.options.playSpeed = parseInt( this.util.allMap[this.util.selectBuild].playSpeed)); this.util.allMap[this.util.selectBuild].hasOwnProperty("collision") && (this.util.options.collision = this.util.allMap[this.util.selectBuild].collision); this.util.allMap[this.util.selectBuild].hasOwnProperty("navColor") && (this.util.options.navColor = this.util.allMap[this.util.selectBuild].navColor); this.util.allMap[this.util.selectBuild].hasOwnProperty("aRadius") && (this.util.options.aRadius = parseInt( this.util.allMap[this.util.selectBuild].aRadius)); this.util.allMap[this.util.selectBuild].hasOwnProperty("boxShop") && (this.util.options.boxShop = this.util.allMap[this.util.selectBuild].boxShop.split(",")); this.util.allMap[this.util.selectBuild].hasOwnProperty("shopStyle") && (this.util.options.shopStyle = this.util.allMap[this.util.selectBuild].shopStyle); this.util.allMap[this.util.selectBuild].hasOwnProperty("modelIcon") && (this.util.options.modelIcon = this.util.allMap[this.util.selectBuild].modelIcon); this.util.allMap[this.util.selectBuild].hasOwnProperty("facSize") && (this.util.options.facSize = this.util.allMap[this.util.selectBuild].facSize); this.util.allMap[this.util.selectBuild].hasOwnProperty("m_scale") && (this.util.sceneGap.scale = this.util.allMap[this.util.selectBuild].m_scale); this.hemiLight.color = new THREE.Color(this.util.allMap[this.util.selectBuild].s_col || "#fffff0"); this.hemiLight.groundColor = new THREE.Color(this.util.allMap[this.util.selectBuild].g_col || "#ffffff"); this.hemiLight.intensity = this.util.allMap[this.util.selectBuild].a_int || 0.6; this.shawLight.color = new THREE.Color( this.util.allMap[this.util.selectBuild].d_col || "#ffffff"); this.shawLight.intensity = this.util.allMap[this.util.selectBuild].d_int || 0.3; if (this.util.allMap[this.util.selectBuild].c_site && this.util.allMap[this.util.selectBuild].c_site.split(",")) { this.util.sceneGap.cameraX = parseInt(this.util.allMap[this.util.selectBuild].c_site.split(",")[0]) || this.util.sceneGap.cameraX; this.util.sceneGap.cameraY = parseInt(this.util.allMap[this.util.selectBuild].c_site.split(",")[1]) || this.util.sceneGap.cameraY; this.util.sceneGap.cameraZ = parseInt(this.util.allMap[this.util.selectBuild].c_site.split(",")[2]) || this.util.sceneGap.cameraZ; } if (this.util.allMap[this.util.selectBuild].m_site && this.util.allMap[this.util.selectBuild].m_site.split(",")) { this.util.sceneGap.x = parseInt(this.util.allMap[this.util.selectBuild].m_site.split(",")[0]) || this.util.sceneGap.x; this.util.sceneGap.y = parseInt(this.util.allMap[this.util.selectBuild].m_site.split(",")[1]) || this.util.sceneGap.y; this.util.sceneGap.z = parseInt(this.util.allMap[this.util.selectBuild].m_site.split(",")[2]) || this.util.sceneGap.z; } if (this.util.allMap[this.util.selectBuild].m_zoom) { this.util.m_zoom = this.util.allMap[this.util.selectBuild].m_zoom; } } let { playSpeed, collision, modelIcon, shopStyle, shadow, otherPath, navColor, iconUrl, iconName, inArea, pathColor, pathStyle} = options; this.util.options.playSpeed = playSpeed != undefined ? playSpeed : this.util.options.playSpeed; this.util.options.collision = collision != undefined ? collision : this.util.options.collision; this.util.options.modelIcon = modelIcon != undefined ? modelIcon : this.util.options.modelIcon; this.util.options.shopStyle = shopStyle != undefined ? shopStyle : this.util.options.shopStyle; this.util.options.otherPath = otherPath != undefined ? otherPath : this.util.options.otherPath; this.util.options.navColor = navColor != undefined ? navColor : this.util.options.navColor; this.util.options.iconName = iconName != undefined ? iconName : this.util.options.iconName; this.util.options.inArea = inArea != undefined ? inArea : this.util.options.inArea; this.util.options.pathColor = pathColor != undefined ? pathColor : this.util.options.pathColor; this.util.options.pathStyle = pathStyle != undefined ? pathStyle : this.util.options.pathStyle; this.util.iconUrl = iconUrl != undefined ? iconUrl : []; if (!isNaN(Number(options.floor))) { this.util.startObj.floor = this.util.deviceObj.floor = parseInt(options.floor) || 0; } else { if (Array.isArray(this.util.allMap)) { for (var iii = 0; iii < this.util.allMap[this.util.startObj.build].buildArr.length; iii++) { if (this.util.allMap[this.util.startObj.build].buildArr[iii].name == options.floor) { this.util.startObj.floor = this.util.deviceObj.floor = this.util.allMap[this.util.startObj.build].buildArr[iii].order; break; } } } } // for (let k = 0; k < this.util.allMap.length; k++) { for (let kk = 0; kk < this.util.allMap[k].buildArr.length; kk++) { let floor = this.util.allMap[k].buildArr[kk].mapData; if (floor.models) { for (let t = 0; t < floor.models.length; t++) { for (let i = 0; i < this.util.modelStr.length; i++) { if (floor.models[t].type == this.util.modelStr[i].key) { this.util.modelStr[i].load = true; break; } } } } } } try { this.initOutModel(); } catch (e) { window.captureException && window.captureException(e); this.callBackLoadOver({ code: 404, msg: "地图数据解析失败" }); this.callBackLoadOver = null; } }, //加载全局模型 initOutModel: function () { let _this = this; if (this.util.initModelArr && this.util.initModelArr.length > 0) { for (let i = 0; i < _this.util.initModelArr.length; i++) { let loader = new THREE.GLTFLoader(); loader.load( _this.util.beforPath + _this.util.initModelArr[i].url, function (collada) { collada.scene.scale.x = collada.scene.scale.y =collada.scene.scale.z = _this.util.initModelArr[i].scale; collada.scene.position.set( _this.util.initModelArr[i].site.x, _this.util.initModelArr[i].site.y,_this.util.initModelArr[i].site.z); collada.scene.rotation.set((_this.util.initModelArr[i].rot.x * Math.PI) / 180, (_this.util.initModelArr[i].rot.y * Math.PI) / 180,(_this.util.initModelArr[i].rot.z * Math.PI) / 180); collada.scene.userData.type = _this.util.initModelArr[i].type; for (let k = 0; k < collada.animations.length; k++) { let mixer = new THREE.AnimationMixer(collada.scene); mixer.clipAction(collada.animations[k]).play(); _this.mixers.push(mixer); } ////////////////////////////////////////////// collada.scene.traverse(function (child) { if (child.type === "Mesh") { child.castShadow = false; child.receiveShadow = false; child.userData.opacity = child.material.opacity; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } } }); collada.scene.name = "model"; //删除其它元素时过滤 if (_this.util.initModelArr[i].type == "out") { _this.outModelGap.add(collada.scene); } else if (_this.util.initModelArr[i].type == "periphery") { _this.peripheryGap.add(collada.scene); } } ); if (i == _this.util.initModelArr.length - 1) { for (let u = 0; u < _this.util.tipArr.length; u++) { let prite = document.createElement("div"); prite.style.zIndex = _this.util.tipArr[u].zIndex || 20; prite.innerHTML = _this.util.tipArr[u].htmlUrl; if (!_this.util.tipArr[u].click) { prite.style.pointerEvents = "none"; } let pointLabel2 = new THREE.CSS2DObject(prite); pointLabel2.position.set(_this.util.tipArr[u].x, _this.util.tipArr[u].z, _this.util.tipArr[u].y); pointLabel2.userData.type = "2d_IP"; pointLabel2.userData.show = _this.util.tipArr[u].show; pointLabel2.userData.name = _this.util.tipArr[u].name || ""; if (pointLabel2.userData.show == language) { pointLabel2.element.style.visibility = "visible"; } else { pointLabel2.element.style.visibility = "hidden"; } if (_this.util.tipArr[u].type == "out") { _this.outObject.add(pointLabel2); } else if (_this.util.tipArr[u].type == "periphery") { _this.perObject.add(pointLabel2); } } _this.initBuild(); } } } else { _this.util.changeDist.inner = _this.util.options.maxDis; _this.initBuild(); } }, changePerTag: function (str) { if (mapState == "periphery") { Map_QM.perObject.traverse(function (child) { if (child.userData && child.userData.show) { if (child.userData.show.includes(str)) { child.element.style.visibility = "visible"; } else { child.element.style.visibility = "hidden"; } } }); } }, initBuild: function () { this.util.pathStateObj.elevator = null; this.util.pathStateObj.straight = null; this.util.pathStateObj.elevatorDown = null; let loader2 = new THREE.GLTFLoader(); let _this = this; loader2.load(this.util.beforPath + "static/img/zhong.glb", function (collada2) { collada2.scene.scale.x = collada2.scene.scale.y = collada2.scene.scale.z = 100; collada2.scene.applyMatrix4(_this.sceneGap.matrix); collada2.scene.renderOrder = 200; collada2.scene.traverse(function (child) { if (child.type === "Mesh") { child.castShadow = false; child.receiveShadow = false; child.userData.opacity = child.material.opacity; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } } }); collada2.scene.name = "Z-model"; for (let k = 0; k < collada2.animations.length; k++) { let mixer = new THREE.AnimationMixer(collada2.scene); mixer.clipAction(collada2.animations[k]).play(); Map_QM.mixers.push(mixer); } _this.endModel = collada2.scene; _this.scene.add(collada2.scene); _this.endModel.visible = false; } ); let spriteMap = new THREE.TextureLoader().load( _this.util.beforPath + "static/img/Z.png" ); let spriteMaterial = new THREE.SpriteMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放 map: spriteMap, depthTest: true, transparent: true, alphaTest: 0.5, }); _this.endIcon = new MySprite_QM(spriteMaterial); _this.endIcon.scale.set(100, 120, 1); _this.endIcon.center = new THREE.Vector2(0.5, 0); _this.endIcon.position.set(0, 55, 0); _this.endIcon.applyMatrix4(_this.sceneGap.matrix); _this.endIcon.renderOrder = 300; _this.endIcon.visible = false; _this.endIcon.name = "Z-model"; _this.scene.add(_this.endIcon); if (_this.util.options.modelIcon) { let loader = new THREE.GLTFLoader(); loader.load(_this.util.beforPath + "static/img/elevator.gltf", function (collada) { collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = _this.util.options.facSize || 20; collada.scene.rotation.x = (-90 * Math.PI) / -180; collada.scene.renderOrder = 300; _this.util.pathStateObj.elevator = collada.scene; new THREE.GLTFLoader().load(_this.util.beforPath + "static/img/elevatorDown.gltf", function (collada) { collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = _this.util.options.facSize || 20; collada.scene.rotation.x = (-90 * Math.PI) / -180; collada.scene.renderOrder = 300; _this.util.pathStateObj.elevatorDown = collada.scene; new THREE.GLTFLoader().load(_this.util.beforPath + "static/img/dt.gltf", function (collada) { collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = _this.util.options.facSize || 20; collada.scene.rotation.x = (-90 * Math.PI) / -180; collada.scene.renderOrder = 300; _this.util.pathStateObj.straight = collada.scene; _this.index = 0; _this.initTreeModel(); } ); } ); } ); } else { _this.index = 0; _this.initTreeModel(); } }, loaderOver: function () { this.sceneGap = new THREE.Group(); this.sceneGap.scale.set(this.util.sceneGap.scale, this.util.sceneGap.scale, this.util.sceneGap.scale); this.scene.add(this.sceneGap); this.buildObj = new THREE.Group(); this.sceneGap.add(this.buildObj); this.CSSObject = new THREE.Object3D(); if (this.moveFloorbg) { this.moveFloorbg.userData.type = "moveFloor"; this.CSSObject.add(this.moveFloorbg); } this.CSSObject.add(this.outObject); this.CSSObject.add(this.perObject); this.buildObj.add(this.CSSObject); this.buildObj.add(this.dtLineGroup); this.initGuide(); if (!this.util.options.deviceAng) { this.cameraPerspective.position.set(this.util.sceneGap.cameraX, this.util.sceneGap.cameraY, this.util.sceneGap.cameraZ ); this.cameraPerspective.updateProjectionMatrix(); //必须update this.cameraOrtho.position.set(this.util.sceneGap.cameraX, this.util.sceneGap.cameraY, this.util.sceneGap.cameraZ); this.cameraOrtho.updateProjectionMatrix(); this.controls.target.set(this.util.sceneGap.x, this.util.sceneGap.y, this.util.sceneGap.z); } let pathData = this.util.allMap[parseInt(this.util.deviceObj.build)].buildArr[parseInt(this.util.deviceObj.floor)].mapData.path; pathData && pathData.nodes.sort(this.util.sortNode); if (parseInt(this.util.deviceObj.node) != -1) { if (pathData &&pathData.nodes.length > parseInt(this.util.deviceObj.node)) { this.util.deviceObj.xaxis = pathData.nodes[parseInt(this.util.deviceObj.node)].x; this.util.deviceObj.yaxis = pathData.nodes[parseInt(this.util.deviceObj.node)].y; } } this.util.pathStateObj.facAllArr = []; this.mapArr.length = 0; this.util.pathStateObj.basePath = "{"; for (let bd = 0; bd < this.util.allMap.length; bd++) { for (let i = 0; i < this.util.allMap[bd].buildArr.length; i++) { this.convertPath(bd, i); } } if (this.util.pathStateObj.basePath.length > 1) { this.util.pathStateObj.basePath = this.util.pathStateObj.basePath.substr(0,this.util.pathStateObj.basePath.length - 1); } this.util.pathStateObj.basePath += "}"; let bjP = JSON.parse(this.util.pathStateObj.basePath); if (this.util.options.otherPath) { //如果多楼栋需要配置楼栋之间通行路径 for (let item of this.util.options.otherPath) { bjP[item.f][item.s] = item.d; bjP[item.s][item.f] = item.d; } } //初始化基础路径; let jcStr = JSON.stringify(bjP); let graphPathObj = JSON.parse(jcStr); let ftPathObj = JSON.parse(jcStr); let dtPathObj = JSON.parse(jcStr); let basePathObj = JSON.parse(jcStr); try { for (let j = 0; j < this.util.pathStateObj.facAllArr.length; j++) { for (let k = 0; k < this.util.pathStateObj.facAllArr[j].length; k++) { let facP =this.util.pathStateObj.facAllArr[j][k].buildOrder +"_" + this.util.pathStateObj.facAllArr[j][k].floorOrder +"_" +this.util.pathStateObj.facAllArr[j][k].navCode; for (let h = 0; h < this.util.pathStateObj.facAllArr[j].length; h++) { if (h != k && this.util.pathStateObj.facAllArr[j][k].buildOrder ==this.util.pathStateObj.facAllArr[j][h].buildOrder) { let nP =this.util.pathStateObj.facAllArr[j][h].buildOrder +"_" +this.util.pathStateObj.facAllArr[j][h].floorOrder +"_" + this.util.pathStateObj.facAllArr[j][h].navCode; if (this.util.pathStateObj.facAllArr[j][h].facCode == "dt") { ftPathObj[facP][nP] =200000 +2000 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder)-parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); if (this.util.pathStateObj.seldtFacNo.type == "dt" &&this.util.pathStateObj.facAllArr[j][k].no == this.util.pathStateObj.seldtFacNo.no) { graphPathObj[facP][nP] =2000 +300 *Math.abs(parseInt( this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); } else { graphPathObj[facP][nP] =5000 +600 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); } dtPathObj[facP][nP] = 5000 +800 *Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder)-parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); basePathObj[facP][nP] = 600 +200 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder )); } else if ( this.util.pathStateObj.facAllArr[j][h].facCode == "td" ) { graphPathObj[facP][nP] =4000 +800 * Math.abs( parseInt( this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); ftPathObj[facP][nP] = 4000 +800 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder )); dtPathObj[facP][nP] = 4000 + 800 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); basePathObj[facP][nP] = 800 *Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt( this.util.pathStateObj.facAllArr[j][k].floorOrder )); } else { dtPathObj[facP][nP] =200000 +2000 * Math.abs(parseInt( this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder) ); if (this.util.pathStateObj.seldtFacNo.type == "ft" &&this.util.pathStateObj.seldtFacNo.no.search(this.util.pathStateObj.facAllArr[j][k].no + ",") != -1) { graphPathObj[facP][nP] = 2000 + 300 *Math.abs( parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); } else { graphPathObj[facP][nP] = 5000 +600 * Math.abs( parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder) ); } ftPathObj[facP][nP] = 5000 + 800 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); basePathObj[facP][nP] = 100 + 400 *Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder)-parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder)); } } } } } } catch (e) { window.captureException && window.captureException(e); console.log("交通设施点位问题: " + e); } this.util.pathStateObj.graphPath = graphPathObj; this.util.pathStateObj.ftPath = ftPathObj; this.util.pathStateObj.dtPath = dtPathObj; this.util.pathStateObj.basePath = basePathObj; var fIndex = 0, bIndex = 0; this.mapArr[bIndex] = []; intTimer = setInterval(() => { if (!Map_QM.util.allMap[bIndex].buildArr[fIndex]) { clearInterval(intTimer); this.initFloor(); return; } let floor = new FloorMap_QM(bIndex, fIndex, Map_QM.util.allMap[bIndex].buildArr[fIndex].name ); floor.floorName = Map_QM.util.allMap[bIndex].buildArr[fIndex].name; floor.initDraw(); floor.allObj.position.set(bIndex * Map_QM.util.options.bSpace, 0, 0); if (fIndex != parseInt(Map_QM.util.deviceObj.floor)) { floor.allObj.visible = false; } this.buildObj.add(floor.allObj); this.mapArr[bIndex].push(floor); fIndex++; if (fIndex >= Map_QM.util.allMap[bIndex].buildArr.length) { if (bIndex == Map_QM.util.allMap.length - 1) { clearInterval(intTimer); let pathData = Map_QM.util.allMap[parseInt(Map_QM.util.deviceObj.build)].buildArr[parseInt(Map_QM.util.deviceObj.floor)].mapData.path; if (Map_QM.util.deviceObj.xaxis) { Map_QM.mapArr[parseInt(Map_QM.util.deviceObj.build)][parseInt(Map_QM.util.deviceObj.floor)].setStartSite(Map_QM.util.deviceObj.xaxis,Map_QM.util.deviceObj.yaxis, parseInt(Map_QM.util.shopHeight) + 20); } else { if (parseInt(Map_QM.util.deviceObj.node) != -1) { pathData && pathData.nodes.sort(Map_QM.util.sortNode); if (pathData &&!Map_QM.util.deviceObj.xaxis && pathData.nodes.length > parseInt(Map_QM.util.deviceObj.node) && parseInt(Map_QM.util.deviceObj.node) >= 0) { Map_QM.util.deviceObj.xaxis = pathData.nodes[parseInt(Map_QM.util.deviceObj.node)].x; Map_QM.util.deviceObj.yaxis = pathData.nodes[parseInt(Map_QM.util.deviceObj.node)].y; } else { console.warn("初始化点位失败"); } Map_QM.mapArr[parseInt(Map_QM.util.deviceObj.build)][parseInt(Map_QM.util.deviceObj.floor)].setStartSite(Map_QM.util.deviceObj.xaxis,Map_QM.util.deviceObj.yaxis,parseInt(Map_QM.util.shopHeight) + 20); } } this.initFloor(); } else { bIndex++; fIndex = 0; this.mapArr[bIndex] = []; } } }, 0); }, beforeDestroy: function () { if (this.scene) { this.controls && this.controls.dispose(); this.renderer.renderLists && this.renderer.renderLists.dispose(); this.renderer.dispose && this.renderer.dispose(); this.renderer.forceContextLoss(); let gl = this.renderer.domElement.getContext('webgl'); gl && gl.getExtension('WEBGL_lose_context').loseContext(); this.util.pathStateObj.basePath = null; this.ele.removeEventListener("click", this.onMouseClickBox); //地图点击 this.controls.removeEventListener("change", this.controlsChock); document.removeEventListener("resize", this.changeDocmentResize); //窗口变化 this.remove_child(this.sceneGap); this.scene.remove(this.sceneGap); while (this.ele.firstChild) { this.ele.firstChild.remove(); } this.renderer.domElement = null; this.renderer.content = null; this.renderer = null; this.scene.clear(); this.scene = null; this.camera = null; this.controls = null; this.util.spriteMaterialArr = []; this.util.lineBasicMaterialArr = []; this.util.meshMaterialArr = []; this.util.parkMaterialArr = []; this.util.shopData = []; //店铺数据 this.util.iconUrl = []; this.util.allMap = []; this.util = null; Map_QM = null; } }, /** * @api {方法} changeLanguage() 切换中英文 * @apiGroup 地图交互 * @apiDescription 切换中英文 zh en * @apiVersion 1.0.0 * @apiParam {String} str 显示语言 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.changeLanguage("en"); * */ changeLanguage: function (lang = "zh") { 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 = lang == "en"? obj.element.dataset.nameEn : obj.element.dataset.name; } }); Map_QM.mapArr[t][i].showTagObj.traverse((obj) => { if (obj.element) { obj.element.style.opacity = obj.userData.show != lang ? 0 : 1; } }); } } Map_QM.outObject.traverse((obj) => { if (obj.element && mapState == "out") { obj.element.style.visibility = obj.userData.show == lang ? "visible" : "hidden"; } }); Map_QM.perObject.traverse((obj) => { if (obj.element && mapState == "periphery") { obj.element.style.visibility = obj.userData.show == lang ? "visible" : "hidden"; } }); Map_QM.controlsChock(); }, initTreeModel: function () { if (this.index < this.util.modelStr.length - 1) { if (this.util.modelStr[this.index].load) { this.gltfLoad(this.util.beforPath + this.util.modelStr[this.index].url); } else { this.index++; this.initTreeModel(); } } else { if (this.util.allMap && this.util.allMap.length > 0) { this.loaderOver(); } } }, gltfLoad: function (url) { let sopce = this; new THREE.GLTFLoader().load(url, function (object) { //加载路径fbx文件 object.scene.traverse(function (child) { if (child.type === "Mesh") { child.castShadow = false; child.receiveShadow = false; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } if (sopce.util.modelStr[sopce.index].colorModel === "gama") { child.material.color.convertGammaToLinear(0.6); } } }); object.scene.children[0].scale.set( sopce.util.modelStr[sopce.index].size.x, sopce.util.modelStr[sopce.index].size.y, sopce.util.modelStr[sopce.index].size.z ); sopce.util.fbxModels.push({key: sopce.util.modelStr[sopce.index].key,obj: object, operation: sopce.util.modelStr[sopce.index],}); if (sopce.index < sopce.util.modelStr.length - 1) { sopce.index++; sopce.initTreeModel(); } else { if (sopce.util.allMap && sopce.util.allMap.length > 0) { sopce.loaderOver(); } } }); }, initGuide: function () { let _this = this; new THREE.GLTFLoader().load( this.util.beforPath + "static/img/runman.gltf", function (obj) { obj.scene.scale.x = obj.scene.scale.y =obj.scene.scale.z = _this.util.options.facSize || 20; obj.scene.children[0].children[1].children[0].material.color = new THREE.Color(0xfe9219); _this.sceneGap.add(obj.scene); obj.scene.traverse(function (child) { if (child.type === "SkinnedMesh") { child.material.map && (child.material.map.encoding = THREE.LinearEncoding); //贴图需要转换成 线性编码 } }); obj.scene.visible = false; obj.scene.children[0].rotation.x = Math.PI / 2; obj.scene.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(); _this.mixers.push(mixer); _this.man_3d = obj.scene; _this.guide = _this.man_3d; } ); new THREE.GLTFLoader().load( this.util.beforPath + "static/img/guide.glb", function (obj) { obj.scene.scale.x =obj.scene.scale.y = obj.scene.scale.z = _this.util.options.facSize * 5 || 100; obj.scene.visible = false; obj.scene.children[0].rotation.x = Math.PI / 2; obj.scene.traverse(function (child) { if (child.type === "Mesh") { child.castShadow = _this.util.options.shadow; child.receiveShadow = _this.util.options.shadow; child.userData.opacity = child.material.opacity; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } } }); for (let k = 0; k < obj.animations.length; k++) { let mixer = new THREE.AnimationMixer(obj.scene); mixer.clipAction(obj.animations[k]).play(); _this.mixers.push(mixer); } _this.man_2d = obj.scene; _this.man_2d.renderOrder = 160; _this.sceneGap.add(_this.man_2d); } ); }, initFloor: function () { this.controls.saveState(); this.changeBuild(this.util.deviceObj.build, this.util.deviceObj.floor); //初始化方向为第一人称方向 this.util.options.deviceAng && this.rotationAngle(this.util.deviceObj.angle); this.startRender(); setTimeout(() => { Map_QM.controls.addEventListener("change", Map_QM.controlsChock); //控制器变化 Map_QM.util.fbxModels = []; let boundBox = new THREE.Box3(); boundBox.setFromObject(Map_QM.sceneGap); if (isNaN(boundBox.min.x) || isNaN(boundBox.min.y)) { Map_QM.controls.minPan = new THREE.Vector3(Map_QM.w / -8,0,Map_QM.h / -8); Map_QM.controls.maxPan = new THREE.Vector3(Map_QM.w / 8, 0,Map_QM.h / 8); } else { boundBox.min.x < -400 && (boundBox.min.x = boundBox.min.z); boundBox.max.x > 400 && (boundBox.max.x = boundBox.max.z); boundBox.min.z < -400 && (boundBox.min.z = boundBox.min.x); boundBox.max.z > 400 && (boundBox.max.z = boundBox.max.x); Map_QM.controls.minPan = boundBox.min; Map_QM.controls.maxPan = boundBox.max; } console.log("Number of Triangles :", Map_QM.renderer.info.render.triangles); if (Map_QM.util.initModelArr.length > 0) { Map_QM.toOutModel(); setTimeout(() => { Map_QM.toOutModelInner(); }, 1000); } }, 200); }, calcFov: function (d, w, r) { let f; let vertical = w; if (r < 1) { vertical = vertical / r; } f = Math.atan(vertical / d / 2) * 2 * (180 / Math.PI); return f; }, /** * 解析路径 */ convertPath: function (buildOrder, floorOrder) { let mapDataA = this.util.allMap[buildOrder].buildArr[floorOrder].mapData; let pathData = mapDataA.path; if (!pathData) { return; } if (pathData.nodes.length > 0) { pathData.nodes.sort(this.util.sortNode); for (let i = 0; i < pathData.nodes.length; i++) { let a = pathData.nodes[i].id; this.util.pathStateObj.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; } this.util.pathStateObj.basePath +='"'+buildOrder+"_" +floorOrder +"_" +b +'":'+pathData.nodes[i]["list"][n].cost +","; } if (pathData.nodes[i]["list"].length > 0) { this.util.pathStateObj.basePath = this.util.pathStateObj.basePath.substr(0,this.util.pathStateObj.basePath.length - 1); } this.util.pathStateObj.basePath += "},"; } } let mindt = 10000, minupft = -1, mindownft = -1, seldtNo, seldownftNo, selupftNo; if (buildOrder == this.util.deviceObj.build &&floorOrder == this.util.deviceObj.floor &&parseInt(this.util.deviceObj.node) >= 0) { if (pathData &&!this.util.deviceObj.xaxis &&pathData.nodes.length > parseInt(this.util.deviceObj.node) && parseInt(this.util.deviceObj.node) > 0 ) { this.util.deviceObj.xaxis = pathData.nodes[parseInt(this.util.deviceObj.node)].x; this.util.deviceObj.yaxis = pathData.nodes[parseInt(this.util.deviceObj.node)].y; } //获取本楼层最近的电梯 for (let n = 0; n < mapDataA.stairs.length; n++) { if ( mapDataA.stairs[n].state && mapDataA.stairs[n].no != "" && parseInt(mapDataA.stairs[n].navCode) > 0 ) { let ms = Math.abs( parseInt(mapDataA.stairs[n].x) - parseInt(this.util.deviceObj.xaxis) ) + Math.abs( parseInt(mapDataA.stairs[n].y) - parseInt(this.util.deviceObj.yaxis) ); if ( mindt > ms && (mapDataA.stairs[n].facCode == "ft" || mapDataA.stairs[n].facCode == "upft" || mapDataA.stairs[n].facCode == "downft" || mapDataA.stairs[n].facCode == "dt") ) { mindt = ms; let fac = mapDataA.stairs[n].facCode == "dt" ? "dt" : "ft"; this.util.pathStateObj.seldtFacNo.type = fac; if (mapDataA.stairs[n].facCode == "dt") { seldtNo = mapDataA.stairs[n].no; } } } } if (this.util.pathStateObj.seldtFacNo.type == "dt") { this.util.pathStateObj.seldtFacNo.no = seldtNo; } else { for (let t = 0; t < this.util.allMap[buildOrder].buildArr.length; t++) { let mapData = this.util.allMap[buildOrder].buildArr[t].mapData; minupft = 100000; mindownft = 100000; selupftNo = ""; seldownftNo = ""; for (let h = 0; h < mapData.stairs.length; h++) { if (mapData.stairs[h].state && mapData.stairs[h].no != "" && parseInt(mapData.stairs[h].navCode) > 0) { let ms = Math.abs(parseInt(mapData.stairs[h].x) - parseInt(this.util.deviceObj.xaxis)) + Math.abs(parseInt(mapData.stairs[h].y) - parseInt(this.util.deviceObj.yaxis)); if (mapData.stairs[h].facCode == "upft" || mapData.stairs[h].downState) { //上扶 if (minupft > ms) { minupft = ms; selupftNo = mapData.stairs[h].no; } } else if (mapData.stairs[h].facCode == "downft" || mapData.stairs[h].upState) { if (mindownft > ms) { mindownft = ms; seldownftNo = mapData.stairs[h].no; } } } } //扶梯距离最小 selupftNo != "" && (this.util.pathStateObj.seldtFacNo.no += selupftNo + ","); seldownftNo != "" && (this.util.pathStateObj.seldtFacNo.no += seldownftNo + ","); } } //console.log(this.util.pathStateObj.seldtFacNo); } let noHas; for (let j = 0; j < mapDataA.stairs.length; j++) { if ( parseInt(mapDataA.stairs[j].navCode) > 0 && mapDataA.stairs[j].state) { //排除禁用的设施 noHas = true; for (let k = 0; k < this.util.pathStateObj.facAllArr.length; k++) { //Map_QM.util.pathStateObj.facAllArr 记录遍历结果 if (this.util.pathStateObj.facAllArr[k][0].no != "" && this.util.pathStateObj.facAllArr[k][0].navCode != "" && parseInt(this.util.pathStateObj.facAllArr[k][0].navCode) > 0 && this.util.pathStateObj.facAllArr[k][0].no == mapDataA.stairs[j].no ) { if (this.util.pathStateObj.facAllArr[k][0].facCode == mapDataA.stairs[j].facCode || (this.util.pathStateObj.facAllArr[k][0].facCode.search("ft") != -1 && mapDataA.stairs[j].facCode.search("ft") != -1) ) { noHas = false; mapDataA.stairs[j].floorOrder = floorOrder; mapDataA.stairs[j].buildOrder = buildOrder; this.util.pathStateObj.facAllArr[k].push(mapDataA.stairs[j]); } } } if (noHas) { mapDataA.stairs[j].buildOrder = buildOrder; mapDataA.stairs[j].floorOrder = floorOrder; let array = [mapDataA.stairs[j]]; this.util.pathStateObj.facAllArr.push(array); } } } }, /** * @api {方法} changeMapState("3d") 地图状态切换 * @apiGroup 地图显示 * @apiDescription 地图展示状态切换 * @apiVersion 4.0.0 * @apiParam {string} state 地图状态 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.changeMapState("2d"); * */ changeMapState: function (state) { Map_QM.controls.reset(); if (state === "3d") { Map_QM.camera = Map_QM.cameraPerspective; Map_QM.controls.object = Map_QM.camera; Map_QM.shawLight.castShadow = Map_QM.util.options.shadow; Map_QM.controls.maxPolarAngle = Math.PI / 2 - 0.2; Map_QM.controls.setZoom(1); Map_QM.changeIconState(state); Map_QM.util.options.deviceAng && Map_QM.rotationAngle(Map_QM.util.deviceObj.angle); } else { Map_QM.camera = Map_QM.cameraOrtho; Map_QM.controls.object = Map_QM.camera; Map_QM.shawLight.castShadow = false; Map_QM.controls.setZoom(Map_QM.util.m_zoom); Map_QM.controls.maxPolarAngle = 0; Map_QM.changeIconState(state); } }, changeIconState: function (state, fIndex = -1) { iconState = state; fIndex = fIndex === -1 ? Map_QM.util.selectFloor : fIndex; try{ for (let i = 0; i < Map_QM.mapArr[Map_QM.util.selectBuild].length; i++) { if (i == fIndex && Map_QM.buildObj.visible) { Map_QM.mapArr[Map_QM.util.selectBuild][i].serObj.traverse((obj) => { if (obj.userData && obj.userData.use) { if (obj.userData.use != "all" && obj.userData.use != state) { obj.visible = false; obj.element && (obj.element.style.display = "none"); } else { obj.visible = true; obj.element && (obj.element.style.display = ""); } } }); } } }catch(e){ window.captureException && window.captureException(e); console.log(e); } if (Map_QM.qiModel) { Map_QM.qiModel.visible = state == "3d" ? true : false; } if (Map_QM.devModel) { Map_QM.devModel.visible = state == "2d" && !Map_QM.util.pathStateObj.isPathState ? true : false; } if (Map_QM.qiIcon) { Map_QM.qiIcon.visible = state == "2d" && Map_QM.util.pathStateObj.isPathState ? true : false; } }, /** * @api {方法} changeBuild(buildOrder,floorOrder) 楼栋切换 * @apiGroup 地图交互 * @apiDescription 楼栋切换 传入楼栋编号,楼层编号 * @apiVersion 4.0.0 * @apiParam {int} buildOrder 传入楼栋编号(默认 0) * @apiParam {int} floorOrder 传入楼栋编号(默认 0) * * @apiSampleRequest off * * @apiParamExample {int, int} 请求示例 * * Map_QM.changeBuild(0, 0); * */ changeBuild: function (buildOrder = 0, floorOrder = 0) { Map_QM.changeMapModel("3D"); Map_QM.resetFloorState(); Map_QM.controls.reset(); Map_QM.util.options.deviceAng && Map_QM.rotationAngle(Map_QM.util.deviceObj.angle); Map_QM.clearFloor(Map_QM.util.selectFloor); this.changeBuildInner(buildOrder, floorOrder); }, changeBuildInner: function (build = -1, fIndex = -1) { fIndex = fIndex == -1 ? parseInt(Map_QM.util.deviceObj.floor) : fIndex; build = build == -1 ? parseInt(Map_QM.util.deviceObj.build) : build; Map_QM.util.selectBuild = build; Map_QM.buildObj.position.x = -1 * build * Map_QM.util.options.bSpace; Map_QM.changeFloorInner(build, fIndex); //结束后切换楼层 renderCount = 0; }, resetFloorState: function () { TweenMax.killAll(true); Map_QM.util.pathStateObj.isPathState = false; Map_QM.controls.maxDistance = Map_QM.util.options.maxDis; clearTimeout(Map_QM.util.timeObj.collTime); Map_QM.controls.enabled = true; Map_QM.controls.enableRotate = true; Map_QM.controls.minAzimuthAngle = -Infinity; Map_QM.controls.maxAzimuthAngle = Infinity; Map_QM.util.pathStateObj.forShopArr = { direction: "", wayList: [] }; if (Map_QM.guide && Map_QM.guide.visible) { Map_QM.guide.visible = false; } if (Map_QM.endModel && Map_QM.endModel.visible) { Map_QM.endModel.visible = false; } }, /** * @api {方法} showFloor(floorOrder) 通过楼层编号切换楼层 * @apiGroup 地图交互 * @apiDescription 楼层切换,传入楼层编号,编号从下到上排序,最下面是0 * @apiVersion 4.0.0 * * @apiParam {int} floorOrder 楼层编号 * * @apiSampleRequest off * * @apiParamExample {int} 请求示例 * * Map_QM.showFloor(1); * */ showFloor: function (fIndex = -1, callBack = undefined) { if (!Map_QM.buildObj.visible) { return; } Map_QM.util.isMorePath = false; Map_QM.util.pathStateObj.isPathState = false; Map_QM.changeStartPoint(); isShowElement = true; allJU = true; Map_QM.changeMapModel("3D"); Map_QM.resetFloorState(); Map_QM.controls.reset(); if (Map_QM.util.initModelArr.length > 0) { Map_QM.controls.setDistance(Map_QM.util.changeDist.inner - 25); Map_QM.controls.update(); } Map_QM.util.options.deviceAng && Map_QM.rotationAngle(Map_QM.util.deviceObj.angle); Map_QM.clearFloor(fIndex); Map_QM.elementDestroy("all"); if (fIndex != -1) { Map_QM.changeFloorInner(-1, fIndex, callBack); } }, /** * @api {方法} getAllIcon() 获取所有Icon * @apiGroup 地图数据 * @apiDescription 获取所有Icon * @apiVersion 2.0.0 * @apiParam {int} floorOrder 楼层编号(默认 所有) * * @apiSampleRequest off * */ getAllIcon: function (floorOrder = -1, buildOrder = -1) { let icons = [] if (floorOrder != -1) { let bd = buildOrder == -1 ? Map_QM.util.selectBuild : buildOrder let sers = Map_QM.mapArr[bd][floorOrder].serObj.children //服务图标 for (let n = 0; n < sers.length; n++) { if (sers[n].type == 'Object3D') { let title = sers[n].userData.title || Map_QM.util.getFacName(sers[n].facCode) let titleEn = sers[n].userData.titleEn || title; let type = sers[n].userData.facCode; let imgUrl = sers[n].userData.src; if (sers[n].facCode == 'upft' || sers[n].facCode == 'downft' || sers[n].facCode == 'ft') { if (title == '上扶梯' || title == '下扶梯') { title = '扶梯' } type = 'ft' } let icon = { type: type, floor: floorOrder, imgUrl: imgUrl, 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 == 'Object3D') { let title = sers[n].userData.title || Map_QM.util.getFacName(sers[n].facCode) let titleEn = sers[n].userData.titleEn || title; let type = sers[n].userData.facCode; let imgUrl = sers[n].userData.src; if (sers[n].facCode == 'upft' || sers[n].facCode == 'downft' || sers[n].facCode == 'ft') { title = '扶梯' type = 'ft' } let icon = { type: type, floor: i, imgUrl: imgUrl, title: title, titleEn: titleEn } iconArr.push(icon) } } } iconBuild.push(iconArr) } icons.push(iconBuild) } return icons }, /** * @api {方法} queryAllMapData() 获取地图原始数据 * @apiGroup 地图数据 * @apiDescription 获取地图接口数据 * @apiVersion 4.0.1 * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * Map_QM.queryAllMapData(); */ queryAllMapData: function () { return JSON.stringify({ mallCode: Map_QM.util.mallCode, MapInfo: Map_QM.util.allMap, key: "Aeditor", }); }, /** * @api {方法} changeFloorByName(floorOrder) 通过楼层名称切换楼层 * @apiGroup 地图交互 * @apiDescription 楼层切换,传入楼层名称, * @apiVersion 4.0.0 * * @apiParam {String} floorName 楼层名称 * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * Map_QM.changeFloorByName("L1"); */ changeFloorByName: function (floorName) { let floors = Map_QM.mapArr[Map_QM.util.selectBuild]; for (let i = 0; i < floors.length; i++) { if (floors[i].floorName == floorName) { Map_QM.showFloor(floors[i].floorOrder); return; } } }, /** * @api {方法} changeFloorByCode(floorCode) 通过楼层code切换楼层 * @apiGroup 地图交互 * @apiDescription 楼层切换,传入楼层code, * @apiVersion 4.0.0 * * @apiParam {String} floorCode 楼层code * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * Map_QM.changeFloorByCode("Ek_MaiuKLPjakB1uB0uQV"); */ changeFloorByCode: function (floorCode) { for (let kk = 0; kk < Map_QM.util.allMap.length; kk++) { for (var iii = 0; iii < Map_QM.util.allMap[kk].buildArr.length; iii++) { if (Map_QM.util.allMap[kk].buildArr[iii].code == floorCode) { Map_QM.changeBuild(kk, iii); return; } } } }, changeFloorInner: function (build = -1,fIndex = -1,callBack = undefined) { fIndex = fIndex != -1 ? fIndex : Map_QM.util.deviceObj.floor; build = build != -1 ? build : Map_QM.util.deviceObj.build; 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 == build ? true : false; Map_QM.mapArr[t][i].CSSObj.traverse((obj) => { obj.element && (obj.element.style.display = "none"); }); } } if (Map_QM.mapArr[build] && Map_QM.mapArr[build][fIndex]) { Map_QM.mapArr[build][fIndex].allObj.visible = true; } else { return; } for (let i = 0; i < Map_QM.mapArr[build].length; i++) { if (i == fIndex) { Map_QM.mapArr[build][i].allObj.visible = true; Map_QM.mapArr[build][i].CSSObj.traverse((obj) => { obj.element && obj.userData.isShow && obj.userData.type == "icon" && (obj.element.style.display = ""); }); Map_QM.changeIconState(iconState, fIndex); } else { Map_QM.mapArr[build][i].allObj.visible = false; } if (i == Map_QM.mapArr[build].length - 1) { if (build == Map_QM.util.selectBuild && fIndex == Map_QM.util.selectFloor ) { if (callBack) callBack(); Map_QM.timeOutInit(); } else { Map_QM.util.selectBuild = build; Map_QM.util.selectFloor = fIndex; Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.position.z = 0; Map_QM.timeOutInit(); if (callBack) callBack(); } } } }, /** * @api {方法} onShowMeDir() 我的方向 * @apiGroup 地图显示 * @apiDescription 我的方向 * @apiVersion 4.0.0 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.onShowMeDir(); * */ onShowMeDir: function () { if (Map_QM.util.pathStateObj.isPathState) { Map_QM.changePathDir("2D"); }else{ this.onInnerMeDir(); } }, onInnerMeDir: function () { if (this.util.selectBuild != this.util.deviceObj.build || this.util.selectFloor != this.util.deviceObj.floor) { this.changeFloorInner(this.util.deviceObj.build, this.util.deviceObj.floor); } TweenMax.killAll(true); this.changeMapModel("2D"); Map_QM.controls.reset(); clearTimeout(shopTime); isJUZ = false; Map_QM.controls.minPolarAngle = 0; if (Map_QM.util.deviceObj.xaxis || Map_QM.util.deviceObj.yaxis) { Map_QM.mapToPoint(Map_QM.util.deviceObj.xaxis, Map_QM.util.deviceObj.yaxis, 0 ); } else { Map_QM.mapToPoint(0, 0, 0); } Map_QM.rotationAngle(Map_QM.util.deviceObj.angle); Map_QM.controls.enableRotate = false; Map_QM.controls.setDistance(150); //放大 Map_QM.updateRender(); Map_QM.collLabel(); }, changeMapModel: function (model) { if (model == '2D') { Map_QM.changeIconState("2d"); Map_QM.controls.maxPolarAngle = 0 Map_QM.camera = Map_QM.cameraOrtho Map_QM.controls.object = Map_QM.camera Map_QM.camera.updateProjectionMatrix() Map_QM.shawLight.castShadow = false; } else { Map_QM.changeIconState("3d"); Map_QM.camera = Map_QM.cameraPerspective Map_QM.controls.object = Map_QM.camera Map_QM.controls.maxPolarAngle = Math.PI / 2 - 0.02 Map_QM.camera.updateProjectionMatrix() Map_QM.shawLight.castShadow = Map_QM.util.options.shadow; } Map_QM.updateRender(); }, /** * @api {方法} toOutModel() 显示外立面模型 * @apiGroup 地图显示 * @apiDescription 显示外立面模型 * @apiVersion 4.0.0 * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * Map_QM.toOutModel(); */ toOutModel: function () { TweenMax.killAll(true); Map_QM.controls.setDistance(Map_QM.util.changeDist.inner + 25); Map_QM.controls.update(); Map_QM.disPlayEvent(); renderCount = 0; Map_QM.resetModel(); }, toOutModelInner: function () { TweenMax.killAll(true); Map_QM.emitChangeMap("out"); Map_QM.hideFloor(); Map_QM.buildObj.visible = false; TweenMax.to(Map_QM.peripheryGap.scale, 0.3, { y: 0.01, ease: Quad.easeIn, onComplete: function () { Map_QM.hideObjecrGap(Map_QM.peripheryGap, false); //隐藏外立面 Map_QM.hideObjecrGap(Map_QM.perObject, false); }, }); if (!Map_QM.outModelGap.visible) { Map_QM.hideObjecrGap(Map_QM.outModelGap, true); Map_QM.hideObjecrGap(Map_QM.outObject, true); TweenMax.to(Map_QM.outModelGap.scale, 0.6, { y: 1, ease: Quad.easeIn, onComplete: function () { }, }); } else { mapState = "out"; } Map_QM.rotateAngle(70); startRotate = true; }, hideFloor: function () { Map_QM.changeMapModel("3D"); Map_QM.resetFloorState(); Map_QM.clearFloor(); Map_QM.hideInnerFloorElement(); }, /** * @api {方法} toPeriphery() 显示周边模型 * @apiGroup 地图显示 * @apiDescription 显示周边模型 * @apiVersion 4.0.0 * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * Map_QM.toPeriphery(); */ toPeriphery: function () { TweenMax.killAll(true); Map_QM.controls.setDistance(Map_QM.util.changeDist.outner + 25); Map_QM.controls.update(); Map_QM.disPlayEvent(); renderCount = 0; }, toPeripheryInner: function () { TweenMax.killAll(true); Map_QM.emitChangeMap("periphery"); startRotate = false; Map_QM.outModelGap.rotateY(-1 * Map_QM.outModelGap.rotation.y); Map_QM.hideFloor(); TweenMax.to(Map_QM.outModelGap.scale, 0.3, { y: 0.01, ease: Quad.easeIn, onComplete: function () { Map_QM.buildObj.visible = false; Map_QM.hideObjecrGap(Map_QM.outModelGap, false); //隐藏外立面 Map_QM.hideObjecrGap(Map_QM.outObject, false); }, }); if (!Map_QM.peripheryGap.visible) { Map_QM.hideObjecrGap(Map_QM.peripheryGap, true); TweenMax.to(Map_QM.peripheryGap.scale, 0.6, { y: 1, ease: Quad.easeIn, onComplete: function () { Map_QM.changePerTag("mark"); }, }); } else { mapState = "periphery"; } Map_QM.rotateAngle(45); }, /** * @api {方法} hideInnerFloorElement() 隐藏室内楼层元素 * @apiGroup 地图显示 * @apiDescription 隐藏室内楼层元素 * @apiVersion 4.0.0 * * @apiSampleRequest off * @apiParamExample 请求示例 * * Map_QM.hideInnerFloorElement(); */ hideInnerFloorElement: function () { isShowElement = false; 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].CSSObj.traverse((obj) => { obj.element && (obj.element.style.display = "none"); if (obj.children && obj.children.length > 0) { obj.traverse((item) => { item.element && (item.element.style.display = "none"); }); } }); } } }, /** * @api {方法} toMall() 显示室内模型 * @apiGroup 地图显示 * @apiDescription 显示室内模型 * @apiVersion 4.0.0 * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * Map_QM.toMall(); */ toMall: function () { Map_QM.controls.setDistance(Map_QM.util.changeDist.inner - 25); Map_QM.controls.update(); Map_QM.disPlayEvent(); renderCount = 0; }, toMallInner: function () { isShowElement = true; TweenMax.killAll(true); Map_QM.emitChangeMap("mall"); startRotate = false; Map_QM.outModelGap.rotateY(-1 * Map_QM.outModelGap.rotation.y); if (Map_QM.outModelGap.visible) { TweenMax.to(Map_QM.outModelGap.scale, 0.5, { y: 0.01, ease: Quad.easeIn, onComplete: function () { Map_QM.buildObj.visible = true; Map_QM.hideObjecrGap(Map_QM.outModelGap, false); //隐藏外立面 Map_QM.hideObjecrGap(Map_QM.outObject, false); Map_QM.onShowDeviceSite(); }, }); } else { if (Map_QM.peripheryGap.visible) { TweenMax.to(Map_QM.peripheryGap.scale, 0.5, { y: 0.01, ease: Quad.easeIn, onComplete: function () { Map_QM.hideObjecrGap(Map_QM.peripheryGap, false); //隐藏外立面 Map_QM.hideObjecrGap(Map_QM.perObject, false); Map_QM.buildObj.visible = true; Map_QM.onShowDeviceSite(); }, }); } else { Map_QM.buildObj.visible = true; Map_QM.onShowDeviceSite(); } } }, //设置地图状态为室内状态 setMall: function () { isShowElement = true; TweenMax.killAll(true); Map_QM.emitChangeMap("mall"); startRotate = false; Map_QM.outModelGap.rotateY(-1 * Map_QM.outModelGap.rotation.y); Map_QM.hideObjecrGap(Map_QM.outModelGap, false); //隐藏外立面 Map_QM.hideObjecrGap(Map_QM.outObject, false); Map_QM.hideObjecrGap(Map_QM.peripheryGap, false); //隐藏外立面 Map_QM.hideObjecrGap(Map_QM.perObject, false); Map_QM.buildObj.visible = true; Map_QM.onShowDeviceSite(); renderCount = 0; }, emitChangeMap: function (state) { if (mapState != state) { mapState = state; Map_QM.dispatchEvent({ type: "mapShowChange", data: mapState, }); } }, hideObjecrGap: function (gap, isShow) { gap.visible = isShow; gap.traverse((obj) => { if (obj.userData && obj.userData.type == "2d_IP") { if (obj.element) { if (isShow) { obj.element.style.visibility = obj.userData.show == language ? "visible" : "hidden"; } else { obj.element.style.visibility = "hidden"; } } } }); }, /** * @api {方法} onShowLocalSite(0) 局部显示放大 * @apiGroup 地图显示 * @apiDescription 局部显示放大 point 传入放大目标点,zoom放大级别 1-5 * @apiVersion 4.0.0 * @apiParam {Object} point 放大的地图位置 * @apiParam {int} zoom 放大倍数(默认 1) * * @apiSampleRequest off * * @apiParamExample {Object} 请求示例 * * Map_QM.onShowLocalSite({x:0,y:0},1); * */ onShowLocalSite: function (centerPoint, juZ = true) { Map_QM.controls.setZoom(1) Map_QM.controls.reset(); if (Map_QM.util.initModelArr.length > 0 && Map_QM.util.changeDist.inner > Map_QM.util.options.minDis) { Map_QM.controls.maxDistance = Map_QM.util.changeDist.inner; } Map_QM.mapToPoint(centerPoint.x, centerPoint.y, 0); if (!juZ) { allJU = false; } isJUZ = juZ; Map_QM.updateRender(); Map_QM.collLabel(); }, /** * @api {方法} mapToPoint() 镜头聚焦特定点 * @apiGroup 地图显示 * @apiDescription 镜头聚焦特定点 * @apiVersion 4.0.0 * @apiParam {int} x x坐标 * @apiParam {int} y y坐标 * @apiParam {int} z z坐标 * * @apiSampleRequest off * * @apiParamExample {Object} 请求示例 * * Map_QM.mapToPoint(0,0,1); * */ mapToPoint: function (mapX, mapY, mapZ) { let tag0 = Map_QM.controls.target; let pos0 = Map_QM.controls.object.position; let vct = new THREE.Vector3(mapX, -1 * mapY, mapZ); vct.applyMatrix4(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.matrix); vct.applyMatrix4(Map_QM.sceneGap.matrix); Map_QM.controls.target = new THREE.Vector3(vct.x, vct.y, vct.z); Map_QM.controls.object.position.set(pos0.x + (vct.x - tag0.x), pos0.y + (vct.y - tag0.y), pos0.z + (vct.z - tag0.z)); return vct; }, /** * @api {方法} onShowDeviceSite() 地图方向复位 * @apiGroup 地图显示 * @apiDescription 地图方向复位 * @apiVersion 4.0.0 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.onShowDeviceSite(); * */ onShowDeviceSite: function () { this.showFloor(this.util.deviceObj.floor); }, /** * 在2D 状态下平移镜头 */ moveCameraBy2D: function (obj) { if (pathCameraState == "2D" && Map_QM.camera == Map_QM.cameraOrtho) { Map_QM.controls.minAzimuthAngle = (Map_QM.util.deviceObj.angle * Math.PI) / -180; Map_QM.controls.maxAzimuthAngle = (Map_QM.util.deviceObj.angle * Math.PI) / -180; Map_QM.mapToPoint(obj.x, obj.y, 0); Map_QM.controls.update(); } }, /** * 方向复位 */ resetMeDir: function () { this.changeMapState("3d"); this.controls.minAzimuthAngle = -Infinity; this.controls.maxAzimuthAngle = Infinity; this.controls.reset(); this.util.options.deviceAng && this.rotationAngle(this.util.deviceObj.angle); }, /** * @api {方法} changePathDir(pathState) 切换导航方向 * @apiGroup 地图交互 * @apiDescription 切换导航方向 * @apiVersion 4.0.0 * * @apiParam {String} pathState 地图导航方向(默认 3D) * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.changePathDir("2D"); * */ changePathDir: function (pathState = "3D") { if (Map_QM.util.pathStateObj.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; } Map_QM.reSetGuide(); Map_QM.pathRePlay(); } }, reSetGuide: function () { if (pathCameraState == "2D") { //2D导航 Map_QM.onInnerMeDir(); Map_QM.guide.visible = false; let pos = Map_QM.guide.position; Map_QM.guide = Map_QM.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.controls.enableRotate = true; Map_QM.guide.visible = false; let pos = Map_QM.guide.position; Map_QM.guide = Map_QM.man_3d; Map_QM.guide.position.x = pos.x; Map_QM.guide.position.y = pos.y; Map_QM.guide.visible = true; } }, /** * @api {方法} queryObject3DByShopNum(ipName) 获取3D对象 * @apiGroup 地图交互 * @apiDescription 获取3D对象 * @apiVersion 4.0.0 * @apiParam {string} ipName POI名称 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.queryObject3DByShopNum("L1001"); * */ queryObject3DByShopNum: function (ipName) { for (let b = 0; b < Map_QM.mapArr.length; b++) { for (let i = 0; i < Map_QM.mapArr[b].length; i++) { let shopArr = Map_QM.mapArr[b][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if (shopArr[k].name == ipName) { return shopArr[k]; } } } } return null; }, /** * @api {方法} parseSelectShop() 设置选中店铺弹跳 * @apiGroup 地图交互 * @apiDescription 设置选中店铺弹跳 * @apiVersion 4.0.0 * * @apiParam {object3D} selObject 传入3D对象 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.parseSelectShop(object); * */ parseSelectShop: function (selObject) { if (selObject) { 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 }); } }, }); if (Map_QM.util.options.inArea && Map_QM.camera != Map_QM.cameraOrtho) { Map_QM.onShowLocalSite(new Map_QM.util.Point(Map_QM.selectShop.xaxis, Map_QM.selectShop.yaxis)); } } }, /** * @api {方法} cancelSelectShop() 取消店铺弹跳 * @apiGroup 地图交互 * @apiDescription 取消店铺弹跳效果 * @apiVersion 4.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 4.0.0 * * @apiParam {boolean} isShow 店铺促销标签是否显示(默认 false) * * @apiSampleRequest off * * @apiParamExample {boolean} 请求示例 * * Map_QM.changeStateShopPro(true); * */ changeStateShopPro: function (isShow = false) { if (Map_QM.mapArr[Map_QM.util.selectBuild]) { Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].tagObj.traverse((obj) => { obj.element && (obj.element.style.display = isShow ? "block" : "none"); }); } }, /** * @api {方法} changeShowTagObjState(isShow) 自定义标签 * @apiGroup 地图交互 * @apiDescription 自定义标签展示/隐藏 * @apiVersion 4.0.0 * * @apiParam {boolean} isShow 自定义标签是否显示(默认 false) * * @apiSampleRequest off * * @apiParamExample {boolean} 请求示例 * * Map_QM.changeShowTagObjState(true); * */ changeShowTagObjState: function (isShow = false) { Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].showTagObj.traverse((obj) => { obj.visible = isShow; }); }, /** * @api {方法} queryShopList() 获取店铺列表信息 * @apiGroup 地图数据 * @apiDescription 店铺列表 * @apiVersion 4.0.0 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.queryShopList() * */ queryShopList: function () { return JSON.parse(JSON.stringify(Map_QM.util.shopData)); }, /** * @api {方法} rotationAngle(angle) 改变水平角度 * @apiGroup 地图显示 * @apiDescription 改变地图水平角度 angle>-180 && angle<180 逆时针旋转 * @apiVersion 4.0.0 * * @apiParam {int} angle 旋转角度 * * @apiSampleRequest off * * @apiParamExample {int} 请求示例 * * Map_QM.rotationAngle(90); * */ rotationAngle: function (angle) { Map_QM.controls.setRotateHorizontal(Map_QM.controls.getRotateHorizontal()); Map_QM.controls.setRotateHorizontal((angle / 180) * Math.PI); }, /** * @api {方法} rotateAngle(angle) 改变垂直角度 * @apiGroup 地图显示 * @apiDescription 改变地图垂直角度 angle>-90 && angle<90 * @apiVersion 4.0.0 * * @apiParam {int} angle 旋转角度 * * @apiSampleRequest off * * @apiParamExample {int} 请求示例 * * Map_QM.rotateAngle(-45); * */ rotateAngle: function (angle) { let r0 = Map_QM.controls.getRotate(); Map_QM.controls.rotate(r0); Map_QM.controls.rotate((angle / -180) * Math.PI); }, /** * @api {方法} setCameraDist(cDist) 调整地图大小 * @apiGroup 地图显示 * @apiDescription 调整地图大小(值越小地图越大) Map_QM.util.options.minDis ~ Map_QM.util.options.maxDis * @apiVersion 4.0.0 * * @apiParam {int} cDist 摄像头距离 * * @apiSampleRequest off * * @apiParamExample {int} 请求示例 * * Map_QM.setCameraDist(150); * */ setCameraDist: function (cDist, updateFun, callBack) { cDist = Map_QM.util.options.minDis > parseInt(cDist) ? Map_QM.util.options.minDis : parseInt(cDist); cDist = parseInt(cDist) > Map_QM.util.options.maxDis ? Map_QM.util.options.minDis : parseInt(cDist); let oldObj = { dis: Map_QM.controls.getDistance() }; TweenMax.killAll(true); TweenMax.to(oldObj, 0.5, { dis: cDist, onUpdate: function () { updateFun && updateFun(); //实时更新地图位置 Map_QM.controls.setDistance(oldObj.dis); Map_QM.controlsChock(); }, onComplete:function(){ updateFun && updateFun(); callBack && callBack(); Map_QM.collLabel(); } }); }, /** * @api {方法} startRender() 启动地图渲染 * @apiGroup 地图显示 * @apiDescription 启动地图渲染 与 cancelRender 配合使用可节约资源 * @apiVersion 4.0.0 * * @apiSampleRequest off * @apiParamExample 请求示例 * * Map_QM.startRender(); * */ startRender: function () { Map_QM.cancelRender(); let T = Map_QM.util._clock.getDelta(); Map_QM.controls.update(); Map_QM.renderer.render(Map_QM.scene, Map_QM.camera); Map_QM.labelRenderer.render(Map_QM.scene, Map_QM.camera); if (renderCount < 3) { if (Map_QM.mapArr[Map_QM.util.selectBuild] && Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor]) { Map_QM.labelRenderer.renderObject(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].CSSObj, Map_QM.scene, Map_QM.camera); } renderCount++; } Map_QM.CSSObject && Map_QM.labelRenderer.renderObject(Map_QM.CSSObject, Map_QM.scene, Map_QM.camera); for (let item of Map_QM.mixers) { item.update(T); } if (startRotate) { let y0 = Map_QM.outModelGap.rotation.y; Map_QM.outModelGap.rotateY(0.002); let ay = Map_QM.outModelGap.rotation.y - y0; //>0 + let ang = -1 * Map_QM.outModelGap.rotation.y; if (ay > 0) { if (Map_QM.outModelGap.rotation.y > 0) { ang = Map_QM.outModelGap.rotation.y - Math.PI; } else { ang = Map_QM.outModelGap.rotation.y + Math.PI; } } ang -= Map_QM.controls.getRotateHorizontal() - Math.PI; ang = ang > Math.PI ? ang - 2 * Math.PI : ang; ang = ang < -1 * Math.PI ? ang + 2 * Math.PI : ang; if (Map_QM.util.options.northShow) { Map_QM.util.img.style.transform = "rotate(" + ((Math.PI - ang) * 180) / Math.PI + "deg)"; } } else if (Map_QM.util.options.northShow) { let a = Map_QM.controls.getRotateHorizontal(); if (Map_QM.outModelGap.visible) { Map_QM.util.img.style.transform = "rotate(" +((Math.PI - (Map_QM.outModelGap.rotation.y - a)) * 180) / Math.PI +"deg)"; } else { Map_QM.util.img.style.transform = "rotate(" + (a * 180) / Math.PI + "deg)"; } } renderFrame = requestAnimationFrame(Map_QM.startRender); }, /** * @api {方法} cancelRender() 取消地图渲染 * @apiGroup 地图显示 * @apiDescription 取消地图渲染 与 startRender 配合使用可节约资源 * @apiVersion 4.0.0 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.cancelRender(); * */ cancelRender: function () { window.cancelAnimationFrame(renderFrame); renderFrame = -1; }, /** * @api {方法} addElementLabel() 地图html标签 * @apiGroup 地图交互 * @apiDescription 地图显示Html标签,返回3d标签对象 * @apiVersion 4.0.0 * * @apiParam {Element} divObj div对象 * @apiParam {int} x 显示X坐标 * @apiParam {int} y 显示Y坐标 * @apiParam {int} z 显示高度坐标(默认 50) * @apiParam {String} type docment元素自定义标识(默认 "shopInfo") * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * Map_QM.addElementLabel(divObj,x,y); */ addElementLabel: function (divObj, x, y, z = 50, type = "shopInfo") { divObj.style.opacity = 0; let shopInfo = new THREE.CSS2DObject(divObj); shopInfo.position.set(x, -1 * y, z); shopInfo.applyMatrix4( Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.matrix ); shopInfo.userData.type = type; shopInfo.userData.isShow = false; shopInfo.userData.floor = parseInt(Map_QM.util.selectFloor); Map_QM.CSSObject.add(shopInfo); TweenMax.to(divObj.style, 0.2, { opacity: 1, delay: 0.1 }); return shopInfo; }, /** * @api {方法} updateElementPosition() 修改标签位置 * @apiGroup 地图交互 * @apiDescription 修改标签位置 * @apiVersion 4.0.0 * @apiParam {Object} obj 对象 * @apiParam {int} x 新的X坐标 * @apiParam {int} y 新的Y坐标 * * @apiSampleRequest off * * @apiParamExample {Object} 请求示例 * * Map_QM.updateElementPosition(obj,x,y); * */ updateElementPosition: function (obj, x, y) { if (obj.hasOwnProperty("position")) { let h = obj.position.z; obj.position.set(x, -1 * y, h); obj.applyMatrix4(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.matrix); } }, /** * @api {方法} elementDestroy(type) 销毁地图标签 * @apiGroup 地图交互 * @apiDescription 销毁地图上的html标签 * @apiVersion 4.0.0 * @apiParam {String} type docment元素自定义标识(默认 "shopInfo") * * @apiSampleRequest off * * @apiParamExample {Object} 请求示例 * * Map_QM.elementDestroy(); * */ elementDestroy: function (type = "shopInfo", isRemove = false) { if (!Map_QM.CSSObject) { return; } for (let i = Map_QM.CSSObject.children.length - 1; i >= 0; i--) { if (Map_QM.CSSObject.children[i].userData.type != "moveFloor") { if (type == "all") { Map_QM.CSSObject.children[i].element.style.visibility = "hidden"; } else { if ( Map_QM.CSSObject.children[i].userData && Map_QM.CSSObject.children[i].userData.type == type ) { let node = Map_QM.CSSObject.children[i]; node.element.style.visibility = "hidden"; if (isRemove && node.element.parentNode) { node.element.parentNode.removeChild(node.element); } Map_QM.CSSObject.remove(node); } } } } }, /** * @api {方法} addElementByNode() 显示地图活动标签 * @apiGroup 地图交互 * @apiDescription 地图显示活动标签,返回3d标签对象 * @apiVersion 4.0.0 * * @apiParam {Element} divObj div对象 * @apiParam {int} node 显示导航点位 * @apiParam {String} type docment元素自定义标识(默认 "tip") * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * Map_QM.addElementByNode(divObj,node,type); */ addElementByNode: function (divObj, node, type = "tip") { let pathData = Map_QM.util.allMap[Map_QM.util.selectBuild].buildArr[parseInt(Map_QM.util.selectFloor)].mapData.path; if (!pathData || !divObj) { return; } if (pathData.nodes.length > 0) { pathData.nodes.sort(Map_QM.util.sortNode); } else { return; } divObj.style.visibility = "visible"; divObj.style.opacity = "0"; let shopInfo = new THREE.CSS2DObject(divObj); shopInfo.position.set( pathData.nodes[parseInt(node)].x, -1 * pathData.nodes[parseInt(node)].y, 60 ); shopInfo.applyMatrix4( Map_QM.mapArr[Map_QM.util.selectBuild][parseInt(Map_QM.util.selectFloor)] .allObj.matrix ); shopInfo.userData.type = type; shopInfo.userData.isShow = false; shopInfo.userData.floor = parseInt(Map_QM.util.selectFloor); Map_QM.CSSObject.add(shopInfo); TweenMax.to(divObj.style, 0.2, { opacity: 1, delay: 0.2 }); return shopInfo; }, /** * @api {方法} changeShowShopName() 修改店铺显示名称 * @apiGroup 地图显示 * @apiDescription 通过店铺编号修改店铺显示名称 * @apiVersion 4.0.0 * @apiParam {Array} houseNumber 店铺编号 * @apiParam {Array} nameStr 字符串 * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * Map_QM.changeShowShopName(["L104"],['

肯德基

']) */ changeShowShopName: function (shopNums, elements) { if (shopNums.length === elements.length) { let labObj = Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].labelObj.children; for (let i = 0; i < shopNums.length; i++) { for (let j = 0; j < labObj.length; j++) { if (labObj[j].name == shopNums[i]) { labObj[j].element.innerHTML = elements[i]; break; } } } } }, /** * @api {方法} showAreaAnimate() 区域定位 * @apiGroup 地图显示 * @apiDescription 通过区域名称凸显区域 * @apiVersion 4.0.0 * @apiParam {String} aName 区域名称,不传则复位 * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * Map_QM.showAreaAnimate("A"); */ showAreaAnimate: function (aName = "") { //在我的方向状态,恢复 Map_QM.changeMapModel("3D"); Map_QM.resetFloorState(); Map_QM.controls.reset(); Map_QM.util.options.deviceAng && Map_QM.rotationAngle(Map_QM.util.deviceObj.angle); TweenMax.killAll(true); if (!aName) { isJUZ = false; allJU = true; return; } Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.traverse((obj) => { if (obj.userData && obj.userData.type == "build") { if (obj.name == aName) { Map_QM.onShowLocalSite({ x: obj.userData.xaxis, y: obj.userData.yaxis }, false); } } }); }, /** * @api {方法} unionShop() 店铺合并 * @apiGroup 地图显示 * @apiDescription 通过店铺编号合并店铺 合铺 * @apiVersion 4.0.0 * @apiParam {Array} shops 店铺编号数组 * @apiParam {Object} data 新的店铺数据(默认 空数据) * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * Map_QM.unionShop(["L105","L106","L107","L108"],{name:"新店",houseNumber:"L104-L108",color:"#F4A460"}) */ unionShop: function ( shops, data = { name: "", houseNumber: "shop", color: "#F4A460" } ) { let shopObj = [], xAll = 0, yAll = 0; if (Array.isArray(shops) && shops.length > 1) { //删除店铺box let shopArea = Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].shopObj .children; for (let i = 0; i < shops.length; i++) { for (let k = 0; k < shopArea.length; k++) { if (shopArea[k].name == shops[i]) { xAll += shopArea[k].xaxis; yAll += shopArea[k].yaxis; shopObj.push(shopArea[k]); Map_QM.mapArr[Map_QM.util.selectBuild][ Map_QM.util.selectFloor ].shopObj.remove(shopArea[k]); break; } } } //删除文本标签 let labObj = Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].labelObj.children; for (let i = 0; i < shops.length; i++) { for (let j = 0; j < labObj.length; j++) { if (labObj[j].name == shops[i]) { if (labObj[j].element && labObj[j].element.parentNode) { labObj[j].element.parentNode.removeChild(labObj[j].element); } Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].labelObj.remove(labObj[j]); break; } } } let point = { x: xAll / shopObj.length, y: yAll / shopObj.length, }; let baseShop; for (let l = 0; l < shopObj.length; l++) { if (l == 0) { baseShop = new ThreeBSP(shopObj[0]); } else { baseShop = baseShop.union(new ThreeBSP(shopObj[l])); } } //ThreeBSP对象转化为网格模型对象 let mesh = baseShop.toMesh(); mesh.userData = data; mesh.userData.shopData = { formatColor: data.color }; mesh.userData.xaxis = point.x >> 0; mesh.userData.yaxis = point.y >> 0; mesh.userData.houseNumber = data.houseNumber; mesh.userData.entColor = data.color; mesh.userData.type = "shop"; if (data.name) { mesh.name = data.name; let shopDiv = document.createElement("div"); shopDiv.style.cssText = css_LR; if (window.innerWidth > 2000) { shopDiv.style.fontSize = "18px"; } shopDiv.innerHTML = data.name; shopDiv.dataset.name = data.name; shopDiv.dataset.nameEn = data.nameEn || data.name; let shopLabel = new THREE.CSS2DObject(shopDiv); shopLabel.position.set(point.x >> 0, (-1 * point.y) >> 0, 30); shopLabel.name = data.houseNumber || ""; shopLabel.userData.mapShow = true; //是否永久显示 shopLabel.userData.isShow = true; Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].labelObj.add(shopLabel); } mesh.material = new THREE.MeshPhongMaterial({ color: data.color || 0xf4a460, transparent: true, opacity: 0.9, side: THREE.DoubleSide, depthTest: true, }); Map_QM.mapArr[Map_QM.util.selectBuild][ Map_QM.util.selectFloor ].allObj.add(mesh); } renderCount = 0; }, //////////////////////////////////////////////////////////////////////////////// /** * @param {Object} e * 地图BOX点击 */ onMouseClickBox: function (event) { startRotate = false; 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); }, onCallTouchORMouse: function (mouse) { if ((!Map_QM.mapArr[Map_QM.util.selectBuild] &&!Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor]) || !Map_QM.buildObj.visible) { return; } let raycaster = new THREE.Raycaster(); raycaster.setFromCamera(mouse, Map_QM.camera); let intersects = raycaster.intersectObjects(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.children, true); let clickShop = false, clickOnly = false, onlyData = null; for (let i = 0; i < intersects.length; i++) { //店铺BOX点击 if (intersects[i].object.userData && intersects[i].object.userData.type == "shop") { if (intersects[i].object.name != "") { if (Map_QM.endModel && Map_QM.endModel.visible) { Map_QM.endModel.visible = false; } clickShop = true; Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].findPath.clearPath(); Map_QM.setSelectShopMat(intersects[i].object); break; } else { //空店铺有编号 if (intersects[i].object.userData.houseNumber && intersects[i].object.userData.houseNumber != "shop") { clickOnly = true; onlyData = intersects[i].object.userData; } } } } /** * @api {事件} shop 点击已绑定品牌的店铺 * @apiGroup 地图事件 * @apiDescription 用户点击店铺后触发自定义事件 * @apiVersion 4.0.0 * @apiSampleRequest off * * @apiParamExample 请求示例 * Map_QM.addEventListener("shop",onClickShop,false); */ if (clickShop && Map_QM.selectShop && Map_QM.selectShop.userData) { if (Map_QM.selectShop.userData.shopData.hasOwnProperty("houseNumber")) { Map_QM.dispatchEvent({ type: "shop", data: Map_QM.selectShop.userData, }); } else { /** * @api {事件} onlyShop 点击未绑定品牌的店铺 * @apiGroup 地图事件 * @apiDescription 用户点击空店铺后触发自定义事件 * @apiVersion 4.0.0 * @apiSampleRequest off * * @apiParamExample 请求示例 * Map_QM.addEventListener("onlyShop",onClickShop,false); */ Map_QM.dispatchEvent({ type: "onlyShop", data: Map_QM.selectShop.userData, }); } } else { if (clickOnly) { Map_QM.dispatchEvent({ type: "onlyShop", data: onlyData, }); } else { Map_QM.dispatchEvent({ type: "shop", data: null, }); } } }, /** * @api {方法} setSelectShopMatByName(houseNumber) 设置box 选中 * @apiGroup 地图交互 * @apiDescription 地图box 选中 * @apiVersion 4.0.0 * @apiParam {String} houseNumber POI编号 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.setSelectShopMatByName("L101"); * */ setSelectShopMatByName: function (ipName) { for (let i = 0; i < Map_QM.mapArr[Map_QM.util.selectBuild].length; i++) { let shopArr = Map_QM.mapArr[Map_QM.util.selectBuild][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if (shopArr[k].name == ipName) { Map_QM.setSelectShopMat(shopArr[k]); break; } } } }, //改变选中店铺box setSelectShopMat: function (selObject) { TweenMax.killAll(true); if (Map_QM.selectShop) { Map_QM.selectShop.scale.z = 1; } Map_QM.parseSelectShop(selObject); }, updateRender: function () { Map_QM.controls.update(); Map_QM.renderer.render(Map_QM.scene, Map_QM.camera); Map_QM.labelRenderer.render(Map_QM.scene, Map_QM.camera); Map_QM.labelRenderer.renderObject(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].CSSObj, Map_QM.scene, Map_QM.camera); Map_QM.labelRenderer.zOrder(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].labelObj); }, /** * 初始化后调用 */ timeOutInit: function () { Map_QM.updateRender(); Map_QM.collLabel(); renderCount = 0; if (Map_QM.callBackLoadOver) { let floorData = []; for (let i = 0; i < Map_QM.util.allMap.length; i++) { let build = []; for (let j = 0; j < Map_QM.util.allMap[i].buildArr.length; j++) { if (Map_QM.util.allMap[i].buildArr[j]) { build.push({ order: Map_QM.util.allMap[i].buildArr[j].order, name: Map_QM.util.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, }); }, autoChangeEleAngle: function () { if (Map_QM.mapArr[Map_QM.util.selectBuild]) { for (let m = 0; m < Map_QM.mapArr[Map_QM.util.selectBuild].length; m++) { if (Map_QM.mapArr[Map_QM.util.selectBuild][m].allObj.visible) { let svgChilds = Map_QM.mapArr[Map_QM.util.selectBuild][m].svgObj.children; let rat = Map_QM.controls.getRotateHorizontal(); svgChilds.forEach((item) => { if (Math.abs(item.rotation.x) < 0.5) { if ( rat - item.userData.rot > 1.7 || rat - item.userData.rot < -1.7 ) { 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 logoChilds = Map_QM.mapArr[Map_QM.util.selectBuild][m].shopObj.children; logoChilds.forEach((item) => { if (item.children.length > 0) { item.children.forEach((obj) => { if (obj.userData.type == "logo") { if ( rat - obj.userData.rot > 1.7 || rat - obj.userData.rot < -1.7 ) { obj.rotation.z = obj.userData.rot < 0 ? obj.userData.rot + 3.1415926 : obj.userData.rot - 3.1415926; } else { obj.rotation.z = obj.userData.rot; } } }); } }); } } } }, disPlayEvent: function () { renderCount = 0; let distance = Map_QM.controls.getDistance(); if (distance > Map_QM.util.changeDist.outner + 20 && mapState != "periphery") { Map_QM.toPeripheryInner(); } else if (distance > Map_QM.util.changeDist.inner + 20 && distance < Map_QM.util.changeDist.outner - 20 && mapState != "out") { Map_QM.toOutModelInner(); } else if (distance < Map_QM.util.changeDist.inner - 20 && mapState != "mall") { Map_QM.toMallInner(); } }, /** * 碰撞检测 * @param {Object} 传入检测楼层下标 */ controlsChock: function () { Map_QM.autoChangeEleAngle(); renderCount = 0; /** * @api {事件} MapAngleChange 地图的方向改变 * @apiGroup 地图事件 * @apiDescription 用户操作地图时触发 * @apiVersion 4.0.0 * @apiSampleRequest off * * @apiParamExample 请求示例 * Map_QM.addEventListener("MapAngleChange",onMapAngleChange,false); */ Map_QM.dispatchEvent({ type: "MapAngleChange", data: { hAngle: Map_QM.controls.getRotateHorizontal(), vAngle: Map_QM.controls.getRotate(), }, }); if (Map_QM.util.options.inArea && isJUZ && allJU) { clearTimeout(shopTime); shopTime = setTimeout(() => { clearTimeout(shopTime); isJUZ = false; Map_QM.controls.reset(); Map_QM.util.options.deviceAng && Map_QM.rotationAngle(Map_QM.util.deviceObj.angle); }, 10000); } }, //内部碰撞检测 collLabel: function () { if (!Map_QM || !isShowElement) { return; } if(window.requestIdleCallback){ requestIdleCallback(Map_QM.runTaskQueue, { timeout: 300 }); }else{ clearTimeout(allTime); allTime = setTimeout(() => { clearTimeout(allTime); Map_QM.runTaskQueue(); }, 300); } }, getlocaleToScreen:function(object,vect){ let standardVec; if(vect){ standardVec = object.localToWorld(vect).project(Map_QM.camera); }else{ standardVec = object.localToWorld(new THREE.Vector3()).project(Map_QM.camera); } const screenX = Math.round(Map_QM.w/2 * standardVec.x + Map_QM.w/2); const screenY = Math.round(Map_QM.h/-2 * standardVec.y + Map_QM.h/2); return {x:screenX, y:screenY}; }, runTaskQueue: function (){ if (Map_QM.mapArr[Map_QM.util.selectBuild] && Map_QM.buildObj.visible && Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor]) { if (Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.visible && (!Map_QM.buildObj.userData.hasOwnProperty("visible") || Map_QM.buildObj.userData.visible)) { let childs = Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].labelObj.children; let len = childs.length; for (let i = 0; i < len; i++) { if (!childs[i].userData.isShow) { //是否可见 continue; } if (!Map_QM.util.options.collision) { childs[i].element.style.display = ""; continue; } let obj = childs[i].element; obj.style.display = ""; let labP = obj.getBoundingClientRect(); for (let j = 0; j < i; j++) { if (childs[j].element.style.display == "") { let pb = childs[j].element.getBoundingClientRect(); let isCol = Map_QM.util.isCollision(labP, pb); if (isCol) { if (!childs[i].userData.mapShow) { childs[i].element.style.display = "none"; break; } else if (!childs[j].userData.mapShow) { childs[j].element.style.display = "none"; } } } } } } } }, /** * 寻路---------------------------------------------------------------------------------------------------------------------------------------- */ /** * @api {方法} bounceIcon("xsj") 图标弹跳 * @apiGroup 地图导航 * @apiDescription 地图图标弹跳效果 * @apiVersion 4.0.0 * @apiParam {String} iconType 设施缩写 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.bounceIcon("xsj"); * */ bounceIcon: function (iconType) { TweenMax.killAll(true); let facs = Map_QM.mapArr[Map_QM.util.selectBuild][parseInt(Map_QM.util.selectFloor)] .serObj.children; //交通图标 for (let i = 0; i < facs.length; i++) { if (facs[i].type == "Object3D") { if (facs[i].userData.facCode == iconType) { facs[i].element.style.zIndex = 200; let oldZ = facs[i].userData.site + 5; TweenMax.fromTo( facs[i].position, 0.5, { z: oldZ }, { z: oldZ + 80, repeat: 1, onUpdate: function () { Map_QM.labelRenderer.renderObject( Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].CSSObj, Map_QM.scene, Map_QM.camera); }, onComplete: function () { TweenMax.to(facs[i].position, 0.2, { z: oldZ, onUpdate: function () { Map_QM.labelRenderer.renderObject(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].CSSObj, Map_QM.scene, Map_QM.camera); }, }); }, } ); } else { facs[i].element.style.zIndex = 100; } } } }, /** * @api {方法} countPath() 方向算法 * @apiGroup 地图导航 * @apiDescription 计算设施、店铺的导航方向, toObj,pathType 不能同时为空 * @apiVersion 4.0.0 * @apiParam {Object} toObj {build,floor,node} //终点 设施寻路可以为空 * @apiParam {String} pathType 公共设施名称或编号(点位寻路此参数为空字符串) * @apiParam {String} countType 8--八方向(默认) 12--十二方向 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.countPath({build:0,floor:0,node:0},"xsj","8"); * */ countPath: function (toObj, pathType = "", _countType = "8") { direction = { code: 500, dir: "", cost: 0, gap: 0 }; countType = _countType; Map_QM.util.overObj = null; if (pathType == "") { //传入终点导航点 Map_QM.util.overObj = toObj; if ( Map_QM.util.startObj.node != "" && Map_QM.util.startObj.node != "-1" && Map_QM.util.overObj.node != "" ) { this.forShopArr.length = 0; return this.forDirPath(); } else { direction.code = "404"; return direction; } } else { // let iconPath = this.pathIcon({ type: pathType }); Map_QM.util.overObj = iconPath; if ( Map_QM.util.startObj.node != "" && Map_QM.util.startObj.node != "-1" && Map_QM.util.overObj.node != "" ) { this.forShopArr.length = 0; return this.forDirPath(); } } return (direction = { code: 404, dir: "", cost: 0, gap: 0 }); }, forDirPath: function () { let startNade = Map_QM.util.startObj.build +"_" +Map_QM.util.startObj.floor +"_" +Map_QM.util.startObj.node; let toNade = Map_QM.util.overObj.build +"_" +Map_QM.util.overObj.floor +"_" +Map_QM.util.overObj.node; let PathPoint; direction = { code: 500, dir: "", cost: 0, gap: 0 }; try { let obj = dijkstra.find_path(Map_QM.util.pathStateObj.graphPath,startNade,toNade); PathPoint = obj.nodes; direction.cost = Math.floor((obj.cost / Map_QM.util.options.mapScale) * 0.9); direction.gap = parseInt(obj.cost / Map_QM.util.options.mapScale); } catch (e) { window.captureException && window.captureException(e); console.log(e); direction.code = 404; return direction; } let index = 0; this.forShopArr = []; if (PathPoint.length > 1) { this.forShopArr.push({build: Map_QM.util.startObj.build,floor: Map_QM.util.startObj.floor,PathPoint: [],}); let pathData; for (let j = 0; j < PathPoint.length; j++) { let array = PathPoint[j].split("_"); pathData = Map_QM.util.allMap[parseInt(array[0])].buildArr[parseInt(array[1])].mapData.path; pathData.nodes.sort(Map_QM.util.sortNumber); if (parseInt(array[1]) == this.forShopArr[index].floor) { //同层 this.forShopArr[index].PathPoint.push(pathData.nodes[parseInt(array[2])]); } else { this.forShopArr.push({ build: parseInt(array[0]), floor: parseInt(array[1]), PathPoint: [], }); index++; this.forShopArr[index].PathPoint.push(pathData.nodes[parseInt(array[2])]); } } } else { this.forShopArr.length = 0; } if (this.forShopArr.length > 0) { //--------------------------计算方向 direction.code = 200; if (countType == "12") { //16方向 Map_QM.countSixteenArrow(); } else { Map_QM.countStartAndEndDire(); } } console.log(this.forShopArr); if (this.forShopArr.length > 1) { let facType; if (this.forShopArr[0].floor > this.forShopArr[1].floor) { //下 if ( Math.abs( parseInt(this.forShopArr[0].floor) - parseInt(this.forShopArr[1].floor) ) < 3 ) { //扶梯 facType = Map_QM.util.getFacType("downft"); } else { facType = Map_QM.util.getFacType("dt"); } } else { if ( Math.abs( parseInt(this.forShopArr[0].floor) - parseInt(this.forShopArr[1].floor) ) < 3 ) { //扶梯 facType = Map_QM.util.getFacType("upft"); } else { facType = Map_QM.util.getFacType("dt"); } } facType = facType + ""; if (facType.length === 1) { direction.dir = "600" + facType; } else if (facType.length === 2) { direction.dir = "60" + facType; } else if (facType.length === 3) { direction.dir = "6" + facType; } } return direction; }, /** * 计算十六方向箭头 */ countSixteenArrow: function () { if (this.forShopArr[0].PathPoint.length > 1) { let keyPoints = [], ishas = false, allCount = 0; for (let i = 1; i < this.forShopArr[0].PathPoint.length; i++) { let s = Math.sqrt(Math.pow(this.forShopArr[0].PathPoint[i].x - this.forShopArr[0].PathPoint[i - 1].x,2) + Math.pow(this.forShopArr[0].PathPoint[i].y -this.forShopArr[0].PathPoint[i - 1].y,2)); if (s < 20) { continue; } ishas = false; let dirObj = { angleName: Map_QM.getPathAngle(this.forShopArr[0].PathPoint[i - 1],this.forShopArr[0].PathPoint[i]), count: s, }; allCount += s; if (keyPoints.length > 0 &&keyPoints[keyPoints.length - 1].angleName == dirObj.angleName) { keyPoints[keyPoints.length - 1].count += s; ishas = true; } if (!ishas) { keyPoints.push(dirObj); } } if (allCount < 150) { //总长度< 150 按8方向 Map_QM.countStartAndEndDire(); return; } if (keyPoints.length == 1) { direction.dir = Map_QM.getDirByName(keyPoints[0].angleName); return; } if (keyPoints.length == 0) { //没有路径,按方向计算 direction.code = 404; return; } let upCount = 0, rightFrontCount = 0, rightCount = 0, leftFrontCount = 0; for (let item of keyPoints) { if (item.angleName == "up") { upCount += item.count; } else if (item.angleName == "down") { upCount -= item.count; } else if (item.angleName == "right") { rightCount += item.count; } else if (item.angleName == "left") { rightCount -= item.count; } else if (item.angleName == "rightFront") { rightFrontCount += item.count; } else if (item.angleName == "rightRear") { leftFrontCount -= item.count; } else if (item.angleName == "leftFront") { leftFrontCount += item.count; } else if (item.angleName == "leftRear") { rightFrontCount -= item.count; } } console.log(keyPoints); //斜方向忽略 let dir1 = ""; let bjCount = Math.max(150, allCount / 10); let onlyDir = ""; for (let item of keyPoints) { if ( item.angleName != "rightFront" && item.angleName != "leftFront" && item.angleName != "rightRear" && item.angleName != "leftRear" ) { onlyDir = dir1.length > 0 ? dir1.substring(dir1.length - 1, dir1.length) : dir1; if ( item.angleName == "down" && (item.count > bjCount || upCount < -1 * bjCount) ) { if (onlyDir != "D") { dir1 += "D"; } } else if ( item.angleName == "up" && (item.count > bjCount || upCount > bjCount) ) { if (onlyDir != "T") { dir1 += "T"; } } else if ( item.angleName == "right" && (item.count > bjCount || rightCount > bjCount) ) { if (onlyDir != "R") { dir1 += "R"; } } else if ( item.angleName == "left" && (item.count > bjCount || rightCount < -1 * bjCount) ) { if (onlyDir != "L") { dir1 += "L"; } } } } //console.log(dir1) if (dir1.length > 2) dir1 = dir1.substring(0, 2); //两个以上方向 direction.dir = Map_QM.getDirByName(dir1); if (!direction.dir) Map_QM.countStartAndEndDire(); } else { //没有路径,按方向计算 direction.code = 404; } }, getDirByName: function (dir) { switch (dir) { default: return ""; case "T": return "1201"; case "R": return "1202"; case "D": return "1203"; case "L": return "1204"; case "TL": return "1205"; case "TR": return "1206"; case "RT": return "1207"; case "RD": return "1208"; case "DL": return "1209"; case "DR": return "1210"; case "LT": return "1211"; case "LD": return "1212"; case "up": return "1201"; case "rightFront": return "8002"; case "right": return "1202"; case "rightRear": return "8004"; case "down": return "1203"; case "leftRear": return "8006"; case "left": return "1204"; case "leftFront": return "8008"; } }, /** * 计算八方向坐标 */ countStartAndEndDire: function () { let sPoint = new Map_QM.util.Point( this.forShopArr[0].PathPoint[0].x, this.forShopArr[0].PathPoint[0].y ); //本层起始点坐标 let ePoint = new Map_QM.util.Point( this.forShopArr[0].PathPoint[this.forShopArr[0].PathPoint.length - 1].x, this.forShopArr[0].PathPoint[this.forShopArr[0].PathPoint.length - 1].y ); //本层结束点坐标 switch (Map_QM.getPathAngle(sPoint, ePoint)) { default: direction.dir = "8001"; case "up": direction.dir = "8001"; break; case "rightFront": direction.dir = "8002"; break; case "right": direction.dir = "8003"; break; case "rightRear": direction.dir = "8004"; break; case "down": direction.dir = "8005"; break; case "leftRear": direction.dir = "8006"; break; case "left": direction.dir = "8007"; break; case "leftFront": direction.dir = "8008"; break; } }, getPathAngle: function (sPoint, ePoint) { let x = Math.abs(sPoint.x - ePoint.x); let y = Math.abs(sPoint.y - ePoint.y); let tan = x / y; let radina = Math.atan(tan); //用反三角函数求弧度 let angle = Math.floor(180 / (Math.PI / radina)) || 0; //将弧度转换成角度 if (ePoint.x > sPoint.x && ePoint.y > sPoint.y) { // 右下方 angle = 180 - angle; } if (ePoint.x == sPoint.x && ePoint.y > sPoint.y) { // 正下方 angle = 180; } if (ePoint.x < sPoint.x && ePoint.y > sPoint.y) { //左下方 angle = angle - 180; } if (ePoint.x < sPoint.x && ePoint.y == sPoint.y) { //左方 angle = -90; } if (ePoint.x < sPoint.x && ePoint.y < sPoint.y) { // 左上方 angle = -1 * angle; } if (ePoint.x == sPoint.x && ePoint.y < sPoint.y) { //上方 angle = 0; } if (ePoint.x > sPoint.x && ePoint.y < sPoint.y) { //右上方 angle = angle; } if (ePoint.x > sPoint.x && ePoint.y == sPoint.y) { //point在x轴正方向上 angle = 90; } angle -= Map_QM.util.deviceObj.angle; angle = angle > 180 ? angle - 360 : angle; angle = angle < -180 ? angle + 360 : angle; if (angle > -22 && angle <= 22) { //前 return "up"; } else if (angle > 22 && angle <= 67) { //右前 return "rightFront"; } else if (angle > 67 && angle <= 112) { //右 return "right"; } else if (angle > 112 && angle <= 158) { //右后 return "rightRear"; } else if (angle > 158 || angle <= -158) { //后 return "down"; } else if (angle > -158 && angle <= -112) { //左后 return "leftRear"; } else if (angle > -112 && angle <= -67) { //左 return "left"; } else { //左前 return "leftFront"; } }, /** * @api {方法} pathIcon({type:"xsj"}) 获取最近设施 * @apiGroup 地图导航 * @apiDescription 获取离当前楼层最近的设施 * @apiVersion 4.0.0 * @apiParam {JSON} type 设施缩写 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.pathIcon({type:"xsj"}); * * @apiSuccessExample 返回示例 * { * "floor": 楼层编号, "node": 设施导航点,"typeCode":设施编号 * } * */ pathIcon: function (iconType) { let selIcon; // let minS = -1; if ( !Map_QM.util.startObj.build && parseInt(Map_QM.util.startObj.build) != 0 ) { Map_QM.util.startObj.build = parseInt(Map_QM.util.deviceObj.build); } try { let startNade = Map_QM.util.startObj.build +"_" +Map_QM.util.startObj.floor +"_" +Map_QM.util.startObj.node; const costAll = dijkstra.single_source_shortest_paths( Map_QM.util.pathStateObj.basePath,startNade,startNade).costs; if (costAll) { for (let i = 0;i < Map_QM.mapArr[parseInt(Map_QM.util.deviceObj.build)].length;i++) { let sers =Map_QM.mapArr[parseInt(Map_QM.util.deviceObj.build)][i].serObj.children; //服务图标 for (let n = 0; n < sers.length; n++) { if (sers[n].userData.facCode == iconType.type ||((iconType.type == "xsjn" || iconType.type == "xsjv") && sers[n].userData.facCode == "xsj")) { let toNade =sers[n].userData.buildOrder +"_" +sers[n].userData.floorOrder +"_" +sers[n].userData.navCode; if (!selIcon) { minS = costAll[toNade]; if (minS) { selIcon = sers[n]; } } else { let s1 = costAll[toNade]; if (s1 && s1 < minS) { minS = s1; selIcon = sers[n]; } } } } } if (selIcon) { return { build: parseInt(Map_QM.util.deviceObj.build), floor: selIcon.userData.floorOrder, site: { x: selIcon.position.x, y: selIcon.position.y }, node: selIcon.userData.navCode, no: selIcon.userData.no, typeCode: Map_QM.util.getFacType(iconType.type), }; } else { // 当前楼栋没有 for (let b = 0; b < Map_QM.mapArr.length; b++) { if (b != parseInt(Map_QM.util.deviceObj.build)) { for (let i = 0; i < Map_QM.mapArr[b].length; i++) { let sers = Map_QM.mapArr[b][i].serObj.children; //服务图标 for (let n = 0; n < sers.length; n++) { if (sers[n].userData.facCode == iconType.type) { let toNade =b +"_" +sers[n].userData.floorOrder +"_" +sers[n].userData.navCode; if (!selIcon) { minS = costAll[toNade]; if (minS) { selIcon = sers[n]; selIcon.build = b; } } else { let s1 = costAll[toNade]; if (s1 && s1 < minS) { minS = s1; selIcon = sers[n]; selIcon.build = b; } } } } } } } if (selIcon) { return { build: selIcon.userData.buildOrder, floor: selIcon.userData.floorOrder, node: selIcon.userData.navCode, site: { x: selIcon.position.x, y: selIcon.position.y }, no: selIcon.userData.no, typeCode: Map_QM.util.getFacType(iconType.type), }; } } } } catch (e) { window.captureException && window.captureException(e); console.log(e); } }, /** * @api {方法} pathByStartAndOver(startObj,toObj,callBackFun) 地图路径规划 * @apiGroup 地图导航 * @apiDescription 根据传入的起、终点;直接导航 * @apiVersion 4.0.0 * @apiParam {String} startObj.houseNumber 店铺编号/车位编号 * @apiParam {String} startObj.type "shop"/"park" * * @apiParam {String} toObj.houseNumber 店铺编号/车位编号 * @apiParam {String} toObj.type "shop"/"park" * * @apiParam {Function} callBackFun 回调函数 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.pathByStartAndOver({"houseNumber":"L102","type":"shop"},{"houseNumber":"L204","type":"shop"}); * */ pathByStartAndOver: function (startObj, toObj, callBackFun) { try { Map_QM.util.startObj = this.shopNumToNavPoint(startObj, startObj.type); let overObj = this.shopNumToNavPoint(toObj, toObj.type); this.pathNode(overObj, callBackFun); } catch (e) { window.captureException && window.captureException(e); return "传入点位无法导航"; } }, /** * @api {方法} changeStartPoint() 设置起始点位 * @apiGroup 地图导航 * @apiDescription 设置起始点位 * @apiVersion 4.0.0 * @apiParam {int} build 起点楼栋编号 * @apiParam {int} floor 起点楼层编号 * @apiParam {String} node 起点编号 * @apiParam {int} angle 起点角度 * * @apiSampleRequest off * * @apiParamExample {String} 请求示例 * * Map_QM.changeStartPoint({"build":0, "floor":3, "node":"20", "angle":0}); * */ changeStartPoint: function (toObj) { this.clearFloor(); if (this.mapArr) { for (let i = 0;i < this.mapArr[parseInt(this.util.startObj.build)].length;i++) { for (let len =this.mapArr[parseInt(this.util.startObj.build)][i].allObj.children.length - 1;len >= 0;len--) { let obj =this.mapArr[parseInt(this.util.startObj.build)][i].allObj.children[len]; if (obj.userData.type == "start") { this.mapArr[parseInt(this.util.startObj.build)][i].allObj.remove(obj); } } } } this.util.startObj = {}; if (toObj && toObj.node) { let pathData =this.util.allMap[parseInt(toObj.build)].buildArr[parseInt(toObj.floor)].mapData.path; this.util.startObj.xaxis = pathData.nodes[parseInt(toObj.node)].x; this.util.startObj.yaxis = pathData.nodes[parseInt(toObj.node)].y; this.util.startObj.build = parseInt(toObj.build); this.util.startObj.floor = parseInt(toObj.floor); this.util.startObj.node = toObj.node; this.util.startObj.angle = toObj.angle || 0; } else { this.util.startObj.xaxis = this.util.deviceObj.xaxis; this.util.startObj.yaxis = this.util.deviceObj.yaxis; this.util.startObj.build = parseInt(this.util.deviceObj.build); this.util.startObj.floor = parseInt(this.util.deviceObj.floor); this.util.startObj.node = this.util.deviceObj.node; this.util.startObj.angle = this.util.deviceObj.angle; this.util.startObj.xaxis = this.util.deviceObj.xaxis; this.util.startObj.yaxis = this.util.deviceObj.yaxis; } this.mapArr[parseInt(this.util.startObj.build)][parseInt(this.util.startObj.floor)].setStartSite( this.util.startObj.xaxis, this.util.startObj.yaxis, parseInt(this.util.shopHeight) + 20 ); }, /** * @api {方法} changeMapIPState(ipName,color) 改变POI颜色 * @apiGroup 地图交互 * @apiDescription 改变POI 颜色 * @apiVersion 4.0.0 * @apiParam {string} ipName POI名称 * @apiParam {string} color 颜色字符串 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.changeMapIPState("L1001","#ffff00"); * */ changeMapIPState: function (ipName, color) { // #775544 #AD8164 for (let i = 0; i < this.mapArr[this.util.selectBuild].length; i++) { let shopArr = this.mapArr[this.util.selectBuild][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if (shopArr[k].name == ipName ||(shopArr[k].userData && shopArr[k].userData.houseNumber == ipName)) { shopArr[k].userData.initMaterial = shopArr[k].material; shopArr[k].material = this.util.getMeshMaterial(color || 0xeab16e); break; } } } }, /** * @api {方法} resetMapIPState(ipName) 恢复POI颜色 * @apiGroup 地图交互 * @apiDescription 恢复POI初始颜色 * @apiVersion 4.0.0 * @apiParam {string} ipName POI名称 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.resetMapIPState("L101"); * */ resetMapIPState: function (ipName) { for (let i = 0; i < this.mapArr[this.util.selectBuild].length; i++) { let shopArr = this.mapArr[this.util.selectBuild][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if (shopArr[k].name == ipName) { shopArr[k].material = shopArr[k].userData.initMaterial; break; } } } }, /** * @api {方法} getMapIPData(ipName) 获取POI 基础数据 * @apiGroup 地图交互 * @apiDescription 获取POI 基础数据 * @apiVersion 4.0.0 * @apiParam {string} ipName POI名称 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.getMapIPData("L1001"); * * @apiSuccessExample 返回示例 * { * houseNumber:店铺编号, shopName:店铺名 node:导航点, floor:楼层编号, xaxis:中心点X坐标, yaxis:中心点Y坐标, borderColor:边框色, entColor:填充色 * } */ getMapIPData: function (ipName) { for (let i = 0; i < Map_QM.mapArr[Map_QM.util.selectBuild].length; i++) { let shopArr = Map_QM.mapArr[Map_QM.util.selectBuild][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if (shopArr[k].name == ipName ||(shopArr[k].userData && shopArr[k].userData.houseNumber == ipName)) { return shopArr[k].userData; } } } }, /** * @api {方法} pathNode() 地图模拟导航 * @apiGroup 地图导航 * @apiDescription 地图路径模拟导航 * @apiVersion 4.0.0 * @apiParam {int} floor 楼层编号 * @apiParam {string} node 路径点位编号 * @apiParam {function} callBackFun 回调方法 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.pathNode({build:0, floor:2,node:"53"},callBackFun); * */ pathNode: function (toObj, callBackFun) { Map_QM.util.isMorePath = false; if (!toObj) { return { direction: "", wayList: [] }; } pathCameraState = Map_QM.util.options.pathStyle; Map_QM.reSetGuide(); Map_QM.onShowDeviceSite(); Map_QM.selectShop = null; Map_QM.util.pathStateObj.isPathState = true; Map_QM.elementDestroy("all"); if ( Map_QM.util.initModelArr && Map_QM.util.initModelArr.length > 0 && Map_QM.util.changeDist.inner > Map_QM.util.options.minDis ) { Map_QM.controls.maxDistance = Map_QM.util.changeDist.inner; } if (!Map_QM.util.startObj.xaxis && !Map_QM.util.startObj.yaxis) { Map_QM.changeStartPoint(null); } Map_QM.util.overObj = null; Map_QM.util.overObj = { build: toObj.build || 0, floor: toObj.floor, node: toObj.node, houseNumber: toObj.houseNumber, comeIn: toObj.comeIn || "", }; if (Map_QM.util.overObj.node != "") { Map_QM.cancelRender(); this.onFindPathModel(); if (callBackFun) { Map_QM.parseForShopArr(); const data = JSON.parse( JSON.stringify(Map_QM.util.pathStateObj.forShopArr) ); callBackFun(data); } Map_QM.startRender(); } }, /** * @api {方法} pathShopList() 指定路径导航 * @apiGroup 地图导航 * @apiDescription 根据传入的店铺编号列表绘制导航路径 * @apiVersion 4.0.0 * @apiParam {Array} shopList 路径的店铺编号数组 * @apiParam {Function} callBackFun 回调函数 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.pathShopList(["L1-1","L1-5","L1-8","L1-10","LA-13"],()=>{}); * */ pathShopList: function (shopList, callBackFun) { if (!shopList || shopList.length < 2) { return { direction: "", wayList: [] }; } let pathList = shopList.map(Map_QM.getPathNodeByHousenumber); Map_QM.pathList(pathList, callBackFun); }, /** * 获取导航点 */ getPathNodeByHousenumber: function (houseNumber) { for (let h = 0; h < Map_QM.mapArr.length; h++) { for (let i = 0; i < Map_QM.mapArr[h].length; i++) { let shopArr = Map_QM.mapArr[h][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if ( shopArr[k].name == houseNumber && parseInt(shopArr[k].node) >= 0 ) { return { build: h, floor: i, path: h + "_" + i + "_" + shopArr[k].node, node: shopArr[k].node, }; } } } } }, getPathNodeByNode: function (nodeObj) { let build = nodeObj.buildOrder || 0; let floor = nodeObj.floorOrder || 0; let node = parseInt(nodeObj.node); if (isNaN(node)) { return null; } else { return { build: build, floor: floor, path: build + "_" + floor + "_" + node, node: node, }; } }, /** * @api {方法} pathShopList() 指定路径导航 * @apiGroup 地图导航 * @apiDescription 根据传入的店铺编号列表绘制导航路径 * @apiVersion 4.0.0 * @apiParam {Array} shopList 路径的店铺编号数组 * @apiParam {Function} callBackFun 回调函数 * * @apiSampleRequest off * * @apiParamExample 请求示例 * [{buildOrder:0,floorOrder:0,node:8},{buildOrder:0,floorOrder:0,node:13},{buildOrder:0,floorOrder:0,node:16},{buildOrder:0,floorOrder:0,node:20}],()=>{} */ pathNodeList: function (nodeList, callBackFun, isShowNo = true) { Map_QM.elementDestroy("map_no", true); if (!nodeList || nodeList.length < 2) { return { direction: "", wayList: [] }; } Map_QM.selectShop = null; Map_QM.util.pathStateObj.isPathState = true; let pathList = nodeList.map(Map_QM.getPathNodeByNode); Map_QM.pathList(pathList, callBackFun, isShowNo); }, pathList: function (pathList, callBackFun, isShowNo = false) { Map_QM.util.isMorePath = true; Map_QM.clearFloor(Map_QM.util.selectFloor || -1); pathCameraState = Map_QM.util.options.pathStyle; Map_QM.selectShop = null; Map_QM.util.pathStateObj.isPathState = true; Map_QM.cancelRender(); let startNode, endNode, isFrist = true, PathPoint = []; try { let index = 0, findIndex = 0, pathNodes = []; pathList.forEach((item, inx) => { if (isShowNo) { //显示序号 let pathN =Map_QM.util.allMap[parseInt(item.build)].buildArr[parseInt(item.floor)].mapData.path.nodes; pathN.sort(Map_QM.util.sortNode); let labelDiv = document.createElement("div"); labelDiv.className = "map_no"; labelDiv.innerText = inx + 1; let img = document.createElement("img"); img.src = "../static/img/arrowBlack.svg"; labelDiv.appendChild(img); let shopLabel = new THREE.CSS2DObject(labelDiv); shopLabel.position.set(pathN[parseInt(item.node)].x,-1 * pathN[parseInt(item.node)].y,30); shopLabel.applyMatrix4(Map_QM.mapArr[parseInt(item.build)][parseInt(item.floor)].allObj.matrix); shopLabel.userData.type = "map_no"; shopLabel.userData.index = inx; shopLabel.userData.mapShow = true; shopLabel.userData.isShow = false; //切换楼层默认不显示,且不参与碰撞检测 Map_QM.CSSObject.add(shopLabel); } if (startNode && startNode.path) { endNode = item; if (endNode && endNode.path) { let iNodes = Map_QM.util.allMap[parseInt(endNode.build)].buildArr[parseInt(endNode.floor)].mapData.path.nodes; iNodes.sort(Map_QM.util.sortNode); Map_QM.util.overObj.build = endNode.build; Map_QM.util.overObj.floor = endNode.floor; Map_QM.util.overObj.node = endNode.node; Map_QM.util.overObj.xaxis = iNodes[parseInt(endNode.node)].x; Map_QM.util.overObj.yaxis = iNodes[parseInt(endNode.node)].y; Map_QM.util.overObj.angle = 0; let pathNode = dijkstra.find_path(Map_QM.util.pathStateObj.graphPath,startNode.path,endNode.path).nodes; if (pathNode.length > 1) { let pathData; for (let j = 0; j < pathNode.length; j++) { let array = pathNode[j].split("_"); if (j == 0 && isFrist) { pathNodes.push({build: parseInt(array[0]),floor: parseInt(array[1]),pathNode: []}); } pathData = Map_QM.util.allMap[parseInt(array[0])].buildArr[parseInt(array[1])].mapData.path; pathData.nodes.sort(Map_QM.util.sortNode); if (array[0] == pathNodes[index].build) { if (array[1] == pathNodes[index].floor) { if (!pathNodes[index].pathNode[findIndex]) { pathNodes[index].pathNode[findIndex] = []; } pathNodes[index].pathNode[findIndex].push(pathData.nodes[parseInt(array[2])]); } else { if (j > 0) { pathNodes[index].Facilities = this.getFacilIcon(pathNode[j - 1].split("_"),parseInt(array[0])); } else { pathNodes[index].Facilities = null; } pathNodes.push({build: parseInt(array[0]),floor: parseInt(array[1]),pathNode: [],}); index++; findIndex = 0; if (!pathNodes[index].pathNode[findIndex]) { pathNodes[index].pathNode[findIndex] = []; } pathNodes[index].pathNode[findIndex].push(pathData.nodes[parseInt(array[2])]); } } else { pathNodes.push({ build: parseInt(array[0]),floor: parseInt(array[1]),pathNode: []}); index++; findIndex = 0; if (!pathNodes[index].pathNode[findIndex]) { pathNodes[index].pathNode[findIndex] = []; } pathNodes[index].pathNode[findIndex].push( pathData.nodes[parseInt(array[2])] ); } } } if (isFrist) { isFrist = false; } else { pathNode.shift(); } PathPoint.push(...pathNode); startNode = endNode; findIndex++; } } else { startNode = item; Map_QM.changeStartPoint({ build: startNode.build, floor: startNode.floor, node: startNode.node, angle: 0, }); } }); } catch (e) { window.captureException && window.captureException(e); console.log(e); return; } Map_QM.forShopArr.length = 0; Map_QM.util._indexPathFloor = 0; Map_QM.util.pathStateObj.isPathPlay = true; Map_QM.forShopListPath(PathPoint); //传入所有导航点 if (callBackFun) { Map_QM.parseForShopArr(); const data = JSON.parse( JSON.stringify(Map_QM.util.pathStateObj.forShopArr) ); callBackFun(data); } Map_QM.startRender(); pathNodeList = null; }, forShopListPath: function (PathPoint) { let index = 0; this.forShopArr = []; if (PathPoint.length > 1) { let pathData; for (let j = 0; j < PathPoint.length; j++) { let array = PathPoint[j].split("_"); if (j == 0) { this.forShopArr.push({ build: parseInt(array[0]), floor: parseInt(array[1]), PathPoint: [], }); } pathData = Map_QM.util.allMap[parseInt(array[0])].buildArr[parseInt(array[1])].mapData.path; pathData.nodes.sort(Map_QM.util.sortNode); if (array[0] == this.forShopArr[index].build) { 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("_"),parseInt(array[0])); } else { this.forShopArr[index].Facilities = null; } this.forShopArr.push({build: parseInt(array[0]),floor: parseInt(array[1]),PathPoint: []}); index++; this.forShopArr[index].PathPoint.push(pathData.nodes[parseInt(array[2])]); } } else { this.forShopArr.push({ build: parseInt(array[0]), floor: parseInt(array[1]), PathPoint: []}); index++; this.forShopArr[index].PathPoint.push(pathData.nodes[parseInt(array[2])]); } } if (Map_QM.forShopArr.length > 0) { // "floor" PathPoint Direction (Facilities) 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].build, Map_QM.forShopArr[m].floor, m ); if (Map_QM.util.overObj.build == Map_QM.forShopArr[m].build &&Map_QM.util.overObj.floor == Map_QM.forShopArr[m].floor) { let len = Map_QM.forShopArr[m].wayShop.length; if (Map_QM.forShopArr[m].wayShop[len - 1] && Map_QM.forShopArr[m].wayShop[len - 1].shop.yaxis == Map_QM.util.overObj.node) { Map_QM.forShopArr[m].wayShop.pop(); } } } } else { console.error("无可行路径"); return; } this.onFindPathToObj(); } pathNodeList = null; }, parseForShopArr: function () { Map_QM.util.pathStateObj.forShopArr = { direction: "", wayList: [] }; Map_QM.forShopArr.forEach((item, index) => { if (item.hasOwnProperty("Direction")) { Map_QM.util.pathStateObj.forShopArr.direction = item.Direction; Map_QM.util.pathStateObj.forShopArr.directionEn = item.DirectionEn; } if (item.hasOwnProperty("wayShop") && item.wayShop) { for (let i = 0; i < item.wayShop.length; i++) { let enTlite = item.wayShop[i].shop.shopNameEn == "" ? item.wayShop[i].shop.shopName : item.wayShop[i].shop.shopNameEn; Map_QM.util.pathStateObj.forShopArr.wayList.push({ isAddPrefix: false, shopName: "经过 " + item.wayShop[i].shop.shopName || item.wayShop[i].shop.name, shopNameEn: "PASS " + enTlite, logoPath: item.wayShop[i].shop.logoPath || item.wayShop[i].shop.logoUrl, shopCode: item.wayShop[i].shop.shopCode, houseNumber: item.wayShop[i].shop.houseNumber, }); } } if (item.hasOwnProperty("Facilities") && item.Facilities) { //设施 Map_QM.util.pathStateObj.forShopArr.wayList.push({ isAddPrefix: true, shopName: "乘坐 " + item.Facilities.userData.title +"到 " + Map_QM.mapArr[parseInt(Map_QM.forShopArr[index + 1].build)][parseInt(Map_QM.forShopArr[index + 1].floor)].floorName, shopNameEn:"BY " +item.Facilities.userData.title +"TO " + Map_QM.mapArr[parseInt(Map_QM.forShopArr[index + 1].build)][parseInt(Map_QM.forShopArr[index + 1].floor)].floorName, logoPath: item.Facilities.imgUrl, shopCode: ((Math.random() * 0x1234567) | 0).toString(16).substring(0), houseNumber:item.Facilities.userData.facCode + item.Facilities.userData.no, }); } }); }, /** * @api {方法} getGapByPathNode() 获取实际距离 * @apiGroup 地图导航 * @apiDescription 通过点位获取距离 * @apiVersion 4.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 = Map_QM.util.deviceObj.build +"_" + Map_QM.util.deviceObj.floor + "_" + Map_QM.util.deviceObj.node; let toNade = toObj.build + "_" + toObj.floor + "_" + toObj.node; let path = { cost: -1 }, minTime = 1; try { path = dijkstra.find_path( Map_QM.util.pathStateObj.basePath,startNade,toNade); minTime = parseInt(path.cost / Map_QM.util.options.mapScale / 50) < 0.5? 0.5 : parseInt(path.cost / Map_QM.util.options.mapScale / 50); console.log(`距离目的地 ${parseInt(path.cost / Map_QM.util.options.mapScale)} 米,预计${minTime} 分钟`); // 21 是比例尺 } catch (e) { window.captureException && window.captureException(e); console.log(e); } return { dis: parseInt(path.cost / Map_QM.util.options.mapScale), time: minTime, }; }, /** * @api {方法} pathPark() 获取车位点位 * @apiGroup 地图数据 * @apiDescription 获取车位导航点 * @apiVersion 4.0.0 * @apiParam {String} houseNumber 车位编号 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.pathPark({houseNumber:"B1002"}); * * @apiSuccessExample 返回示例 * { * houseNumber: 车位编号, node: 导航点, floor: 楼层编号, xaxis: 中心点X坐标, yaxis: 中心点Y坐标 * } */ pathPark: function (toObj) { return this.shopNumToNavPoint(toObj, "park"); }, /** * @api {方法} pathShopByName() 获取店铺点位 * @apiGroup 地图数据 * @apiDescription 通过店铺名称获取点位 * @apiVersion 4.0.0 * @apiParam {String} shopName 店铺名称 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.pathShopByName("金拱门"); * * @apiSuccessExample 返回示例 * { * houseNumber: 店铺编号, node: 导航点, floor: 楼层编号, xaxis: 中心点X坐标, yaxis: 中心点Y坐标, comeIn:店铺多门点 * } */ pathShopByName: function (shopName) { for (let item of Map_QM.util.shopData) { if (item.name === shopName) { let toObj = { houseNumber: item.houseNumber, node: item.yaxis }; for (let h = 0; h < Map_QM.util.allMap.length; h++) { let sArr = Map_QM.util.allMap[h].buildArr; for (let i = 0; i < sArr.length; i++) { let shops = Map_QM.util.allMap[h].buildArr[i].mapData.shopArea; for (let k = 0; k < shops.length; k++) { if (shops[k].name == toObj.houseNumber) { toObj.floor = i; toObj.build = h; toObj.node = shops[k].shopNav; toObj.xaxis = shops[k].xaxis; toObj.yaxis = shops[k].yaxis; if (shops[k].comeIn) { toObj.comeIn = shops[k].comeIn; } return toObj; } } } } return toObj; } } }, /** * @api {方法} changeBoxStateByFormat() 切换box显示状态 * @apiGroup 地图交互 * @apiDescription 根据业态切换box显示状态 * @apiVersion 4.0.0 * @apiParam {String} formatCode 业态Id * @apiParam {Boolean} isShow 是否显示 * * @apiSampleRequest off * * @apiParamExample {Object} 请求示例 * * Map_QM.changeBoxStateByFormat("X8f1sfGl0gfa_QwVcMy86",false); * */ changeBoxStateByFormat: function (formatCode, isShow) { for (let h = 0; h < Map_QM.mapArr.length; h++) { for (let i = 0; i < Map_QM.mapArr[h].length; i++) { let shopArr = Map_QM.mapArr[h][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if ( shopArr[k].userData && shopArr[k].userData.formatCode == formatCode ) { shopArr[k].visible = isShow; } } Map_QM.mapArr[h][i].labelObj.traverse((obj) => { if (obj.element && obj.userData.formatCode == formatCode) { obj.element.style.display = isShow ? "" : "none"; obj.userData.isShow = isShow; } }); } } Map_QM.updateRender(); Map_QM.collLabel(); }, /** * @api {方法} changeBoxStateByName() 切换box显示状态 * @apiGroup 地图交互 * @apiDescription 根据名称切换box显示状态 * @apiVersion 4.0.0 * @apiParam {String} houseNumber box名称 * @apiParam {Boolean} isShow 是否显示 * * @apiSampleRequest off * * @apiParamExample {Object} 请求示例 * * Map_QM.changeBoxStateByName("L101", true); * */ changeBoxStateByName: function (houseNumber, isShow) { for (let h = 0; h < Map_QM.mapArr.length; h++) { for (let i = 0; i < Map_QM.mapArr[h].length; i++) { let shopArr = Map_QM.mapArr[h][i].shopObj.children; for (let k = 0; k < shopArr.length; k++) { if (shopArr[k].name == houseNumber) { shopArr[k].visible = isShow; } } Map_QM.mapArr[h][i].labelObj.traverse((obj) => { if (obj.name == houseNumber) { obj.element.style.display = isShow ? "" : "none"; obj.userData.isShow = isShow; } }); } } Map_QM.updateRender(); Map_QM.collLabel(); }, /** * @api {方法} shopNumToNavPoint() 获取导航点位 * @apiGroup 地图导航 * @apiDescription 通过店铺编号或车位获取导航点位 * @apiVersion 4.0.0 * @apiParam {Object} object build,floor,houseNumber 楼栋编号,楼层编号,店铺或车位编号 * @apiParam {String} type 店铺或车位标识 "shop" "park" * * @apiSampleRequest off * * @apiSuccessExample 返回示例 * { * houseNumber: 店铺编号, node: 导航点, floor: 楼层编号, xaxis: 中心点X坐标, yaxis: 中心点Y坐标, comeIn:店铺多门点 * } */ shopNumToNavPoint: function (obj, type) { let shopArr; let reObj = { build: Map_QM.util.selectBuild, node: "", xaxis: "", yaxis: "", floor: "", comeIn: "", }; for (let h = 0; h < Map_QM.util.allMap.length; h++) { let sArr = Map_QM.util.allMap[h].buildArr; for (let i = 0; i < sArr.length; i++) { if (type == "shop") { shopArr = sArr[i].mapData.shopArea; } else if (type == "park") { shopArr = sArr[i].mapData.parkArea; } for (let k = 0; k < shopArr.length; k++) { if (shopArr[k].name == obj.houseNumber) { reObj.floor = i; reObj.build = h; reObj.xaxis = shopArr[k].xaxis; reObj.yaxis = shopArr[k].yaxis; reObj.node = shopArr[k].shopNav; reObj.houseNumber = obj.houseNumber; if (shopArr[k].comeIn) { reObj.comeIn = shopArr[k].comeIn; } return reObj; } } } } }, /** * 模拟导航获取路线 */ onFindPathModel: function (usePath = null) { Map_QM.forShopArr.length = 0; Map_QM.util._indexPathFloor = 0; Map_QM.util.pathStateObj.isPathPlay = true; if (isNaN(parseInt(Map_QM.util.startObj.node)) ||parseInt(Map_QM.util.startObj.node) == -1) { return; } try { if (!Map_QM.util.startObj.xaxis) { let pathData = Map_QM.util.allMap[parseInt(Map_QM.util.startObj.build)].buildArr[parseInt(Map_QM.util.startObj.floor)].mapData.path; Map_QM.util.startObj.xaxis = pathData.nodes[parseInt(Map_QM.util.startObj.node)].x; Map_QM.util.startObj.yaxis = pathData.nodes[parseInt(Map_QM.util.startObj.node)].y; } if (!usePath) { usePath = Map_QM.util.pathStateObj.graphPath; } if (Map_QM.util.overObj.comeIn) { const costall = dijkstra.single_source_shortest_paths( Map_QM.util.pathStateObj.graphPath, startNade,startNade).costs; if (costall) { let inArray = Map_QM.util.overObj.comeIn.split(","); Map_QM.util.overObj.node = Map_QM.getMinCostByArray( Map_QM.util.overObj.floor,inArray, costall); } } let startNade = Map_QM.util.startObj.build + "_" + Map_QM.util.startObj.floor + "_" + Map_QM.util.startObj.node; let toNade = Map_QM.util.overObj.build + "_" + Map_QM.util.overObj.floor + "_" + Map_QM.util.overObj.node; let path = dijkstra.find_path(usePath, startNade, toNade); Map_QM.forShopPath(path.nodes); } catch (e) { window.captureException && window.captureException(e); console.log(e); return; } }, forShopPath: function (PathPoint) { let Dir = "向前出发", index = 0; let DirEn = "to forward"; this.forShopArr = []; if (PathPoint.length > 1) { this.forShopArr.push({ build: Map_QM.util.startObj.build, floor: Map_QM.util.startObj.floor, PathPoint: [], }); let pathData; for (let j = 0; j < PathPoint.length; j++) { let array = PathPoint[j].split("_"); pathData = Map_QM.util.allMap[parseInt(array[0])].buildArr[parseInt(array[1])].mapData.path; if (array[0] == this.forShopArr[index].build) { 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("_"),parseInt(array[0])); } else { this.forShopArr[index].Facilities = null; } this.forShopArr.push({ build: parseInt(array[0]), floor: parseInt(array[1]), PathPoint: [] }); index++; this.forShopArr[index].PathPoint.push(pathData.nodes[parseInt(array[2])]); } } else { this.forShopArr.push({ build: parseInt(array[0]), 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 - Map_QM.util.deviceObj.angle; ang = ang > 180 ? ang - 360 : ang; ang = ang < -180 ? ang + 360 : ang; if (ang < -50 && ang >= -130) { Dir = "向前出发"; DirEn = "to forward"; } else if (ang >= -50 && ang < 50) { Dir = "向右出发"; DirEn = "to right"; } else if (ang >= 50 && ang < 130) { Dir = "向后出发"; DirEn = "to back"; } else { Dir = "向左出发"; DirEn = "to left"; } } let pLen = Map_QM.forShopArr[Map_QM.forShopArr.length - 1].PathPoint.length; Map_QM.util.overObj.xaxis = Map_QM.forShopArr[Map_QM.forShopArr.length - 1].PathPoint[pLen - 1].x; Map_QM.util.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; Map_QM.forShopArr[0].DirectionEn = DirEn; 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].build, Map_QM.forShopArr[m].floor, m ); if (Map_QM.util.overObj.build == Map_QM.forShopArr[m].build && Map_QM.util.overObj.floor == Map_QM.forShopArr[m].floor ) { let len = Map_QM.forShopArr[m].wayShop.length; if (Map_QM.forShopArr[m].wayShop[len - 1] &&Map_QM.forShopArr[m].wayShop[len - 1].shop.yaxis == Map_QM.util.overObj.node) { Map_QM.forShopArr[m].wayShop.pop(); } } } /** * @api {事件} InitPathOver 地图导航状态完成 * @apiGroup 地图事件 * @apiDescription 地图开始导航时触发 * @apiVersion 4.0.0 * @apiSampleRequest off * * @apiParamExample 请求示例 * Map_QM.addEventListener("InitPathOver",onInitPathOver,false); */ Map_QM.dispatchEvent({ type: "InitPathOver", data: Map_QM.forShopArr, }); } else { console.error("无可行路径,请检查起、终点位"); return; } this.onFindPathToObj(); } }, getMinCostByArray: function (floor, array, costall) { if (!Map_QM.util.startObj) { Map_QM.changeStartPoint(); } if (!Map_QM.util.numBuild) { Map_QM.util.numBuild = 0; } let mis = -1, nodeP; for (let i = 0; i < array.length; i++) { let toNade = Map_QM.util.numBuild + "_" + floor + "_" + array[i]; let PathPoint = costall[toNade]; if (mis == -1) { mis = PathPoint; nodeP = array[i]; } else { if (mis > PathPoint) { mis = PathPoint; nodeP = array[i]; } } } return nodeP; }, /** * 途径店铺 */ foreignShop: function (pathArr, build, cFloor, m) { let shopList = []; let shops = Map_QM.mapArr[parseInt(build)][parseInt(cFloor)].shopObj.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, build = -1) { if (build === -1) { build = Map_QM.util.selectBuild; } let childs = this.mapArr[build][fromFArr[1]].serObj.children; let selectEle; for (let i = 0; i < childs.length; i++) { if (childs[i].type == "Object3D" &&childs[i].userData.navCode == fromFArr[2] &&"dt,ft,upft,lt,downft".search(childs[i].userData.facCode) != -1 ) { selectEle = { imgUrl: childs[i].userData.src, userData: childs[i].userData, position: { x: childs[i].position.x, y: childs[i].position.y } }; break; } } return selectEle; }, /** * 寻路动画方法 */ onFindPathToObj: function () { Map_QM.util._indexPathFloor = 0; Map_QM.callBackLoadOver = Map_QM.callBackForPathShop; //楼层初始化完成后回调 if (pathCameraState == "2D") { Map_QM.onInnerMeDir(); Map_QM.controls.enabled = false; Map_QM.guide = Map_QM.man_2d; } Map_QM.changeBuildInner( Map_QM.forShopArr[Map_QM.util._indexPathFloor].build,Map_QM.forShopArr[Map_QM.util._indexPathFloor].floor); }, /** * 播放楼层动画完成后 */ callBackForPathShop: function () { Map_QM.callBackLoadOver = null; if (Map_QM.util.pathStateObj.isPathState) { //如果是寻路状态,继续导航 Map_QM.onFindPath(); } }, /** * 寻路方法 * @param {Object} startN * @param {Object} endN */ onFindPath: function () { console.log(Map_QM.forShopArr); TweenMax.killAll(true); if (Map_QM.util.overObj.floor == Map_QM.util.selectFloor && Map_QM.util.overObj.xaxis) { Map_QM.mapArr[Map_QM.util.overObj.build][Map_QM.util.overObj.floor].setOverSite(Map_QM.util.overObj.xaxis, Map_QM.util.overObj.yaxis,parseInt(Map_QM.util.shopHeight)); } else { Map_QM.endModel && (Map_QM.endModel.visible = false); Map_QM.endIcon && (Map_QM.endIcon.visible = false); } if (Map_QM.forShopArr.length > 0) { const postArr = Map_QM.forShopArr[Map_QM.util._indexPathFloor].PathPoint; const len = postArr.length; let leftX = 50000, rightX=-50000, topY=50000, bottomY = -50000; for(let i=0; i 5) { floorArr.splice(2, floorArr.length - 3); floorArr[1] = "..."; } return floorArr; }, //导航完成事件 onFindPathFloor: function (event) { document.removeEventListener("pathOver", Map_QM.onFindPathFloor); if (Map_QM.forShopArr.length <= Map_QM.util._indexPathFloor) { return; } if (Map_QM.util._indexPathFloor < Map_QM.forShopArr.length - 1) { //楼层切换 if (Map_QM.forShopArr[Map_QM.util._indexPathFloor].Facilities) { let pathFloor = Map_QM.forShopArr[Map_QM.util._indexPathFloor].floor; let x0 =Map_QM.forShopArr[Map_QM.util._indexPathFloor].Facilities.position.x +64; let y0 = Map_QM.forShopArr[Map_QM.util._indexPathFloor].Facilities.position.y; let model = Map_QM.forShopArr[Map_QM.util._indexPathFloor].Facilities.userData.model; /** * @api {事件} PathPlaying 地图导航的实时状态 * @apiGroup 地图事件 * @apiDescription 地图导航过程中实时触发 * @apiVersion 4.0.0 * @apiSampleRequest off * * @apiParamExample 请求示例 * Map_QM.addEventListener("PathPlaying",onPathPlaying,false); */ Map_QM.dispatchEvent({ //寻路中返回小人当前所在点位 type: "PathPlaying", data: { houseNumber:Map_QM.forShopArr[Map_QM.util._indexPathFloor].Facilities.userData.facCode + Map_QM.forShopArr[Map_QM.util._indexPathFloor].Facilities.userData.no, }, }); let box; if (model && model.userData.name == "dt") { model.traverse(function (child) { if (child.isMesh && child.name == "zhitibox") { box = child; } if (child.isMesh && (child.name == "zhitijiegou" || child.name == "zhitiboli")) { child.scale.y = 3; } }); } let zo = 2, tz = 2, boxT = 0, boxZ = 0; let add = window.innerWidth > 2000 ? 80 : 40; let lft = window.innerWidth > 2000 ? 8 : 4; Map_QM.util._indexPathFloor++; let toFloor = parseInt( Map_QM.forShopArr[Map_QM.util._indexPathFloor].floor ); Map_QM.util.selectFloor = toFloor; let floorArr = Map_QM.showNavFloor( pathFloor, toFloor, parseInt(Map_QM.forShopArr[Map_QM.util._indexPathFloor].build) ); //电梯旁显示的楼层名称 if (pathFloor < toFloor) { tz = (floorArr.length - 1) * add; boxT = 12; } else { zo = (floorArr.length - 1) * add; boxZ = 12; } document.getElementById("moveFloor").style.bottom = zo + "px"; document.getElementById("moveFloor").style.width = add + "px"; document.getElementById("moveFloor").style.height = add + "px"; Map_QM.moveFloorbg.element.style.width = add + lft + "px"; Map_QM.moveFloorbg.element.style.height = floorArr.length * add + "px"; Map_QM.moveFloorbg.position.set(x0, y0, (floorArr.length * add) / -1); Map_QM.moveFloorbg.applyMatrix4( Map_QM.mapArr[ parseInt(Map_QM.forShopArr[Map_QM.util._indexPathFloor].build) ][pathFloor].allObj.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 = "display: block;color: #000000; text-align: center;"; span2.style.fontSize = "16px"; if (window.innerWidth > 2000) { span2.style.fontSize = "24px"; } span2.style.width = add + lft + "px"; span2.style.height = add + "px"; span2.style.lineHeight = add + "px"; span2.innerText = floorArr[i]; floorBox.appendChild(span2); } TweenMax.fromTo("#moveFloor",1.5,{ bottom: zo }, { bottom: tz, delay: 0.1, onComplete: function () { Map_QM.moveFloorbg.element.style.display = "none"; Map_QM.callBackLoadOver = Map_QM.callBackForPathShop; //楼层初始化完成后回调 Map_QM.changeFloorInner( Map_QM.forShopArr[Map_QM.util._indexPathFloor].build, Map_QM.forShopArr[Map_QM.util._indexPathFloor].floor ); }, } ); Map_QM.moveFloorbg.element.style.display = "block"; if (box) { TweenMax.fromTo(box.position, 1.2, { y: boxZ }, { y: boxT, delay: 0.2, onComplete: function () { box.position.y = 0; model.traverse(function (child) { if ( child.isMesh && (child.name == "zhitijiegou" || child.name == "zhitiboli") ) { child.scale.y = 1; } }); }, } ); } 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; 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 { //楼栋切换 Map_QM.util._indexPathFloor++; Map_QM.callBackLoadOver = Map_QM.callBackForPathShop; Map_QM.changeBuildInner( Map_QM.forShopArr[Map_QM.util._indexPathFloor].build, Map_QM.forShopArr[Map_QM.util._indexPathFloor].floor ); } } else { Map_QM.util.startObj = Map_QM.util.deviceObj; /** * @api {事件} PathPlayOver 地图导航完成 * @apiGroup 地图事件 * @apiDescription 地图导航到达目标点时触发 * @apiVersion 4.0.0 * @apiSampleRequest off * * @apiParamExample 请求示例 * Map_QM.addEventListener("PathPlayOver",onPathPlayOver,false); */ Map_QM.dispatchEvent({ //寻路完成 type: "PathPlayOver", data: "PathPlayOver", }); } }, /** * 楼层状态清理 */ clearFloor: function (fIndex = -1, reSet = true) { isJUZ = false; if (fIndex == -1) { fIndex = Map_QM.util.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.display = "none"; } if (reSet) { //叠层不处理 if (Map_QM.mapArr[Map_QM.util.selectBuild] && Map_QM.mapArr[Map_QM.util.selectBuild].length > 0) { for (let i = 0; i < Map_QM.mapArr[Map_QM.util.selectBuild].length; i++) { let child = Map_QM.mapArr[Map_QM.util.selectBuild][i].allObj; for (let k = child.children.length - 1; k >= 0; k--) { if (child.children[k].name == "lineDash") { Map_QM.mapArr[Map_QM.util.selectBuild][i].allObj.remove(child.children[k]); } } Map_QM.mapArr[Map_QM.util.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 != "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 4.0.0 * * @apiSampleRequest off * */ pathStop: function (isPlaying) { Map_QM.util.pathStateObj.isPathPlay =isPlaying === undefined? !Map_QM.util.pathStateObj.isPathPlay : isPlaying; Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].findPath.pathPlay.isPlay = Map_QM.util.pathStateObj.isPathPlay; }, /** * @api {方法} pathRePlay() 导航动画重播 * @apiGroup 地图导航 * @apiDescription 导航动画重播 * @apiVersion 4.0.0 * * @apiSampleRequest off * */ pathRePlay: function () { clearTimeout(Map_QM.util.timeObj.pathTime); TweenMax.killAll(true); if (!Map_QM.util.overObj.node) { return; } Map_QM.util.timeObj.pathTime = setTimeout(() => { clearTimeout(Map_QM.util.timeObj.pathTime); Map_QM.controls.reset(); if (Map_QM.util.overObj && Map_QM.forShopArr[0]) { Map_QM.util.pathStateObj.isPathPlay = true; Map_QM.clearFloor(); Map_QM.onFindPathToObj(); } }, 100); }, /** * @api {方法} ChangePathByFt() 切换扶梯模式 * @apiGroup 地图导航 * @apiDescription 导航切换扶梯模式 * @apiVersion 4.0.0 * * @apiParam {function} callBack 回调函数 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.ChangePathByFt(function); * */ ChangePathByFt: function (callBack) { clearTimeout(Map_QM.util.timeObj.pathTime); TweenMax.killAll(true); if (!Map_QM.util.overObj.node || Map_QM.util.isMorePath) { return; } Map_QM.util.timeObj.pathTime = setTimeout(() => { clearTimeout(Map_QM.util.timeObj.pathTime); Map_QM.controls.reset(); if (Map_QM.util.overObj) { Map_QM.clearFloor(); Map_QM.onFindPathModel(Map_QM.util.pathStateObj.ftPath); if (callBack) { Map_QM.parseForShopArr(); const data = JSON.parse(JSON.stringify(Map_QM.util.pathStateObj.forShopArr)); callBack(data); } } }, 100); }, /** * @api {方法} ChangePathByDt() 切换电梯模式 * @apiGroup 地图导航 * @apiDescription 导航切换电梯模式 * @apiVersion 4.0.0 * * @apiParam {function} callBack 回调函数 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.ChangePathByDt(function); * */ ChangePathByDt: function (callBack) { clearTimeout(Map_QM.util.timeObj.pathTime); TweenMax.killAll(true); if (!Map_QM.util.overObj.node || Map_QM.util.isMorePath) { return; } Map_QM.util.timeObj.pathTime = setTimeout(() => { clearTimeout(Map_QM.util.timeObj.pathTime); Map_QM.controls.reset(); if (Map_QM.util.overObj) { Map_QM.clearFloor(); Map_QM.onFindPathModel(Map_QM.util.pathStateObj.dtPath); if (callBack) { Map_QM.parseForShopArr(); const data = JSON.parse(JSON.stringify(Map_QM.util.pathStateObj.forShopArr)); callBack(data); } } }, 100); }, /** * @api {方法} ChangePathByGood() 切换最佳模式 * @apiGroup 地图导航 * @apiDescription 导航切换最佳模式 * @apiVersion 4.0.0 * * @apiParam {function} callBack 回调函数 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.ChangePathByGood(function); * */ ChangePathByGood: function (callBack) { clearTimeout(Map_QM.util.timeObj.pathTime); TweenMax.killAll(true); if (!Map_QM.util.overObj.node || Map_QM.util.isMorePath) { return; } Map_QM.util.timeObj.pathTime = setTimeout(() => { clearTimeout(Map_QM.util.timeObj.pathTime); Map_QM.controls.reset(); if (Map_QM.util.overObj) { Map_QM.clearFloor(); Map_QM.onFindPathModel(Map_QM.util.pathStateObj.graphPath); if (callBack) { Map_QM.parseForShopArr(); const data = JSON.parse(JSON.stringify(Map_QM.util.pathStateObj.forShopArr)); callBack(data); } } }, 100); }, /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// changeDocmentResize: function (e) { let w = parseInt(Map_QM.ele.clientWidth) || parseInt(window.getComputedStyle(Map_QM.ele, null).getPropertyValue("width")); let h = parseInt(Map_QM.ele.clientHeight) || parseInt( window.getComputedStyle(Map_QM.ele, null).getPropertyValue("height")); Map_QM.changeWindowResize(w, h); }, /** * @api {方法} changeWindowResize() 窗口变化 * @apiGroup 地图交互 * @apiDescription 窗口变化 * @apiVersion 4.0.0 * * @apiParam {int} width 窗口宽 * @apiParam {int} height 窗口高 * * @apiSampleRequest off * * @apiParamExample 请求示例 * * Map_QM.changeWindowResize(1280,1080); */ changeWindowResize: function (width, height) { if(!width){ width = parseInt(Map_QM.ele.clientWidth) || parseInt(window.getComputedStyle(Map_QM.ele, null).getPropertyValue("width")); } if(!height){ height = parseInt(Map_QM.ele.clientHeight) || parseInt(window.getComputedStyle(Map_QM.ele, null).getPropertyValue("height")); } Map_QM.aspect = width / height; Map_QM.cameraPerspective.aspect = Map_QM.aspect; Map_QM.cameraPerspective.updateProjectionMatrix(); Map_QM.cameraOrtho.left = -150 * Map_QM.aspect Map_QM.cameraOrtho.right = 150 * Map_QM.aspect Map_QM.cameraOrtho.top = 150; Map_QM.cameraOrtho.bottom = -150; Map_QM.cameraOrtho.updateProjectionMatrix(); Map_QM.renderer.setSize(width, height); Map_QM.labelRenderer.setSize(width, height); Map_QM.updateRender(); Map_QM.collLabel(); Map_QM.w = width; Map_QM.h = height; }, }; /** * @api {方法} init(callBack,options) 地图初始化 * @apiGroup 地图数据 * @apiDescription 初始化地图赋值 Map_QM * @apiVersion 4.0.0 * * @apiParam {function} callBack 初始化成功后的回调函数 * @apiParam {object} options 初始化对象 * @apiParam {int} options.build 设备所在楼栋编号 默认值6 * @apiParam {int} options.floor 设备所在楼层编号 默认值 true * @apiParam {int} options.navPoint 设备导航点 默认值 -1 * @apiParam {int} options.angle 起点设备角度 默认值 0 * @apiParam {string} options.perc_H 弹窗的偏移量 默认值 "-50%"; * @apiParam {string} options.containerId 地图div容器Id 默认值 "mapContainer" * @apiParam {string} options.playSpeed 动画播放速度 默认值8 * @apiParam {boolean} options.collision 是否支持名称的碰撞检测 默认值 true * @apiParam {boolean} options.modelIcon 交通设施是否使用模型 默认值 true * @apiParam {Array} options.otherPath 人为干预的路线 默认值 []; * @apiParam {int} options.fSpace 双叠层状态下楼层的间距 默认值 500 * @apiParam {uint} options.navColor 途径店铺颜色 默认值 0xEE6A50 * @apiParam {boolean} options.shadow 是否显示阴影 默认值 false * @apiParam {boolean} options.iconName 图标名称是否显示 默认值false * @apiParam {uint} options.pathColor 导航路径颜色 默认值 0xb47834, * @apiParam {string} options.pathStyle 导航第一视角 默认值 "2D", * @apiParam {string} options.shopStyle 店铺显示字段编号(houseNumber)名称(shopName) 默认值 "shopName", * @apiParam {boolean} options.inArea 地图点击后是否聚焦到当前位置 默认值 false * @apiParam {string} options.mapData 地图数据 res.data.mapData * @apiParam {string} options.shopData 店铺数据 res.data * @apiParam {Array} options.iconUrl 设施库图标 默认值 [] * * @apiSampleRequest off * @apiParamExample {String} 请求示例 * * MainMap_QM.init(callBackLoadOver,{build : 0, floor : 3, navPoint : 7, angle : 0, perc_H : "-50%",containerId : "mapContainer"}); */ MainMap_QM.init = function (callBack, options) { if (Map_QM) { Map_QM.cancelRender(); Map_QM.beforeDestroy(); } Map_QM = new MainMap_QM(callBack, options); return Map_QM; }; Object.assign(MainMap_QM.prototype, THREE.EventDispatcher.prototype); //////////////////////////////////////-------------------------------FloorMap var 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.CSSObj = new THREE.Group(); this.labelObj = new THREE.Group(); this.labelObj.renderOrder = 100; this.floorOrder = fIndex; this.buildOrder = bIndex; this.floorName = floorName; //存第三方 this.otherObj = new THREE.Object3D(); this.allObj.add(this.otherObj); //存放设施图标 this.serObj = new THREE.Object3D(); //存放车位box this.parkObj = new THREE.Group(); //标签 this.tagObj = new THREE.Group(); this.tagObj.renderOrder = 100; //存放设施图标 this.svgObj = new THREE.Group(); //店铺 this.shopObj = new THREE.Group(); this.allObj.add(this.shopObj); this.allObj.add(this.svgObj); this.allObj.add(this.CSSObj); this.CSSObj.add(this.serObj); this.CSSObj.add(this.labelObj); this.CSSObj.add(this.tagObj); //标签 this.showTagObj = new THREE.Group(); this.showTagObj.renderOrder = 100; this.CSSObj.add(this.showTagObj); //线条 this.lineObj = new THREE.Group(); this.lineObj.renderOrder = 100; this.allObj.add(this.lineObj); this.startIcon; }; FloorMap_QM.prototype = { initDraw: function () { this.initFloor(); this.initFacilitie(); this.initStairs(); this.initTextArea(); this.initWall(); this.initDecos(); this.initPark(); this.initModel(); this.initTree(); //植树 this.initLogos(); //贴图 }, initLogos: function () { let sopce = this; if (Map_QM.util.logos) { Map_QM.util.logos.map((item) => { if (item.build == sopce.buildOrder && item.floor == sopce.floorOrder) { sopce.logoUtil.renderIcon(item, sopce, item.site || 0); } }); } }, initModel: function () { let sopce = this; if (Map_QM.util.modelArr) { for (let i = 0; i < Map_QM.util.modelArr.length; i++) { if (Map_QM.util.modelArr[i].build == this.buildOrder && Map_QM.util.modelArr[i].floor == this.floorOrder) { new THREE.GLTFLoader().load( Map_QM.util.beforPath + Map_QM.util.modelArr[i].url, function (object) { //加载路径fbx文件 let mod = object.scene; mod.traverse(function (child) { if (child.isMesh) { child.receiveShadow = Map_QM.util.options.shadow; child.castShadow = Map_QM.util.options.shadow; child.userData.opacity = child.material.opacity; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } child.material.color.convertGammaToLinear(0.7); } }); for (let t = 0; t < Map_QM.util.modelArr[i].list.length; t++) { let obj = mod.clone(); obj.position.set( Map_QM.util.modelArr[i].list[t].site.x, -1 * Map_QM.util.modelArr[i].list[t].site.y, Map_QM.util.modelArr[i].list[t].site.z ); obj.scale.set( Map_QM.util.modelArr[i].list[t].size.x, Map_QM.util.modelArr[i].list[t].size.y, Map_QM.util.modelArr[i].list[t].size.z ); obj.rotateX((Map_QM.util.modelArr[i].list[t].rot.x * Math.PI) / 180); obj.rotateY((Map_QM.util.modelArr[i].list[t].rot.y * Math.PI) / 180); obj.rotateZ((Map_QM.util.modelArr[i].list[t].rot.z * Math.PI) / 180); sopce.allObj.add(obj); } } ); } } } if (Map_QM.util.labelIconArr) { for (let i = 0; i < Map_QM.util.labelIconArr.length; i++) { if (Map_QM.util.labelIconArr[i].build == this.buildOrder && Map_QM.util.labelIconArr[i].floor == this.floorOrder) { let SpriteDiv = document.createElement("div"); SpriteDiv.className = Map_QM.util.labelIconArr[i].className; SpriteDiv.innerHTML = Map_QM.util.labelIconArr[i].title; SpriteDiv.dataset.id = Map_QM.util.labelIconArr[i].data.id; SpriteDiv.dataset.x = Map_QM.util.labelIconArr[i].site.x; SpriteDiv.dataset.y = Map_QM.util.labelIconArr[i].site.y; SpriteDiv.dataset.z = Map_QM.util.labelIconArr[i].site.z; let pointLabel = new THREE.CSS2DObject(SpriteDiv); pointLabel.position.set( Map_QM.util.labelIconArr[i].site.x, -1 * Map_QM.util.labelIconArr[i].site.y, Map_QM.util.labelIconArr[i].site.z ); pointLabel.name = Map_QM.util.labelIconArr[i].title; pointLabel.userData = Map_QM.util.labelIconArr[i].data; pointLabel.userData.site = Map_QM.util.labelIconArr[i].site; pointLabel.userData.mapShow = true; pointLabel.userData.isShow = true; pointLabel.userData.type = "icon"; if (Map_QM.util.labelIconArr[i].click) { //可点击 SpriteDiv.addEventListener("click", (event) => { Map_QM.dispatchEvent({ type: "labelIcon", data: event.target.dataset, }); }, false ); } else { pointLabel.element.style.pointerEvents = "none"; } pointLabel.userData.floor = Map_QM.util.labelIconArr[i].floor; sopce.showTagObj.add(pointLabel); } } } }, initTree: function () { let mapData = Map_QM.util.allMap[this.buildOrder].buildArr[this.floorOrder].mapData; if (mapData.models) { for (let t = 0; t < mapData.models.length; t++) { for (let i = 0; i < Map_QM.util.fbxModels.length; i++) { if (mapData.models[t].type == Map_QM.util.fbxModels[i].key) { let obj = Map_QM.util.fbxModels[i].obj.scene.clone(); obj.position.set(mapData.models[t].x, -1 * mapData.models[t].y, mapData.models[t].site); obj.scale.set(mapData.models[t].scale,mapData.models[t].scale,mapData.models[t].scale); obj.rotateX(Map_QM.util.fbxModels[i].operation.rot.x); obj.rotateY((-1 * mapData.models[t].angle * Math.PI) / 180); obj.renderOrder = 100; for (let k = 0;k < Map_QM.util.fbxModels[i].obj.animations.length; k++ ) { let mixer = new THREE.AnimationMixer(obj); mixer.clipAction(Map_QM.util.fbxModels[i].obj.animations[k]).play(); Map_QM.mixers.push(mixer); } //加载编辑器动画 obj.name = mapData.models[t].name; if (mapData.animations) { mapData.animations.forEach((item) => { if (mapData.models[t].name == item.name) { obj.rotateY(mapData.models[t].angle * Math.PI / 180); let posArr = [], rotArr = [], scaleArr = [], keyArr = [], proArr = [], clip; item.frames.forEach((it) => { keyArr.push(it.time); posArr.push(it.pos.x, -1 * it.pos.y, it.pos.z); rotArr.push((it.rot / -180) * Math.PI); scaleArr.push(it.size, it.size, it.size); proArr.push(it.pro); }); if (item.isType) { //特殊模型动画 let rotKF = new THREE.KeyframeTrack(item.sonName, keyArr, proArr); clip = new THREE.AnimationClip(item.name, keyArr[keyArr.length - 1], [rotKF]); } else { let posKF = new THREE.KeyframeTrack(item.name + ".position",keyArr,posArr); let rotKF = new THREE.KeyframeTrack(item.name + ".rotation[y]", keyArr,rotArr); let scalKF = new THREE.KeyframeTrack(item.name + ".scale",keyArr,scaleArr); clip = new THREE.AnimationClip(item.name,keyArr[keyArr.length - 1],[posKF, rotKF, scalKF]); } if (clip) { let mixer = new THREE.AnimationMixer(obj); mixer.clipAction(clip).play(); Map_QM.mixers.push(mixer); } } }); } this.allObj.add(obj); } } } } }, //初始化单楼层 initFloor: function () { let floor; let mapData = Map_QM.util.allMap[this.buildOrder].buildArr[this.floorOrder].mapData; let entColor, borderColor; if (mapData.floorArea) { floor = Map_QM.util.changeAreaToString(mapData.floorArea); } let bLen = mapData.buildArea.length; let hLen = mapData.hollowArea.length; let hows_f = []; for (let m = 0; m < hLen; m++) { let isIn = Map_QM.util.checkAreaInArea(mapData.hollowArea[m],mapData.floorArea); if (isIn) { hows_f.push(Map_QM.util.changeAreaToString(mapData.hollowArea[m])); } } if (floor) { entColor = mapData.floorArea.entColor; borderColor = mapData.floorArea.borderColor; floorH = parseInt(mapData.floorArea.toHeight); let mash = this.Model_QM.MyModelShape(floor,hows_f,mapData.floorArea,entColor,borderColor,10 + 100 * this.floorOrder); mash.receiveShadow = true; mash.castShadow = false; mash.userData = { type: "floor", order: this.floorOrder, }; mash.userData.opacity = mapData.floorArea.alphaModle / 100 || 0; mash.name = "floor"; this.allObj.add(mash); } /////////////////////初始化楼栋 for (let i = 0; i < bLen; i++) { let build = Map_QM.util.changeAreaToString(mapData.buildArea[i]); let hows = []; for (let t = 0; t < hLen; t++) { let isIn = Map_QM.util.checkAreaInArea(mapData.hollowArea[t],mapData.buildArea[i]); if (isIn) { hows.push(Map_QM.util.changeAreaToString(mapData.hollowArea[t])); } } entColor = mapData.buildArea[i].entColor; borderColor = mapData.buildArea[i].borderColor; buildH = parseInt(mapData.buildArea[i].toHeight); let mash = this.Model_QM.MyPlaneShape(build,hows,mapData.buildArea[i],entColor,borderColor,30 + 100 * this.floorOrder); mash.receiveShadow = true; mash.castShadow = false; mash.userData = { type: "build", order: this.floorOrder, xaxis: mapData.buildArea[i].xaxis, yaxis: mapData.buildArea[i].yaxis, }; mash.userData.opacity = mapData.buildArea[i].alphaModle / 100 || 0; mash.name = mapData.buildArea[i].name; this.allObj.add(mash); } //店铺 let sLen = mapData.shopArea.length; let show = "", showE = "", showLeb = "", formatCode = "", mapShow = false; let logo = "", navRecommend = false, shopD = {}; let shopData = Map_QM.util.shopData; for (let i = 0; i < sLen; i++) { if (Map_QM.util.changeAreaToString(mapData.shopArea[i]) != "") { for (let t = 0; t < sLen; t++) { let isIn = Map_QM.util.checkAreaInArea(mapData.shopArea[i], mapData.shopArea[t]); isIn &&(mapData.shopArea[i].site = parseInt(mapData.shopArea[i].site) + 1); } let arr = Map_QM.util.changeShopLinesToString(mapData.shopArea[i]); entColor = mapData.shopArea[i].entColor || "#b79266"; borderColor = mapData.shopArea[i].borderColor || "#b79266"; show = showE = mapData.shopArea[i].name; logo = ""; showLeb = ""; navRecommend = false; mapShow = false; shopD = {}; if (shopData) { for (let h = 0; h < shopData.length; h++) { if (shopData[h].houseNumber === mapData.shopArea[i].name) { showLeb = shopData[h].houseNumber; show = shopData[h].shopName == undefined ? shopData[h].name : shopData[h].shopName; showE = shopData[h].shopNameEn == undefined ? shopData[h].nameEn : shopData[h].shopNameEn; logo = shopData[h].logoUrl; mapShow = shopData[h].mapShow ?? false; //是否常显示 formatCode = shopData[h].industryFatherCode; if (shopData[h].isPass) { navRecommend = shopData[h].isPass; } else { navRecommend = false; } shopD = shopData[h]; if (shopData[h].isNewShop) { //新店 mapData.shopArea[i].type = "new-shop"; this.addTagLabel(mapData.shopArea[i], {node: mapData.shopArea[i].shopNav, floor: this.floorOrder, build: this.buildOrder}); } else { if (shopData[h].activityList &&shopData[h].activityList.length > 0) { //促销 mapData.shopArea[i].type = "promotion"; this.addTagLabel(mapData.shopArea[i], {node: mapData.shopArea[i].shopNav, floor: this.floorOrder, build: this.buildOrder }); } } shopData[h].color && (entColor = shopData[h].color); shopData[h].formatColor && (entColor = shopData[h].formatColor); shopData[h].borderColor && (borderColor = shopData[h].borderColor); break; } } } let hollShop = []; if (mapData.shopArea[i].hollArea) { for (let k = 0; k < mapData.shopArea[i].hollArea.length; k++) { hollShop.push(Map_QM.util.changeAreaToString(mapData.shopArea[i].hollArea[k])); } } let mahc = this.Model_QM.MyModelShape(arr,hollShop,mapData.shopArea[i],entColor,borderColor,60 + 100 * this.floorOrder); mahc.node = mapData.shopArea[i].shopNav; mahc.userData = { id: mapData.shopArea[i].id, shopData: shopD, xaxis: mapData.shopArea[i].xaxis >> 0, yaxis: mapData.shopArea[i].yaxis >> 0, node: mahc.node, floor: this.floorOrder, build: this.buildOrder, navRecommend: navRecommend, type: "shop", houseNumber: mapData.shopArea[i].name, shopName: show, formatCode: formatCode, logo: logo, opacity: mapData.shopArea[i].alphaModle / 100 || 0, }; mahc.name = showLeb; mahc.xaxis = mapData.shopArea[i].xaxis >> 0; mahc.yaxis = mapData.shopArea[i].yaxis >> 0; this.shopObj.add(mahc); if (mapData.shopArea[i].logoUrl && mapData.shopArea[i].isLabel == 0) { //添加logo this.logoUtil.renderIcon(mapData.shopArea[i],mahc,parseInt(mapData.shopArea[i].toHeight) +1 ); } else { //添加文字 let some = false; if (Map_QM.util.options.boxShop.length && Map_QM.util.options.boxShop[0] !== "") { some = Map_QM.util.options.boxShop.some((item) => { return mapData.shopArea[i].name.includes(item); }); } if (showLeb != "" || some) { let shopDiv = document.createElement("div"); shopDiv.style.cssText = css_LR; if (window.innerWidth > 2000) { shopDiv.style.fontSize = "18px"; } shopDiv.innerHTML =Map_QM.util.options.shopStyle == "shopName" ? show : mapData.shopArea[i].name; shopDiv.dataset.name = show; shopDiv.dataset.nameEn = showE; shopDiv.style.display = "none"; 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) + parseInt(mapData.shopArea[i].site || 0)); shopLabel.name = mapData.shopArea[i].name; shopLabel.userData.mapShow = mapShow; //是否永久显示 shopLabel.userData.formatCode = formatCode; shopLabel.userData.isShow = true; this.labelObj.add(shopLabel); } } } } }, addTagLabel: function (obj, userData) { let shopDiv = document.createElement("img"); shopDiv.src = Map_QM.util.beforPath + "static/img/" + obj.type + ".png"; shopDiv.style.zIndex = 30; shopDiv.style.width = "3.125vw"; let shopLabel = new THREE.CSS2DObject(shopDiv); shopLabel.userData = userData; shopLabel.userData.mapShow = true; //是否永久显示 shopLabel.userData.isShow = false; shopLabel.userData.type = obj.type; shopLabel.position.set(obj.xaxis >> 0, (-1 * obj.yaxis) >> 0, Map_QM.util.shopHeight + 30); this.tagObj.add(shopLabel); }, //初始化服务图标 initFacilitie: function () { let serArr = Map_QM.util.allMap[this.buildOrder].buildArr[this.floorOrder].mapData.icons; for (let i = 0; i < serArr.length; i++) { if (serArr[i].hasOwnProperty("iShow")) { if (serArr[i].iShow) { serArr[i].floorOrder = this.floorOrder; serArr[i].buildOrder = this.buildOrder; this.facUtil.renderIcon(serArr[i], this); } } else { serArr[i].floorOrder = this.floorOrder; serArr[i].buildOrder = this.buildOrder; this.facUtil.renderIcon(serArr[i], this); } } }, //初始化电梯图标 initStairs: function () { let facArr = Map_QM.util.allMap[this.buildOrder].buildArr[this.floorOrder].mapData.stairs; for (let i = 0; i < facArr.length; i++) { if (facArr[i].facCode == "ft") { if (Map_QM.util.pathStateObj.elevatorDown && Map_QM.util.pathStateObj.elevator && Map_QM.util.options.modelIcon) { if (facArr[i].downState) { //上扶梯 let ex = Map_QM.util.pathStateObj.elevator.clone(); ex.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site || 0); ex.rotation.y = ((facArr[i].angle || 0) * Math.PI) / -180; ex.userData.type = "icon"; ex.userData.use = "3d"; ex.userData.name = "upft"; ex.userData.buildOrder = facArr[i].buildOrder; ex.userData.floorOrder = facArr[i].floorOrder; ex.userData.navCode = facArr[i].navCode; ex.userData.src = "static/img/ft.png"; ex.userData.facCode = facArr[i].facCode; ex.userData.title = facArr[i].title; this.serObj.add(ex); facArr[i].facCode = "ft"; this.facUtil.renderIcon(facArr[i], this, false, ex); } else if (facArr[i].upState) { //下扶梯 let ex = Map_QM.util.pathStateObj.elevatorDown.clone(); ex.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site || 0); ex.rotation.y = ((facArr[i].angle || 0) * Math.PI) / -180; ex.userData.type = "icon"; ex.userData.use = "3d"; ex.userData.name = "downft"; ex.userData.buildOrder = facArr[i].buildOrder; ex.userData.floorOrder = facArr[i].floorOrder; ex.userData.navCode = facArr[i].navCode; ex.userData.src = "static/img/ft.png"; ex.userData.facCode = facArr[i].facCode; ex.userData.title = facArr[i].title; this.serObj.add(ex); facArr[i].facCode = "ft"; this.facUtil.renderIcon(facArr[i], this, false, ex); } else { this.facUtil.renderIcon(facArr[i], this, true); } } else { this.facUtil.renderIcon(facArr[i], this, true); } } else if (facArr[i].facCode == "upft") { if (Map_QM.util.pathStateObj.elevator && Map_QM.util.options.modelIcon) { let ex = Map_QM.util.pathStateObj.elevator.clone(); ex.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site || 0); ex.rotation.y = ((facArr[i].angle || 0) * Math.PI) / -180; ex.userData.type = "icon"; ex.userData.use = "3d"; ex.userData.name = "upft"; ex.userData.buildOrder = facArr[i].buildOrder; ex.userData.floorOrder = facArr[i].floorOrder; ex.userData.navCode = facArr[i].navCode; ex.userData.src = "static/img/ft.png"; ex.userData.facCode = facArr[i].facCode; ex.userData.title = facArr[i].title; 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 (Map_QM.util.pathStateObj.elevatorDown && Map_QM.util.options.modelIcon) { let ex = Map_QM.util.pathStateObj.elevatorDown.clone(); ex.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site || 0); ex.rotation.y = ((facArr[i].angle || 0) * Math.PI) / -180; ex.userData.type = "icon"; ex.userData.use = "3d"; ex.userData.name = "downft"; ex.userData.buildOrder = facArr[i].buildOrder; ex.userData.floorOrder = facArr[i].floorOrder; ex.userData.navCode = facArr[i].navCode; ex.userData.src = "static/img/ft.png"; ex.userData.facCode = facArr[i].facCode; ex.userData.title = facArr[i].title; 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 (Map_QM.util.pathStateObj.straight && Map_QM.util.options.modelIcon) { let stra = Map_QM.util.pathStateObj.straight.clone(); stra.position.set(facArr[i].x, -1 * facArr[i].y, facArr[i].site || 0); stra.rotation.y = ((facArr[i].angle || 0) * Math.PI) / -180; stra.userData.type = "icon"; stra.userData.use = "3d"; stra.userData.name = "dt"; stra.userData.buildOrder = facArr[i].buildOrder; stra.userData.floorOrder = facArr[i].floorOrder; stra.userData.navCode = facArr[i].navCode; stra.userData.src = "static/img/dt.png"; stra.userData.facCode = facArr[i].facCode; stra.userData.title = facArr[i].title; 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); } } }, //初始化装饰图标 initDecos: function () { let mapData = Map_QM.util.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++) { let arr = Map_QM.util.changeAreaToString(mapData.decos[i]); if (mapData.decos[i].gid && mapData.decos[i].gid == mapData.groupArea[k].name && arr.length > 0) { entColor = mapData.decos[i].entColor; borderColor = mapData.decos[i].borderColor; let show = mapData.decos[i].name == "deco" ? "" : mapData.decos[i].name; let hollShop = []; if (mapData.decos[i].hollArea) { for (let k = 0; k < mapData.decos[i].hollArea.length; k++) { hollShop.push(Map_QM.util.changeAreaToString(mapData.decos[i].hollArea[k])); } } let mahc = this.Model_QM.MyModelShape(arr,hollShop,mapData.decos[i],entColor,borderColor,70 + 100 * this.floorOrder); mahc.xaxis = mapData.decos[i].xaxis >> 0; mahc.yaxis = mapData.decos[i].yaxis >> 0; mahc.node = mapData.decos[i].shopNav; mahc.userData = { type: "deco", name: show, }; mahc.userData.opacity = mapData.decos[i].alphaModle / 100 || 0; 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 || 0; gp.scale.set(mapData.groupArea[k].scale,mapData.groupArea[k].scale,mapData.groupArea[k].scale); } } for (let i = 0; i < sLen; i++) { let arr = Map_QM.util.changeAreaToString(mapData.decos[i]); if (!mapData.decos[i].gid && arr.length > 0) { entColor = mapData.decos[i].entColor; borderColor = mapData.decos[i].borderColor; let show = mapData.decos[i].name == "deco" ? "" : mapData.decos[i].name; let hollShop = []; if (mapData.decos[i].hollArea) { for (let k = 0; k < mapData.decos[i].hollArea.length; k++) { hollShop.push(Map_QM.util.changeAreaToString(mapData.decos[i].hollArea[k])); } } let mahc; mahc = this.Model_QM.MyModelShape(arr,hollShop,mapData.decos[i],entColor,borderColor,70 + 100 * this.floorOrder ); mahc.userData = { type: "deco", node: mapData.decos[i].shopNav, xaxis: mapData.decos[i].xaxis, yaxis: mapData.decos[i].yaxis, houseNumber: mahc.name, name: show, }; this.allObj.add(mahc); } } }, /** * 渲染墙体 */ initWall: function () { let mapData = Map_QM.util.allMap[this.buildOrder].buildArr[this.floorOrder].mapData; //渲染 if (mapData.wallArea) { let sLen = mapData.wallArea.length; for (let i = 0; i < sLen; i++) { let arr = Map_QM.util.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", }; mahc.userData.opacity = mapData.wallArea[i].alphaModle / 100 || 0; this.allObj.add(mahc); } } }, /** * 渲染文本 */ initTextArea: function () { let mapData = Map_QM.util.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, houseNumber: mapData.svgArea[i].name, }; this.svgObj.add(mahc); } } }, /** * 设置终点图标 */ 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.applyMatrix4(Map_QM.sceneGap.matrix); if (Map_QM.endIcon) { Map_QM.endIcon.visible = pathCameraState == "2D" ? true : false; Map_QM.endIcon.scale.x = 100; Map_QM.endIcon.scale.y = 120; Map_QM.endIcon.position.set(shopX, 100, shopY); //x,z,y Map_QM.endIcon.applyMatrix4(Map_QM.sceneGap.matrix); } } else { try { Map_QM.scene.traverse((item) => { if (item.name == "Z-model") { Map_QM.scene.remove(item); } }); } catch (e) { window.captureException && window.captureException(e); console.log("traverse"); } let loader2 = new THREE.GLTFLoader(); loader2.load( Map_QM.util.beforPath + "static/img/zhong.glb", function (collada2) { 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.applyMatrix4(Map_QM.sceneGap.matrix); collada2.scene.renderOrder = 200; collada2.scene.traverse(function (child) { if (child.type === "Mesh") { child.castShadow = Map_QM.util.options.shadow; child.receiveShadow = Map_QM.util.options.shadow; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } } }); for (let k = 0; k < collada2.animations.length; k++) { let mixer = new THREE.AnimationMixer(collada2.scene); mixer.clipAction(collada2.animations[k]).play(); Map_QM.mixers.push(mixer); } collada2.scene.name = "Z-model"; 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( Map_QM.util.beforPath + "static/img/Z.png" ); let spriteMaterial = new THREE.SpriteMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放 map: spriteMap, depthTest: true, transparent: true, alphaTest: 0.5, }); Map_QM.endIcon = new MySprite_QM(spriteMaterial); Map_QM.endIcon.scale.set(100, 120, 1); Map_QM.endIcon.center = new THREE.Vector2(0.5, 0); Map_QM.endIcon.position.set(shopX, 100, shopY); Map_QM.endIcon.applyMatrix4(Map_QM.sceneGap.matrix); Map_QM.endIcon.renderOrder = 300; Map_QM.endIcon.name = "Z-model"; Map_QM.endIcon.visible = pathCameraState == "2D" ? true : false; Map_QM.scene.add(Map_QM.endIcon); } }, /** * 设置起点图标 */ setStartSite: function (shopX, shopY, shopZ) { let _this = this; if (Map_QM.qiModel) { Map_QM.devModel.position.set(shopX, -1 * shopY, 20); _this.allObj.add(Map_QM.devModel); Map_QM.qiModel.position.set(shopX, -1 * shopY, 10); _this.allObj.add(Map_QM.qiModel); Map_QM.qiIcon.position.set(shopX, -1 * shopY, shopZ); _this.allObj.add(Map_QM.qiIcon); } else { new THREE.GLTFLoader().load( Map_QM.util.beforPath + "static/img/guide.glb", function (obj) { obj.scene.scale.x = obj.scene.scale.y = obj.scene.scale.z = 100; obj.scene.rotation.x = Math.PI / 2; obj.scene.rotation.y = (Map_QM.util.deviceObj.angle * Math.PI) / -180; obj.scene.traverse(function (child) { if (child.type === "Mesh") { child.castShadow = Map_QM.util.options.shadow; child.receiveShadow = Map_QM.util.options.shadow; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } } }); if (shopX != 0 && shopY != 0) { obj.scene.position.set(shopX, -1 * shopY, 50); //x,z,y } for (let k = 0; k < obj.animations.length; k++) { let mixer = new THREE.AnimationMixer(obj.scene); mixer.clipAction(obj.animations[k]).play(); Map_QM.mixers.push(mixer); } Map_QM.devModel = obj.scene; Map_QM.devModel.visible = false; Map_QM.devModel.renderOrder = 160; _this.allObj.add(Map_QM.devModel); } ); new THREE.GLTFLoader().load( Map_QM.util.beforPath + "static/img/qi.glb", function (collada) { collada.scene.scale.x = collada.scene.scale.y = collada.scene.scale.z = 100; collada.scene.rotateX(Math.PI / 2); collada.scene.traverse(function (child) { if (child.type === "Mesh") { child.castShadow = Map_QM.util.options.shadow; child.receiveShadow = Map_QM.util.options.shadow; if (child.material.map) { child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码 } } }); if (shopX != 0 && shopY != 0) { collada.scene.position.set( shopX, -1 * shopY, parseInt(Map_QM.util.buildHeight) + 5); //x,z,y } for (let k = 0; k < collada.animations.length; k++) { let mixer = new THREE.AnimationMixer(collada.scene); mixer.clipAction(collada.animations[k]).play(); Map_QM.mixers.push(mixer); } collada.scene.renderOrder = 200; collada.scene.userData.type = "start"; Map_QM.qiModel = collada.scene; _this.allObj.add(collada.scene); //-------------------------------------------------------------- let spriteMap = new THREE.TextureLoader().load( Map_QM.util.beforPath + "static/img/Q.png" ); let spriteMaterial = new THREE.SpriteMaterial({ //sizeAttenuation: false 禁止跟随鼠标缩放 map: spriteMap, depthTest: true, transparent: true, alphaTest: 0.5, }); Map_QM.qiIcon = new MySprite_QM(spriteMaterial); Map_QM.qiIcon.scale.set(100, 120, 1); Map_QM.qiIcon.center = new THREE.Vector2(0.5, 0); Map_QM.qiIcon.position.set(shopX, -1 * shopY, shopZ + 50); Map_QM.qiIcon.renderOrder = 500; Map_QM.qiIcon.visible = false; Map_QM.qiIcon.userData.type = "start"; _this.allObj.add(Map_QM.qiIcon); } ); } }, /** * 查找线 * @param {Object} startNode * @param {Object} endNode */ 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; }, //初始化停车位 initPark: function () { let mapData = Map_QM.util.allMap[this.buildOrder].buildArr[this.floorOrder].mapData; //渲染车位 if (mapData.parkArea) { let sLen = mapData.parkArea.length; if (sLen > 0) { this.allObj.add(this.parkObj); } let shapeArr = [], materials = [], parkHeight = 1, borderColor = 0xaaaaaa; for (let i = 0; i < sLen; i++) { let arr = Map_QM.util.changeParkToString(mapData.parkArea[i]); if (arr != "") { parkHeight = Math.max(parseInt(mapData.parkArea[i].toHeight), parkHeight); borderColor = mapData.parkArea[i].borderColor; if (arr.length > 0) { let shape = new THREE.Shape(); shape.moveTo(arr[0][0], -1 * arr[0][1]); for (let k = 1; k < arr.length; k++) { shape.lineTo(arr[k][0], -1 * arr[k][1]); } shapeArr.push(shape); let meshMaterial; let color2 = new THREE.Color(mapData.parkArea[i].entColor); for (let e = 0; e < Map_QM.util.parkMaterialArr.length; e++) { if (Map_QM.util.parkMaterialArr[e].color.equals(color2)) { meshMaterial = Map_QM.util.parkMaterialArr[e]; } } if (!meshMaterial) { meshMaterial = new THREE.MeshBasicMaterial({ color: mapData.parkArea[i].entColor, }); Map_QM.util.parkMaterialArr.push(meshMaterial); } materials.push(meshMaterial); if (mapData.parkArea[i].childArea && mapData.parkArea[i].childArea.length > 0) { for (let m = 0; m < mapData.parkArea[i].childArea.length; m++) { let meshMaterial0; if (mapData.parkArea[i].childArea[m].color && mapData.parkArea[i].childArea[m].color != "#FFffff") { let color2 = new THREE.Color(mapData.parkArea[i].childArea[m].color); for (let e = 0; e < Map_QM.util.parkMaterialArr.length; e++) { if (Map_QM.util.parkMaterialArr[e].color.equals(color2)) { meshMaterial0 = Map_QM.util.parkMaterialArr[e]; } } if (!meshMaterial0) { meshMaterial0 = new THREE.MeshBasicMaterial({ color: mapData.parkArea[i].childArea[m].color, }); Map_QM.util.parkMaterialArr.push(meshMaterial0); } } else { meshMaterial0 = meshMaterial; } let ps = mapData.parkArea[i].childArea[m].points; let shape0 = new THREE.Shape(); // 设置开始点的位置 shape0.moveTo(ps[0].x, -1 * ps[0].y); for (let t = 0; t < ps.length; t++) { shape0.lineTo(ps[t].x, -1 * ps[t].y); } shapeArr.push(shape0); materials.push(meshMaterial0); } } } //显示车位编号 if (mapData.parkArea[i].parkNum != "NaN" && i % 20 == 0) { let shopDiv = document.createElement("div"); shopDiv.style.cssText = css_LR shopDiv.style.display = "none"; shopDiv.textContent = mapData.parkArea[i].parkNum; let shopLabel = new THREE.CSS2DObject(shopDiv); shopLabel.userData.mapShow = true; //是否永久显示 shopLabel.name = mapData.parkArea[i].name; shopLabel.position.set(mapData.parkArea[i].xaxis >> 0,(-1 * mapData.parkArea[i].yaxis) >> 0,parseInt(mapData.parkArea[i].toHeight) + 1); this.labelObj.add(shopLabel); } } } let mahc = this.Model_QM.MyParkShape(shapeArr, materials, parkHeight); this.parkObj.add(mahc); } }, }; /** * 渲染3D模型类 * 传入区域点list * 镂空点 howllowArr * 模型对象 options */ MyModel_QM = function () { this.xaxis = 0; this.yaxis = 0; this.node = 0; }; MyModel_QM.prototype.MyParkShape = function (shapes, materials, toHeight = 5) { let scanGeometry = new THREE.ShapeBufferGeometry(shapes, 1); let material = new THREE.LineBasicMaterial({ color: "#aeaeae", }); //材质对象lineColor Map_QM.util.lineBasicMaterialArr.push(material); // 创建模型 let mesh = new THREE.Mesh(scanGeometry, materials); mesh.position.z = toHeight; mesh.renderOrder = 300; mesh.userData.type = "park"; let cubeEdges = new THREE.EdgesGeometry(scanGeometry, 60); let cubeLine = new THREE.LineSegments(cubeEdges, material); mesh.add(cubeLine); return mesh; }; 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(); // 设置开始点的位置 shape.moveTo(areaArr[0][0], -1 * areaArr[0][1]); for (let i = 0; i < areaArr.length; i++) { 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; let matcolor = new THREE.Color(lineColor); for (let k = 0; k < Map_QM.util.lineBasicMaterialArr.length; k++) { if (Map_QM.util.lineBasicMaterialArr[k].color.equals(matcolor)) { material = Map_QM.util.lineBasicMaterialArr[k]; } } if (!material) { material = new THREE.LineBasicMaterial({ color: lineColor, opacity: 0.8, transparent: true, }); //材质对象lineColor Map_QM.util.lineBasicMaterialArr.push(material); } if (howllowArr && howllowArr.length > 0) { for (let n = 0; n < howllowArr.length; n++) { let hole = new THREE.Path(); // 添加孔洞 hole.moveTo(howllowArr[n][0][0], -1 * howllowArr[n][0][1]); for (let k = 0; k < howllowArr[n].length; k++) { 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: 12, bevelThickness: 0, bevelSize: 0, bevelSegments: 0, material: 0, //frontMaterial = green extrudeMaterial: 1, //sideMaterial = gray }; scanGeometry = new THREE.ExtrudeGeometry(shape, options); let meshColor = new THREE.Color(entityColor); for (let e = 0; e < Map_QM.util.meshMaterialArr.length; e++) { if (Map_QM.util.meshMaterialArr[e].color && Map_QM.util.meshMaterialArr[e].color.equals(meshColor) && Map_QM.util.meshMaterialArr[e].opacity == alphaModle && !Map_QM.util.meshMaterialArr[e].userData.map ) { meshMaterial = Map_QM.util.meshMaterialArr[e]; } } if (!meshMaterial) { meshMaterial = new THREE.MeshPhongMaterial({ //MeshStandardMaterial MeshPhongMaterial MeshBasicMaterial color: entityColor, transparent: true, opacity: alphaModle, side: THREE.DoubleSide, depthTest: true, }); Map_QM.util.meshMaterialArr.push(meshMaterial); } if (opObj.angleY || opObj.angleZ) { Map_QM.util.rotateYZ(scanGeometry,(opObj.angleY * Math.PI) / 180,(opObj.angleZ * Math.PI) / 180); } // 创建模型 let mesh; if (opObj.map == "home") { Map_QM.util.assignUVs(scanGeometry); let mapMaterial, ceMaterial; for (let e = 0; e < Map_QM.util.meshMaterialArr.length; e++) { if (Map_QM.util.meshMaterialArr[e].userData.map == "front" && Map_QM.util.meshMaterialArr[e].opacity == alphaModle) { mapMaterial = Map_QM.util.meshMaterialArr[e]; } if (Map_QM.util.meshMaterialArr[e].userData.map == "c50" && Map_QM.util.meshMaterialArr[e].opacity == alphaModle) { ceMaterial = Map_QM.util.meshMaterialArr[e]; } } if (!mapMaterial) { let texture = new THREE.TextureLoader().load(Map_QM.util.beforPath + "static/img/map/front.png"); texture.wrapS = THREE.ClampToEdgeWrapping; texture.wrapT = THREE.RepeatWrapping; mapMaterial = new THREE.MeshPhongMaterial({ color: entityColor, map: texture, transparent: true, opacity: alphaModle, side: THREE.DoubleSide, depthTest: true, }); mapMaterial.userData.map = "front"; Map_QM.util.meshMaterialArr.push(mapMaterial); } if (!ceMaterial) { let texture2 = new THREE.TextureLoader().load(Map_QM.util.beforPath + "static/img/map/c50.png"); texture2.wrapS = THREE.RepeatWrapping; texture2.wrapT = THREE.ClampToEdgeWrapping; ceMaterial = new THREE.MeshPhongMaterial({ color: entityColor, map: texture2, transparent: true, opacity: alphaModle, side: THREE.DoubleSide, depthTest: true, }); ceMaterial.userData.map = "c50"; Map_QM.util.meshMaterialArr.push(ceMaterial); } mesh = new THREE.Mesh(scanGeometry, [meshMaterial, ceMaterial, mapMaterial,]); } else if (opObj.map) { Map_QM.util.packUv(scanGeometry); let ceMaterial; for (let e = 0; e < Map_QM.util.meshMaterialArr.length; e++) { if (Map_QM.util.meshMaterialArr[e].userData.map == opObj.map && Map_QM.util.meshMaterialArr[e].opacity == alphaModle) { ceMaterial = Map_QM.util.meshMaterialArr[e]; } } if (!ceMaterial) { let texture2 = new THREE.TextureLoader().load(Map_QM.util.beforPath + "static/img/map/" + opObj.map + ".png"); texture2.wrapS = THREE.RepeatWrapping; texture2.wrapT = THREE.ClampToEdgeWrapping; ceMaterial = new THREE.MeshPhongMaterial({ color: entityColor, map: texture2, transparent: true, opacity: alphaModle, side: THREE.DoubleSide, depthTest: true, }); ceMaterial.userData.map = opObj.map; Map_QM.util.meshMaterialArr.push(ceMaterial); } mesh = new THREE.Mesh(scanGeometry, [meshMaterial, ceMaterial]); } else { mesh = new THREE.Mesh(scanGeometry, meshMaterial); } if (opObj.type != "wall") { let cubeEdges = new THREE.EdgesGeometry(scanGeometry, 60); let cubeLine = new THREE.LineSegments(cubeEdges, material); cubeLine.renderOrder = indexOrder - 5; mesh.add(cubeLine); } if (opObj.name != "floor") { mesh.position.z = opObj.site || 0; } else { mesh.position.z = -1 * parseInt(opObj.toHeight) - 1; } mesh.castShadow = true; mesh.renderOrder = indexOrder; mesh.name = opObj.name || ""; return mesh; }; //绘制平面 MyModel_QM.prototype.MyPlaneShape = function (areaArr,howllowArr,opObj,entityColor = "#dadada",lineColor = "#eeeeee",indexOrder = 1) { let len = areaArr.length; if (len == 0) { return; } let alphaModle = opObj.alphaModle / 100 || 0; // 实例化shape对象 let shape = new THREE.Shape(); // 设置开始点的位置 shape.moveTo(areaArr[0][0], -1 * areaArr[0][1]); for (let i = 0; i < areaArr.length; i++) { 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 < Map_QM.util.lineBasicMaterialArr.length; k++) { let color2 = new THREE.Color(lineColor); if (Map_QM.util.lineBasicMaterialArr[k].color.equals(color2)) { material = Map_QM.util.lineBasicMaterialArr[k]; } } if (!material) { material = new THREE.LineBasicMaterial({ color: lineColor, opacity: 0.8, transparent: true, }); //材质对象lineColor Map_QM.util.lineBasicMaterialArr.push(material); } if (howllowArr && howllowArr.length > 0) { for (let n = 0; n < howllowArr.length; n++) { let hole = new THREE.Path(); // 添加孔洞 hole.moveTo(howllowArr[n][0][0], -1 * howllowArr[n][0][1]); for (let k = 0; k < howllowArr[n].length; k++) { 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; scanGeometry = new THREE.ShapeGeometry(shape, 8); Map_QM.util.assignUVs(scanGeometry); if (opObj.map) { let texture = new THREE.TextureLoader().load( Map_QM.util.beforPath + "static/img/map/" + opObj.map + ".png" ); meshMaterial = new THREE.MeshPhongMaterial({ //MeshStandardMaterial MeshPhongMaterial olor: entityColor, color: entityColor, map: texture, transparent: true, opacity: alphaModle, side: THREE.DoubleSide, depthTest: true, }); meshMaterial.userData.map = opObj.map; Map_QM.util.meshMaterialArr.push(meshMaterial); } else { for (let e = 0; e < Map_QM.util.meshMaterialArr.length; e++) { let color2 = new THREE.Color(entityColor); if ( Map_QM.util.meshMaterialArr[e].color && Map_QM.util.meshMaterialArr[e].color.equals(color2) && Map_QM.util.meshMaterialArr[e].opacity == alphaModle && !Map_QM.util.meshMaterialArr[e].userData.map ) { meshMaterial = Map_QM.util.meshMaterialArr[e]; } } if (!meshMaterial) { meshMaterial = new THREE.MeshPhongMaterial({ color: entityColor, transparent: true, opacity: alphaModle, side: THREE.DoubleSide, depthTest: true, }); Map_QM.util.meshMaterialArr.push(meshMaterial); } if (opObj.angleY || opObj.angleZ) { Map_QM.util.rotateYZ( scanGeometry, (opObj.angleY * Math.PI) / 180, (opObj.angleZ * Math.PI) / 180 ); } } // 创建模型 let mesh = new THREE.Mesh(scanGeometry, meshMaterial); let cubeEdges = new THREE.EdgesGeometry(scanGeometry, 60); let cubeLine = new THREE.LineSegments(cubeEdges, material); cubeLine.renderOrder = indexOrder - 5; mesh.add(cubeLine); if (opObj.name != "floor") { mesh.position.z = parseInt(opObj.toHeight) || 0; } 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.position.x = parseInt(svgArea.xaxis); group.position.y = -1 * parseInt(svgArea.yaxis); group.position.z = parseInt(svgArea.site || 0); 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.scale.y *= -1; let meshMaterial; for (let e = 0; e < Map_QM.util.meshMaterialArr.length; e++) { let color2 = new THREE.Color().setHex(svgArea.entColor); if (Map_QM.util.meshMaterialArr[e].color && Map_QM.util.meshMaterialArr[e].color.equals(color2) && Map_QM.util.meshMaterialArr[e].opacity == svgArea.alphaModle ) { meshMaterial = Map_QM.util.meshMaterialArr[e]; } } if (!meshMaterial) { meshMaterial = new THREE.MeshStandardMaterial({ color: svgArea.entColor, opacity: parseInt(svgArea.alphaModle) / 100, }); Map_QM.util.meshMaterialArr.push(meshMaterial); } for (let i = 0; i < paths.length; i++) { const path = paths[i]; let shapes = path.toShapes(true); const geometry = new THREE.ShapeGeometry(shapes, 36); const mesh = new THREE.Mesh(geometry, meshMaterial); mesh.renderOrder = 50; mesh.name = svgArea.name || ""; mesh.position.set( svgArea.width / -2, svgArea.height / -2, parseInt(svgArea.toHeight) + 1); group.add(mesh); } return group; }; /** * 公共设施 */ var 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.build = obj.buildOrder; this.site = parseInt(obj.site) || Map_QM.util.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; /** * 渲染公共设施 */ var Facilities_QM = function () { this.renderIcon = function (obj, _this, isShow = true, ele = null) { if (obj) { let url = Map_QM.util.beforPath + "static/img/" + obj.facCode + ".png"; let name = obj.title; let nameEn = obj.title; if (Map_QM.util.iconUrl.length > 0) { //使用设施库 for (let i = 0; i < Map_QM.util.iconUrl.length; i++) { if (Map_QM.util.iconUrl[i].abbreviation == obj.facCode) { url = Map_QM.util.beforPath+"static/offline/"+Map_QM.util.iconUrl[i].filePath; name = Map_QM.util.iconUrl[i].name; nameEn = Map_QM.util.iconUrl[i].nameEn; } } } let shopDiv = document.createElement("img"); shopDiv.src = url; shopDiv.style.zIndex = 100; shopDiv.style.width = "1.2vw"; shopDiv.style.display = isShow ? "" : "none"; shopDiv.dataset.name = name; shopDiv.dataset.src = url; shopDiv.dataset.nameEn = nameEn; shopDiv.dataset.buildOrder = obj.buildOrder; shopDiv.dataset.floorOrder = obj.floorOrder; shopDiv.dataset.facCode = obj.facCode; shopDiv.dataset.node = obj.navCode; shopDiv.addEventListener("click", (event) => { /** * @api {事件} icon 点击设施图标 * @apiGroup 地图事件 * @apiDescription 用户点击设施图标后触发自定义事件 * @apiVersion 4.0.0 * @apiSampleRequest off * * @apiParamExample 请求示例 * Map_QM.addEventListener("icon",onClickIcon,false); */ Map_QM.dispatchEvent({ type: "icon", data: { buildOrder: event.target.dataset.buildOrder, floorOrder: event.target.dataset.floorOrder, node: event.target.dataset.node, src: event.target.dataset.src, facCode: event.target.dataset.facCode, title: event.target.dataset.name, }, }); }); let shopLabel = new THREE.CSS2DObject(shopDiv); shopLabel.userData.mapShow = true; //是否永久显示 shopLabel.userData = obj; shopLabel.userData.type = "icon"; shopLabel.userData.use = ele ? "2d" : "all"; shopLabel.userData.model = ele; shopLabel.userData.src = url; shopLabel.userData.isShow = true; shopLabel.position.set(obj.x, -1*obj.y, Math.max(30, parseInt(obj.site) || 0)); _this.serObj.add(shopLabel); if (Map_QM.util.options.iconName) { let titleDiv = document.createElement("div"); titleDiv.style.cssText = css_LR; if (window.innerWidth > 2000) { titleDiv.style.fontSize = "18px"; } titleDiv.innerText = obj.title; titleDiv.dataset.name = name; titleDiv.dataset.nameEn = nameEn; titleDiv.style.zIndex = 480; let shopLabel = new THREE.CSS2DObject(titleDiv); shopLabel.position.set(obj.x, -1 * obj.y, parseInt(obj.site) + 85); shopLabel.userData.mapShow = true; shopLabel.userData.isShow = true; _this.labelObj.add(shopLabel); } } }; }; /** * 店铺LOGO地图展示类 */ var ShopLogo_QM = function () { this.renderIcon = function (obj, _this, z) { if (obj) { let x = obj.xaxis >> 0; let y = (-1 * obj.yaxis) >> 0; 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: true, transparent: true, alphaTest: 0.01, }); 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, obj.site || z); plane.userData.rot = 0; plane.userData.type = "logo"; plane.renderOrder = 70; _this.add(plane); }); } }; }; var _selfFindPath; var FindPath_QM = function () { this.pathArr = []; this.lineDashed; this.lineDashed_old; //路线指引箭头皮肤 this.planeGeometry = new THREE.PlaneGeometry(128, 128); this.morePath = false; 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[Map_QM.util.selectBuild][Map_QM.util.selectFloor]) { Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.remove(this.lineDashed); } this.lineDashed.destroy(); this.lineDashed = null; } if (this.lineDashed_old) { if (Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor]) { Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.remove(this.lineDashed_old); } this.lineDashed_old.destroy(); this.lineDashed_old = null; } if (Map_QM.guide) { Map_QM.guide.visible = false; if (Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor]) { Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.remove(Map_QM.man_2d); Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.remove(Map_QM.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,morePath = false,floorOrder = -1) { this.morePath = morePath; if (pathArray && pathArray.length > 0) { this.pathState = "isPlay"; this._index = 0; this.pathArr = []; if (floorOrder === -1) { floorOrder = Map_QM.util.selectFloor; } if (morePath) { for (let j = 0; j < pathArray.length; j++) { this.drawPath(floorOrder,pathArray[j], parseInt(Map_QM.util.buildHeight) + j); } } else { for (let j = 0; j < pathArray.length; j++) { this.pathArr.push(pathArray[j]); } this.drawPath(floorOrder); } } }; FindPath_QM.prototype.drawPath = function (floorOrder, pathArr = null, height = 1) { let linePath = []; if (!pathArr) { 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]); } } } else { for (let i = 0; i < pathArr.length; i++) { if (i < pathArr.length) { linePath.push([pathArr[i].x, -1 * pathArr[i].y]); } } } if (this.morePath) { this.lineDashed_old = new PathLine(12,linePath,height,Map_QM.util.options.pathColor,Map_QM.util.options.pathColor2,true); } else { this.lineDashed_old = new PathLine(12,linePath,parseInt(Map_QM.util.buildHeight) + 1,Map_QM.util.options.pathColor,Map_QM.util.options.pathColor2,true); } this.lineDashed_old.name = "lineDash"; this.lineDashed_old.renderOrder = 128; Map_QM.mapArr[Map_QM.util.selectBuild][floorOrder].allObj.add(this.lineDashed_old); }; 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]); Map_QM.man_2d.position.z = parseInt(Map_QM.util.buildHeight) + 120; Map_QM.man_3d.position.z = parseInt(Map_QM.util.buildHeight) + 5; Map_QM.guide.visible = true; Map_QM.mapArr[Map_QM.util.selectBuild][paths.floor].allObj.add(Map_QM.man_2d); Map_QM.mapArr[Map_QM.util.selectBuild][paths.floor].allObj.add(Map_QM.man_3d); } } this.pathArr = paths.PathPoint; _selfFindPath = this; if (Map_QM.util.pathStateObj.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 / (Map_QM.util.options.playSpeed * Map_QM.util.options.speedMult)); 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 }); _selfFindPath._index++; if (_selfFindPath._index > 0 && _selfFindPath._index < _selfFindPath.pathArr.length) { Map_QM.man_3d.rotation.z = Map_QM.man_2d.rotation.z = 0; //180; 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) { Map_QM.man_3d.rotation.z = Map_QM.man_2d.rotation.z = Math.PI - ang; } else { Map_QM.man_3d.rotation.z = Map_QM.man_2d.rotation.z = Math.PI + ang; } } let pathShop = ""; for (let t = 0; t < Map_QM.forShopArr[Map_QM.util._indexPathFloor].wayShop.length; t++) { if (Map_QM.forShopArr[Map_QM.util._indexPathFloor].wayShop[t].pathIndex ==_selfFindPath._index) { let shop_ = Map_QM.forShopArr[Map_QM.util._indexPathFloor].wayShop[t].shop; pathShop = shop_.houseNumber; let shops = Map_QM.mapArr[Map_QM.util.selectBuild][parseInt(Map_QM.forShopArr[Map_QM.util._indexPathFloor].wayShop[t].shop.floorOrder)].shopObj.children; for (let i = 0; i < shops.length; i++) { let _shop = shops[i].userData.shopData; if (_shop && _shop.houseNumber == pathShop) { let shopModel = shops[i]; let material = shopModel.material; shopModel.material = new THREE.MeshBasicMaterial({ color: Map_QM.util.options.navColor, }); TweenMax.to(shopModel.scale, 0.8, { z: 3, yoyo: true, ease: Cubic.easeIn, onComplete: function () { if (shopModel) { TweenMax.to(shopModel.scale, 0.5, { z: 1 }); shopModel.material = material; } }, }); break; } } break; } } Map_QM.dispatchEvent({ //寻路中返回小人当前所在点位 type: "PathPlaying", data: { houseNumber: pathShop }, }); } 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"; } } };