var Map_QM,
renderFrame = -1,
renderCount = 0,
pathCameraState,
mapState = "mall",
iconState = "3d",
heatmapInstance,
isShowElement = true,
isJUZ = false,
allJU = true,
hasLine = false,
intTimer,
shopTime,
pathNodes,
actionTime=-1,
allTime,
language = "zh";
//basePath 基础路径 graphPath最佳路径 ftPath 扶梯路径 dtPath 电梯路径
var QMUtil = function () {
this.shopServerInfo = "./offline/queryShopList.json";
this.mapServerInfo = "./offline/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}];
fSpace: 500, //双叠层状态下楼层的间距
maxDis: 700,
minDis: 80,
shadow: true, //是否显示阴影
navColor: 0xee6a50, //途径店铺颜色
aRadius: 2, //圆角半径 大于2 则店铺box显示圆角
iconName: false, //图标名称是否显示
pathColor: "#6e95fe", //
pathColor2: "#6e7dfe", //'rgb(110,125,254)'
pathBgColor: "#a9b5d3", //'rgb(169,181,211)'
pathBgColor2: "#bdc0cb", //'rgb(189, 192, 203)',
pathStyle: "2D",
shopStyle: "shopName", //设置box显示名称shopName或编号shopNum
inArea: false, //点击后是否聚焦到店铺
boxShop: [], //设置box上显示的文字(过滤指),可点击触发onlyShop
deviceAng: false, //地图初始化方向是否使用设备角度
northShow: false, //指南针显示
facSize: 20, //设施大小
};
this.lightOptions = {
d_col: "#ffffff",
d_int: 0.15,
s_col: "#fffffa",
g_col: "#ffffff",
a_int: 0.2,
};
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: 170, cameraZ: 170, 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 = []; //
/**
* 一直显示不隐藏, 在楼层内显示
* {build:15, floor:0, url:"static/img/out/floor.glb", list:[{size:{x:4.35,y:4.35,z:4.35}, rot:{x:90,y:0,z:0}, site:{x:-35,y:70,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: "subway", url: "static/img/model/subway.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 = []; //精灵模型
/**
* 模型弹窗
*/
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;
};
//店铺排序
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.MeshStandardMaterial({
color: color,
emissive: 0x000000,
specular: 0x000000,
transparent: true,
side: THREE.DoubleSide,
opacity: alphaModle,
emissive : 0x000000,
roughness:0.8
});
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) {
spriteScale = window.innerWidth>2000 ? 0.16 : 0.2;
const sprite = new SpriteText(text, 32, "#000000");
sprite.renderOrder = 800;
sprite.material.transparent = true;
sprite.material.alphaTest = 0.5;
sprite.material.sizeAttenuation = false;
sprite.userData.scaleX = sprite.scale.x;
sprite.userData.scaleY = sprite.scale.y;
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.physicallyCorrectLights = true;
this.renderer.setSize(this.w, this.h);
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.shadowMap.enabled = this.util.options.shadow;
// 阴影类型
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.65);
light.name = "light";
this.scene.add(light);
let dLight = new THREE.DirectionalLight(0xffffff, 0.35); //
dLight.name = "light";
dLight.position.set(-280, 400, 300);
this.scene.add(dLight);
this.hemiLight = new THREE.DirectionalLight(this.util.lightOptions.s_col, this.util.lightOptions.a_int); //
this.hemiLight.name = "light";
this.hemiLight.position.set(280, -400, 300);
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, -200);
this.shawLight.castShadow = this.util.options.shadow; //阴影
this.shawLight.shadow.camera.top = 200;
this.shawLight.shadow.camera.bottom = -200;
this.shawLight.shadow.camera.right = 200;
this.shawLight.shadow.camera.left = -200;
this.shawLight.shadow.camera.far = 800;
this.shawLight.shadow.camera.near = 100;
this.shawLight.shadow.bias = -0.001;
this.shawLight.shadow.darkness = 0.3;
this.shawLight.shadow.mapSize.set(2048, 2048);
this.scene.add(this.shawLight);
this.cost = -1;
this.controls = new THREE.OrbitControls(this.camera, this.ele);
this.controls.minZoom = 0.5;
this.controls.maxZoom = 2.8;
//设置相机距离原点的最远距离
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
document.addEventListener("resize", this.changeDocmentResize); //窗口变化
this.mapArr = [];
this.selectShop;
this.selectEle = null; //当前使用的电梯
this.overShop; //终点店铺
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();
Map_QM.controls.autoRotate = 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.controls.autoRotate = true;
} else {
Map_QM.controls.reset();
Map_QM.controls.setDistance(Map_QM.util.changeDist.outner + 25);
Map_QM.controls.autoRotate = false;
}
Map_QM.controls.update();
},
//隐藏活动标签(万象定制)
mouseMove: function () {
Map_QM.CSSObject && Map_QM.CSSObject.traverse((obj) => {
if (obj.userData.type == "tip") {
obj.element.style.visibility = "hidden";
}
});
},
//显示活动标签(万象定制)
mouseUp: function () {
Map_QM.CSSObject && Map_QM.CSSObject.traverse((obj) => {
if (obj.userData.type == "tip") {
obj.element.style.visibility = parseInt(obj.userData.floor) == Map_QM.util.selectFloor ? "visible": "hidden";
}
});
},
/**
* @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[parseInt(nodes[0])].buildArr[parseInt(nodes[1])].mapData.path.nodes.sort(Map_QM.util.sortNode);
return Map_QM.util.allMap[parseInt(nodes[0])].buildArr[parseInt(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) {
res.data.listObject.forEach((item) => {
_space.util.shopData.push(item);
});
}
_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("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);
if (this.util.allMap[this.util.selectBuild].hasOwnProperty("m_shadow")) {
this.util.options.shadow = this.util.allMap[this.util.selectBuild].m_shadow;
}
this.hemiLight.color = new THREE.Color(this.util.allMap[this.util.selectBuild].s_col || "#ffffff");
this.hemiLight.intensity = this.util.allMap[this.util.selectBuild].a_int || 0.2;
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.15;
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.shadow = shadow != undefined ? shadow : this.util.options.shadow;
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 : [];
this.renderer.shadowMap.enabled = this.util.options.shadow;
this.shawLight.castShadow = this.util.options.shadow; //阴影
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 = _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; //贴图需要转换成 线性编码
}
}
});
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 == "all" ||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 = 80;
collada2.scene.applyMatrix4(_this.sceneGap.matrix);
collada2.scene.renderOrder = 200;
collada2.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; //贴图需要转换成 线性编码
}
if(child.material.roughness && child.material.roughness<0.8){
child.material.roughness=0.8;
}
}
});
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();
_this.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.glb",
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;
collada.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; //贴图需要转换成 线性编码
}
if(child.material.roughness && child.material.roughness<0.8){
child.material.roughness=0.8;
}
}
});
new THREE.GLTFLoader().load(_this.util.beforPath + "static/img/elevatorDown.glb",
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;
collada.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; //贴图需要转换成 线性编码
}
if(child.material.roughness && child.material.roughness<0.8){
child.material.roughness=0.8;
}
}
});
new THREE.GLTFLoader().load(_this.util.beforPath + "static/img/dt.glb",
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;
collada.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; //贴图需要转换成 线性编码
}
if(child.material.roughness && child.material.roughness<0.8){
child.material.roughness=0.8;
}
}
});
_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.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);
}
this.controls.saveState();
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++) {
if(!this.util.pathStateObj.facAllArr[j][k].hasOwnProperty("toState") || this.util.pathStateObj.facAllArr[j][k].toState){ //增加扶梯停靠状态
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] = 20000 +200 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder)-parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder));
graphPathObj[facP][nP] = 500 +100 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder));
dtPathObj[facP][nP] = 300 +80 *Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder)-parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder));
basePathObj[facP][nP] = 35;
} else if (this.util.pathStateObj.facAllArr[j][h].facCode == "td") {
graphPathObj[facP][nP] = 400 +80 * Math.abs( parseInt( this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder));
ftPathObj[facP][nP] = 400 +80 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder ));
dtPathObj[facP][nP] = 400 + 80 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder));
basePathObj[facP][nP] = 30 *Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt( this.util.pathStateObj.facAllArr[j][k].floorOrder ));
} else {
dtPathObj[facP][nP] = 20000 +200 * Math.abs(parseInt( this.util.pathStateObj.facAllArr[j][h].floorOrder) - parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder) );
graphPathObj[facP][nP] = 200 + 300 * Math.abs( parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder) );
ftPathObj[facP][nP] = 300 + 80 * Math.abs(parseInt(this.util.pathStateObj.facAllArr[j][h].floorOrder) -parseInt(this.util.pathStateObj.facAllArr[j][k].floorOrder));
basePathObj[facP][nP] = 20 *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;
let fIndex = 0, bIndex = 0;
this.mapArr[bIndex] = new Array();
let _this = this;
intTimer = setInterval(() => {
if (!_this.util.allMap[bIndex].buildArr[fIndex]) {
clearInterval(intTimer);
_this.initFloor();
return;
}
let floor = new FloorMap_QM(bIndex, fIndex, _this.util.allMap[bIndex].buildArr[fIndex].name );
floor.floorName = _this.util.allMap[bIndex].buildArr[fIndex].name;
floor.initDraw();
floor.allObj.position.set(0, 0, 0);
if (bIndex != parseInt(_this.util.deviceObj.build) || fIndex != parseInt(_this.util.deviceObj.floor)) {
floor.allObj.visible = false;
}
_this.buildObj.add(floor.allObj);
_this.mapArr[bIndex].push(floor);
fIndex++;
if (fIndex >= _this.util.allMap[bIndex].buildArr.length) {
if (bIndex == _this.util.allMap.length - 1) {
clearInterval(intTimer);
let pathData = _this.util.allMap[parseInt(_this.util.deviceObj.build)].buildArr[parseInt(_this.util.deviceObj.floor)].mapData.path;
if (_this.util.deviceObj.xaxis) {
_this.mapArr[parseInt(_this.util.deviceObj.build)][parseInt(_this.util.deviceObj.floor)].setStartSite(_this.util.deviceObj.xaxis,_this.util.deviceObj.yaxis, parseInt(_this.util.shopHeight) + 20);
} else {
if (parseInt(_this.util.deviceObj.node) != -1) {
pathData && pathData.nodes.sort(_this.util.sortNode);
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;
} else {
console.warn("初始化点位失败");
}
_this.mapArr[parseInt(_this.util.deviceObj.build)][parseInt(_this.util.deviceObj.floor)].setStartSite(_this.util.deviceObj.xaxis,_this.util.deviceObj.yaxis,parseInt(_this.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("touchmove", this.mouseMove);
this.ele.removeEventListener("click", this.onMouseClickBox); //地图点击
this.ele.removeEventListener("touchend", this.mouseUp);
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) : 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") {
if(obj.userData.show == "all"){
obj.element.style.visibility = "visible";
}else{
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.CSSObject.traverse((obj) => {
if (obj.element && obj.userData.type == "dirLabel") {
obj.element.children[0].children[1].innerText = lang == "en" ? obj.element.dataset.nameEn : obj.element.dataset.name;
}
});
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 = sopce.util.options.shadow;
child.receiveShadow = sopce.util.options.shadow;
if (child.material.map) {
child.material.map.encoding = THREE.LinearEncoding; //贴图需要转换成 线性编码
}
if (sopce.util.modelStr[sopce.index].colorModel === "gama") {
child.material.color.convertGammaToLinear(0.6);
}
if(child.material.roughness && child.material.roughness<0.8){
child.material.roughness=0.8;
}
}
});
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 = 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.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 = 90;
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; //贴图需要转换成 线性编码
}
if(child.material.roughness && child.material.roughness<0.8){
child.material.roughness = 0.8;
}
}
});
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.changeBuild(this.util.deviceObj.build, this.util.deviceObj.floor);
//初始化方向为第一人称方向
this.util.options.deviceAng && this.rotationAngle(this.util.deviceObj.angle);
this.startRender();
setTimeout(() => {
Map_QM.ele.addEventListener("touchmove", Map_QM.mouseMove);
Map_QM.ele.addEventListener("touchend", Map_QM.mouseUp);
Map_QM.ele.addEventListener("click", Map_QM.onMouseClickBox); //地图点击
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 blc = this.util.allMap[buildOrder].scale || 10; //每米多少像素
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 +'":'+parseFloat(pathData.nodes[i]["list"][n].cost/blc).toFixed(2) +",";
}
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 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();
Map_QM.util.options.deviceAng && Map_QM.rotationAngle(Map_QM.util.deviceObj.angle);
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);
} else {
Map_QM.camera = Map_QM.cameraOrtho;
Map_QM.controls.object = Map_QM.camera;
Map_QM.shawLight.castShadow = false;
Map_QM.controls.maxPolarAngle = 0;
Map_QM.changeIconState(state);
}
},
changeIconState: function (state, fIndex = -1) {
iconState = state;
fIndex = fIndex === -1 ? Map_QM.util.selectFloor : fIndex;
if(!Map_QM.mapArr || !Map_QM.mapArr[Map_QM.util.selectBuild]){
return;
}
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 = "block");
}
}
});
}
}
}catch(e){
window.captureException && window.captureException(e);
console.log(e);
}
if (Map_QM.qiModel) {
Map_QM.qiModel.visible = state == "3d" ? true : false;
Map_QM.qiModel.children[0].children[0].visible= Map_QM.util.pathStateObj.isPathState ?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);
buildOrder = buildOrder == -1 ? parseInt(Map_QM.util.selectBuild) : buildOrder;
Map_QM.clearFloor(Map_QM.util.selectFloor);
this.changeBuildInner(buildOrder, floorOrder);
},
changeBuildInner: function (build = -1, fIndex = -1) {
fIndex = fIndex == -1 ? 0 : fIndex;
build = build == -1 ? parseInt(Map_QM.util.selectBuild) : build;
Map_QM.util.selectBuild = build;
Map_QM.changeFloorInner(build, fIndex); //结束后切换楼层
},
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.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) {
clearTimeout(actionTime); //清理导航
if (!Map_QM.buildObj.visible) {
return;
}
Map_QM.util.isMorePath = false;
Map_QM.util.pathStateObj.isPathState = false;
//Map_QM.changeStartPoint();
isShowElement = true;
allJU = true;
try{
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(fIndex);
Map_QM.elementDestroy("all");
if (fIndex != -1) {
Map_QM.changeFloorInner(-1, fIndex, callBack);
}
}catch(e){
}
},
/**
* @api {方法} bindingShop(mesh,shop,isBinding) 绑定或解绑店铺
* @apiGroup 地图交互
* @apiDescription 给3D对象绑定数据
* @apiVersion 4.0.0
*
* @apiParam {Object3D} mesh 3D对象
* @apiParam {Object} shop 要绑定的数据对象(houseNumber是必需属性)。解绑可以不传
* @apiParam {Boolean} isBinding 默认true。 true是绑定,false是解绑
*
* @apiSampleRequest off
* @apiParamExample 请求示例
*
* Map_QM.bindingShop(mesh, {shopName:"shop",houseNumber:"L101",color:"", ...},true);
*/
bindingShop: function (mesh, shop, isBinding = true) {
if (!isBinding || (shop && shop.houseNumber)) {
for (let i = 0; i < Map_QM.util.allMap.length; i) {
for (let j = 0; j < Map_QM.util.allMap[i].buildArr.length; j++) {
let shopArea = Map_QM.util.allMap[i].buildArr[j].mapData.shopArea;
for (let k = 0; k < shopArea.length; k++) {
if (shopArea[k].id === mesh.userData.id) {
if (isBinding) {
shopArea[k].name = shop.houseNumber; //修改地图原始数据的box名称
mesh.userData.shopData = shop;
mesh.name = shop.houseNumber;
if (shop.color) {
// 替换材质
mesh.userData.initMaterial = mesh.material;
let meshMat = new THREE.MeshStandardMaterial({
color: shop.color,
transparent: true,
opacity: mesh.material.opacity,
side: THREE.DoubleSide,
depthTest: true,
emissive : 0x000000,
roughness:0.8
});
Map_QM.util.meshMaterialArr.push(meshMat);
mesh.material = meshMat;
}
//添加名称标签
let shopLabel = Map_QM.util.addMapLabel(shop.shopName, shop.shopName, shop.houseNumber);
shopLabel.position.set(mesh.xaxis >> 0, (-1 * mesh.yaxis) >> 0, mesh.zaxis);
Map_QM.mapArr[mesh.userData.build][mesh.userData.floor].labelObj.add(shopLabel);
Map_QM.updateRender();
Map_QM.collLabel();
} else {
shopArea[k].name = "shop";
mesh.userData.shopData = {};
if (mesh.userData.initMaterial) {
mesh.material = mesh.userData.initMaterial;
}
//删除文本标签
let labObj = Map_QM.mapArr[mesh.userData.build][mesh.userData.floor].labelObj.children;
for (let j = 0; j < labObj.length; j++) {
if (labObj[j].name == mesh.name) {
if (labObj[j].element && labObj[j].element.parentNode) {
labObj[j].element.parentNode.removeChild(labObj[j].element);
}
Map_QM.mapArr[mesh.userData.build][mesh.userData.floor].labelObj.remove(labObj[j]);
break;
}
}
}
return;
}
}
}
}
}
},
/**
* @api {方法} getAllIcon() 获取所有Icon
* @apiGroup 地图数据
* @apiDescription 获取所有Icon
* @apiVersion 2.0.0
* @apiParam {int} floorOrder 楼层编号(默认 所有楼层)
*
* @apiSampleRequest off
*
*/
getAllIcon: function (floorOrder = -1) {
let icons = new Array();
if (floorOrder != -1) {
let bd = Map_QM.util.selectBuild;
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.name||sers[n].userData.title;
let titleEn = sers[n].userData.nameEn || 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.name||sers[n].userData.title;
let titleEn = sers[n].userData.nameEn || 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) {
Map_QM.elementDestroy("dirLabel",true);
if (Map_QM.util.initModelArr.length > 0) {
Map_QM.controls.setDistance(Map_QM.util.changeDist.inner - 25);
Map_QM.controls.update();
}
fIndex = fIndex != -1 ? fIndex : Map_QM.util.deviceObj.floor;
build = build != -1 ? build : Map_QM.util.selectBuild;
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 = "block");
});
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;
if (Map_QM.util.options.shadow) {
TweenMax.fromTo( Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.position,
0.2,
{ z: Map_QM.util.options.fSpace },
{ z: 0, ease: Cubic.easeIn,
onComplete: function () {
Map_QM.timeOutInit();
if (callBack) callBack();
},
}
);
} else {
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 (this.util.selectBuild != this.util.deviceObj.build || this.util.selectFloor != this.util.deviceObj.floor) {
this.changeFloorInner(this.util.deviceObj.build, this.util.deviceObj.floor);
}
this.onInnerMeDir();
},
onInnerMeDir: function () {
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, false );
} else {
Map_QM.mapToPoint(0, 0, 0, false);
}
Map_QM.rotationAngle(Map_QM.util.deviceObj.angle);
Map_QM.controls.setZoom(2);
Map_QM.controls.enableRotate = false;
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(true);
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});
} else {
mapState = "out";
}
Map_QM.rotateAngle(70);
Map_QM.controls.autoRotate = 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.reset();
Map_QM.controls.setDistance(Map_QM.util.changeDist.outner + 25);
Map_QM.controls.update();
Map_QM.disPlayEvent(true);
},
toPeripheryInner: function () {
TweenMax.killAll(true);
Map_QM.emitChangeMap("periphery");
Map_QM.controls.autoRotate = false;
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.reset();
Map_QM.controls.setDistance(Map_QM.util.changeDist.inner - 25);
Map_QM.controls.update();
Map_QM.disPlayEvent(true);
},
toMallInner: function () {
isShowElement = true;
TweenMax.killAll(true);
Map_QM.emitChangeMap("mall");
Map_QM.controls.autoRotate = false;
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");
Map_QM.controls.autoRotate = false;
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();
},
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) {
if(obj.userData.show == "all"){
obj.element.style.visibility = "visible";
obj.element.style.display = "block";
}else{
obj.element.style.visibility = obj.userData.show == lang ? "visible" : "hidden";
obj.element.style.display = obj.userData.show == language ? "block" : "none";
}
} 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) {
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, iskill=true, onCompleteFun=null) {
let tag0 = Map_QM.controls.target.clone();
let pos0 = Map_QM.controls.object.position.clone();
let vct = new THREE.Vector3(mapX, -1 * mapY, mapZ);
vct.applyMatrix4(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].floorObj.matrix);
vct.applyMatrix4(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.matrix);
vct.applyMatrix4(Map_QM.buildObj.matrix);
vct.applyMatrix4(Map_QM.sceneGap.matrix);
let oldObj = {x:tag0.x, y:tag0.y, z:tag0.z, cx:pos0.x, cy:pos0.y, cz: pos0.z};
if(iskill){
TweenMax.killAll(true);
TweenMax.to(oldObj, 0.5, {
x: vct.x,
y: vct.y,
z: vct.z,
cx: pos0.x + (vct.x - tag0.x),
cy: pos0.y + (vct.y - tag0.y),
cz: pos0.z + (vct.z - tag0.z),
ease: Quad.easeOut,
onUpdate: function () {
let vt = new THREE.Vector3(oldObj.x, oldObj.y, oldObj.z);
Map_QM.controls.target = vt;
Map_QM.controls.object.position.set(oldObj.cx, oldObj.cy, oldObj.cz);
Map_QM.controls.object.lookAt(vt);
Map_QM.controls.update();
},
onComplete:function(){
let vt = new THREE.Vector3(oldObj.x, oldObj.y, oldObj.z);
Map_QM.controls.target = vt;
Map_QM.controls.object.position.set(oldObj.cx, oldObj.cy, oldObj.cz);
Map_QM.controls.object.lookAt(vt);
Map_QM.controls.update();
onCompleteFun && onCompleteFun();
}
});
}else{ //立即执行
Map_QM.controls.target = vct;
Map_QM.controls.object.position.set(pos0.x + (vct.x - tag0.x), pos0.y + (vct.y - tag0.y), pos0.z + (vct.z - tag0.z));
Map_QM.controls.object.lookAt(vct);
Map_QM.controls.update();
}
return vct;
},
/**
* @api {方法} onShowDeviceSite() 地图方向复位
* @apiGroup 地图显示
* @apiDescription 地图方向复位
* @apiVersion 4.0.0
*
* @apiSampleRequest off
*
* @apiParamExample 请求示例
*
* Map_QM.onShowDeviceSite();
*
*/
onShowDeviceSite: function () {
this.changeBuild(this.util.deviceObj.build,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, false);
}
},
// 一个地方调用
tweenMoveCameraBy2D: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,true,()=>{
if (Map_QM.util.pathStateObj.isPathPlay && _selfFindPath) {
_selfFindPath.pathPlay.isPlay = true;
}
});
}else{
if (Map_QM.util.pathStateObj.isPathPlay && _selfFindPath) {
_selfFindPath.pathPlay.isPlay = true;
}
}
},
/**
* 方向复位
*/
resetMeDir: function () {
this.changeMapState("3d");
this.controls.minAzimuthAngle = -Infinity;
this.controls.maxAzimuthAngle = Infinity;
this.shawLight.castShadow = this.util.options.shadow;
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(Map_QM.guide){
if (pathCameraState == "2D") {
//2D导航
Map_QM.onShowMeDir();
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.enableRotate = false;
} else {
Map_QM.resetMeDir();
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;
if (Map_QM.util.options.inArea && iconState == "3d") {
Map_QM.onShowLocalSite(new Map_QM.util.Point(Map_QM.selectShop.xaxis, Map_QM.selectShop.yaxis));
}
TweenMax.to(Map_QM.selectShop.scale, 0.5, {
z: 3, repeat: 4, yoyo: true, ease: Cubic.easeIn,
onComplete: function () {
Map_QM.selectShop && TweenMax.to(Map_QM.selectShop.scale, 0.5, { z: 1 });
},
});
}
},
/**
* @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 {方法} drawCurveLine(startShop,endShop,color) 绘制引导线
* @apiGroup 地图交互
* @apiDescription 绘制引导线
* @apiVersion 4.0.0
*
* @apiParam {string/Array} startShop 起始店铺编号或编号数组
* @apiParam {string/Array} endShop 终点店铺编号或编号数组
* @apiParam {string} color 绘制颜色 (默认 "#0099ff")
*
* @apiSampleRequest off
*
* @apiParamExample 请求示例
* //绘制一到多
* Map_QM.drawCurveLine("L125",["L117","L127","L130"],"#2246d8")
* //绘制多到一
* Map_QM.drawCurveLine(["L117","L127","L130"],"L125","#66ffff")
*
*/
drawCurveLine: function (startShop, endShop, color = "#3969f7") {
let sp, ep, cp1, cp2;
hasLine = true;
if (Array.isArray(startShop) && Array.isArray(endShop)) {
return { msg: "只能有一个数组" };
}
if (Array.isArray(startShop)) {
//如果是数组
endShop = Map_QM.shopNumToNavPoint({ houseNumber: endShop }, "shop");
for (let i = 0; i < startShop.length; i++) {
startShop[i] = Map_QM.shopNumToNavPoint({houseNumber: startShop[i] }, "shop");
sp = new THREE.Vector3(startShop[i].xaxis, -1 * startShop[i].yaxis, Map_QM.util.shopHeight);
ep = new THREE.Vector3(endShop.xaxis, -1 * endShop.yaxis, Map_QM.util.shopHeight);
let s = Math.sqrt((endShop.xaxis - startShop[i].xaxis) * (endShop.xaxis - startShop[i].xaxis) + (endShop.yaxis - startShop[i].yaxis) * (endShop.yaxis - startShop[i].yaxis));
cp1 = new THREE.Vector3(startShop[i].xaxis + (endShop.xaxis - startShop[i].xaxis)/3, -1 * startShop[i].yaxis - (endShop.yaxis - startShop[i].yaxis)/3,Map_QM.util.shopHeight + s/5);
cp2 = new THREE.Vector3(endShop.xaxis, -1 * endShop.yaxis, Map_QM.util.shopHeight + s/3);
Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].lineObj.add(Map_QM.drawToLine(sp, ep, s/10, color, cp1, cp2));
}
} else {
startShop = Map_QM.shopNumToNavPoint({ houseNumber: startShop }, "shop");
if (Array.isArray(endShop)) {
//如果是数组
for (let i = 0; i < endShop.length; i++) {
endShop[i] = Map_QM.shopNumToNavPoint({ houseNumber: endShop[i] }, "shop");
sp = new THREE.Vector3(startShop.xaxis, -1 * startShop.yaxis, Map_QM.util.shopHeight);
ep = new THREE.Vector3( endShop[i].xaxis, -1 * endShop[i].yaxis, Map_QM.util.shopHeight);
let s = Math.sqrt((endShop[i].xaxis - startShop.xaxis) *(endShop[i].xaxis - startShop.xaxis) +(endShop[i].yaxis - startShop.yaxis) *(endShop[i].yaxis - startShop.yaxis));
cp1 = new THREE.Vector3(startShop.xaxis+(endShop[i].xaxis-startShop.xaxis)/3, -1*startShop.yaxis-(endShop[i].yaxis-startShop.yaxis)/3, Map_QM.util.shopHeight+s/5);
cp2 = new THREE.Vector3(endShop[i].xaxis, -1*endShop[i].yaxis, Map_QM.util.shopHeight+s/3);
Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].lineObj.add(Map_QM.drawToLine(sp, ep, s/10, color, cp1, cp2));
}
} else {
endShop = Map_QM.shopNumToNavPoint({ houseNumber: endShop }, "shop");
sp = new THREE.Vector3(startShop.xaxis,-1 * startShop.yaxis, Map_QM.util.shopHeight);
ep = new THREE.Vector3( endShop.xaxis, -1 * endShop.yaxis, Map_QM.util.shopHeight);
let s = Math.sqrt((endShop.xaxis - startShop.xaxis) *(endShop.xaxis - startShop.xaxis) +(endShop.yaxis-startShop.yaxis) *(endShop.yaxis - startShop.yaxis));
cp1 = new THREE.Vector3(startShop.xaxis+(endShop.xaxis - startShop.xaxis)/3, -1*startShop.yaxis-(endShop.yaxis-startShop.yaxis)/3, Map_QM.util.shopHeight+s/5);
cp2 = new THREE.Vector3(endShop.xaxis, -1*endShop.yaxis, Map_QM.util.shopHeight + s/3 );
Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].lineObj.add(Map_QM.drawToLine(sp, ep, s/10, color, cp1, cp2));
}
}
},
drawToLine: function (startPoint, endPoint, dash = 50, color = 0x2269dd, ctrlPoint1 = null, ctrlPoint2 = null) {
let curve = new THREE.CubicBezierCurve3(startPoint,ctrlPoint1,ctrlPoint2,endPoint);
let points = curve.getPoints(dash);
let colorChange = [];
for (let i = 1; i < 7; i += 2) {
colorChange.push(parseInt("0x" + color.slice(i, i+2))/255);
}
let flyLine = createFlyCurve(points, new THREE.Vector3(colorChange[0], colorChange[1], colorChange[2]), false);
flyLine.userData.type = "toLine";
return flyLine;
},
/**
* @api {方法} drawColumnar(source,property) 绘制柱状图
* @apiGroup 地图交互
* @apiDescription 绘制柱状图
* @apiVersion 4.0.0
*
* @apiParam source 起始店铺编号或编号数组
* @apiParam property 控制参数对象
*
* @apiSampleRequest off
*
* @apiParamExample 请求示例
* //绘制多个
* Map_QM.drawColumnar(["L117","L127","L130"],{"height":200,"width":20,"color":"#2246d8"})
* //绘制单个
* Map_QM.drawColumnar("L125",{"height":200,"width":20,"color":"#2246d8"})
*/
drawColumnar: function (source, property) {
if (Array.isArray(source)) {
if (source.length == 0) {
return { msg: "不能解析空数组" };
}
for (let i = 0; i < source.length; i++) {
Map_QM.drawOnlyColumer(source[i], property);
}
} else {
Map_QM.drawOnlyColumer(source, property);
}
},
drawOnlyColumer: function (houseNumber, property) {
if (houseNumber.trim() != "" && property) {
let endShop = Map_QM.shopNumToNavPoint({ houseNumber: houseNumber }, "shop");
let geometry = new THREE.BoxGeometry(property.width * 2, property.width * 2, property.width * 2);
let c = new THREE.Color(property.color);
let material;
let color2 = new THREE.Color(property.color);
for (let k = 0; k < Map_QM.util.meshMaterialArr.length; k++) {
if (Map_QM.util.meshMaterialArr[k].color && Map_QM.util.meshMaterialArr[k].color.equals(color2) && Map_QM.util.meshMaterialArr[k].isShaderMaterial) {
material = Map_QM.util.meshMaterialArr[k];
}
}
if (!material) {
material = new THREE.ShaderMaterial({
uniforms: {
targetColor: { value: new THREE.Vector3(c.r, c.g, c.b) },
height: { value: property.height / 5 },
},
transparent: true,
//depthTest:false,
vertexShader: [
"varying vec3 modelPos;",
"void main() {",
" modelPos = position;",
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}",
].join("\n"),
fragmentShader: [
"uniform vec3 targetColor;",
"uniform float height;",
"varying vec3 modelPos;",
"void main() {",
" gl_FragColor = vec4(targetColor.xyz,(0.9 - modelPos.y/height)*(0.9 - modelPos.y/height));",
"}",
].join("\n"),
});
Map_QM.util.meshMaterialArr.push(material);
}
let mesh = new THREE.Mesh(geometry, material);
mesh.position.set(endShop.xaxis, -1 * endShop.yaxis, property.height);
mesh.rotation.x = Math.PI / -2;
mesh.scale.setY(property.height / property.width);
let cubeEdges = new THREE.EdgesGeometry(geometry, 60);
mesh.add(new THREE.LineSegments(cubeEdges, material));
mesh.userData.type = "columer";
Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].lineObj.add(mesh);
}
},
/**
* @api {方法} removeDrawEle(type) 删除绘制元素
* @apiGroup 地图交互
* @apiDescription 删除绘制元素
* @apiVersion 4.0.0
*
* @apiParam type 传入删除的类型(默认 all) toLine--引导线 columer--柱状样式 all---所有
*
* @apiSampleRequest off
*
* @apiParamExample 请求示例
*
* Map_QM.removeDrawEle("toLine")
*
*/
removeDrawEle: function (type = "all") {
if (type == "all" || type == "toLine") {
hasLine = false;
}
for (let i = 0; i < Map_QM.mapArr.length; i++) {
for (let k = 0; k < Map_QM.mapArr[i].length; k++) {
let lineObj = Map_QM.mapArr[i][k].lineObj;
for (let j = lineObj.children.length - 1; j >= 0; j--) {
if (type == "all" || lineObj.children[j].userData.type == type) {
lineObj.remove(lineObj.children[j]);
}
}
}
}
},
setHeatMapData: function () {
let points = [];
let max = 0;
let childRen = Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].shopObj.children;
for (let i = 0; i < childRen.length; i++) {
let val = Math.random() * 100;
max = Math.max(max, val);
var point = {
x: parseInt(childRen[i].xaxis),
y: parseInt(childRen[i].yaxis),
value: val,
};
points.push(point);
}
// 准备 heatmap 的数据
const data = {max: max, data: points};
Map_QM.heatMap(data);
Map_QM.hideInnerFloorElement();
},
/**
* @api {方法} heatMap(data) 热力图
* @apiGroup 地图交互
* @apiDescription 绘制热力图
* @apiVersion 4.0.0
*
* @apiParam {object} data 热力图的绘制数据
*
* @apiSampleRequest off
*
* @apiParamExample 请求示例
*
* Map_QM.heatMap({max: 100, data: [{x:0,y:0,value:50},...]})
*/
heatMap: function (data) {
let heatMap = document.getElementById("heatmap");
Map_QM.removeHeatMap();
heatMap.style.pointerEvents = "none";
let mapW = Map_QM.util.allMap[Map_QM.util.selectBuild].mapW || 5000;
let mapH = Map_QM.util.allMap[Map_QM.util.selectBuild].mapH || 5000;
heatMap.style.width = mapW + "px";
heatMap.style.height = mapH + "px";
if (!heatmapInstance) {
heatmapInstance = h337.create({
container: heatMap,
gradient: {
1.0: "#f00",
0.9: "#e2fa00",
0.6: "#33f900",
0.3: "#0349df",
0.0: "#0f00ff",
},
radius: 120,
maxOpacity: 1,
minOpacity: 0,
});
}
if (data.data && data.data.length > 0) {
data.data.map((item) => {
item.x += mapW / 2;
item.y += mapH / 2;
});
}
heatmapInstance.setData(data);
// 获取 heatmap
let texture = new THREE.Texture(heatmapInstance._renderer.canvas);
const material = new THREE.MeshLambertMaterial({
map: texture,
transparent: true,
opacity: 1,
});
let mesh = new THREE.Mesh(new THREE.PlaneGeometry(mapW, mapH, 10),material);
Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].otherObj.add(mesh);
mesh.renderOrder = 800;
mesh.position.set(0, 0, 60);
// 更新图片
texture && (texture.needsUpdate = true);
},
/**
* @api {方法} removeHeatMap() 清除外加图层
* @apiGroup 地图交互
* @apiDescription 清除外加图层
* @apiVersion 4.0.0
*
* @apiSampleRequest off
*
* @apiParamExample 请求示例
*
* Map_QM.removeHeatMap()
*/
removeHeatMap: function () {
for (let i = 0; i < Map_QM.mapArr.length; i++) {
for (let j = 0; j < Map_QM.mapArr[i].length; j++) {
Map_QM.remove_child(Map_QM.mapArr[i][j].otherObj);
}
}
},
/**
* @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();
}
});
},
//设置相机缩放
setCameraZoom: function (cZoom, updateFun, callBack) {
cZoom = cZoom < 0 ? 1 : cZoom;
let oldObj = { zoom: Map_QM.controls.object.zoom};
TweenMax.killAll(true);
TweenMax.to(oldObj, 0.5, {
zoom: cZoom,
onUpdate: function () {
updateFun && updateFun();
Map_QM.controls.setZoom(oldObj.zoom);
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 (hasLine) {
const elapsed = Map_QM.util._clock.getElapsedTime();
uniforms.u_time.value = elapsed;
}
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") {
let shopInfo;
Map_QM.CSSObject && Map_QM.CSSObject.traverse((obj) => {
if (obj.userData.type == type) {
shopInfo = obj;
}
});
if(!shopInfo){
divObj.style.opacity = 0;
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].floorObj.matrix);
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 });
}else{
Map_QM.updateElementPosition(shopInfo, x, y, z);
}
return shopInfo;
},
addDirectionLabel:function(angle){
if(Map_QM.qiModel){
let divObj = document.createElement("div");
divObj.style.position = "absolute";
divObj.style.zIndex = 499;
divObj.dataset.name = "出发方向";
divObj.dataset.nameEn = "Starting direction";
let div0 = document.createElement("div");
div0.className = "dir_map";
divObj.appendChild(div0);
let divImg = document.createElement("div");
divImg.className = "dir-divimg";
div0.appendChild(divImg);
let img = document.createElement("img");
img.src="./static/img/jt.png";
divImg.appendChild(img);
img.style.transform=`rotate(${angle}deg)`;
let txt = document.createElement("span");
txt.innerText = "出发方向";
div0.appendChild(txt);
let toDir = new THREE.CSS2DObject(divObj);
toDir.position.set(Map_QM.qiModel.position.x, Map_QM.qiModel.position.y, Map_QM.qiModel.position.z+80);
toDir.applyMatrix4(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].floorObj.matrix);
toDir.applyMatrix4(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].allObj.matrix);
toDir.userData.type = "dirLabel";
toDir.userData.isShow = false;
toDir.userData.floor = parseInt(Map_QM.util.selectFloor);
Map_QM.CSSObject.add(toDir);
}
},
/**
* @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, z) {
if (obj.hasOwnProperty("position")) {
obj.position.set(x, -1 * y, z);
obj.applyMatrix4(Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].floorObj.matrix);
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 && (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];
if(node.element){
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)].floorObj.matrix);
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) { 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].floorObj.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); let dis = Map_QM.controls.getDistance()-100; Map_QM.controls.setDistance(dis); } } }); }, /** * @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.className = "map_label"; if (window.innerWidth > 2000) { shopDiv.style.fontSize = "16px"; } 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.MeshStandardMaterial({ color: data.color || 0xf4a460, transparent: true, opacity: 0.9, side: THREE.DoubleSide, depthTest: true, emissive : 0x000000, roughness:0.8 }); Map_QM.mapArr[Map_QM.util.selectBuild][Map_QM.util.selectFloor].floorObj.add(mesh); } renderCount = 0; }, //////////////////////////////////////////////////////////////////////////////// /** * @param {Object} e * 地图BOX点击 */ onMouseClickBox: function (event) { Map_QM.controls.autoRotate = 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 || Map_QM.util.pathStateObj.isPathState) { 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].floorObj.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.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]); return [shopArr[k].xaxis, shopArr[k].yaxis]; } } } }, //改变选中店铺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); if(Map_QM.mapArr && 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); 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.enableRotate = 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 (isChange=false) { //默认值false 则手动缩放不能切换状态 if(isChange){ 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 || !Map_QM.util.options.collision) { return; } clearTimeout(allTime); allTime = setTimeout(() => { clearTimeout(allTime); Map_QM.runTaskQueue(); }, 400); }, //世界坐标转屏幕坐标 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 = "block"; continue; } let obj = childs[i].element; obj.style.display = "block"; let labP = obj.getBoundingClientRect(); for (let j=Math.max(i-10, 0); j < i; j++) { if (childs[j].element.style.display == "block") { 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 {方法} 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.basePath,startNade,toNade); PathPoint = obj.nodes; direction.cost = Math.ceil(obj.cost / 50); direction.gap = Math.floor(obj.cost); } 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(); } } 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 = 2; //downft } else { facType = 5; } } else { if (Math.abs(parseInt(this.forShopArr[0].floor) - parseInt(this.forShopArr[1].floor)) < 3 ) { //扶梯 facType = 1; //upft } else { facType = 5; //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; } } //斜方向忽略 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 {方法} 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; } } } }, //获取目标物角度和距离 deviceObj getObjectAngle:function(objArr){ if(parseInt(Map_QM.util.startObj.node) || parseInt(Map_QM.util.startObj.node) == 0){ let pathData =Map_QM.util.allMap[parseInt(Map_QM.util.startObj.build)].buildArr[parseInt(Map_QM.util.startObj.floor)].mapData.path; pathData.nodes.sort(Map_QM.util.sortNode); 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; 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; for(let i=0;i