diff --git a/Frontend/_dashboard.html b/Frontend/_dashboard.html index 4eb48fb..1630c84 100644 --- a/Frontend/_dashboard.html +++ b/Frontend/_dashboard.html @@ -267,57 +267,7 @@ }; var contractCapacity = 0; - var sysIconList = [ - { mainSys: "EE", subSys: "E1", iconClass: "./gif/E1_white.png" }, - { mainSys: "EE", subSys: "E2", iconClass: "./gif/E2_white.png" }, - { mainSys: "EE", subSys: "E3", iconClass: "./gif/E3_white.png" }, - { mainSys: "EE", subSys: "E4", iconClass: "./gif/E4-1_white.png" }, // 電表 - { mainSys: "LT", subSys: "L1", iconClass: "./gif/L1_white.png" }, - { mainSys: "LT", subSys: "L2", iconClass: "./gif/L2_white.png" }, // 景觀照明 0131目前沒有 - { mainSys: "ME", subSys: "M1", iconClass: "./gif/M1_white.png" }, // 儲冰 0131目前沒有 - { mainSys: "ME", subSys: "M5", iconClass: "./gif/M5-2_white.png" }, // 送排風 - { mainSys: "ME", subSys: "M8", iconClass: "./gif/M8_white.png" }, // 排油煙0131目前沒有 - { mainSys: "ME", subSys: "M10", iconClass: "./gif/M10_white.png" }, - { mainSys: "ME", subSys: "M12", iconClass: "./gif/M12_white.png" }, - { mainSys: "ELEV", subSys: "EL", iconClass: "./gif/EL_white.png" }, - { mainSys: "FE", subSys: "F1", iconClass: "./gif/F1_white.png" }, - { mainSys: "FE", subSys: "F2", iconClass: "./gif/lamp_white.png" }, // 排煙 0131目前沒有 - { mainSys: "WP", subSys: "W1", iconClass: "./gif/W1_white.png" }, // 電子水表0131目前沒有 - { mainSys: "WP", subSys: "W2", iconClass: "./gif/W2_white.png" }, - { mainSys: "WP", subSys: "P1", iconClass: "./gif/P1_white.png" }, - { mainSys: "S", subSys: "C", iconClass: "./gif/C_white.png" }, // CCTV - { mainSys: "S", subSys: "P", iconClass: "./gif/P_white.png" }, // 緊急求救 - { mainSys: "S", subSys: "R", iconClass: "./gif/R_white.png" }, // 門禁 - { mainSys: "P", subSys: "PSC", iconClass: "./gif/PSC_white.png" }, // 停管 - { mainSys: "W3", subSys: "W1", iconClass: "./gif/W3_white.png" }, // 0131目前沒有 - ]; - - var tempSysSubText = [ - { text: "水錶系統", mainSys: "WP", subSys: "W1" }, - { text: "空調系統", mainSys: "ME", subSys: "M10" }, // 2 - { text: "照明系統", mainSys: "LT", subSys: "L1" }, // 3 - { text: "CCTV系統", mainSys: "S", subSys: "C" }, //12 - { text: "太陽能管理", mainSys: "S", subSys: "C" }, //12 - { text: "冰水主機", mainSys: "WP", subSys: "W2" }, // 6 - { text: "緊急發電機", mainSys: "EE", subSys: "E3" }, //10 - { text: "電梯系統", mainSys: "ELEV", subSys: "EL" }, // 1 - { text: "環境感測設備", mainSys: "ME", subSys: "M12" }, // 4 - { text: "電錶系統", mainSys: "EE", subSys: "E4" }, // 5 - { text: "高壓配電盤", mainSys: "EE", subSys: "E1" }, // 7 - { text: "汙廢水設備", mainSys: "WP", subSys: "P1" }, // 8 - { text: "低壓配電盤", mainSys: "EE", subSys: "E2" }, //9 - { text: "消防設備", mainSys: "FE", subSys: "F1" }, //11 - { text: "門禁系統", mainSys: "S", subSys: "R" }, //13 - { text: "停管系統", mainSys: "P", subSys: "PSC" }, //14 - { text: "緊急求救系統", mainSys: "S", subSys: "P" }, //15 - { text: "送排風系統", mainSys: "ME", subSys: "M5" }, //16 - //{ text: "景觀照明系統", mainSys: "LT", subSys: "L2", }, - //{ text: "儲冰系統", mainSys: "ME", subSys: "M1", }, - // { text: "排油煙設備", mainSys: "ME", subSys: "M8", }, - //{ text: "排煙系統", mainSys: "FE", subSys: "F2", }, - //{ text: "電子水錶", mainSys: "WP", subSys: "W1", }, - // { text: "熱水系統", mainSys: "W3", subSys: "W1", }, - ]; + $(document).ready(function () { $(loadEle).Loading("start"); diff --git a/Frontend/css/yourteam/plugins/yt-navbar/yt-navbar.css b/Frontend/css/yourteam/plugins/yt-navbar/yt-navbar.css index c38941a..5bff785 100644 --- a/Frontend/css/yourteam/plugins/yt-navbar/yt-navbar.css +++ b/Frontend/css/yourteam/plugins/yt-navbar/yt-navbar.css @@ -21,7 +21,7 @@ .yt-navbar::-webkit-scrollbar-thumb:hover { background: #555; } -.yt-left-navbar { position: fixed; left: 0; top: 0; height: 100%; z-index: 10; background-color: rgb(25 25 25 / 95%); width: auto; max-width: 300px; margin-top: 4.125rem; } +.yt-left-navbar { position: absolute; left: 0; top: 0; height: calc(100% - 4.125rem); z-index: 10; background-color: rgb(25 25 25 / 95%); width: auto; max-width: 300px; margin-top: 4.125rem; } .yt-navbar-content ul { padding: 1rem 0rem; list-style-type: none; } .yt-navbar-content ul li { position: relative; display: flex; flex-wrap: wrap; flex-direction: column; } .yt-navbar-content ul li a { font-size: 0.9rem; padding: 0.75rem 1rem 0.75rem 2rem; position: relative; width: 100%; display:flex; justify-content: space-between;} @@ -29,14 +29,16 @@ .yt-navbar-content ul li a:active, .yt-navbar-content ul li a.active { background-color: var(--theme-light); } .yt-navbar ul li a[data-nb-node-type=parent]::after { - content: "◀"; - margin-left:1rem; + content: ">"; + font-family: cursive; + font-weight: 700; + margin-left:4rem; transform:rotate(0deg); transition:0.2s } .yt-navbar ul li a[data-nb-node-type=parent][data-nb-node-status=open]::after { - transform:rotate(-90deg); + transform:rotate(90deg); } .yt-navbar-content ul li a[data-nb-node-type=parent] span:hover { @@ -59,5 +61,5 @@ } .yt-navbar-content ul.yt-navbar-dropdown li a { - padding: 0.75rem 0.5rem 0.75rem 2.5rem; + padding: 0.75rem 0.5rem 0.75rem 3.5rem; } diff --git a/Frontend/index.html b/Frontend/index.html index af9d90c..10e2ecd 100644 --- a/Frontend/index.html +++ b/Frontend/index.html @@ -1029,6 +1029,58 @@ License: You must have a valid license purchased only from wrapbootstrap.com (li var allDevices = []; var tempSubTag = ["M10", "M12"]; // 溫度向小類 + var sysIconList = [ + { mainSys: "EE", subSys: "E1", iconClass: "./gif/E1_white.png" }, + { mainSys: "EE", subSys: "E2", iconClass: "./gif/E2_white.png" }, + { mainSys: "EE", subSys: "E3", iconClass: "./gif/E3_white.png" }, + { mainSys: "EE", subSys: "E4", iconClass: "./gif/E4-1_white.png" }, // 電表 + { mainSys: "LT", subSys: "L1", iconClass: "./gif/L1_white.png" }, + { mainSys: "LT", subSys: "L2", iconClass: "./gif/L2_white.png" }, // 景觀照明 0131目前沒有 + { mainSys: "ME", subSys: "M1", iconClass: "./gif/M1_white.png" }, // 儲冰 0131目前沒有 + { mainSys: "ME", subSys: "M5", iconClass: "./gif/M5-2_white.png" }, // 送排風 + { mainSys: "ME", subSys: "M8", iconClass: "./gif/M8_white.png" }, // 排油煙0131目前沒有 + { mainSys: "ME", subSys: "M10", iconClass: "./gif/M10_white.png" }, + { mainSys: "ME", subSys: "M12", iconClass: "./gif/M12_white.png" }, + { mainSys: "ELEV", subSys: "EL", iconClass: "./gif/EL_white.png" }, + { mainSys: "FE", subSys: "F1", iconClass: "./gif/F1_white.png" }, + { mainSys: "FE", subSys: "F2", iconClass: "./gif/lamp_white.png" }, // 排煙 0131目前沒有 + { mainSys: "WP", subSys: "W1", iconClass: "./gif/W1_white.png" }, // 電子水表0131目前沒有 + { mainSys: "WP", subSys: "W2", iconClass: "./gif/W2_white.png" }, + { mainSys: "WP", subSys: "P1", iconClass: "./gif/P1_white.png" }, + { mainSys: "S", subSys: "C", iconClass: "./gif/C_white.png" }, // CCTV + { mainSys: "S", subSys: "P", iconClass: "./gif/P_white.png" }, // 緊急求救 + { mainSys: "S", subSys: "R", iconClass: "./gif/R_white.png" }, // 門禁 + { mainSys: "P", subSys: "PSC", iconClass: "./gif/PSC_white.png" }, // 停管 + { mainSys: "W3", subSys: "W1", iconClass: "./gif/W3_white.png" }, // 0131目前沒有 + ]; + + var tempSysSubText = [ + { text: "水錶系統", mainSys: "WP", subSys: "W1" }, + { text: "空調系統", mainSys: "ME", subSys: "M10" }, // 2 + { text: "照明系統", mainSys: "LT", subSys: "L1" }, // 3 + { text: "CCTV系統", mainSys: "S", subSys: "C" }, //12 + { text: "太陽能管理", mainSys: "S", subSys: "C" }, //12 + { text: "冰水主機", mainSys: "WP", subSys: "W2" }, // 6 + { text: "緊急發電機", mainSys: "EE", subSys: "E3" }, //10 + { text: "電梯系統", mainSys: "ELEV", subSys: "EL" }, // 1 + { text: "環境感測設備", mainSys: "ME", subSys: "M12" }, // 4 + { text: "電錶系統", mainSys: "EE", subSys: "E4" }, // 5 + { text: "高壓配電盤", mainSys: "EE", subSys: "E1" }, // 7 + { text: "汙廢水設備", mainSys: "WP", subSys: "P1" }, // 8 + { text: "低壓配電盤", mainSys: "EE", subSys: "E2" }, //9 + { text: "消防設備", mainSys: "FE", subSys: "F1" }, //11 + { text: "門禁系統", mainSys: "S", subSys: "R" }, //13 + { text: "停管系統", mainSys: "P", subSys: "PSC" }, //14 + { text: "緊急求救系統", mainSys: "S", subSys: "P" }, //15 + { text: "送排風系統", mainSys: "ME", subSys: "M5" }, //16 + //{ text: "景觀照明系統", mainSys: "LT", subSys: "L2", }, + //{ text: "儲冰系統", mainSys: "ME", subSys: "M1", }, + // { text: "排油煙設備", mainSys: "ME", subSys: "M8", }, + //{ text: "排煙系統", mainSys: "FE", subSys: "F2", }, + //{ text: "電子水錶", mainSys: "WP", subSys: "W1", }, + // { text: "熱水系統", mainSys: "W3", subSys: "W1", }, + ]; + /** * 頁面 Loading 建立 * */ @@ -2095,7 +2147,7 @@ License: You must have a valid license purchased only from wrapbootstrap.com (li
首頁 @@ -2215,11 +2267,30 @@ License: You must have a valid license purchased only from wrapbootstrap.com (li } ); }); + const ulLen = ul.find("li").length; + for(let i = 0; i < 8 - ulLen; i++){ + let li2 = creEle("li"); + let a2 = creA( + tempSysSubText[i].text, + { href: "javascript:;" }, + [], + `subSysBtn${tempSysSubText[i].subSys}`, + { + page: "systemMonitor", + tabname: "systemMonitor", + "building-tag": building.building_tag, + }, + "topFunBtn" + ); + li2.append(a2); + ul.append(li2); + } + li.append(ul); $("#sysMonBtnList").append(li); }); - $("#sysMonTopBtn").YTNavbar("init"); + $("#sysMonTopBtn").YTNavbar("init",{onlyOneOpen: true}); $("span[id^=buildTab]").first().YTTab("setAndClick",{triggerType:"first"}); } diff --git a/Frontend/js/forge/forgemodel.js b/Frontend/js/forge/forgemodel.js index dc5fb0c..dcc1ecc 100644 --- a/Frontend/js/forge/forgemodel.js +++ b/Frontend/js/forge/forgemodel.js @@ -1,6 +1,4 @@ -var viewer; - -let fragProxy; +let fragProxy; var targetFloorZ; var elevatorSpeed; var selector = "#forgeViewer"; @@ -11,1483 +9,1401 @@ var levels; //剖面用 var lowerIdx = 0; //剖面的下方樓層 var upperIdx = 0; //剖面的上方樓層 -function launchViewer(urn, callback, failCallback, _selector = "#forgeViewer") { - selector = _selector; - var options = { - env: "AutodeskProduction", - getAccessToken: getForgeToken, - settings: { - ambientShadows: false, - groundShadows: false, - }, - }; - - Autodesk.Viewing.Initializer(options, () => { - viewer = new Autodesk.Viewing.GuiViewer3D($(selector)[0]); - //viewer = new Autodesk.Viewing.Viewer3D(document.getElementById('forgeViewer')); - viewer.start(); - var documentId = "urn:" + urn; - - Autodesk.Viewing.Document.load( - documentId, - onDocumentLoadSuccess, - onDocumentLoadFailure - ); - setShadowShow(); - - $(selector).on("autodesk:loaded", function (e, nodeIds) { - callback ? callback(viewer, nodeIds) : ""; - }); - $(selector).on("autodesk:loaded:fail", function (e) { - failCallback ? failCallback(viewer) : ""; - }); - - //test - // for (let i = 0; i < urn.length; i++) { - // Autodesk.Viewing.Document.load(urn[i]["urn"], async (doc) => { - // let viewables = doc.getRoot().getDefaultGeometry(); - // let model = await viewer.loadDocumentNode(doc, viewables, { - // preserveView: false, - // keepCurrentModels: true, - // placementTransform: (new THREE.Matrix4()).setPosition(urn[i]["xform"]), - // keepCurrentModels: true, - // globalOffset: { - // x: 0, - // y: 0, - // z: 0 - // } - // }); - - // await viewer.waitForLoadDone(); //!<<< Wait for loading materials, properties and geometries for this model (URN) - // }); - // } - - //loadHeatmaps(viewer.getAllModels()[0]); //!<<< equals to viewer.model - }); -} - -function launchViewerForHotspot( - urn, - callback, - failCallback, - _selector = "#forgeViewer" -) { - selector = _selector; - var av = Autodesk.Viewing; - var options = { - env: "AutodeskProduction", - getAccessToken: getForgeToken, - settings: { - ambientShadows: false, - groundShadows: false, - }, - }; - - Autodesk.Viewing.Initializer(options, () => { - viewer = new Autodesk.Viewing.GuiViewer3D($(selector)[0]); - viewer.start(); - var documentId = "urn:" + urn; - - viewer.addEventListener(av.GEOMETRY_LOADED_EVENT, addHotPoint, { - once: true, - }); - - Autodesk.Viewing.Document.load( - documentId, - onDocumentLoadSuccess, - onDocumentLoadFailure - ); - setShadowShow(); - $(selector).on("autodesk:loaded", function (e, nodeIds) { - callback ? callback(viewer, nodeIds) : ""; - }); - - $(selector).on("autodesk:loaded:fail", function (e) { - failCallback ? failCallback(viewer) : ""; - }); - }); -} - -function launchViewerNoTools( - urn, - callback, - failCallback, - _selector = "#forgeViewer" -) { - selector = _selector; - var options = { - env: "AutodeskProduction", - getAccessToken: getForgeToken, - settings: { - ambientShadows: false, - groundShadows: false, - }, - }; - - Autodesk.Viewing.Initializer(options, () => { - //viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer')); - viewer = new Autodesk.Viewing.Viewer3D($(selector)[0]); - viewer.start(); - var documentId = "urn:" + urn; - - Autodesk.Viewing.Document.load( - documentId, - onDocumentLoadSuccess, - onDocumentLoadFailure - ); - setShadowShow(); - $(selector).on("autodesk:loaded", function (e, nodeIds) { - callback ? callback(viewer, nodeIds) : ""; - }); - - $(selector).on("autodesk:loaded:fail", function (e) { - failCallback ? failCallback(viewer) : ""; - }); - }); -} - function getAllLeafComponents(viewer, callback) { - var cbCount = 0; - var tree; - var jsData = []; + var cbCount = 0; + var tree; + var jsData = []; - function getLeafComponentsRec(current, parent) { - cbCount++; - if (tree.getChildCount(current) != 0) { - tree.enumNodeChildren( - current, - function (children) { - getLeafComponentsRec(children, current); - }, - false - ); - } - var nodeName = viewer.model.getInstanceTree().getNodeName(current); - jsData.push({ id: current, parent: parent, text: nodeName }); - - if (--cbCount == 0) callback(jsData); + function getLeafComponentsRec(current, parent) { + cbCount++; + if (tree.getChildCount(current) != 0) { + tree.enumNodeChildren( + current, + function (children) { + getLeafComponentsRec(children, current); + }, + false + ); } - viewer.getObjectTree(function (objectTree) { - tree = objectTree; - var rootId = tree.getRootId(); - var nodeName = viewer.model.getInstanceTree().getNodeName(rootId); - jsData.push({ id: rootId, parent: "#", text: nodeName }); - var allLeafComponents = getLeafComponentsRec(rootId, "#"); - }); + var nodeName = viewer.model.getInstanceTree().getNodeName(current); + jsData.push({ id: current, parent: parent, text: nodeName }); + + if (--cbCount == 0) callback(jsData); + } + viewer.getObjectTree(function (objectTree) { + tree = objectTree; + var rootId = tree.getRootId(); + var nodeName = viewer.model.getInstanceTree().getNodeName(rootId); + jsData.push({ id: rootId, parent: "#", text: nodeName }); + var allLeafComponents = getLeafComponentsRec(rootId, "#"); + }); } class elevator3D { - constructor(option = {}) { - this.ele = option.element; - this.viewer = option.viewer; - this.nodeId = option.nodeId; - this.speed = option.speed ?? 0.18; - this.tagValue = option.tagValue ?? ""; - this.fragProxys = []; - this.fragProxy = null; - this.initCallback = option.inited ?? null; - this.movStatus = 0; - this.targetFloorZ = 0; - this.floorHeight = option.floorHeight ?? [{}]; - this.sensorObjs = option.sensorObjs ?? null; - this.init(); + constructor(option = {}) { + this.ele = option.element; + viewer = option.viewer; + this.nodeId = option.nodeId; + this.speed = option.speed ?? 0.07; + this.tagValue = option.tagValue ?? ""; + this.fragProxys = []; + this.fragProxy = null; + this.initCallback = option.inited ?? null; + this.movStatus = 0; + this.targetFloorZ = 0; + this.floorHeight = option.floorHeight ?? [{}]; + this.sensorObjs = option.sensorObjs ?? null; + this.init(); + } + + // 定義遍歷模型中所有片段的異步函數 + enumFragments = function (nodeId) { + return new Promise((resolve, reject) => { + // 定義結果陣列 + let result = []; + // 使用 InstanceTree.enumNodeFragments 遍歷模型中的所有片段 + 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 = viewer?.model?.getData().instanceTree; + if (!tree) { + return; } - // 定義遍歷模型中所有片段的異步函數 - 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); - }); - }; + let nodeId = this.nodeId; - // 設置樹狀結構中片段 - setTreeFrag = async function (callback) { - let tree = this.viewer?.model?.getData().instanceTree; - if (!tree) { - return; - } - - let nodeId = this.nodeId; - - if (nodeId) { - // 刪除 fragmentProxys 中與當前 nodeId 相同的項目 - this.fragProxys - .filter((x) => x.nodeId == nodeId) - .forEach((x) => { - let idx = this.fragProxys.indexOf(x); - this.fragProxys.splice(idx, 1); - }); - - // 遍歷當前 nodeId 中的所有片段 - let fragments = await this.enumFragments(nodeId); - - fragments.forEach((frag) => { - // 取得當前片段的 FragmentProxy 物件 - let fragProxy = this.viewer.impl.getFragmentProxy( - this.viewer.model, - frag - ); - // 將當前片段的信息添加到 fragProxys 陣列中 - this.fragProxys.push({ nodeId: nodeId, fragId: frag, frag: fragProxy }); - // 取得當前片段的動畫變換矩陣 - fragProxy.getAnimTransform(); - // 定義當前片段的位置向量 - let fragPosition = new THREE.Vector3(0, 0, 0); // 一樓0 二樓15 三樓 26 - // 設置當前片段的位置 - fragProxy.position = fragPosition; - - // 更新當前片段的動畫變換矩陣 - fragProxy.updateAnimTransform(); - }); - } - // 通知檢視器更新場景 - this.viewer.impl.sceneUpdated(true); - - if (!$(this.ele)[0]) { - callback ? callback() : ""; - return; - } - - if (typeof $(this.ele)[0]._elevator3D == "undefined") { - $(this.ele)[0]._elevator3D = []; - } - - $(this.ele)[0]._elevator3D.push({ nodeId: nodeId, obj: this }); - - this.initCallback ? this.initCallback() : ""; - callback ? callback() : ""; - }; - - init = function (callback = null) { - this.setTreeFrag(callback); - }; - - setElevatorFloor = function (floor) { - this.targetFloorZ = - this.floorHeight.filter((x) => x.floor == floor)[0]?.height ?? 0; - }; - - setElevatorSpeed = function (speed) { - //0.01 ~ 1 - this.speed = speed; - }; - - // 電梯移動 - movElevator = async function () { - let nodeId = this.nodeId; - let fragProxyZ = 0; // 定義 fragProxyZ 變量,用於存儲當前片段的 z 坐標 - - // 取得當前 nodeId 的片段代理對象 - let fragProxy = this.fragProxys.filter((x) => x.nodeId == nodeId)[0]?.frag; - if (!fragProxy) { - return; - } - - changeColor(nodeId); - - if ( - (this.movStatus == 2 && - fragProxy.position.z.roundDecimal(2) < - this.targetFloorZ.roundDecimal(2)) || - (this.movStatus == 1 && - fragProxy.position.z.roundDecimal(2) > - this.targetFloorZ.roundDecimal(2)) || - fragProxy.position.z.roundDecimal(2) == this.targetFloorZ.roundDecimal(2) - ) { - stoped(this); - } - - if ( - fragProxy.position.z.roundDecimal(2) > this.targetFloorZ.roundDecimal(2) - ) { - this.movStatus = 2; - } else if ( - fragProxy.position.z.roundDecimal(2) < this.targetFloorZ.roundDecimal(2) - ) { - this.movStatus = 1; - } - - // 遍歷當前 nodeId 中的所有片段 - let fragments = await this.enumFragments(nodeId); - - fragments.forEach((frag) => { - let fragProxy = this.viewer.impl.getFragmentProxy( - this.viewer.model, - frag - ); - fragProxy.getAnimTransform(); - - if (this.movStatus == 2) { - fragProxy.position.z -= this.speed; - } else if (this.movStatus == 1) { - fragProxy.position.z += this.speed; - } - 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; - - // 改變感測器熱點位置 - this.sensorObjs && this.sensorObjs[0]?.changePos(nodeId + 2, fragProxyZ); - // if(nodeId === 15200) { - // } - fragProxy.updateAnimTransform(); + if (nodeId) { + // 刪除 fragmentProxys 中與當前 nodeId 相同的項目 + this.fragProxys + .filter((x) => x.nodeId == nodeId) + .forEach((x) => { + let idx = this.fragProxys.indexOf(x); + this.fragProxys.splice(idx, 1); }); - this.viewer.impl.sceneUpdated(true); + // 遍歷當前 nodeId 中的所有片段 + let fragments = await this.enumFragments(nodeId); - let movElevator = $(this.ele)[0] - ._elevator3D.filter((x) => x.nodeId == this.nodeId)[0] - ?.obj.movElevator.bind(this); + fragments.forEach((frag) => { + // 取得當前片段的 FragmentProxy 物件 + let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag); + // 將當前片段的信息添加到 fragProxys 陣列中 + this.fragProxys.push({ nodeId: nodeId, fragId: frag, frag: fragProxy }); + // 取得當前片段的動畫變換矩陣 + fragProxy.getAnimTransform(); + // 定義當前片段的位置向量 + let fragPosition = new THREE.Vector3(0, 0, 0); // 一樓0 二樓15 三樓 26 + // 設置當前片段的位置 + fragProxy.position = fragPosition; - if (this.movStatus == 2) { - if (fragProxyZ >= this.targetFloorZ) { - requestAnimationFrame(() => { - movElevator(); - }); - } else { - stoped(this); - } - } else if (this.movStatus == 1) { - if (fragProxyZ <= this.targetFloorZ) { - requestAnimationFrame(() => { - movElevator(); - }); - } else { - stoped(this); - } - } else { - stoped(this); - } + // 更新當前片段的動畫變換矩陣 + fragProxy.updateAnimTransform(); + }); + } + // 通知檢視器更新場景 + viewer.impl.sceneUpdated(true); - function stoped(obj) { - obj.movStatus = 0; - hideColor(nodeId); - return; - } - }; -} + if (!$(this.ele)[0]) { + callback ? callback() : ""; + return; + } -function onDocumentLoadSuccess(doc, eleOption) { - var viewables = doc.getRoot().getDefaultGeometry(); - viewer.loadDocumentNode(doc, viewables).then((i) => { - // documented loaded, any action? + if (typeof $(this.ele)[0]._elevator3D == "undefined") { + $(this.ele)[0]._elevator3D = []; + } + + $(this.ele)[0]._elevator3D.push({ nodeId: nodeId, obj: this }); + + this.initCallback ? this.initCallback() : ""; + callback ? callback() : ""; + }; + + init = function (callback = null) { + this.setTreeFrag(callback); + }; + + setElevatorFloor = function (floor) { + this.targetFloorZ = + this.floorHeight.filter((x) => x.floor == floor)[0]?.height ?? 0; + }; + + setElevatorSpeed = function (speed) { + //0.01 ~ 1 + this.speed = speed; + }; + + // 電梯移動 + movElevator = async function () { + let nodeId = this.nodeId; + let fragProxyZ = 0; // 定義 fragProxyZ 變量,用於存儲當前片段的 z 坐標 + + // 取得當前 nodeId 的片段代理對象 + let fragProxy = this.fragProxys.filter((x) => x.nodeId == nodeId)[0]?.frag; + if (!fragProxy) { + return; + } + + changeColor(nodeId); + + if ( + (this.movStatus == 2 && + fragProxy.position.z.roundDecimal(2) < + this.targetFloorZ.roundDecimal(2)) || + (this.movStatus == 1 && + fragProxy.position.z.roundDecimal(2) > + this.targetFloorZ.roundDecimal(2)) || + fragProxy.position.z.roundDecimal(2) == this.targetFloorZ.roundDecimal(2) + ) { + stoped(this); + } + + if ( + fragProxy.position.z.roundDecimal(2) > this.targetFloorZ.roundDecimal(2) + ) { + this.movStatus = 2; + } else if ( + fragProxy.position.z.roundDecimal(2) < this.targetFloorZ.roundDecimal(2) + ) { + this.movStatus = 1; + } + + // 遍歷當前 nodeId 中的所有片段 + let fragments = await this.enumFragments(nodeId); + + fragments.forEach((frag) => { + let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag); + fragProxy.getAnimTransform(); + + if (this.movStatus == 2) { + fragProxy.position.z -= this.speed; + } else if (this.movStatus == 1) { + fragProxy.position.z += this.speed; + } + 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; + + // 改變感測器熱點位置 + this.sensorObjs && this.sensorObjs[0]?.changePos(nodeId + 2, fragProxyZ); + // if(nodeId === 15200) { + // } + fragProxy.updateAnimTransform(); }); - // viewer.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT, (args) => { - // var currSelection = viewer.getSelection(); - // var domElem = document.getElementById('id_printer'); - // domElem.innerText = currSelection[0]; - // }); - viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, function () { - let instanceTree = viewer.model?.getData().instanceTree; - // console.log(instanceTree.nodeAccess) - allDbIdsStr = Object.keys(instanceTree.nodeAccess.dbIdToIndex); - /*getNodeIdByDbIds("【電梯】", (nodeIds) => {*/ - $(selector).trigger("autodesk:loaded"); - /*});*/ - }); + viewer.impl.sceneUpdated(true); + + let movElevator = $(this.ele)[0] + ._elevator3D.filter((x) => x.nodeId == this.nodeId)[0] + ?.obj.movElevator.bind(this); + + if (this.movStatus == 2) { + if (fragProxyZ >= this.targetFloorZ) { + requestAnimationFrame(() => { + movElevator(); + }); + } else { + stoped(this); + } + } else if (this.movStatus == 1) { + if (fragProxyZ <= this.targetFloorZ) { + requestAnimationFrame(() => { + movElevator(); + }); + } else { + stoped(this); + } + } else { + stoped(this); + } + + function stoped(obj) { + obj.movStatus = 0; + hideColor(nodeId); + return; + } + }; } // 輔助函數,使用 Promise 封裝 viewer.getProperties 函數 function viewerGetProperties(dbIds, attributeName = null) { - // 在這裡,我們使用 viewer.getProperties 函數的成功回調函數作為 resolve 函數, - // 並使用 viewer.getProperties 函數的失敗回調函數作為 resolve 函數的參數 - // 這樣,當 viewer.getProperties 函數成功時,Promise 會傳回 properties 物件; - // 當 viewer.getProperties 函數失敗時,Promise 會傳回 null。 - return new Promise((resolve, reject) => { - let option = {}; - if (attributeName != null) { - option.propFilter = [attributeName]; // 限制只返回指定的屬性 - } - viewer.model.getBulkProperties2( - dbIds, - option, // 取得指定元素的屬性信息 - function (elements) { - resolve(elements); // 成功時傳回 elements 物件 - } - ); - }); + // 在這裡,我們使用 viewer.getProperties 函數的成功回調函數作為 resolve 函數, + // 並使用 viewer.getProperties 函數的失敗回調函數作為 resolve 函數的參數 + // 這樣,當 viewer.getProperties 函數成功時,Promise 會傳回 properties 物件; + // 當 viewer.getProperties 函數失敗時,Promise 會傳回 null。 + return new Promise((resolve, reject) => { + let option = {}; + if (attributeName != null) { + option.propFilter = [attributeName]; // 限制只返回指定的屬性 + } + viewer.model.getBulkProperties2( + dbIds, + option, // 取得指定元素的屬性信息 + function (elements) { + resolve(elements); // 成功時傳回 elements 物件 + } + ); + }); } // 輔助函數,使用 Promise 封裝 viewer.search 函數 async function getNodeIdBySearch(text) { - return new Promise((resolve, reject) => { - viewer.search( - text, - (e) => { - // 在 3D 模型中搜索具有指定文本的元素 - resolve(e); // 成功時傳回搜索結果 - }, - (e) => { - resolve(null); // 失敗時傳回 null - } - ); - }); + return new Promise((resolve, reject) => { + viewer.search( + text, + (e) => { + // 在 3D 模型中搜索具有指定文本的元素 + resolve(e); // 成功時傳回搜索結果 + }, + (e) => { + resolve(null); // 失敗時傳回 null + } + ); + }); } // 主函數 - 透過 model 全部 node 取得特定 nodeId async function getNodeIdByDbIds(checkValue = [], callback = null) { - let evelMap = new Map(); - let hasElement = false; // 設置是否有 【tag_id】的node - let targetNodeIds = await getNodeIdBySearch(checkValue); - let elements = await viewerGetProperties(targetNodeIds, "【tag_id】"); + let evelMap = new Map(); + let hasElement = false; // 設置是否有 【tag_id】的node + let targetNodeIds = await getNodeIdBySearch(checkValue); + let elements = await viewerGetProperties(targetNodeIds, "【tag_id】"); - // 從 elements 中篩選出包含 【tag_id】 屬性的元素 - elements = elements.filter( - (x) => - x.properties.findIndex( - (y) => - y.displayName == "【tag_id】" && - checkValue.indexOf(y.displayValue) != -1 - ) != -1 + // 從 elements 中篩選出包含 【tag_id】 屬性的元素 + elements = elements.filter( + (x) => + x.properties.findIndex( + (y) => + y.displayName == "【tag_id】" && + checkValue.indexOf(y.displayValue) != -1 + ) != -1 + ); + + if (elements) { + hasElement = true; + } + + for (var e of elements) { + let name = e.properties[0].displayValue; // 獲取元素的 【tag_id】 屬性 + let chiElements = null; + + // 獲取 node 元素的子元素信息 + targetNodeIds = await viewerGetProperties([e.dbId], "child"); + // 二次篩選 + chiElements = targetNodeIds.filter( + (x) => x.properties.findIndex((y) => y.displayName == "child") != -1 ); - if (elements) { - hasElement = true; - } + // 獲取子元素的 nodeId + targetNodeIds = chiElements.map((x) => x.properties[0].displayValue); + // 獲取子元素的屬性信息 + chiElements = await viewerGetProperties(targetNodeIds); - for (var e of elements) { - let name = e.properties[0].displayValue; // 獲取元素的 【tag_id】 屬性 - let chiElements = null; + // 將 node 元素的 【tag_id】 屬性和子元素的 nodeId 加入 Map 中 + evelMap.set(name, chiElements[0]?.dbId); + } - // 獲取 node 元素的子元素信息 - targetNodeIds = await viewerGetProperties([e.dbId], "child"); - // 二次篩選 - chiElements = targetNodeIds.filter( - (x) => x.properties.findIndex((y) => y.displayName == "child") != -1 - ); + if (!hasElement) { + callback ? callback([]) : ""; + return []; + } - // 獲取子元素的 nodeId - targetNodeIds = chiElements.map((x) => x.properties[0].displayValue); - // 獲取子元素的屬性信息 - chiElements = await viewerGetProperties(targetNodeIds); - - // 將 node 元素的 【tag_id】 屬性和子元素的 nodeId 加入 Map 中 - evelMap.set(name, chiElements[0]?.dbId); - } - - if (!hasElement) { - callback ? callback([]) : ""; - return []; - } - - callback ? callback(evelMap) : ""; - return evelMap; + callback ? callback(evelMap) : ""; + return evelMap; } function setElevatorFloor(floor) { - if (floor == 0) targetFloorZ = 0; - else if (floor == 1) targetFloorZ = 15; - else if (floor == 2) targetFloorZ = 26; + if (floor == 0) targetFloorZ = 0; + else if (floor == 1) targetFloorZ = 15; + else if (floor == 2) targetFloorZ = 26; } function setElevatorSpeed(speed) { - //0.01 ~ 1 - elevatorSpeed = speed; + //0.01 ~ 1 + elevatorSpeed = speed; } function movElevator() { - let tree = viewer.model?.getData().instanceTree; - let nodeId = 10952; - let fragProxyZ = 0; - var movStatus = 0; // 0=no 1=up 2=down + let tree = viewer.model?.getData().instanceTree; + let nodeId = 10952; + let fragProxyZ = 0; + var movStatus = 0; // 0=no 1=up 2=down - if (fragProxy.position.z > targetFloorZ) { - movStatus = 2; - } else if (fragProxy.position.z < targetFloorZ) { - movStatus = 1; - } + if (fragProxy.position.z > targetFloorZ) { + movStatus = 2; + } else if (fragProxy.position.z < targetFloorZ) { + movStatus = 1; + } - if (movStatus == 0) { - return; - } - - tree.enumNodeFragments(nodeId, function (frag) { - fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag); - fragProxy.getAnimTransform(); - //let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26 - if (movStatus == 2) { - fragProxy.position.z -= elevatorSpeed; - } else if (movStatus == 1) { - fragProxy.position.z += elevatorSpeed; - } - - fragProxyZ = fragProxy.position.z; - fragProxy.updateAnimTransform(); - }); - viewer.impl.sceneUpdated(true); + if (movStatus == 0) { + return; + } + tree.enumNodeFragments(nodeId, function (frag) { + fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag); + fragProxy.getAnimTransform(); + //let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26 if (movStatus == 2) { - if (fragProxyZ >= targetFloorZ) { - requestAnimationFrame(movElevator); - } + fragProxy.position.z -= elevatorSpeed; } else if (movStatus == 1) { - if (fragProxyZ <= targetFloorZ) { - requestAnimationFrame(movElevator); - } + fragProxy.position.z += elevatorSpeed; } - //let fragPosition = new THREE.Vector3(position);// 一樓0 二樓15 三樓 26 + fragProxyZ = fragProxy.position.z; + fragProxy.updateAnimTransform(); + }); + viewer.impl.sceneUpdated(true); - //fragProxy.position = fragPosition; + if (movStatus == 2) { + if (fragProxyZ >= targetFloorZ) { + requestAnimationFrame(movElevator); + } + } else if (movStatus == 1) { + if (fragProxyZ <= targetFloorZ) { + requestAnimationFrame(movElevator); + } + } - //fragProxy.updateAnimTransform(); + //let fragPosition = new THREE.Vector3(position);// 一樓0 二樓15 三樓 26 - //viewer.impl.sceneUpdated(true); + //fragProxy.position = fragPosition; + + //fragProxy.updateAnimTransform(); + + //viewer.impl.sceneUpdated(true); } function getAllDbIds(viewer) { - var instanceTree = viewer.model?.getData().instanceTree; + var instanceTree = viewer.model?.getData().instanceTree; - var allDbIdsStr = Object.keys(instanceTree.nodeAccess.dbIdToIndex); + var allDbIdsStr = Object.keys(instanceTree.nodeAccess.dbIdToIndex); - return allDbIdsStr.map(function (id) { - return parseInt(id); - }); -} - -/** - * Autodesk.Viewing.Document.load() failuire callback. - */ -function onDocumentLoadFailure(viewerErrorCode) { - $(selector).trigger("autodesk:loaded:fail"); - console.error("onDocumentLoadFailure() - errorCode:" + viewerErrorCode); -} - -function getForgeToken(callback) { - fetch(forgeTokenBase.url).then((res) => { - res.json().then((data) => { - let limitResType = ["object", "undefined"]; - let access_token = data; - $.each(forgeTokenBase.res_access_token, (idx, dict) => { - access_token = access_token[dict]; - }); - - let expires_in = data; - $.each(forgeTokenBase.res_expires_in, (idx, dict) => { - expires_in = expires_in[dict]; - }); - - if ( - limitResType.includes(typeof access_token) || - limitResType.includes(typeof expires_in) - ) { - (access_token = ""), (expires_in = ""); - throw "access_token or expires_in on the ForgeTokenBase object for getting forge token by URL is not the correct path."; - } - - callback(access_token, expires_in); - }); - }); - //callback("eyJhbGciOiJSUzI1NiIsImtpZCI6IlU3c0dGRldUTzlBekNhSzBqZURRM2dQZXBURVdWN2VhIn0.eyJzY29wZSI6WyJkYXRhOndyaXRlIiwiZGF0YTpyZWFkIiwiYnVja2V0OnJlYWQiLCJidWNrZXQ6dXBkYXRlIiwiYnVja2V0OmNyZWF0ZSJdLCJjbGllbnRfaWQiOiJUQTNocXNGZnpRYk5PVVhLcGxkS1VLU2V3NFNKMjF3NSIsImF1ZCI6Imh0dHBzOi8vYXV0b2Rlc2suY29tL2F1ZC9hand0ZXhwNjAiLCJqdGkiOiJiemxzWE5qWElvZ2R1UjUzTUJkdlhrTTNTT01qeVB1bHJrMmdTVWJudGNTeDg1b01kRG1xejg3Z05jenJkRzhpIiwiZXhwIjoxNjY4MTgzMDM2fQ.VU3qLwTJ9nlXnomKCdk4y5UcgszGEO_zlvE7w5mWWajeBMwKLo-zw7LJEqUEajRksvssppR9SbVsjLSx-vDVc3DRhCo3jYTWKPT1T3wQrlkOSqLeIrAdnKdBDNBWKgrGJt_xcmXc3dZ3XNKf9L_F6Ex808rUlo6cem1mcPpKl1jCBDqKu1mAX7aDtZ65TTQZbGGhbG4HdnET-d1i5w4LunGN11UAHhDUW3n0SWWIBL27PiiUQONZttajhD5st6IngYLcjr93BYVyJmDF7-wm4WZlHSw2OnXIfbJcFXEd83uVv_Rej4UXjzZ0e6kHwzc2nvGvKSIFu3Nt7CabdR8CkA", 3599); + return allDbIdsStr.map(function (id) { + return parseInt(id); + }); } //------------------ 熱圖 ------------------------------- class ADHeatMaps { - constructor(option = {}) { - this.devices = option.devices ?? []; - this.checkNodeString = "【ROOM】"; - this.tempVals = []; - this.roomDbIds = []; //房間 dbId - this.model = null; - this.dataVizExtn = null; - this.shadingData = null; - this.onComplete = option.onComplete ?? null; - this.init(); + constructor(option = {}) { + this.devices = option.devices ?? []; + this.checkNodeString = "【ROOM】"; + this.tempVals = []; + this.roomDbIds = []; //房間 dbId + this.model = null; + this.dataVizExtn = null; + this.shadingData = null; + this.onComplete = option.onComplete ?? null; + this.init(); + } + + init = async function () { + // 儲存 Viewer 的模型 + this.model = viewer.model; + this.addHeatMaps(); + }; + + async addHeatMaps() { + // 載入 Autodesk Viewer 的資料視覺化擴充功能 + const dataVizExtn = await viewer.loadExtension( + "Autodesk.DataVisualization" + ); + const { + SurfaceShadingData, + SurfaceShadingPoint, + SurfaceShadingNode, + SurfaceShadingGroup, + } = Autodesk.DataVisualization.Core; + // test + const shadingGroup = new SurfaceShadingGroup("iot-heatmap"); + const rooms = new Map(); + + for (const { id, roomDbId, forge_dbid, position, sensorTypes } of this + .devices) { + if (!id || roomDbId == -1) { + continue; + } + + if (!rooms.has(roomDbId)) { + const room = new SurfaceShadingNode(id, roomDbId); + shadingGroup.addChild(room); + rooms.set(roomDbId, room); + } + let room = rooms.get(roomDbId); + room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes)); } - init = async function () { - // 載入 Autodesk Viewer 的資料視覺化擴充功能 - const dataVizExtn = await viewer.loadExtension( - "Autodesk.DataVisualization" - ); - this.dataVizExtn = dataVizExtn; - // 儲存 Viewer 的模型 - this.model = viewer.model; - this.addHeatMaps(); - }; + const shadingData = new SurfaceShadingData(); + shadingData.addChild(shadingGroup); - async addHeatMaps() { - const { - SurfaceShadingData, - SurfaceShadingPoint, - SurfaceShadingNode, - SurfaceShadingGroup, - } = Autodesk.DataVisualization.Core; - // test - const shadingGroup = new SurfaceShadingGroup("iot-heatmap"); - const rooms = new Map(); + shadingData.initialize(this.model); + this.shadingData = shadingData; - console.log(this.devices); - for (const { id, roomDbId, position, sensorTypes } of this.devices) { - if (!id || roomDbId == -1) { - continue; - } - - if (!rooms.has(roomDbId)) { - const room = new SurfaceShadingNode(id, roomDbId); - shadingGroup.addChild(room); - rooms.set(roomDbId, room); - } - const room = rooms.get(roomDbId); - room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes)); - } - this.shadingData = new SurfaceShadingData(); - this.shadingData.addChild(shadingGroup); - this.shadingData.initialize(this.model); - - if (pageAct.sysSubTag == "L1") { - await this.dataVizExtn.setupSurfaceShading(this.model, this.shadingData, { - type: "PlanarHeatmap", - placementPosition: 0.7, - confidence: 240.0, - }); - this.dataVizExtn.registerSurfaceShadingColors( - "temperature", - [0x000000, 0xffd524] - ); - } else { - await this.dataVizExtn.setupSurfaceShading(this.model, this.shadingData); - this.dataVizExtn.registerSurfaceShadingColors( - "temperature", - [0x0000ff, 0x00ff00, 0xffff00, 0xff0000] - ); - } - this.dataVizExtn.renderSurfaceShading( - "iot-heatmap", - "temperature", - this.getSensorValue.bind(this) - ); - - //let nodeIds = await getNodeIdByDbIds(this.checkNodeString); - //nodeIds = Array.from(nodeIds); - //nodeIds = nodeIds.map(x => { return { room: x[0] , nodeId: x[1]} }); - // this.roomDbIds = this.devices.filter(x => x.roomDbId != -1).map(x => x.roomDbId).Distinct(); - - // // 建立一個 SurfaceShadingData 物件,並將 SurfaceShadingNode 加入到該物件中 - // const heatmapData = new SurfaceShadingData(); - - // $.each(this.roomDbIds, (idx, rDbid) => { - // // 建立一個名為 "Room Panel" 的 SurfaceShadingNode 物件,並將房間的模型給傳入,只在該房間呈現溫度 - // const shadingNode = new SurfaceShadingNode("RoomPanel" + rDbid, rDbid); - - // // 遍歷每個設備,建立一個 SurfaceShadingPoint 物件並加入到 SurfaceShadingNode 中,透過這些設備渲染溫度 - // this.devices.filter(x => x.roomDbId == rDbid).forEach((device) => { - // const shadingPoint = new SurfaceShadingPoint( - // device.id, - // undefined, - // device.sensorTypes - // ); - // shadingPoint.positionFromDBId(this.model, device.roomDbId) - // shadingNode.addPoint(shadingPoint); - // // device.temp = 0; - // }); - - // heatmapData.addChild(shadingNode); - // }) - - // // 將資料初始化並顯示在模型上 - // heatmapData.initialize(this.model); - - // // 對模型做表面顏色的渲染 - // await this.dataVizExtn.setupSurfaceShading(this.model, heatmapData); - - // // 對 "temperature" 的溫度設定兩種顏色:紅色和藍色 - // this.dataVizExtn.registerSurfaceShadingColors("temperature", [0x0000ff, 0x00ff00, 0xffff00, 0xff0000]); - - // $.each(this.roomDbIds, (idx, rDbid) => { - // this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", this.getSensorValue.bind(this)); - // }) - - // /*this.changeTemp(this.tempVal);*/ - this.onComplete ? this.onComplete() : ""; + if (pageAct.sysSubTag == "L1") { + await dataVizExtn.setupSurfaceShading(this.model, shadingData, { + type: "PlanarHeatmap", + placementPosition: 0.7, + confidence: 240.0, + }); + dataVizExtn.registerSurfaceShadingColors( + "temperature", + // [0x000000, 0xffd524] + [0xff0000, 0x0000ff] + ); + } else { + await dataVizExtn.setupSurfaceShading(this.model, shadingData); + dataVizExtn.registerSurfaceShadingColors( + "temperature", + [0x0000ff, 0x00ff00, 0xffff00, 0xff0000] + ); } + dataVizExtn.renderSurfaceShading( + "iot-heatmap", + "temperature", + this.getSensorValue.bind(this) + ); - getSensorValue = function (device, sensorType) { - let dev = this.devices.filter((x) => x.id == device.id)[0]; - // shadingPoint.positionFromDBId(this.model, device.roomDbId) - return dev.temp / 40; - }; + this.onComplete ? this.onComplete() : ""; + } - // 改變溫度 - changeTemp = async function (devId, temp) { - // console.log("changeTemp",devId, temp) - this.tempVal = temp; - // 透過 device id 取得 roomDbId - this.devices.forEach((dev) => { - if (devId == dev.id) { - dev.temp = temp; - } - }); + getSensorValue = function (device, sensorType) { + let dev = this.devices.filter((x) => x.id == device.id)[0]; + return dev._temp / 40; + }; - if (!this.shadingData) { - await this.addHeatMaps(); - this.dataVizExtn.renderSurfaceShading( - "iot-heatmap", - "temperature", - this.getSensorValue.bind(this) - ); - } else { - this.dataVizExtn.updateSurfaceShading(this.getSensorValue.bind(this)); - } - // $.each(this.roomDbIds, async (idx, rDbid) => { - // this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", this.getSensorValue.bind(this)); - // }) + // 改變溫度 + changeTemp = async function (devId, temp) { + const dataVizExtn = await viewer.loadExtension( + "Autodesk.DataVisualization" + ); + // console.log("changeTemp",devId, temp) + this.tempVal = temp; + // 透過 device id 取得 roomDbId + this.devices.forEach((dev) => { + if (devId == dev.id) { + dev._temp = temp; + } + }); - //if (rDbid != null) { - // // 取得新的溫度值 - // let getSensorValue = (device, sensorType) => { - // return this.tempVal / 40; - // } - // // 對 "Room Panel" 做表面顏色的渲染,並使用新的溫度值 - // this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", getSensorValue); - //} - }; + if (!this.shadingData) { + await this.addHeatMaps(); + dataVizExtn.renderSurfaceShading( + "iot-heatmap", + "temperature", + this.getSensorValue.bind(this) + ); + } else { + dataVizExtn.updateSurfaceShading(this.getSensorValue.bind(this)); + } + // $.each(this.roomDbIds, async (idx, rDbid) => { + // this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", this.getSensorValue.bind(this)); + // }) + + //if (rDbid != null) { + // // 取得新的溫度值 + // let getSensorValue = (device, sensorType) => { + // return this.tempVal / 40; + // } + // // 對 "Room Panel" 做表面顏色的渲染,並使用新的溫度值 + // this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", getSensorValue); + //} + }; + + // 改變設備顏色 + changeErrorDevice() { + const ErrorDeviceList = new ErrorDevice({ + errorDevices: alarmDbIdList.map((d) => ({ + ...d, + roomDbId: !isNaN(parseInt(x.room_dbid)) ? parseInt(x.room_dbid) : -1, + id: d.device_number, + position: isJSON(d.device_coordinate_3d) + ? JSON.parse(d.device_coordinate_3d) + : {}, // x: 0, y: 25, z: -2.5 (3.35, -4.81, 12.88 + sensorTypes: ["error", "temperature", "humidity", "CO2"], + forge_dbid: parseInt(d.forge_dbid), + })), + }); + } } //全部物件 透明度: 輸入0:透明;輸入1:不透明 function setTransparentBuilding(transparent, filDbids = []) { - for (var i = 0; i < allDbIdsStr.length; i++) { - setTransparency(parseInt(allDbIdsStr[i]), transparent); - } + for (var i = 0; i < allDbIdsStr.length; i++) { + setTransparency(parseInt(allDbIdsStr[i]), transparent); + } - for (var i = 0; i < filDbids.length; i++) { - setTransparency(parseInt(filDbids[i]), transparent == 0 ? 1 : 0); - } + for (var i = 0; i < filDbids.length; i++) { + setTransparency(parseInt(filDbids[i]), transparent == 0 ? 1 : 0); + } } //設定模型 透明度 function setTransparency(nodeId, opacity) { - var model = viewer.model; - var fragList = viewer.model.getFragmentList(); - var fragIds = []; + var model = viewer.model; + var fragList = viewer.model.getFragmentList(); + var fragIds = []; - model.getData().instanceTree.enumNodeFragments( - nodeId, - (fragId) => { - // 將遍歷到的片段 ID 添加到結果陣列中 - fragIds.push(fragId); - }, - (nodeId) => { - // 如果遍歷到的節點是葉節點,则返回 true,表示繼續遍歷該節點的片段 - return model.getData().instanceTree.isLeaf(nodeId); - } - ); + model.getData().instanceTree.enumNodeFragments( + nodeId, + (fragId) => { + // 將遍歷到的片段 ID 添加到結果陣列中 + fragIds.push(fragId); + }, + (nodeId) => { + // 如果遍歷到的節點是葉節點,则返回 true,表示繼續遍歷該節點的片段 + return model.getData().instanceTree.isLeaf(nodeId); + } + ); - fragIds.forEach((fragId) => { - //获取材质 - var material = fragList.getMaterial(fragId); + fragIds.forEach((fragId) => { + //获取材质 + var material = fragList.getMaterial(fragId); - if (material) { - //设置透明度 - material.opacity = opacity; //0.5; - material.transparent = true; - //标记更新 - material.needsUpdate = true; - } - }); + if (material) { + //设置透明度 + material.opacity = opacity; //0.5; + material.transparent = true; + //标记更新 + material.needsUpdate = true; + } + }); - //更新viewer - viewer.impl.invalidate(true, true, true); + //更新viewer + viewer.impl.invalidate(true, true, true); } function changeColor(nodeId, color = [0, 255, 0, 1]) { - //電梯變綠色 - let model = viewer.model; - let fragList = viewer.model.getFragmentList(); - let instanceTree = viewer.model?.getData().instanceTree; - color = color.map((x, i) => (i < 3 ? x / 255 : x)); - color = new THREE.Vector4().fromArray(color); - model.getData().instanceTree.enumNodeFragments( - nodeId, - (fragId) => { - // 將遍歷到的片段 ID 添加到結果陣列中 - let material = fragList.getMaterial(fragId); + //電梯變綠色 + let model = viewer.model; + let fragList = viewer.model.getFragmentList(); + let instanceTree = viewer.model?.getData().instanceTree; + color = color.map((x, i) => (i < 3 ? x / 255 : x)); + color = new THREE.Vector4().fromArray(color); + model.getData().instanceTree.enumNodeFragments( + nodeId, + (fragId) => { + // 將遍歷到的片段 ID 添加到結果陣列中 + let material = fragList.getMaterial(fragId); - if (material) { - //设置透明度 - material.opacity = 1; //0.5; - material.transparent = true; - //标记更新 - material.needsUpdate = true; - } - }, - (nodeId) => { - // 如果遍歷到的節點是葉節點,则返回 true,表示繼續遍歷該節點的片段 - return model.getData().instanceTree.isLeaf(nodeId); - } - ); - instanceTree.enumNodeChildren( - nodeId, - function (chiNodeId) { - viewer.setThemingColor(chiNodeId, color); - }, - (chiNodeId) => { - // 如果遍歷到的節點是葉節點,则返回 true,表示繼續遍歷該節點的片段 - return model.getData().instanceTree.isLeaf(chiNodeId); - } - ); + if (material) { + //设置透明度 + material.opacity = 1; //0.5; + material.transparent = true; + //标记更新 + material.needsUpdate = true; + } + }, + (nodeId) => { + // 如果遍歷到的節點是葉節點,则返回 true,表示繼續遍歷該節點的片段 + return model.getData().instanceTree.isLeaf(nodeId); + } + ); + instanceTree.enumNodeChildren( + nodeId, + function (chiNodeId) { + viewer.setThemingColor(chiNodeId, color); + }, + (chiNodeId) => { + // 如果遍歷到的節點是葉節點,则返回 true,表示繼續遍歷該節點的片段 + return model.getData().instanceTree.isLeaf(chiNodeId); + } + ); } function hideColor(nodeId) { - //顏色改成透明 - let instanceTree = viewer.model?.getData().instanceTree; - instanceTree.enumNodeChildren( - nodeId, - function (chiNodeId) { - var color = new THREE.Vector4(0, 1, 0, 0); - viewer.setThemingColor(chiNodeId, color); - }, - true - ); + //顏色改成透明 + let instanceTree = viewer.model?.getData().instanceTree; + instanceTree.enumNodeChildren( + nodeId, + function (chiNodeId) { + var color = new THREE.Vector4(0, 1, 0, 0); + viewer.setThemingColor(chiNodeId, color); + }, + true + ); } //紀錄燈具座標 async function getLightData(data) { - lightList = []; - lightDataList = data; + lightList = []; + lightDataList = data; } async function testNewLight(dataList) { - dataList.forEach((myData, index) => { - const position = myData.position; - if (lightList.findIndex((x) => x.device_guid == myData.device_guid) == -1) { - lightList.push({ - dbid: myData.forge_dbid, - device_guid: myData.device_guid, - lightObject: new THREE.SpotLight(0xe1cf18, 10, 200, 1, 1, 2), - }); - } else if ( - lightList.findIndex((x) => x.device_guid == myData.device_node_guid) == -1 - ) { - lightList.push({ - dbid: myData.forge_dbid, - device_guid: myData.device_node_guid, - lightObject: new THREE.SpotLight(0xe1cf18, 10, 200, 1, 1, 2), - }); - } - if (position && position.x && position.y && position.z) { - lightList[index].lightObject.position.set( - position.x, - position.y, - position.z - ); - lightList[index].lightObject.castShadow = true; - lightList[index].lightObject.visible = true; - lightList[index].lightObject.target.position.set( - position.x, - position.y, - position.z - 100 - ); - viewer.scene.add(lightList[index].lightObject.target); - viewer.scene.add(lightList[index].lightObject); - } - - //let spotLightHelper = new THREE.SpotLightHelper(lightList[index].lightObject); - //viewer.scene.add(spotLightHelper); - }); - viewer.impl.sceneUpdated(true); + // changeColorForHotspot; } //------------------- 加入熱點 ----------------- async function addHotPoint(data) { - var viewer = data.target ? data.target : data; - const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); - const DataVizCore = Autodesk.DataVisualization.Core; - const viewableType = Autodesk.DataVisualization.Core.ViewableType.SPRITE; //DataVizCore.ViewableType.SPRITE; - let spriteColor = null; - let spriteIcon = ""; - const dbIdStart = 10; - const dbIdEnd = 19; - if (pageAct.sysSubTag === "M12") { - return; - } else { - spriteColor = new THREE.Color(0xffffff); - spriteIcon = "/file/img/forge/hotspot.svg"; - if (location.href.indexOf("localhost:5966") != -1) { - spriteIcon = "/img/forge/hotspot.svg"; + // console.log("addHotPoint", data) + if (!pageAct.sysSubTag && !pageAct.sysMainTag) { + return; + } + var viewer = data.target ? data.target : data; + const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); + const DataVizCore = Autodesk.DataVisualization.Core; + const viewableType = Autodesk.DataVisualization.Core.ViewableType.SPRITE; //DataVizCore.ViewableType.SPRITE; + let spriteColor = null; + let url = ""; + const dbIdStart = 10; + const dbIdEnd = 19; + spriteColor = new THREE.Color(0xffffff); + url = "/file/img/forge/sensor_circle.svg"; + if (location.href.indexOf("localhost:5966") != -1) { + url = "/img/forge/sensor_circle.svg"; + } + + const style = new DataVizCore.ViewableStyle(viewableType, spriteColor, url); + + if ( + lightDataList != undefined && + lightDataList != null && + lightDataList.length > 0 + ) { + testNewLight(lightDataList); + } + + //熱點 點擊事件註冊 + viewer.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClicked); // SPRITE_SELECTED + // viewer.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClickedOut); + //viewer.addEventListener( + // Autodesk.Viewing.SELECTION_CHANGED_EVENT, + // onSelectionChange + //); + + const viewableData = new DataVizCore.ViewableData(); + viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels + myDataList.forEach((myData, index) => { + const dbId = 10 + index; + const myPosition = myData.position; + const viewable = new DataVizCore.SpriteViewable(myPosition, style, dbId); + myData._dbId = dbId; + viewableData.addViewable(viewable); + }); + await viewableData.finish(); + dataVizExtn.addViewables(viewableData); + // console.log(dataVizExtn) + $(selector).trigger("autodesk:complete:sprite", { myDataList }); + + //---------------- 熱點點擊事件 -------------------- + function onSpriteClicked(event) { + event.hasStopped = true; + if (event != undefined && event != null) { + if (event.dbId >= dbIdStart) { + //event.dbId > 0 && event.dbId < 19 + // console.log(`Sprite clicked: ${event.dbId}`); + + + for (let i = dbIdStart; i <= myDataList.length + 10; i++) { + !alarmDbIdList.some(({ spriteDbid }) => spriteDbid == i) && + pageAct.sysSubTag !== "L1" && + changeColorForHotspot(i); + changeScaleForHotspot(i, true); } - } - const style = new DataVizCore.ViewableStyle( - viewableType, - spriteColor, - spriteIcon - ); - - if ( - lightDataList != undefined && - lightDataList != null && - lightDataList.length > 0 - ) { - testNewLight(lightDataList); - } - - //熱點 點擊事件註冊 - viewer.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClicked); // SPRITE_SELECTED - // viewer.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClickedOut); - //viewer.addEventListener( - // Autodesk.Viewing.SELECTION_CHANGED_EVENT, - // onSelectionChange - //); - - const viewableData = new DataVizCore.ViewableData(); - viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels - myDataList.forEach((myData, index) => { - const dbId = 10 + index; - const myPosition = myData.position; - const viewable = new DataVizCore.SpriteViewable(myPosition, style, dbId); - myData._dbId = dbId; - viewableData.addViewable(viewable); - }); - await viewableData.finish(); - dataVizExtn.addViewables(viewableData); - // console.log(dataVizExtn) - $(selector).trigger("autodesk:complete:sprite", { myDataList }); - - //---------------- 熱點點擊事件 -------------------- - function onSpriteClicked(event) { - event.hasStopped = true; - if (event != undefined && event != null) { - if (event.dbId >= dbIdStart) { - //event.dbId > 0 && event.dbId < 19 - // console.log(`Sprite clicked: ${event.dbId}`); - - for (let i = dbIdStart; i <= myDataList.length + 10; i++) { - !alarmDbIdList.some((dbId) => dbId == i) && - pageAct.sysSubTag !== "L1" && - changeColorForHotspot(i); - changeScaleForHotspot(i, true); - } - let myData = myDataList.filter((x) => x._dbId == event.dbId)[0]; - if ( - lightList != undefined && - lightList != null && - lightList.length > 0 - ) { - //setLightOpenOrClose(false, myData.device_guid);//關燈測試 - //setLightValues(myData.device_guid, 20, 0x00ff00);//更改燈光顏色和強度的測試 - moveViewToDevice(myData.forge_dbid); //移動視角至該設備 - } - $(selector).trigger("autodesk:click:sprite", { event, myData }); - } else { - !alarmDbIdList.some((dbId) => dbId == i) && - pageAct.sysSubTag !== "L1" && - changeColorForHotspot(event.dbId, null); - changeScaleForHotspot(event.dbId, false); - $(selector).trigger("autodesk:clickOut:sprite", { event }); - } - - if (event.clickInfo != null) { - //document.getElementById('deviceName').innerHTML = viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId); - //document.getElementById('deviceDbid').innerHTML = event.clickInfo.dbId; - //document.getElementById('devicePosition').innerHTML = "(" + (event.clickInfo.point.x).toFixed(2) + ", " + (event.clickInfo.point.y).toFixed(2) + ", " + (event.clickInfo.point.z).toFixed(2) + ")"; - // console.log(`event>> dbId: ${event.clickInfo.dbId}, id: ${event.clickInfo.object.id}, position.x: ${event.clickInfo.point.x}, y: ${event.clickInfo.point.y}, z: ${event.clickInfo.point.z}, name: ${viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId)}`); - } + let myData = myDataList.filter((x) => x._dbId == event.dbId)[0]; + if (myData && pageAct.sysSubTag == "L1" && pageAct.floTag == null) { + getLTNode(myData); } + if ( + lightList != undefined && + lightList != null && + lightList.length > 0 + ) { + //setLightOpenOrClose(false, myData.device_guid);//關燈測試 + //setLightValues(myData.device_guid, 20, 0x00ff00);//更改燈光顏色和強度的測試 + moveViewToDevice(myData.forge_dbid); //移動視角至該設備 + } + $(selector).trigger("autodesk:click:sprite", { event, myData }); + } else { + !alarmDbIdList.some(({ spriteDbid }) => spriteDbid == event.dbId) && + pageAct.sysSubTag !== "L1" && + changeColorForHotspot(event.dbId, null); + changeScaleForHotspot(event.dbId, false); + $(selector).trigger("autodesk:clickOut:sprite", { event }); + } + + if (event.clickInfo != null) { + //document.getElementById('deviceName').innerHTML = viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId); + //document.getElementById('deviceDbid').innerHTML = event.clickInfo.dbId; + //document.getElementById('devicePosition').innerHTML = "(" + (event.clickInfo.point.x).toFixed(2) + ", " + (event.clickInfo.point.y).toFixed(2) + ", " + (event.clickInfo.point.z).toFixed(2) + ")"; + // console.log(`event>> dbId: ${event.clickInfo.dbId}, id: ${event.clickInfo.object.id}, position.x: ${event.clickInfo.point.x}, y: ${event.clickInfo.point.y}, z: ${event.clickInfo.point.z}, name: ${viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId)}`); + } } + } - // function onSpriteClickedOut(event){ - // event.hasStopped = true; - // if (event != undefined && event != null) { - // if (event.dbId >= dbIdStart) { - // for (let i = dbIdStart; i <= myDataList.length + 10; i++) { - // changeColorForHotspot(event.dbId); - // changeScaleForHotspot(event.dbId, false); - // } - // let myData = myDataList.filter(x => x._dbId == event.dbId)[0]; - // debugger - // $(selector).trigger("autodesk:clickOut:sprite", { event }); - // } - // } - // } + // function onSpriteClickedOut(event){ + // event.hasStopped = true; + // if (event != undefined && event != null) { + // if (event.dbId >= dbIdStart) { + // for (let i = dbIdStart; i <= myDataList.length + 10; i++) { + // changeColorForHotspot(event.dbId); + // changeScaleForHotspot(event.dbId, false); + // } + // let myData = myDataList.filter(x => x._dbId == event.dbId)[0]; + // debugger + // $(selector).trigger("autodesk:clickOut:sprite", { event }); + // } + // } + // } - //function onSelectionChange(event) { - // if (event != undefined && event != null) { - // const dbIds = event.dbIdArray; + //function onSelectionChange(event) { + // if (event != undefined && event != null) { + // const dbIds = event.dbIdArray; - // if (dbIds.length > 0) { - // // 處理已選取元件的邏輯 - // $(selector).trigger("autodesk:click:sprite", event); - // console.log(`------ name: ${viewer.model.getInstanceTree().getNodeName(dbIds)} , dbId: ${dbIds}`);//, id: ${event.clickInfo.object.id}, position.x: ${event.clickInfo.point.x}, y: ${event.clickInfo.point.y}, z: ${event.clickInfo.point.z} - // } else { - // // 處理沒有選取元件的邏輯 - // $(selector).trigger("autodesk:click:sprite", event); - // console.log("no item"); - // } - // } - //} + // if (dbIds.length > 0) { + // // 處理已選取元件的邏輯 + // $(selector).trigger("autodesk:click:sprite", event); + // console.log(`------ name: ${viewer.model.getInstanceTree().getNodeName(dbIds)} , dbId: ${dbIds}`);//, id: ${event.clickInfo.object.id}, position.x: ${event.clickInfo.point.x}, y: ${event.clickInfo.point.y}, z: ${event.clickInfo.point.z} + // } else { + // // 處理沒有選取元件的邏輯 + // $(selector).trigger("autodesk:click:sprite", event); + // console.log("no item"); + // } + // } + //} +} + +//hex -> rgb +function hexToRgb(hex) { + return ( + "rgb(" + + parseInt("0x" + hex.slice(1, 3)) + + "," + + parseInt("0x" + hex.slice(3, 5)) + + "," + + parseInt("0x" + hex.slice(5, 7)) + + ")" + ); } // 熱點 更換顏色 -async function changeColorForHotspot(dbId, type = null, lightOn = false) { - const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); - let spriteColorFocus = new THREE.Color(0xffffff); - if (pageAct.sysSubTag == "L1") { - spriteColorFocus = lightOn - ? new THREE.Color(0xffd524) - : new THREE.Color(0x40525e); - if (lightOn) { - console.log(dbId); - } - } else if (type == "focus" && pageAct.sysSubTag !== "M12") { - spriteColorFocus = new THREE.Color(0x00ffe1); - } else if (type == "error") { - spriteColorFocus = new THREE.Color(0xff0000); +async function changeColorForHotspot(dbId, type = null, OnOff = false) { + const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); + let spriteColorFocus = new THREE.Color(0xffffff); + + spriteColorFocus = OnOff + ? pageAct.sysSubObj.device_normal_color + ? new THREE.Color(hexToRgb(pageAct.sysSubObj.device_normal_color)) + : new THREE.Color(0xffffff) + : pageAct.sysSubObj.device_close_color + ? new THREE.Color(hexToRgb(pageAct.sysSubObj.device_close_color)) + : new THREE.Color(0xffffff); + + if (type == "focus") { + spriteColorFocus = new THREE.Color(0x00ffe1); + } else if (type == "error") { + spriteColorFocus = new THREE.Color( + hexToRgb(pageAct.sysSubObj.device_error_color) + ); + spriteErrIcon = baseForgeApiUrl + "/file/img/forge/sensor_circle.svg"; + if (location.href.indexOf("localhost:5966") != -1) { + spriteErrIcon = baseForgeApiUrl + "/img/forge/sensor_circle.svg"; } - const viewablesToUpdate = dbId; - dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => { - return { - color: spriteColorFocus, - }; - }); + } + const viewablesToUpdate = dbId; + dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => { + return { + url: "/file/img/forge/sensor_circle.svg", + color: spriteColorFocus, + }; + }); +} + +// 更換 icon +async function changeScaleForHotspot(dbId, type = true) { + const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); + let spriteErrIcon = baseForgeApiUrl + "/file/img/forge/sensor_circle.svg"; + if (location.href.indexOf("localhost:5966") != -1) { + spriteErrIcon = baseForgeApiUrl + "/img/forge/hotspot.svg"; + } + const viewablesToUpdate = dbId; + dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => { + return { + url: spriteErrIcon, + }; + }); } // 熱點 更換大小 async function changeScaleForHotspot(dbId, type = true) { - const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); - let scale = 1; - if (type) { - scale = 1.2; - } - const viewablesToUpdate = dbId; - dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => { - return { - scale: scale, // Restore the viewable size - //url: "https://.../circle.svg", - }; - }); + const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); + let scale = 1; + if (type) { + scale = 1.5; + } + const viewablesToUpdate = dbId; + dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => { + return { + scale: scale, // Restore the viewable size + //url: "https://.../circle.svg", + }; + }); } //------------------- end -------------- //------------------ 熱圖 ------------------------------- async function loadHeatmaps(model) { - //console.log("熱圖 loadHeat") - const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); + //console.log("熱圖 loadHeat") + const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); - //取三個空調設備的位置打點 - const devices = [ - { - id: "Oficina 5", - //name: "Oficina-", - position: { x: 6.98, y: -19.0, z: 16.86 }, // x: 0, y: 25, z: -2.5 (-4.93, -20.61, 16.86) - sensorTypes: ["temperature", "humidity"], - }, - { - id: "Oficina 4", - //name: "Oficina-", - position: { x: 35.85, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (23.94, -3.85, 16.86) - sensorTypes: ["temperature", "humidity"], - }, - { - id: "Oficina 3", - //name: "Oficina-", - position: { x: 6.98, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (-4.93, -3.85, 16.86) - sensorTypes: ["temperature", "humidity"], - }, - ]; - //冷氣N5: (-4.93, -20.61, 16.86), N4: (23.94, -3.85, 16.86), N3: (-4.93, -3.85, 16.86) + //取三個空調設備的位置打點 + const devices = [ + { + id: "Oficina 5", + //name: "Oficina-", + position: { x: 6.98, y: -19.0, z: 16.86 }, // x: 0, y: 25, z: -2.5 (-4.93, -20.61, 16.86) + sensorTypes: ["temperature", "humidity"], + }, + { + id: "Oficina 4", + //name: "Oficina-", + position: { x: 35.85, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (23.94, -3.85, 16.86) + sensorTypes: ["temperature", "humidity"], + }, + { + id: "Oficina 3", + //name: "Oficina-", + position: { x: 6.98, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (-4.93, -3.85, 16.86) + sensorTypes: ["temperature", "humidity"], + }, + ]; + //冷氣N5: (-4.93, -20.61, 16.86), N4: (23.94, -3.85, 16.86), N3: (-4.93, -3.85, 16.86) - // Initialize sensor values - let sensorVals = []; + // Initialize sensor values + let sensorVals = []; + for (let i = 0; i < devices.length; i++) { + sensorVals[i] = Math.random(); + } + + const roomDbIds = []; + roomDbIds.push(7567); + + const { SurfaceShadingData, SurfaceShadingPoint, SurfaceShadingNode } = + Autodesk.DataVisualization.Core; + + const shadingNode = new SurfaceShadingNode("Room Panel", roomDbIds); + + devices.forEach((device) => { + const shadingPoint = new SurfaceShadingPoint( + device.id, + device.position, + device.sensorTypes + ); + shadingNode.addPoint(shadingPoint); + }); + + const heatmapData = new SurfaceShadingData(); + heatmapData.addChild(shadingNode); + heatmapData.initialize(model); + + // Setup surface shading + await dataVizExtn.setupSurfaceShading(model, heatmapData); + + dataVizExtn.registerSurfaceShadingColors("temperature", [0xff0000, 0x0000ff]); + + function getSensorValue(device, sensorType) { + return sensorVals[parseInt(device.id.slice(-1)) - 1]; + } + + dataVizExtn.renderSurfaceShading("Room Panel", "temperature", getSensorValue); + + setInterval(() => { + // Modify sensor values. for (let i = 0; i < devices.length; i++) { - sensorVals[i] = Math.random(); + sensorVals[i] = Math.random(); } - - const roomDbIds = []; - roomDbIds.push(7567); - - const { SurfaceShadingData, SurfaceShadingPoint, SurfaceShadingNode } = - Autodesk.DataVisualization.Core; - - const shadingNode = new SurfaceShadingNode("Room Panel", roomDbIds); - - devices.forEach((device) => { - const shadingPoint = new SurfaceShadingPoint( - device.id, - device.position, - device.sensorTypes - ); - shadingNode.addPoint(shadingPoint); - }); - - const heatmapData = new SurfaceShadingData(); - heatmapData.addChild(shadingNode); - heatmapData.initialize(model); - - // Setup surface shading - await dataVizExtn.setupSurfaceShading(model, heatmapData); - - dataVizExtn.registerSurfaceShadingColors("temperature", [0xff0000, 0x0000ff]); - - function getSensorValue(device, sensorType) { - return sensorVals[parseInt(device.id.slice(-1)) - 1]; - } - - dataVizExtn.renderSurfaceShading("Room Panel", "temperature", getSensorValue); - - setInterval(() => { - // Modify sensor values. - for (let i = 0; i < devices.length; i++) { - sensorVals[i] = Math.random(); - } - dataVizExtn.updateSurfaceShading(getSensorValue); - }, 2000); + dataVizExtn.updateSurfaceShading(getSensorValue); + }, 2000); } //------------------ end -------------------------------- async function loadHeatmapsForFloor(model) { - const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); + const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); - //x: -17.33, y: 51.03, z: -2.52 - const devices = [ - { - id: "Oficina 5", - //name: "Oficina-", - position: { x: 6.98, y: -19.0, z: 16.86 }, // x: 0, y: 25, z: -2.5 (-4.93, -20.61, 16.86) - sensorTypes: ["temperature", "humidity"], - }, - { - id: "Oficina 4", - //name: "Oficina-", - position: { x: 35.85, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (23.94, -3.85, 16.86) - sensorTypes: ["temperature", "humidity"], - }, - { - id: "Oficina 3", - //name: "Oficina-", - position: { x: 6.98, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (-4.93, -3.85, 16.86) - sensorTypes: ["temperature", "humidity"], - }, - ]; + //x: -17.33, y: 51.03, z: -2.52 + const devices = [ + { + id: "Oficina 5", + //name: "Oficina-", + position: { x: 6.98, y: -19.0, z: 16.86 }, // x: 0, y: 25, z: -2.5 (-4.93, -20.61, 16.86) + sensorTypes: ["temperature", "humidity"], + }, + { + id: "Oficina 4", + //name: "Oficina-", + position: { x: 35.85, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (23.94, -3.85, 16.86) + sensorTypes: ["temperature", "humidity"], + }, + { + id: "Oficina 3", + //name: "Oficina-", + position: { x: 6.98, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (-4.93, -3.85, 16.86) + sensorTypes: ["temperature", "humidity"], + }, + ]; - // Initialize sensor values - let sensorVals = []; + // Initialize sensor values + let sensorVals = []; + for (let i = 0; i < devices.length; i++) { + sensorVals[i] = Math.random(); + } + + const roomDbIds = []; + + roomDbIds.push(7567); + + const { SurfaceShadingData, SurfaceShadingPoint, SurfaceShadingNode } = + Autodesk.DataVisualization.Core; + + const shadingNode = new SurfaceShadingNode("Room Panel", roomDbIds); + + devices.forEach((device) => { + const shadingPoint = new SurfaceShadingPoint( + device.id, + device.position, + device.sensorTypes + ); + shadingNode.addPoint(shadingPoint); + }); + + const heatmapData = new SurfaceShadingData(); + heatmapData.addChild(shadingNode); + heatmapData.initialize(model); + + // Setup surface shading + await dataVizExtn.setupSurfaceShading(model, heatmapData); + + //dataVizExtn.registerSurfaceShadingColors("co2", [0x00ff00, 0xff0000]); + dataVizExtn.registerSurfaceShadingColors("temperature", [0xff0000, 0x0000ff]); + + function getSensorValue(device, sensorType) { + return sensorVals[parseInt(device.id.slice(-1)) - 1]; + } + + dataVizExtn.renderSurfaceShading("Room Panel", "temperature", getSensorValue); + + setInterval(() => { + // Modify sensor values. for (let i = 0; i < devices.length; i++) { - sensorVals[i] = Math.random(); + sensorVals[i] = Math.random(); } - - const roomDbIds = []; - - roomDbIds.push(7567); - - const { SurfaceShadingData, SurfaceShadingPoint, SurfaceShadingNode } = - Autodesk.DataVisualization.Core; - - const shadingNode = new SurfaceShadingNode("Room Panel", roomDbIds); - - devices.forEach((device) => { - const shadingPoint = new SurfaceShadingPoint( - device.id, - device.position, - device.sensorTypes - ); - shadingNode.addPoint(shadingPoint); - }); - - const heatmapData = new SurfaceShadingData(); - heatmapData.addChild(shadingNode); - heatmapData.initialize(model); - - // Setup surface shading - await dataVizExtn.setupSurfaceShading(model, heatmapData); - - //dataVizExtn.registerSurfaceShadingColors("co2", [0x00ff00, 0xff0000]); - dataVizExtn.registerSurfaceShadingColors("temperature", [0xff0000, 0x0000ff]); - - function getSensorValue(device, sensorType) { - return sensorVals[parseInt(device.id.slice(-1)) - 1]; - } - - dataVizExtn.renderSurfaceShading("Room Panel", "temperature", getSensorValue); - - setInterval(() => { - // Modify sensor values. - for (let i = 0; i < devices.length; i++) { - sensorVals[i] = Math.random(); - } - dataVizExtn.updateSurfaceShading(getSensorValue); - }, 2000); + dataVizExtn.updateSurfaceShading(getSensorValue); + }, 2000); } // async function loadHeatmap() { - const model = viewer.model; - loadHeatmaps(model); + const model = viewer.model; + loadHeatmaps(model); } async function loadHeatmapForFloor() { - const model = viewer.model; - loadHeatmapsForFloor(model); + const model = viewer.model; + loadHeatmapsForFloor(model); } //------------ 剖面 ---------------------- function findLevels(model) { - return new Promise((resolve, reject) => { - model.search( - "layer", - (nodeIds) => { - let levels = []; - const tree = viewer.model.getInstanceTree(); - for (let i = 0; i < nodeIds.length; i++) { - const dbId = nodeIds[i]; - const name = tree.getNodeName(dbId); - if (!name || name.includes("<沒有層級>")) continue; - levels.push({ - guid: dbId, - name, - dbId, - extension: { - buildingStory: true, - structure: false, - computationHeight: 0, - groundPlane: false, - hasAssociatedViewPlans: false, - }, - }); - } - resolve(levels); + return new Promise((resolve, reject) => { + model.search( + "layer", + (nodeIds) => { + let levels = []; + const tree = viewer.model.getInstanceTree(); + for (let i = 0; i < nodeIds.length; i++) { + const dbId = nodeIds[i]; + const name = tree.getNodeName(dbId); + if (!name || name.includes("<沒有層級>")) continue; + levels.push({ + guid: dbId, + name, + dbId, + extension: { + buildingStory: true, + structure: false, + computationHeight: 0, + groundPlane: false, + hasAssociatedViewPlans: false, }, - (e) => { - reject(e); - } - ); - }); + }); + } + resolve(levels); + }, + (e) => { + reject(e); + } + ); + }); } async function getRemoteLevels() { - let aecData = await Autodesk.Viewing.Document.getAecModelData( - this.viewer.model.getDocumentNode() - ); + let aecData = await Autodesk.Viewing.Document.getAecModelData( + viewer.model.getDocumentNode() + ); - let levels; - if (!aecData || !aecData.levels) { - const levelExt = await viewer.loadExtension("Autodesk.AEC.LevelsExtension"); - levelExt.setAecModelData(undefined, viewer.model); //!<<< Clear before reset - levels = await findLevels(viewer.model); - aecdata = Autodesk.AEC.AecModelData.computeLevels(levels, viewer.model); //!<<< Rebuild aec model data - } else { - levels = aecData.levels; - } - levels.sort((a, b) => b.elevation - a.elevation); - return levels; + let levels; + if (!aecData || !aecData.levels) { + const levelExt = await viewer.loadExtension("Autodesk.AEC.LevelsExtension"); + levelExt.setAecModelData(undefined, viewer.model); //!<<< Clear before reset + levels = await findLevels(viewer.model); + aecdata = Autodesk.AEC.AecModelData.computeLevels(levels, viewer.model); //!<<< Rebuild aec model data + } else { + levels = aecData.levels; + } + levels.sort((a, b) => b.elevation - a.elevation); + return levels; } async function getLevelsData(lowerFloor, upperFloor, callback = null) { - // 樓層正規化 取得樓層 - const floorRegex = /[\d|\w]+F/gim; - const floorRegex2 = /^FL[\d|\w]+/gim; - const data = await this.getRemoteLevels(); - for (var i = 0; i < data.length; i++) { - let name = - data[i].name?.match(floorRegex) || data[i].name?.match(floorRegex2); - if ( - name && - (name[0] == lowerFloor || name[0].split("L")[1] + "F" == lowerFloor) - ) { - lowerIdx = i; - } - if ( - name && - (name[0] == upperFloor || name[0].split("L")[1] + "F" == upperFloor) - ) { - if (i > upperIdx && lowerFloor == upperFloor) { - } else { - upperIdx = i; - } - } + // 樓層正規化 取得樓層 + const floorRegex = /[\d|\w]+F/gim; + const floorRegex2 = /^FL[\d|\w]+/gim; + const data = await getRemoteLevels(); + for (var i = 0; i < data.length; i++) { + let name = + data[i].name?.match(floorRegex) || data[i].name?.match(floorRegex2); + if ( + name && + (name[0] == lowerFloor || name[0].split("L")[1] + "F" == lowerFloor) + ) { + lowerIdx = i; } + if ( + name && + (name[0] == upperFloor || name[0].split("L")[1] + "F" == upperFloor) + ) { + if (i > upperIdx && lowerFloor == upperFloor) { + } else { + upperIdx = i; + } + } + } - this.levels = data; - profile(callback); + this.levels = data; + profile(callback); } function getCutPlaneParam(idx, n) { - if (idx < 0 || !n) return; + if (idx < 0 || !n) return; - const level = this.levels[idx]; - if (!level) return; + const level = this.levels[idx]; + if (!level) return; - const model = this.viewer.model; - const globalOffset = model.getData().globalOffset; - const units = model.getUnitString(); - const elevRaw = Autodesk.Viewing.Private.convertUnits( - "ft", - units, - 1, - level.elevation - ); - let d = elevRaw - globalOffset.z - 0.5; - if (n == 1) d = -1 * d; + const model = viewer.model; + const globalOffset = model.getData().globalOffset; + const units = model.getUnitString(); + const elevRaw = Autodesk.Viewing.Private.convertUnits( + "ft", + units, + 1, + level.elevation + ); + let d = elevRaw - globalOffset.z - 0.5; + if (n == 1) d = -1 * d; - return new THREE.Vector4(0, 0, n, d); + return new THREE.Vector4(0, 0, n, d); } function profile(callback = null) { - //const upperIdx = 6; - const upperCutPlaneParam = this.getCutPlaneParam(upperIdx, 1); - //const lowerIdx = 7; - const lowerCutPlaneParam = this.getCutPlaneParam(lowerIdx, -1); - this.viewer.setCutPlanes([upperCutPlaneParam, lowerCutPlaneParam]); - callback ? callback() : ""; + //const upperIdx = 6; + const upperCutPlaneParam = this.getCutPlaneParam(upperIdx, 1); + //const lowerIdx = 7; + const lowerCutPlaneParam = this.getCutPlaneParam(lowerIdx, -1); + viewer.setCutPlanes([upperCutPlaneParam, lowerCutPlaneParam]); + callback ? callback() : ""; } //----------------- end ----------------------------------------------- //新增燈光 async function newLight(lightPosition) { - //聚光燈 - var spotLight = new THREE.SpotLight(0xe1cf18, 0, 20, 0.6, 0.5, 10); - spotLight.position.set(lightPosition.x, lightPosition.y, lightPosition.z); - // console.log(lightPosition.x, lightPosition.y, lightPosition.z) - spotLight.castShadow = false; - spotLight.visible = true; - spotLight.target.position.set( - lightPosition.x, - lightPosition.y, - lightPosition.z - 20 - ); - viewer.scene.add(spotLight.target); - viewer.scene.add(spotLight); - viewer.impl.sceneUpdated(true); + //聚光燈 + var spotLight = new THREE.SpotLight(0xe1cf18, 0, 20, 0.6, 0.5, 10); + spotLight.position.set(lightPosition.x, lightPosition.y, lightPosition.z); + // console.log(lightPosition.x, lightPosition.y, lightPosition.z) + spotLight.castShadow = false; + spotLight.visible = true; + spotLight.target.position.set( + lightPosition.x, + lightPosition.y, + lightPosition.z - 20 + ); + viewer.scene.add(spotLight.target); + viewer.scene.add(spotLight); + viewer.impl.sceneUpdated(true); - return spotLight; + return spotLight; } //調整燈光 強度、顏色 async function setLightValues(deviceGuid, intensity, color) { - const light = lightList.find(({ device_guid }) => device_guid === deviceGuid); - if (light) { - console.log(light, intensity, color); - light.lightObject.intensity = intensity; - var tempcolor = new THREE.Color().setHex(color); - light.lightObject.color = tempcolor; - } - // for (var i = 0; i < lightList.length; i++) { - // if (lightList[i].device_guid == deviceGuid) { - // lightList[i].lightObject.intensity = intensity; + const light = lightList.find(({ device_guid }) => device_guid === deviceGuid); - // var tempcolor = new THREE.Color().setHex(color); - // lightList[i].lightObject.color = tempcolor; - // } - // } - viewer.impl.sceneUpdated(true); + if (light) { + light.lightObject.intensity = intensity; + var tempcolor = new THREE.Color().setHex(color); + light.lightObject.color = tempcolor; + } + // for (var i = 0; i < lightList.length; i++) { + // if (lightList[i].device_guid == deviceGuid) { + // lightList[i].lightObject.intensity = intensity; + + // var tempcolor = new THREE.Color().setHex(color); + // lightList[i].lightObject.color = tempcolor; + // } + // } + viewer.impl.sceneUpdated(true); } //燈光開關 async function setLightOpenOrClose(value, deviceGuid) { - for (var i = 0; i < lightList.length; i++) { - if (lightList[i].device_guid == deviceGuid) { - lightList[i].lightObject.visible = value; - } + for (var i = 0; i < lightList.length; i++) { + if (lightList[i].device_guid == deviceGuid) { + lightList[i].lightObject.visible = value; } - viewer.impl.sceneUpdated(true); + } + viewer.impl.sceneUpdated(true); } //透過nodeId,更改物件顏色或顯示與否;color請填寫THREE.Vector4 function changeColorTransparency(nodeId, color) { - //變綠色 - //var color = new THREE.Vector4(0, 1, 0, 1);//綠色;前三個代表r、g、b; 亦可填入255/255 - //var color = new THREE.Vector4(0, 1, 0, 0);//不顯示顏色;最後的參數為透明度 - viewer.setThemingColor(nodeId, color); + //變綠色 + //var color = new THREE.Vector4(0, 1, 0, 1);//綠色;前三個代表r、g、b; 亦可填入255/255 + //var color = new THREE.Vector4(0, 1, 0, 0);//不顯示顏色;最後的參數為透明度 + viewer.setThemingColor(nodeId, color); } //隱藏全物件 function hideAllObjects(filDbids = []) { - //viewer.hide(4);//只針對一個物件(dbid為4)做隱藏 - for (var i = 0; i < allDbIdsStr.length; i++) { - viewer.hide(parseInt(allDbIdsStr[i])); - } + //viewer.hide(4);//只針對一個物件(dbid為4)做隱藏 + for (var i = 0; i < allDbIdsStr.length; i++) { + viewer.hide(parseInt(allDbIdsStr[i])); + } - for (var i = 0; i < filDbids.length; i++) { - viewer.show(parseInt(filDbids[i]), viewer.model); - } + for (var i = 0; i < filDbids.length; i++) { + viewer.show(parseInt(filDbids[i]), viewer.model); + } } //顯示全物件 function showAllObjects() { - //viewer.show(4); //只針對一個物件(dbid為4)做顯示 - for (var i = 0; i < allDbIdsStr.length; i++) { - viewer.show(parseInt(allDbIdsStr[i])); - } + //viewer.show(4); //只針對一個物件(dbid為4)做顯示 + for (var i = 0; i < allDbIdsStr.length; i++) { + viewer.show(parseInt(allDbIdsStr[i])); + } } function showHeat(selector) { - const labels = [ - `${(10).toFixed(2)}${"°C"}`, - `${(40 / 2).toFixed(2)}${"°C"}`, - `${(30).toFixed(2)}${"°C"}`, - ]; - const colorStops = ["blue", "green", "yellow", "red"]; - createHeatmapRect(labels, colorStops, selector); + const labels = [ + `${(10).toFixed(2)}${"°C"}`, + `${(40 / 2).toFixed(2)}${"°C"}`, + `${(30).toFixed(2)}${"°C"}`, + ]; + const colorStops = ["blue", "green", "yellow", "red"]; + createHeatmapRect(labels, colorStops, selector); +} + +function showHeatCO2(selector) { + const labels = [ + `${(400).toFixed(2)}`, + `${(1600 / 2 + 400).toFixed(2)}`, + `${(2000).toFixed(2)}`, + ]; + const colorStops = ["blue", "green", "yellow", "red"]; + createHeatmapRect(labels, colorStops, selector); } function createHeatmapRect(labels, colorStops, selector) { - if (!$(selector)[0]) { - return; + if (!$(selector)[0]) { + return; + } + const context = $(selector)[0].getContext("2d"); + let i, len; + context.clearRect(0, 0, 200, 50); + context.fillStyle = "back"; //white + for (i = 0, len = labels.length; i < len; i++) { + let x = 10 + (180 * i) / (len - 1); + if (i === len - 1) { + x -= context.measureText(labels[i]).width; + } else if (i > 0) { + x -= 0.5 * context.measureText(labels[i]).width; } - const context = $(selector)[0].getContext("2d"); - let i, len; - context.clearRect(0, 0, 200, 50); - context.fillStyle = "back"; //white - for (i = 0, len = labels.length; i < len; i++) { - let x = 10 + (180 * i) / (len - 1); - if (i === len - 1) { - x -= context.measureText(labels[i]).width; - } else if (i > 0) { - x -= 0.5 * context.measureText(labels[i]).width; - } - context.fillText(labels[i], x, 10); - } - const gradient = context.createLinearGradient(0, 0, 200, 0); - for (i = 0, len = colorStops.length; i < len; i++) { - gradient.addColorStop(i / (len - 1), colorStops[i]); - } - context.fillStyle = gradient; - context.fillRect(10, 20, 200, 25); + context.fillText(labels[i], x, 10); + } + const gradient = context.createLinearGradient(0, 0, 200, 0); + for (i = 0, len = colorStops.length; i < len; i++) { + gradient.addColorStop(i / (len - 1), colorStops[i]); + } + context.fillStyle = gradient; + context.fillRect(10, 20, 200, 25); } //======================== 外部呼叫function =========================== //紀錄熱點座標 function getHopspotPoint(data) { - myDataList = data; + myDataList = data; } //呼叫載入熱圖 async function toLoadHeatmap(roomArr) { - const model = viewer.model; - loadHeatmaps(model, roomArr); + const model = viewer.model; + loadHeatmaps(model, roomArr); } function setShadowShow(type = false) { - viewer.setGroundShadow(type); - viewer.impl.sceneUpdated(true); + viewer.setGroundShadow(type); + viewer.impl.sceneUpdated(true); } //============================= end =================================== function moveViewToDevice(letter) { - if (letter != "") { - viewer.clearSelection(); - viewer.select(letter); - viewer.fitToView([letter]); - } else { - viewer.clearSelection(); - } + if (letter != "") { + viewer.clearSelection(); + viewer.select(letter); + viewer.fitToView([letter]); + } else { + viewer.clearSelection(); + } +} + +class ErrorDevice { + constructor(options) { + this.errorDevices = options.errorDevices ?? []; + this.model = null; + this.#init(); + } + + #init = async function () { + this.model = viewer.model; + // 載入 Autodesk Viewer 的資料視覺化擴充功能 + const dataVizExtn = await viewer.loadExtension( + "Autodesk.DataVisualization" + ); + // dataVizExtn.removeSurfaceShading(this.model); + // 儲存 Viewer 的模型 + this.addHeatMaps(); + }; + + async addHeatMaps() { + const dataVizExtn = await viewer.loadExtension( + "Autodesk.DataVisualization" + ); + const { + SurfaceShadingData, + SurfaceShadingPoint, + SurfaceShadingNode, + SurfaceShadingGroup, + } = Autodesk.DataVisualization.Core; + // test + const shadingGroup = new SurfaceShadingGroup("device-error-heatmap"); + const rooms = new Map(); + for (const { id, forge_dbid, roomDbId, position, sensorTypes } of this + .errorDevices) { + if (!id || forge_dbid == -1 || roomDbId == -1) { + continue; + } + + if (!rooms.has(forge_dbid) || !rooms.has(roomDbId)) { + const room = new SurfaceShadingNode(`error_${id}`, forge_dbid); + shadingGroup.addChild(room); + rooms.set(forge_dbid, room); + } + const room = rooms.get(forge_dbid); + room.addPoint( + new SurfaceShadingPoint(`error_${id}`, position, sensorTypes) + ); + } + const shadingData = new SurfaceShadingData(); + shadingData.addChild(shadingGroup); + + shadingData.initialize(this.model); + + await dataVizExtn.setupSurfaceShading(this.model, shadingData); + dataVizExtn.registerSurfaceShadingColors("error", [0xff0000, 0xff0000]); + + dataVizExtn.renderSurfaceShading( + "device-error-heatmap", + "error", + this.getSensorValue.bind(this) + ); + } + + getSensorValue = function (device, sensorType) { + let dev = this.errorDevices.filter((x) => `error_${x.id}` == device.id)[0]; + if (sensorType === "error") { + return 0; + } + }; +} +// =================================燈光用=============================================== +async function getLTNode(device) { + // 處理 node 的資料 + const nodes = device.device_nodes?.map((n) => ({ + ...n, + position: isJSON(n.device_node_coordinate_3D) + ? JSON.parse(n.device_node_coordinate_3D) + : {}, // x: 0, y: 25, z: -2.5 (3.35, -4.81, 12.88 + sensorTypes: ["TrafficDensity"], + forgeDbId: parseInt(n.forge_dbid), + dbId: parseInt(n.forge_dbid), + })); + + // 載入 Autodesk Viewer 的資料視覺化擴充功能 + const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); + + const { + SurfaceShadingGroup, + SurfaceShadingData, + SurfaceShadingPoint, + SurfaceShadingNode, + } = Autodesk.DataVisualization.Core; + + dataVizExtn.removeSurfaceShading(viewer.model); + + // Group to select both north and southbound + const shadingGroup = new SurfaceShadingGroup("LT"); + + nodes.forEach(({ position, forgeDbId, sensorTypes, device_number }) => { + const LTGroup = new SurfaceShadingNode("LTGroup" + forgeDbId, forgeDbId); + LTGroup.addPoint( + new SurfaceShadingPoint(device_number, position, sensorTypes) + ); + shadingGroup.addChild(LTGroup); + }); + + const heatmapData = new SurfaceShadingData(); + heatmapData.addChild(shadingGroup); + + // Initialize with model loaded from APS + heatmapData.initialize(viewer.model); + await dataVizExtn.setupSurfaceShading(viewer.model, heatmapData); + const sensorColors = [0x0080FF, 0x0080FF]; + + // Set heatmap colors for temperature + const sensorType = "TrafficDensity"; + dataVizExtn.registerSurfaceShadingColors(sensorType, sensorColors); + dataVizExtn.renderSurfaceShading("LT", "TrafficDensity", getLTSensorValue); + console.log("dataVizExtn", dataVizExtn); +} + +// Function that provides a [0,1] value for the Heatmap +function getLTSensorValue(surfaceShadingPoint, sensorType) { + return 1; } diff --git a/Frontend/js/init.js b/Frontend/js/init.js index a32da02..c6723eb 100644 --- a/Frontend/js/init.js +++ b/Frontend/js/init.js @@ -3,14 +3,14 @@ // var baseImgUrl = "https://localhost:44376"; // 本地開發用 // Mitsubishi -var baseApiUrl = "http://220.132.206.5:8005"; // production 用 +// var baseApiUrl = "http://220.132.206.5:8005"; // production 用 var baseImgUrl = "http://220.132.206.5:8053"; // production 用 // WSP // var baseApiUrl = "http://192.168.0.136:8005"; // production 用 // var baseImgUrl = "http://192.168.0.136:8053"; // production 用 -// var baseApiUrl = "http://localhost:3604"; +var baseApiUrl = "http://localhost:3604"; //var baseImgUrl = "http://localhost:8848"; var varRegApiUrl = "/reg/api/"; //註冊API路徑 diff --git a/Frontend/js/n4js/alarmbaja.js b/Frontend/js/n4js/alarmbaja.js index 8095336..9101649 100644 --- a/Frontend/js/n4js/alarmbaja.js +++ b/Frontend/js/n4js/alarmbaja.js @@ -103,16 +103,16 @@ function getAlarmByBaja( require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:|alarm:|bql:select timestamp, ackTime, ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where alarmClass = '" + - alarmClass + - "' and timestamp.millis > " + - startDate_millisecond + - " and timestamp.millis < " + - endDate_millisecond + - " and sourceState " + - _recoverState + - " and ackState " + - _ackState + - " order by timestamp asc" + alarmClass + + "' and timestamp.millis > " + + startDate_millisecond + + " and timestamp.millis < " + + endDate_millisecond + + " and sourceState " + + _recoverState + + " and ackState " + + _ackState + + " order by timestamp asc" ) .get() .then(function (table) { @@ -202,8 +202,8 @@ function getOneDeviceAlarmTop10ByBaja(devicePath, callback) { require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:|alarm:|bql:select top 10 timestamp, ackState, alarmData, alarmData.sourceName, sourceState, uuid, alarmData.msgText, normalTime where alarmData.sourceName like '%" + - devicePath + - "%' order by timestamp desc" + devicePath + + "%' order by timestamp desc" ) .get() .then(function (table) { @@ -300,8 +300,8 @@ function getOneSystemAlarmStateByBaja(systemPath, callback) { require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:|alarm:|bql:select alarmData, alarmData.sourceName, sourceState, uuid where alarmData.sourceName like '%" + - systemPath + - "%' order by timestamp desc" + systemPath + + "%' order by timestamp desc" ) .get() .then(function (table) { @@ -355,10 +355,10 @@ function getOneSystemStateByBaja(systemPath, callback) { require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:" + - port + - "|alarm:|bql:select top 1 alarmData, alarmData.sourceName, sourceState where alarmData.sourceName like '%" + - systemPath + - "%' order by timestamp desc" + port + + "|alarm:|bql:select top 1 alarmData, alarmData.sourceName, sourceState where alarmData.sourceName like '%" + + systemPath + + "%' order by timestamp desc" ) .get() .then(function (table) { @@ -415,8 +415,8 @@ function getAlarmCountByBaja(callback) { require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:" + - port + - "|alarm:|bql:select COUNT(*) where sourceState = 'offnormal'" + port + + "|alarm:|bql:select COUNT(*) where sourceState = 'offnormal'" ) .get() .then(function (table) { @@ -463,8 +463,8 @@ function getRecoverCountByBaja(callback) { require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:" + - port + - "|alarm:|bql:select COUNT(*) where normalTime != null" + port + + "|alarm:|bql:select COUNT(*) where normalTime != null" ) .get() .then(function (table) { @@ -510,8 +510,8 @@ function getCheckedAckedCountByBaja(callback) { require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:" + - port + - "|alarm:|bql:select COUNT(*) where ackState='acked'" + port + + "|alarm:|bql:select COUNT(*) where ackState='acked'" ) .get() .then(function (table) { @@ -557,8 +557,8 @@ function getUnCheckedAckedCountByBaja(callback) { require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:" + - port + - "|alarm:|bql:select COUNT(*) where ackState='unacked'" + port + + "|alarm:|bql:select COUNT(*) where ackState='unacked'" ) .get() .then(function (table) { @@ -588,8 +588,8 @@ function getSystemAlarmByBaja(callback) { //baja.Ord.make("local:|foxs:|alarm:|bql:select timestamp, ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where isAlarm").get() baja.Ord.make( "local:|foxs:" + - port + - "|alarm:|bql:select alarmClass where sourceState = 'offnormal'" + port + + "|alarm:|bql:select alarmClass where sourceState = 'offnormal'" ) .get() .then(function (table) { @@ -704,8 +704,8 @@ function getOneDeviceAlarmByBaja(devicePath, callback) { // console.log("local:|foxs:|alarm:|bql:select timestamp, ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where alarmData.sourceName like '%" + devicePath + "%' order by timestamp desc"); baja.Ord.make( "local:|foxs:|alarm:|bql:select timestamp, ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where alarmData.sourceName like '%" + - devicePath + - "%' order by timestamp desc" + devicePath + + "%' order by timestamp desc" ) .get() .then(function (table) { @@ -765,18 +765,6 @@ function getOtherAlarmByBaja( console.log( "告警2", "local:|foxs:|alarm:|bql:select timestamp, ackTime, priority ,ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where " + - startUrl + - "timestamp.millis <= " + - endDate_millisecond + - " and sourceState " + - _recoverState + - " and ackState " + - _ackState + - " order by timestamp desc" - ); - require(["baja!"], function (baja) { - baja.Ord.make( - "local:|foxs:|alarm:|bql:select timestamp, ackTime, priority ,ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where " + startUrl + "timestamp.millis <= " + endDate_millisecond + @@ -785,6 +773,18 @@ function getOtherAlarmByBaja( " and ackState " + _ackState + " order by timestamp desc" + ); + require(["baja!"], function (baja) { + baja.Ord.make( + "local:|foxs:|alarm:|bql:select timestamp, ackTime, priority ,ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where " + + startUrl + + "timestamp.millis <= " + + endDate_millisecond + + " and sourceState " + + _recoverState + + " and ackState " + + _ackState + + " order by timestamp desc" ) .get() .then(function (table) { @@ -863,51 +863,54 @@ function getAllDeviceAlarmByBaja( require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:|alarm:|bql:select timestamp, ackTime, priority ,ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where " + - startUrl + - "timestamp.millis <= " + - endDate_millisecond + - " and sourceState " + - _recoverState + - " and ackState " + - _ackState + - " order by timestamp desc" + startUrl + + "timestamp.millis <= " + + endDate_millisecond + + " and sourceState " + + _recoverState + + " and ackState " + + _ackState + + " order by timestamp desc" ) .get() .then(function (table) { return table.cursor({ each: function (record) { - let main = {}; - // const alarmDisplayName = record.get('alarmData').get('sourceName').split(":")[1] ?? record.get('alarmData').get('sourceName').split(":")[0] - const alarmDisplayName = - record.get("alarmData").get("sourceName").split(":")[1] ?? - record.get("alarmData").get("sourceName"); - _sourceTmp = alarmDisplayName.split("_"); - let _bfName = _sourceTmp[1] + "-" + _sourceTmp[4]; - let _sourceName = _sourceTmp.slice(0, 8).join("_"); - _sourceTmp = _sourceTmp[7] + "-" + _sourceTmp[8]; + if (record.get("alarmData").get("sourceName")) { + let main = {}; + // console.log("告警", record.get("alarmData").get("sourceName")); + // const alarmDisplayName = record.get('alarmData').get('sourceName').split(":")[1] ?? record.get('alarmData').get('sourceName').split(":")[0] + const alarmDisplayName = + record.get("alarmData").get("sourceName").split(":")[1] ?? + record.get("alarmData").get("sourceName"); + _sourceTmp = alarmDisplayName.split("_"); + let _bfName = _sourceTmp[1] + "-" + _sourceTmp[4]; + let _sourceName = _sourceTmp.slice(0, 8).join("_"); + _sourceTmp = _sourceTmp[7] + "-" + _sourceTmp[8]; - main.buildingFloorName_zh = _bfName; - main.sourceName_zh = _sourceName; - main.uuid = record.get("uuid").$val; - main.timestamp = record.get("timestamp").$cEncStr; - main.alarmClass = record.get("alarmClass"); - main.point = _sourceTmp; - main.sourceTmp = _sourceTmp; - main.devicePath = _sourceName; - main.msgText = record.get("alarmData").get("msgText"); - main.normalTime = record.get("normalTime"); - main.priority = record.get("priority"); - main.ackedTime = record.get("ackTime").$cEncStr; - main.ackState = record.get("ackState").$ordinal; - if (_sourceTmp.includes("undefined")) { - // console.log(main.ackState) - main.buildingFloorName_zh = ""; - //main.alarmClass = "系統異常"; - main.sourceTmp = ""; - //main.msgText = ""; + main.buildingFloorName_zh = _bfName; + main.sourceName_zh = _sourceName; + main.uuid = record.get("uuid").$val; + main.timestamp = record.get("timestamp").$cEncStr; + main.alarmClass = record.get("alarmClass"); + main.point = _sourceTmp; + main.sourceTmp = _sourceTmp; + main.devicePath = _sourceName; + main.msgText = record.get("alarmData").get("msgText"); + main.normalTime = record.get("normalTime"); + main.priority = record.get("priority"); + main.ackedTime = record.get("ackTime").$cEncStr; + main.ackState = record.get("ackState").$ordinal; + if (_sourceTmp.includes("undefined")) { + // console.log(main.ackState) + main.buildingFloorName_zh = ""; + //main.alarmClass = "系統異常"; + main.sourceTmp = ""; + //main.msgText = ""; + } + _result.data.push(main); + _index++; } - _result.data.push(main); - _index++; }, after: function () { _result.count = _index; @@ -943,14 +946,14 @@ function getDeviceAlarmCardByBaja( require(["baja!"], function (baja) { baja.Ord.make( "local:|foxs:|alarm:|bql:select timestamp, ackTime, priority ,ackState, alarmClass, alarmClassDisplayName, alarmValue, alarmData, alarmData.sourceName, uuid, alarmData.msgText, alarmData.numericValue, alarmData.presentValue, alarmData.status, alarmData.toState, normalTime where " + - startUrl + - "timestamp.millis <= " + - endDate_millisecond + - " and sourceState " + - _recoverState + - " and ackState " + - _ackState + - " order by timestamp desc" + startUrl + + "timestamp.millis <= " + + endDate_millisecond + + " and sourceState " + + _recoverState + + " and ackState " + + _ackState + + " order by timestamp desc" ) .get() .then(function (table) { diff --git a/Frontend/js/n4js/historybaja.js b/Frontend/js/n4js/historybaja.js index c0c179e..8180461 100644 --- a/Frontend/js/n4js/historybaja.js +++ b/Frontend/js/n4js/historybaja.js @@ -42,40 +42,42 @@ function getHistoryDataByBaja(devicePath, startDate_millisecond, endDate_millise require(['baja!'], function (baja) { console.log('local:|foxs:|history:/' + company + '/' + devicePath + '|bql:select * from control:ControlPoint where timestamp.millis > ' + startDate_millisecond + ' and timestamp.millis < ' + endDate_millisecond); baja.Ord.make('local:|foxs:|history:/' + company + '/' + devicePath + '|bql:select * from control:ControlPoint where timestamp.millis > ' + startDate_millisecond + ' and timestamp.millis < ' + endDate_millisecond).get() - .then(function (table) { - return table.cursor({ - each: function (record) { - console.log(record.get('timestamp')) - // if (_index == 0) - // _ss += '{"deviceName":"' + deviceName + '", "value":' + record.get('value') + ', "timestamp":"' + record.get('timestamp').$cEncStr - // + '"}'; - // else - // _ss += ',{"deviceName":"' + deviceName + '", "value":' + record.get('value') + ', "timestamp":"' + record.get('timestamp').$cEncStr - // + '"}'; - _ss.push({deviceName:deviceName, value:record.get('value'), timestamp:record.get('timestamp').$cEncStr - }); - _index++; - }, - after: function () { - _result={count: _index, data: _ss} - // _result += '{' + '"count": ' + _index + ', "data":['; - // _result += _ss; - // _result += ']}'; - if (typeof callback === 'function') { - // console.log(_result) - _result = JSON.stringify(_result) - callback(_result); - } - }, - limit: -1, - offset: 0 + .then(function (table) { + $(loadEle).Loading("start"); + return table.cursor({ + each: function (record) { + console.log(record.get('timestamp')) + // if (_index == 0) + // _ss += '{"deviceName":"' + deviceName + '", "value":' + record.get('value') + ', "timestamp":"' + record.get('timestamp').$cEncStr + // + '"}'; + // else + // _ss += ',{"deviceName":"' + deviceName + '", "value":' + record.get('value') + ', "timestamp":"' + record.get('timestamp').$cEncStr + // + '"}'; + _ss.push({deviceName:deviceName, value:record.get('value'), timestamp:record.get('timestamp').$cEncStr }); - }) - .catch(()=>{ - console.log("error"); - // const res = JSON.stringify({count:0, data:[]}) - callback() + _index++; + }, + after: function () { + $(loadEle).Loading("close"); + _result={count: _index, data: _ss} + // _result += '{' + '"count": ' + _index + ', "data":['; + // _result += _ss; + // _result += ']}'; + if (typeof callback === 'function') { + // console.log(_result) + _result = JSON.stringify(_result) + callback(_result); + } + }, + limit: -1, + offset: 0 }); + }) + .catch(()=>{ + console.log("error"); + // const res = JSON.stringify({count:0, data:[]}) + callback() + }); }); } diff --git a/Frontend/js/yourteam/plugins/yt-navbar/yt-navbar.js b/Frontend/js/yourteam/plugins/yt-navbar/yt-navbar.js index 8ca82fd..c837a11 100644 --- a/Frontend/js/yourteam/plugins/yt-navbar/yt-navbar.js +++ b/Frontend/js/yourteam/plugins/yt-navbar/yt-navbar.js @@ -35,10 +35,15 @@ class YourTeamNavbar { this.element = option.element; this.type = option.type ?? "left"; this.isOpen = false; + this.onlyOneOpen = false; this.init(); } - init = function () { + init = function (option = {}) { + // this = Object.assign(option ?? {}); + Object.keys(option).forEach(k => { + this[k] = option[k]; + }); this.initClose(); this.checkIsOpen(); $(this.element)[0]._ytNavbar = this; @@ -115,24 +120,43 @@ class YourTeamNavbar { $(this.element).find("[data-nb-node-type=parent]").on("click",this.nbNodeParentOnClick.bind(this)) } - nbNodeParentOnClick(e){ - if(this.chkNbNodeParentIsOpen(e.target)){ - $(e.target).data("nb-node-status","close").attr("data-nb-node-status","close"); - $(e.target).next("ul").css({transform:"translateY(-5%)"}); - $(e.target).next("ul").animate({ - opacity:0, + closeParentCollapse(ele,isAnimation = true){ + $(ele).data("nb-node-status","close").attr("data-nb-node-status","close"); + $(ele).next("ul").css({transform:"translateY(-5%)"}); + if(isAnimation){ + $(ele).next("ul").animate({ + opacity:0, },200, () => { - $(e.target).next("ul").hide(); + $(ele).next("ul").hide(); }) - - } else { - $(e.target).data("nb-node-status","open").attr("data-nb-node-status","open"); - $(e.target).next("ul").show(); - $(e.target).next("ul").animate({ + $(ele).next("ul").css({opacity:0}).hide(); + } + } + + openParentCollapse(ele){ + $(ele).data("nb-node-status","open").attr("data-nb-node-status","open"); + $(ele).next("ul").show(); + $(ele).next("ul").animate({ opacity:1, },200) - $(e.target).next("ul").css({transform:"translateY(0%)"}); + $(ele).next("ul").css({transform:"translateY(0%)"}); + + } + + nbNodeParentOnClick(e){ + if(this.chkNbNodeParentIsOpen(e.target)){ + + this.closeParentCollapse(e.target); + + } else { + + if(this.onlyOneOpen === true){ + this.closeParentCollapse($(this.element).find("[data-nb-node-type=parent]").filter((i,ele) => ele != e.target),false); + } + + this.openParentCollapse(e.target) + } } @@ -140,9 +164,16 @@ class YourTeamNavbar { return $(ele).is("[data-nb-node-status=open]"); } + openAllCollapse(){ + $(this.element).find("[data-nb-node-type=parent]").each((i,ele) => { + if(!this.chkNbNodeParentIsOpen(ele)){ + $(this.element).find("[data-nb-node-type=parent]").click(); + } + }) + } } -$.fn.YTNavbar = function (method) { +$.fn.YTNavbar = function (method,...arg) { let nbObj = $(this)[0]._ytNavbar; let target = $(this).data("target"); if (!nbObj && $(target).length != 0) { @@ -156,7 +187,9 @@ $.fn.YTNavbar = function (method) { } else if (method == "hide") { nbObj.close(); } else if (method == "init") { - nbObj.init(); + nbObj.init(arg[0]); + } else if(method == "openAllCollapse") { + nbObj.openAllCollapse(); } return nbObj;