[Frontend][全域功能] 電梯 elevator3D Forge 遍歷遍到底程序建置 | ADHeatMaps 熱圖 roomDbid以外部傳入程序調整 | 3D 剖面框程序原以模糊比對樓層名稱改以正規化字串比對 | 取得資料庫電梯設備,根據baja訂閱移動3D電梯共用CLASS(Forge3DElevFull)程序建置 | Map to ArrObj 程序建置 | [儀錶板] 套用 Forge3DElevFull class | [能源管理] 須量用電只有電源才有程序調整 | [電梯管理] 套用 Forge3DElevFull class | [系統監控] 總攬、平面圖套用 Forge3DElevFull class

This commit is contained in:
dev01 2023-01-03 16:47:23 +08:00
parent 48b3fa8579
commit c4a1360677
8 changed files with 717 additions and 471 deletions

View File

@ -783,12 +783,13 @@
//} //}
function show3DModel() { function show3DModel() {
launchViewerNoTools(pageAct.urn, (viewer, nodeIds) => { launchViewerNoTools(pageAct.urn, (viewer) => {
nodeIds = Array.from(nodeIds); let nodeIds = allEleDevList.filter(x => !isNaN(parseInt(x.forge_dbid))).map(x => { return { devNum: x.device_number, nodeId: parseInt(x.forge_dbid) } });
$.each(nodeIds, (idx, item) => { $.each(nodeIds, (idx, item) => {
elev3DBind[item[0]] = item[1]; elev3DBind[item.devNum] = item.nodeId;
}) })
nodeIds = nodeIds.map(x => x[1]); nodeIds = nodeIds.map(x => x.nodeId);
$.each(nodeIds, function (idx, node) { $.each(nodeIds, function (idx, node) {
let options = { let options = {
element: $("#forgeViewer"), element: $("#forgeViewer"),
@ -838,7 +839,6 @@
myBaja = new subscriptionDevices(); myBaja = new subscriptionDevices();
myBaja.setSubscribeDevicesByBql(subOrdPath); myBaja.setSubscribeDevicesByBql(subOrdPath);
myBaja.setSubscribeDevicesCallBack(function (data) { myBaja.setSubscribeDevicesCallBack(function (data) {
try {
if (allEleDevList.length == 0) { if (allEleDevList.length == 0) {
return false; return false;
@ -873,9 +873,7 @@
if (subData) { if (subData) {
subData[data.point_name] = data.value; subData[data.point_name] = data.value;
} }
} catch (e) {
console.log("e", e)
}
}); });
myBaja.setSubscribeDeviceEndCallBack(function (data) { myBaja.setSubscribeDeviceEndCallBack(function (data) {

View File

@ -48,7 +48,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row flex-column col-xl-6 m-0 p-0"> <div id="elecAutoReq" class="row flex-column col-xl-6 m-0 p-0">
<div class="col-auto mb-2"> <div class="col-auto mb-2">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
@ -245,6 +245,23 @@
} }
}) })
}) })
if (type == 3) {
strHtml += `<div class="col-sm-12 col-xl-4 mb-2">
<div class="card elecCard cur-poi">
<div class="card-body">
<h4 class="card-title color-white">太陽能設備用電</h4>
<p class="card-text color-white pl-5 pr-3 d-flex justify-content-between">
<span>${elecCardConText[type]?.text1}</span>
<span id="insPow">---</span>
</p>
<p class="card-text color-white pl-5 pr-3 d-flex justify-content-between">
<span>${elecCardConText[type]?.text2}</span>
<span id="insPow">---</span>
</p>
</div>
</div>
</div>`;
}
$("#eneSubSysList").html(strHtml); $("#eneSubSysList").html(strHtml);
} }
}, null, "POST").send(); }, null, "POST").send();
@ -518,5 +535,11 @@
if (type == "1" || type == "2") { if (type == "1" || type == "2") {
$("#eneSubSysList").parent("div").hide(); $("#eneSubSysList").parent("div").hide();
} }
// 自動需量
if (type != "0") {
$("#elecAutoReq").hide();
} else {
$("#elecAutoReq").show();
}
}) })
</script> </script>

View File

@ -1,63 +1,25 @@
<style> <style>
.elevator { .elevator { background-color: #fff; min-height: 520px; }
background-color: #fff;
min-height: 520px;
}
.elevator-table-wrapper { .elevator-table-wrapper { padding: 0.8rem; }
padding: 0.8rem;
}
table.elevator-build { table.elevator-build { /*border: 1px double #000;*/ }
/*border: 1px double #000;*/
}
table.elevator-build td { table.elevator-build td { padding: 0.2rem 0.5rem; height: 50px; width: 45px; border: 1px solid #000; }
padding: 0.2rem 0.5rem;
height: 50px;
width: 45px;
border: 1px solid #000;
}
elevator .elevator-body, elevator .elevator-header { elevator .elevator-body, elevator .elevator-header { padding: 0.7rem; }
padding: 0.7rem;
}
.elevator-item { .elevator-item { position: absolute; width: 43px; height: 47px; border: 4px solid orange; }
position: absolute;
width: 43px;
height: 47px;
border: 4px solid orange;
}
.elevator-item-toup { .elevator-item-toup { border: 4px solid rgba(255,255,255,0); position: absolute; border-bottom: 0; z-index: 2; }
border: 4px solid rgba(255,255,255,0);
position: absolute;
border-bottom: 0;
z-index: 2;
}
.elevator-item-todown { .elevator-item-todown { border: 4px solid rgba(255,255,255,0); position: absolute; border-top: 0; z-index: 2; }
border: 4px solid rgba(255,255,255,0);
position: absolute;
border-top: 0;
z-index: 2;
}
.table-compact td{ .table-compact td { padding: 0.2rem 0.3rem; }
padding:0.2rem 0.3rem;
}
#emerTurn tr td:nth-child(2) { #emerTurn tr td:nth-child(2) { width: 50%; text-align: center; justify-content: center; }
width: 50%;
text-align: center;
justify-content: center;
}
#emerTurn tr td:nth-child(1) {
width:35%;
}
#emerTurn tr td:nth-child(1) { width: 35%; }
</style> </style>
<div class="d-flex"> <div class="d-flex">
@ -915,10 +877,6 @@
var subSeviceData = []; //每個設備訂閱點位值 var subSeviceData = []; //每個設備訂閱點位值
var floList = []; //每個樓層 var floList = []; //每個樓層
var elevObj = null; //左側 2D 電梯物件 var elevObj = null; //左側 2D 電梯物件
var viewer3DNodeIds = [];
var elev3DBind = {};
var elev3DOption = {};
var elev3DObj = [];
var subOrdPath = { var subOrdPath = {
"area_tag": pageAct.AreaTag, "area_tag": pageAct.AreaTag,
"building_tag": pageAct.buiTag, "building_tag": pageAct.buiTag,
@ -938,7 +896,7 @@
setBuildFloor(); setBuildFloor();
setCards(); setCards();
subDeviceSetStatus();
setEleManTable(); setEleManTable();
show3D(); show3D();
}) })
@ -948,17 +906,16 @@
} }
//baja 訂閱設備 //baja 訂閱設備
function subDeviceSetStatus() { function subDeviceSetStatus(data) {
myBaja = new subscriptionDevices();
myBaja.setSubscribeDevicesByBql(subOrdPath);
myBaja.setSubscribeDevicesCallBack(function (data) {
try {
if (allDevList.length == 0) { if (allDevList.length == 0) {
return false; return false;
} }
data.device_number = data.device_number_full; data.device_number = data.device_number_full;
let matchDevice = allDevList.filter(x => x.device_number == data.device_number)[0]; let matchDevice = allDevList.filter(x => x.device_number == data.device_number)[0];
if (!matchDevice) return;
let master = matchDevice.device_number.split("_")[5]; let master = matchDevice.device_number.split("_")[5];
//將訂閱值塞入 subSeviceData //將訂閱值塞入 subSeviceData
@ -1065,64 +1022,7 @@
subDeviceSetEleManDet(matchDevice.device_number); subDeviceSetEleManDet(matchDevice.device_number);
// 電梯管理 不服務樓層 detail // 電梯管理 不服務樓層 detail
subDeviceSetEleManNotSerFloor(master); subDeviceSetEleManNotSerFloor(master);
} catch (e) {
console.log("e", e)
}
});
myBaja.setSubscribeDeviceEndCallBack(function (data) {
let devNumArr = data.map(x => { return { devNum: x.device_number_full, priority: allDevList.filter(y => y.device_number == x.device_number_full)[0]?.priority } }).DistinctBy("devNum");
devNumArr = devNumArr.oSort("priority");
$.each(devNumArr, (idx, devObj) => {
devNum = devObj.devNum;
let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
if (subData) {
//// 左側 3D 電梯 nodeID 與 device_number match
//if (Object.keys(elev3DBind).indexOf(devNum) == -1 && viewer3DNodeIds.length != 0) {
// elev3DBind[devNum] = viewer3DNodeIds[Object.keys(elev3DBind).length];
//}
// 左側 3D 電梯 Viewer Option 設置
/*elev3DOption.nodes = Object.keys(elev3DBind).map(x => elev3DBind[x]);*/
elev3DOption.nodeId = elev3DBind[devNum];
elev3DOption.floorHeight = floList.map((x) => { return { floor: x } });
elev3DOption.floorHeight.forEach((floObj, idx) => {
if (floObj.floor.startsWith("B")) {
let floor = parseInt(floObj.floor.split("B")[1].split("F")[0]);
floObj.height = floor * -13;
} else {
let floor = parseInt(floObj.floor.split("F")[0]);
if (floor == 1) {
floObj.height = 0;
} else if (floor == 2) {
floObj.height = 14.75;
} else {
floObj.height = (14.75 + ((floor - 2) * 9.75));
}
}
})
if (isFirstLoad3D == false && elev3DObj.length != 0) {
let elevObj = elev3DObj.filter(x => x.nodeId == elev3DBind[devNum])[0];
if (!elevObj.id) {
elevObj.id = devNum;
}
elevObj.obj = Object.assign(elevObj.obj, elev3DOption);
elevObj.obj.init(function () {
let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == elev3DBind[devNum]);
frags.forEach((fragProxy) => {
fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
fragProxy.frag.updateAnimTransform();
})
elevObj.obj.viewer.impl.sceneUpdated(true);
});
}
}
})
reloadEleManTable(setEleManTabDataFromBaja());
$(loadEle).Loading("close");
})
} }
// baja 訂閱 變更 電梯管理 Table // baja 訂閱 變更 電梯管理 Table
@ -1200,15 +1100,6 @@
elevObj.setElevFloor(matchDevice.device_number, subData["CP"]); elevObj.setElevFloor(matchDevice.device_number, subData["CP"]);
} }
if (elev3DObj.length != 0) {
let elevObj = elev3DObj.filter(x => x.nodeId == elev3DBind[devNum])[0];
if (elevObj && elevObj.id) {
elevObj.obj.setElevatorFloor(subData["CP"])
elevObj.obj.movElevator();
}
}
elevObj.setEleMovStatus(matchDevice.device_number, subData["RD"] == "UP" ? 1 : subData["RD"] == "DOWN" ? 2 : 0);
//現在樓層 //現在樓層
if (subData["CP"]) { if (subData["CP"]) {
$(`#imdStaTable_${devNum} [name=curFloor]`).text(subData["CP"]); $(`#imdStaTable_${devNum} [name=curFloor]`).text(subData["CP"]);
@ -1249,7 +1140,6 @@
let sendData = { let sendData = {
sub_system_tag: pageAct.sysSubTag, sub_system_tag: pageAct.sysSubTag,
building_tag: pageAct.buiTag, building_tag: pageAct.buiTag,
floor_tag: pageAct.floTag,
}; };
objSendData.Data = sendData; objSendData.Data = sendData;
ytAjax = new YourTeam.Ajax(url, objSendData, function (res) { ytAjax = new YourTeam.Ajax(url, objSendData, function (res) {
@ -2482,56 +2372,22 @@
//載入3D模型 //載入3D模型
function load3DModel() { function load3DModel() {
launchViewer(pageAct.urn, (viewer, nodeIds) => { launchViewer(pageAct.urn, (viewer) => {
nodeIds = Array.from(nodeIds); let elevOption = {
$.each(nodeIds, (idx, item) => { selector: "#forgeViewer",
elev3DBind[item[0]] = item[1];
})
nodeIds = nodeIds.map(x => x[1]);
$.each(nodeIds, function (idx, node) {
let options = {
element: $("#forgeViewer"),
viewer: viewer, viewer: viewer,
nodeId: node, ordPath: subOrdPath
floorHeight: elev3DOption.floorHeight ?? [],
inited: function () {
}
}
let elevator3DObj = new elevator3D(options);
let devNum = Object.keys(elev3DBind).filter(x => elev3DBind[x] == node)[0];
let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
if (elev3DObj.filter(x => x.nodeId == node).length == 0) {
elev3DObj.push({ id: devNum, nodeId: node, obj: elevator3DObj });
} }
if (subData) { // 電梯移動訂閱程序載入
let elevObj = elev3DObj.filter(x => x.nodeId == node)[0]; let forge3DElev = new Forge3DElevFull(elevOption);
if (!elevObj.id) { forge3DElev.bajaEndCallback = function () {
elevObj.id = devNum; endPageLoading();
} }
elevObj.obj = Object.assign(elevObj, elevator3DObj ?? {}) forge3DElev.bajaChaCallback = function (data) {
elevObj.obj.init(function () { subDeviceSetStatus(data);
let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == node);
frags.forEach((fragProxy) => {
fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
fragProxy.frag.updateAnimTransform()
})
elevObj.obj.viewer.impl.sceneUpdated(true);
})
} }
}) forge3DElev.init();
//let elevator = elev3DObj[0];
//elevator.obj.setElevatorFloor(3)
//elevator.obj.movElevator()
//setElevatorSpeed(0.2)
//setElevatorFloor(2)
//requestAnimationFrame(movElevator);
}); });
} }

View File

@ -44,7 +44,7 @@
getFloDevList(); getFloDevList();
setLightColor(); setLightColor();
} }
if (arr.indexOf(5) != -1) { if (arr.indexOf(3) != -1) {
getHotspotPoint(() => { getHotspotPoint(() => {
show3DModel(data.urn_3D); show3DModel(data.urn_3D);
}); });
@ -82,7 +82,7 @@
</div>`; </div>`;
break; break;
case 5: case 3:
strHtml = `<div name="forgeViewer" style="height:85vh;"></div>`; strHtml = `<div name="forgeViewer" style="height:85vh;"></div>`;
break; break;
} }
@ -105,6 +105,7 @@
if (!matchDevice) { if (!matchDevice) {
return false; return false;
} }
let norDevPoiName = matchDevice.device_normal_point_name; let norDevPoiName = matchDevice.device_normal_point_name;
let cloDevPoiName = matchDevice.device_close_point_name; let cloDevPoiName = matchDevice.device_close_point_name;
let errDevPoiName = matchDevice.device_error_point_name; let errDevPoiName = matchDevice.device_error_point_name;
@ -132,7 +133,7 @@
}); });
} }
//根據 data-type 設置顏色 (判斷後台是否有設定,若無則帶預設)
function setLightColor() { function setLightColor() {
$("[data-light-type]").each((index, ele) => { $("[data-light-type]").each((index, ele) => {
let type = $(ele).data("light-type"); let type = $(ele).data("light-type");
@ -214,7 +215,6 @@
}, null, "POST").send(); }, null, "POST").send();
} }
// 取得根據棟別顯示左右區塊資訊
function getBuildMenu(callback = null) { function getBuildMenu(callback = null) {
let url = baseApiUrl + "/api/Device/GetBuildMenu"; let url = baseApiUrl + "/api/Device/GetBuildMenu";
let sendData = { let sendData = {
@ -283,9 +283,25 @@
}) })
} }
let elevOption = {
selector:"[name=forgeViewer]",
viewer: viewer,
ordPath: {
"area_tag": pageAct.AreaTag,
"building_tag": pageAct.buiTag,
},
}
// 電梯移動訂閱程序載入
let forge3DElev = new Forge3DElevFull(elevOption);
forge3DElev.bajaEndCallback = function () {
endPageLoading();
}
forge3DElev.init();
}, "[name=forgeViewer]"); }, "[name=forgeViewer]");
} }
function getHotspotPoint(callback = null) { function getHotspotPoint(callback = null) {
let url = baseApiUrl + "/api/GetDevForCor"; let url = baseApiUrl + "/api/GetDevForCor";
let sendData = { let sendData = {

View File

@ -31,7 +31,6 @@
var allDeviceRowData = []; //所有設備原始資料 var allDeviceRowData = []; //所有設備原始資料
var global_emergency_alarm_device_number = []; var global_emergency_alarm_device_number = [];
var zoomToggle = 3; var zoomToggle = 3;
$(function () { $(function () {
getHotspotPoint(() => { getHotspotPoint(() => {
show3DModel(pageAct.urn); show3DModel(pageAct.urn);
@ -469,6 +468,110 @@
}); });
} }
// 電梯 3D 位置呈現
function set3DElevPos(viewer) {
let nodeIds = allElevDevList.filter(x => !isNaN(parseInt(x.forge_dbid))).map(x => { return { devNum: x.device_number, nodeId: parseInt(x.forge_dbid) } });
$.each(nodeIds, (idx, item) => {
elev3DBind[item.devNum] = item.nodeId;
})
nodeIds = nodeIds.map(x => x.nodeId);
$.each(nodeIds, function (idx, node) {
let options = {
element: $("[name=forgeViewer]"),
viewer: viewer,
nodeId: node,
floorHeight: elev3DOption.floorHeight ?? [],
inited: function () {
}
}
let elevator3DObj = new elevator3D(options);
let devNum = Object.keys(elev3DBind).filter(x => elev3DBind[x] == node)[0];
let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
if (elev3DObj.filter(x => x.nodeId == node).length == 0) {
elev3DObj.push({ id: devNum, nodeId: node, obj: elevator3DObj });
}
if (subData) {
let elevObj = elev3DObj.filter(x => x.nodeId == node)[0];
if (!elevObj.id) {
elevObj.id = devNum;
}
elevObj.obj = Object.assign(elevObj, elevator3DObj ?? {})
elevObj.obj.init(function () {
let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == node);
frags.forEach((fragProxy) => {
fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
fragProxy.frag.updateAnimTransform()
})
elevObj.obj.viewer.impl.sceneUpdated(true);
})
}
})
}
// 電梯 3D Option 設置
function set3DElevOpt(data) {
let devNumArr = data.map(x => { return { devNum: x.device_number_full, priority: allElevDevList.filter(y => y.device_number == x.device_number_full)[0]?.priority } }).DistinctBy("devNum");
devNumArr = devNumArr.oSort("priority");
$.each(devNumArr, (idx, devObj) => {
devNum = devObj.devNum;
let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
if (subData) {
//// 左側 3D 電梯 nodeID 與 device_number match
//if (Object.keys(elev3DBind).indexOf(devNum) == -1 && viewer3DNodeIds.length != 0) {
// elev3DBind[devNum] = viewer3DNodeIds[Object.keys(elev3DBind).length];
//}
// 左側 3D 電梯 Viewer Option 設置
/*elev3DOption.nodes = Object.keys(elev3DBind).map(x => elev3DBind[x]);*/
elev3DOption.nodeId = elev3DBind[devNum];
elev3DOption.floorHeight = floList.map((x) => { return { floor: x } });
elev3DOption.floorHeight.forEach((floObj, idx) => {
if (floObj.floor.startsWith("B")) {
let floor = parseInt(floObj.floor.split("B")[1].split("F")[0]);
floObj.height = floor * -13;
} else {
let floor = parseInt(floObj.floor.split("F")[0]);
if (floor == 1) {
floObj.height = 0;
} else if (floor == 2) {
floObj.height = 14.75;
} else {
floObj.height = (14.75 + ((floor - 2) * 9.75));
}
}
})
if (elev3DObj.length != 0) {
let elevObj = elev3DObj.filter(x => x.nodeId == elev3DBind[devNum])[0];
if (!elevObj.id) {
elevObj.id = devNum;
}
elevObj.obj = Object.assign(elevObj.obj, elev3DOption);
elevObj.obj.init(function () {
let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == elev3DBind[devNum]);
frags.forEach((fragProxy) => {
fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
fragProxy.frag.updateAnimTransform();
})
elevObj.obj.viewer.impl.sceneUpdated(true);
});
}
}
})
}
// //訂閱設備的回傳值,並塞到全域變數 // //訂閱設備的回傳值,並塞到全域變數
// function subscribeCallBack(change_device, is_need_reset = false) { // function subscribeCallBack(change_device, is_need_reset = false) {
// if (change_device != undefined && change_device != null) { // if (change_device != undefined && change_device != null) {
@ -934,7 +1037,7 @@
launchViewerForHotspot(urn, (viewer, nodeIds) => { launchViewerForHotspot(urn, (viewer, nodeIds) => {
let nextFloor = getNextFloor(pageAct.floGuid); let nextFloor = getNextFloor(pageAct.floGuid);
let curFloTag = pageAct.floTag; let curFloTag = pageAct.floTag;
debugger
if (!nextFloor) { if (!nextFloor) {
toast_warning("超出樓層範圍"); toast_warning("超出樓層範圍");
return; return;
@ -949,6 +1052,20 @@
getLevelsData(curFloTag, nextFloor); getLevelsData(curFloTag, nextFloor);
setHeatMap(); setHeatMap();
let elevOption = {
viewer: viewer,
ordPath: {
"area_tag": pageAct.AreaTag,
"building_tag": pageAct.buiTag,
}
}
// 電梯移動訂閱程序載入
let forge3DElev = new Forge3DElevFull(elevOption);
forge3DElev.bajaEndCallback = function () {
endPageLoading();
}
forge3DElev.init();
}); });
} }

View File

@ -134,6 +134,7 @@ class elevator3D {
this.viewer = option.viewer; this.viewer = option.viewer;
this.nodeId = option.nodeId; this.nodeId = option.nodeId;
this.speed = option.speed ?? 0.03; this.speed = option.speed ?? 0.03;
this.tagValue = option.tagValue ?? "";
this.fragProxys = []; this.fragProxys = [];
this.fragProxy = null; this.fragProxy = null;
this.initCallback = option.inited ?? null; this.initCallback = option.inited ?? null;
@ -143,7 +144,26 @@ class elevator3D {
this.init(); this.init();
} }
setTreeFrag = function (callback) { // 定義遍歷模型中所有片段的異步函數
enumFragments = function (nodeId) {
return new Promise((resolve, reject) => {
// 定義結果陣列
let result = [];
// 使用 InstanceTree.enumNodeFragments 遍歷模型中的所有片段
this.viewer?.model?.getData().instanceTree.enumNodeFragments(nodeId,(fragId) => {
// 將遍歷到的片段 ID 添加到結果陣列中
result.push(fragId);
}, (nodeId) => {
// 如果遍歷到的節點是葉節點,则返回 true表示繼續遍歷該節點的片段
return model.getData().instanceTree.isLeaf(nodeId);
});
// 将结果陣列作為参数调用 resolve 函数
resolve(result);
});
}
// 設置樹狀結構中片段
setTreeFrag = async function (callback) {
let tree = this.viewer?.model?.getData().instanceTree; let tree = this.viewer?.model?.getData().instanceTree;
if (!tree) { if (!tree) {
return; return;
@ -152,36 +172,42 @@ class elevator3D {
let nodeId = this.nodeId; let nodeId = this.nodeId;
if (nodeId) { if (nodeId) {
let childCnt = tree.getChildCount(nodeId); // 刪除 fragmentProxys 中與當前 nodeId 相同的項目
let curIdx = 1;
this.fragProxys.filter(x => x.nodeId == nodeId).forEach((x) => { this.fragProxys.filter(x => x.nodeId == nodeId).forEach((x) => {
let idx = this.fragProxys.indexOf(x); let idx = this.fragProxys.indexOf(x);
this.fragProxys.splice(idx, 1); this.fragProxys.splice(idx, 1);
}) })
tree.enumNodeFragments(nodeId, (frag) => {
// 遍歷當前 nodeId 中的所有片段
let fragments = await this.enumFragments(nodeId);
fragments.forEach((frag) => {
// 取得當前片段的 FragmentProxy 物件
let fragProxy = this.viewer.impl.getFragmentProxy(this.viewer.model, frag); let fragProxy = this.viewer.impl.getFragmentProxy(this.viewer.model, frag);
// 將當前片段的信息添加到 fragProxys 陣列中
this.fragProxys.push({ nodeId: nodeId, fragId: frag, frag: fragProxy }); this.fragProxys.push({ nodeId: nodeId, fragId: frag, frag: fragProxy });
// 取得當前片段的動畫變換矩陣
fragProxy.getAnimTransform(); fragProxy.getAnimTransform();
// 定義當前片段的位置向量
let fragPosition = new THREE.Vector3(0, 0, 0);// 一樓0 二樓15 三樓 26 let fragPosition = new THREE.Vector3(0, 0, 0);// 一樓0 二樓15 三樓 26
// 設置當前片段的位置
fragProxy.position = fragPosition; fragProxy.position = fragPosition;
// 更新當前片段的動畫變換矩陣
fragProxy.updateAnimTransform(); fragProxy.updateAnimTransform();
if (childCnt == curIdx) { })
this.initCallback ? this.initCallback() : "";
callback ? callback() : "";
}
curIdx++;
}, true);
} }
// 通知檢視器更新場景
this.viewer.impl.sceneUpdated(true); this.viewer.impl.sceneUpdated(true);
if (typeof $(this.ele)[0]._elevator3D == "undefined") { if (typeof $(this.ele)[0]._elevator3D == "undefined") {
$(this.ele)[0]._elevator3D = []; $(this.ele)[0]._elevator3D = [];
} }
$(this.ele)[0]._elevator3D.push({ nodeId: nodeId, obj: this }); $(this.ele)[0]._elevator3D.push({ nodeId: nodeId, obj: this });
this.initCallback ? this.initCallback() : "";
callback ? callback() : "";
} }
init = function (callback = null) { init = function (callback = null) {
@ -196,15 +222,17 @@ class elevator3D {
this.speed = speed; this.speed = speed;
} }
movElevator = function () { // 電梯移動
movElevator = async function () {
let tree = this.viewer.model.getData().instanceTree;
let nodeId = this.nodeId; let nodeId = this.nodeId;
let fragProxyZ = 0; let fragProxyZ = 0; // 定義 fragProxyZ 變量,用於存儲當前片段的 z 坐標
// 取得當前 nodeId 的片段代理對象
let fragProxy = this.fragProxys.filter(x => x.nodeId == nodeId)[0]?.frag; let fragProxy = this.fragProxys.filter(x => x.nodeId == nodeId)[0]?.frag;
if (!fragProxy) { if (!fragProxy) {
return; return;
} }
changeColor(nodeId); changeColor(nodeId);
if ((this.movStatus == 2 && fragProxy.position.z.roundDecimal(2) < this.targetFloorZ.roundDecimal(2)) || if ((this.movStatus == 2 && fragProxy.position.z.roundDecimal(2) < this.targetFloorZ.roundDecimal(2)) ||
@ -213,11 +241,6 @@ class elevator3D {
stoped(this); stoped(this);
} }
//if (movStatus == 0) {
// recoverTransparentBuilding();
// return;
//}
if (fragProxy.position.z.roundDecimal(2) > this.targetFloorZ.roundDecimal(2)) { if (fragProxy.position.z.roundDecimal(2) > this.targetFloorZ.roundDecimal(2)) {
this.movStatus = 2; this.movStatus = 2;
} }
@ -225,25 +248,29 @@ class elevator3D {
this.movStatus = 1; this.movStatus = 1;
} }
tree.enumNodeFragments(nodeId, (frag) => { // 遍歷當前 nodeId 中的所有片段
let fragments = await this.enumFragments(nodeId);
fragments.forEach((frag) => {
let fragProxy = this.viewer.impl.getFragmentProxy(this.viewer.model, frag); let fragProxy = this.viewer.impl.getFragmentProxy(this.viewer.model, frag);
fragProxy.getAnimTransform(); fragProxy.getAnimTransform();
//let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26
if (this.movStatus == 2) { if (this.movStatus == 2) {
fragProxy.position.z -= this.speed; fragProxy.position.z -= this.speed;
} }
else if (this.movStatus == 1) { else if (this.movStatus == 1) {
fragProxy.position.z += this.speed; fragProxy.position.z += this.speed;
} }
this.fragProxys.filter(x => x.nodeId == nodeId && x.fragId == frag)[0].frag.position.z = fragProxy.position.z; let tarFrag = this.fragProxys.filter(x => x.nodeId == nodeId && x.fragId == frag)[0];
if (tarFrag) {
tarFrag.frag.position.z = fragProxy.position.z;
}
fragProxyZ = fragProxy.position.z; fragProxyZ = fragProxy.position.z;
fragProxy.updateAnimTransform() fragProxy.updateAnimTransform()
})
}, true);
this.viewer.impl.sceneUpdated(true); this.viewer.impl.sceneUpdated(true);
/*setTransparentBuilding();*/
let movElevator = $(this.ele)[0]._elevator3D.filter(x => x.nodeId == this.nodeId)[0]?.obj.movElevator.bind(this); let movElevator = $(this.ele)[0]._elevator3D.filter(x => x.nodeId == this.nodeId)[0]?.obj.movElevator.bind(this);
if (this.movStatus == 2) { if (this.movStatus == 2) {
@ -269,17 +296,9 @@ class elevator3D {
function stoped(obj) { function stoped(obj) {
obj.movStatus = 0; obj.movStatus = 0;
/*recoverTransparentBuilding();*/
hideColor(nodeId); hideColor(nodeId);
return; return;
} }
//let fragPosition = new THREE.Vector3(position);// 一樓0 二樓15 三樓 26
//fragProxy.position = fragPosition;
//fragProxy.updateAnimTransform();
//viewer.impl.sceneUpdated(true);
} }
} }
@ -338,14 +357,14 @@ async function getNodeIdBySearch(text) {
} }
// 主函數 - 透過 model 全部 node 取得特定 nodeId // 主函數 - 透過 model 全部 node 取得特定 nodeId
async function getNodeIdByDbIds(checkName = "【電梯】", callback = null) { async function getNodeIdByDbIds(checkValue = [], callback = null) {
let evelMap = new Map(); let evelMap = new Map();
let hasElement = false; // 設置是否有 【tag_id】的node let hasElement = false; // 設置是否有 【tag_id】的node
let targetNodeIds = await getNodeIdBySearch(checkName); let targetNodeIds = await getNodeIdBySearch(checkValue);
let elements = await viewerGetProperties(targetNodeIds,"【tag_id】"); let elements = await viewerGetProperties(targetNodeIds,"【tag_id】");
// 從 elements 中篩選出包含 【tag_id】 屬性的元素 // 從 elements 中篩選出包含 【tag_id】 屬性的元素
elements = elements.filter(x => x.properties.findIndex(y => y.displayName == "【tag_id】" && y.displayValue.indexOf(checkName) != -1) != -1); elements = elements.filter(x => x.properties.findIndex(y => y.displayName == "【tag_id】" && checkValue.indexOf(y.displayValue) != -1) != -1);
if (elements) { if (elements) {
hasElement = true; hasElement = true;
@ -514,15 +533,15 @@ class ADHeatMaps {
SurfaceShadingNode, SurfaceShadingNode,
} = Autodesk.DataVisualization.Core; } = Autodesk.DataVisualization.Core;
let nodeIds = await getNodeIdByDbIds(this.checkNodeString); //let nodeIds = await getNodeIdByDbIds(this.checkNodeString);
nodeIds = Array.from(nodeIds); //nodeIds = Array.from(nodeIds);
nodeIds = nodeIds.map(x => { return { room: x[0] , nodeId: x[1]} }); //nodeIds = nodeIds.map(x => { return { room: x[0] , nodeId: x[1]} });
this.roomDbIds = nodeIds; this.roomDbIds = this.devices.filter(x => x.roomDbId != -1).map(x => x.roomDbId).Distinct();
// 建立一個 SurfaceShadingData 物件,並將 SurfaceShadingNode 加入到該物件中 // 建立一個 SurfaceShadingData 物件,並將 SurfaceShadingNode 加入到該物件中
const heatmapData = new SurfaceShadingData(); const heatmapData = new SurfaceShadingData();
$.each(this.roomDbIds.map(x => x.nodeId), (idx, rDbid) => { $.each(this.roomDbIds, (idx, rDbid) => {
// 建立一個名為 "Room Panel" 的 SurfaceShadingNode 物件,並將房間的模型給傳入,只在該房間呈現溫度 // 建立一個名為 "Room Panel" 的 SurfaceShadingNode 物件,並將房間的模型給傳入,只在該房間呈現溫度
const shadingNode = new SurfaceShadingNode("RoomPanel" + rDbid, rDbid); const shadingNode = new SurfaceShadingNode("RoomPanel" + rDbid, rDbid);
@ -551,7 +570,7 @@ class ADHeatMaps {
this.dataVizExtn = dataVizExtn; this.dataVizExtn = dataVizExtn;
$.each(this.roomDbIds.map(x => x.nodeId), (idx, rDbid) => { $.each(this.roomDbIds, (idx, rDbid) => {
this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", this.getSensorValue.bind(this)); this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", this.getSensorValue.bind(this));
}) })
@ -977,13 +996,15 @@ async function getRemoteLevels() {
} }
async function getLevelsData(lowerFloor, upperFloor) { async function getLevelsData(lowerFloor, upperFloor) {
// 樓層正規化 取得樓層
const floorRegex = /[\d|\w]+F/gmi;
const data = await this.getRemoteLevels(); const data = await this.getRemoteLevels();
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
if ((data[i].name).indexOf(lowerFloor) != -1) { let name = data[i].name?.match(floorRegex);
if (name && name[0] == lowerFloor) {
lowerIdx = i; lowerIdx = i;
} }
if ((data[i].name).indexOf(upperFloor) != -1) { if (name && name[0] == upperFloor) {
upperIdx = i; upperIdx = i;
} }
} }

View File

@ -398,3 +398,206 @@ function isJSON(str) {
return false; return false;
} }
} }
/**
* 取得資料庫電梯設備根據 baja 訂閱移動 3D 電梯
* */
class Forge3DElevFull {
constructor(option = {}) {
this.allElevDevList = []; //全電梯設備清單
this.subSeviceData = []; //每個設備訂閱點位值
this.floList = [];
this.elev3DBind = {};
this.elev3DOption = {};
this.elev3DObj = [];
this.viewer = option.viewer ?? null;
this.ordPath = option.ordPath ?? {};
this.sysMainTag = option.system_tag ?? "ELEV";
this.sysSubTag = option.name_tag ?? "EL";
this.selector = option.selector ?? "#forgeViewer";
this.bajaChaCallback = option.bajaChaCallback ?? null;
this.bajaEndCallback = option.bajaEndCallback ?? null;
}
init = function () {
// 系統大類、小類固定
this.ordPath.system_tag = this.sysMainTag;
this.ordPath.name_tag = this.sysSubTag;
this.getElevDevList();
}
// 訂閱電梯設備
subElevDevice = function () {
let myBaja = new subscriptionDevices();
let ordPath = this.ordPath;
myBaja.setSubscribeDevicesByBql(ordPath);
myBaja.setSubscribeDevicesCallBack((data) => {
this.bajaChaCallback ? this.bajaChaCallback(data) : "";
if (this.allElevDevList.length == 0) {
return false;
}
data.device_number = data.device_number_full;
let matchDevice = this.allElevDevList.filter(x => x.device_number == data.device_number)[0];
if (!matchDevice) {
return;
}
//將訂閱值塞入 subSeviceData
if (this.subSeviceData.findIndex(x => x.device_number == matchDevice.device_number) == -1) {
let obj = {};
obj.device_number = matchDevice.device_number;
this.subSeviceData.push(obj)
}
let subData = this.subSeviceData.filter(x => x.device_number == matchDevice.device_number)[0];
if (subData) {
subData[data.point_name] = data.value;
}
if (data.point_name == "CP") {
if (this.elev3DObj.length != 0) {
let elevObj = this.elev3DObj.filter(x => x.nodeId == this.elev3DBind[matchDevice.device_number])[0];
if (elevObj && elevObj.id) {
elevObj.obj.setElevatorFloor(data.value)
elevObj.obj.movElevator();
}
}
}
});
myBaja.setSubscribeDeviceEndCallBack((data) => {
this.floList = data.filter(x => x.point_name.startsWith("SP_FLS_")).map(x => x?.point_name?.split("SP_FLS_")[1]).Distinct();
this.set3DElevOpt(data);
this.bajaEndCallback != null ? this.bajaEndCallback() : "";
});
}
// 電梯 3D Option 設置
set3DElevOpt = function (data) {
let devNumArr = data.map(x => { return { devNum: x.device_number_full, priority: this.allElevDevList.filter(y => y.device_number == x.device_number_full)[0]?.priority } }).DistinctBy("devNum");
devNumArr = devNumArr.oSort("priority");
$.each(devNumArr, (idx, devObj) => {
let devNum = devObj.devNum;
let subData = this.subSeviceData.filter(x => x.device_number == devNum)[0];
if (subData) {
//// 左側 3D 電梯 nodeID 與 device_number match
//if (Object.keys(elev3DBind).indexOf(devNum) == -1 && viewer3DNodeIds.length != 0) {
// elev3DBind[devNum] = viewer3DNodeIds[Object.keys(elev3DBind).length];
//}
// 左側 3D 電梯 Viewer Option 設置
/*elev3DOption.nodes = Object.keys(elev3DBind).map(x => elev3DBind[x]);*/
this.elev3DOption.nodeId = this.elev3DBind[devNum];
this.elev3DOption.floorHeight = this.floList.map((x) => { return { floor: x } });
this.elev3DOption.floorHeight.forEach((floObj, idx) => {
if (floObj.floor.startsWith("B")) {
let floor = parseInt(floObj.floor.split("B")[1].split("F")[0]);
floObj.height = floor * -13;
} else {
let floor = parseInt(floObj.floor.split("F")[0]);
if (floor == 1) {
floObj.height = 0;
} else if (floor == 2) {
floObj.height = 14.75;
} else {
floObj.height = (14.75 + ((floor - 2) * 9.75));
}
}
})
if (this.elev3DObj.length != 0) {
let elevObj = this.elev3DObj.filter(x => x.nodeId == this.elev3DBind[devNum])[0];
if (!elevObj.id) {
elevObj.id = devNum;
}
elevObj.obj = Object.assign(elevObj.obj, this.elev3DOption);
elevObj.obj.init(() => {
let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == this.elev3DBind[devNum]);
frags.forEach((fragProxy) => {
fragProxy.frag.position.z = this.elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
fragProxy.frag.updateAnimTransform();
})
elevObj.obj.viewer.impl.sceneUpdated(true);
});
}
}
})
this.set3DElevPos();
}
// 電梯 3D 位置呈現
set3DElevPos = function () {
let nodeIds = this.allElevDevList.filter(x => !isNaN(parseInt(x.forge_dbid))).map(x => { return { devNum: x.device_number, nodeId: parseInt(x.forge_dbid) } });
$.each(nodeIds, (idx, item) => {
this.elev3DBind[item.devNum] = item.nodeId;
})
nodeIds = nodeIds.map(x => x.nodeId);
$.each(nodeIds, (idx, node) => {
let options = {
element: $(this.selector),
viewer: this.viewer,
nodeId: node,
floorHeight: this.elev3DOption.floorHeight ?? [],
inited: function () {
}
}
let elevator3DObj = new elevator3D(options);
let devNum = Object.keys(this.elev3DBind).filter(x => this.elev3DBind[x] == node)[0];
let subData = this.subSeviceData.filter(x => x.device_number == devNum)[0];
if (this.elev3DObj.filter(x => x.nodeId == node).length == 0) {
this.elev3DObj.push({ id: devNum, nodeId: node, obj: elevator3DObj });
}
if (subData) {
let elevObj = this.elev3DObj.filter(x => x.nodeId == node)[0];
if (!elevObj.id) {
elevObj.id = devNum;
}
elevObj.obj = Object.assign(elevObj, elevator3DObj ?? {})
elevObj.obj.init(() => {
let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == node);
frags.forEach((fragProxy) => {
fragProxy.frag.position.z = this.elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
fragProxy.frag.updateAnimTransform()
})
elevObj.obj.viewer.impl.sceneUpdated(true);
})
}
})
}
// 取得設備列表
getElevDevList = function () {
let url = baseApiUrl + "/api/Device/GetDeviceList";
let sendData = {
sub_system_tag: this.ordPath.name_tag,
building_tag: this.ordPath.building_tag,
};
objSendData.Data = sendData;
ytAjax = new YourTeam.Ajax(url, objSendData, (res) => {
if (!res || res.code != "0000" || !res.data) {
} else {
$.each(res.data, (index, floObj) => {
$.each(floObj.device_list, (index2, devObj) => {
this.allElevDevList.push(devObj);
})
})
this.subElevDevice();
}
}, null, "POST").send();
}
}

View File

@ -74,8 +74,20 @@ Array.prototype.sum = function () {
return a + b; return a + b;
}, 0); }, 0);
} }
BigInt.prototype.toJSON = function () { return this.toString() } BigInt.prototype.toJSON = function () { return this.toString() }
Map.prototype.toArrObj = function () {
let result = [];
tarArr = Array.from(this);
tarArr.forEach((target) => {
let resObj = {};
resObj[target[0]] = target[1];
result.push(resObj);
})
return result;
}
$.fn.classList = function () { return this[0].className.split(/\s+/); }; $.fn.classList = function () { return this[0].className.split(/\s+/); };
$.fn.replaceClass = function (oriClass, newClass) { $(this).removeClass(oriClass).addClass(newClass); return $(this) }; $.fn.replaceClass = function (oriClass, newClass) { $(this).removeClass(oriClass).addClass(newClass); return $(this) };