如今的製造行業,基於數據進行生產策略制定與管理已經成為一種趨勢,特別是 工業4.0 的浪潮下,數據戰略已經成為很多製造企業的優先戰略,而數據可視化以更直觀的方式,幫助指導決策,成為數據分析傳遞信息的重要工具。通過數據可視化系統助力實現數據驅動的工業世界,為 工業4.0 提供更加靈活、敏捷、高效、個性... ...
前言
如今的製造行業,基於數據進行生產策略制定與管理已經成為一種趨勢,特別是 工業4.0 的浪潮下,數據戰略已經成為很多製造企業的優先戰略,而數據可視化以更直觀的方式,幫助指導決策,成為數據分析傳遞信息的重要工具。通過數據可視化系統助力實現數據驅動的工業世界,為 工業4.0 提供更加靈活、敏捷、高效、個性化的數據支撐。今天就給大家帶來一個採用 Hightopo 的 HT for Web 產品實現了一個水泥工廠可視化系統。
系統預覽
本案例共有七個子系統:
- 數據概況 -- 展示全廠年月時間單位的各項數據概況
- 窯系統運行 -- 用窯工藝流程動畫展示窯系統實時運行狀態
- 系統運行情況 -- 用動畫流程圖展示整個系統運行情況
- 生料質量控制 -- 用圖表和流程圖展示各種生料的配比情況
- 熟料質量控制 -- 用動畫流程圖展示各種熟料的配比情況
- 煤粉質量控制 -- 用圖表和流程圖對煤粉質量進行監控
- 智能物流 -- 通過 3D 場景實時監控進出廠車輛,和各項原料運輸情
子系統頁面切換
切換不同子系統時,左側菜單和頂部標題是不需要切換的,所以我們把需要切換的內容部分別放在不同的 Block 中,Block 類型,本身不繪製任何內容,用於作為其它節點的父節點,可以與子節點同步大小,當它隱藏或顯示時,所有子節點都會跟著隱藏或顯示。所以當我們切換子系統時只需要控制對應的 Block 顯示隱藏,而不需要去載入切換多張圖紙。
流向地圖
在數據概況頁面中,流向地圖展示年度水泥向各地區的銷售情況,這裡我們用 Shape 類型繪製線段來連接源地和匯地,用流動效果表示銷售關係。流動效果只需引入 HT 的 ht-flow.js 插件,即可通過簡單的屬性設置實現,代碼如下:
// 獲取線段的父節點 this.flowParent = dm.getDataByTag('saleFlowParent'); // 遍歷得到所有線段 this.flowParent.eachChild(child => { // 開啟流動,設置流動樣式 child.s({ // 開啟流動 'flow': true, // 設置流動組中最大元素的尺寸 'flow.element.max': 4, // 設置流動組中的元素的漸變陰影中心顏色 'flow.element.shadow.begincolor': '#49e5fe', // 設置流動組中的最大元素的漸變陰影尺寸 'flow.element.shadow.max': 16, // 設置流動組中的元素的漸變陰影邊緣顏色 'flow.element.shadow.endcolor': 'rgba(73, 229, 254, 0)', }); });
窯系統動畫
在窯系統運行頁面中,窯工藝流程動畫很直觀的展示了窯系統實時運行狀態。畫面中火焰、水和熟料在傳送帶上運輸的動畫效果,為了在性能較差的設備上也能流暢運行,我通過切換不同矢量圖形的方式實現。這裡用到了 HT 矢量中狀態機制,先繪製多個不同的矢量組件,每個組件都可以定義狀態來決定自己在哪個狀態下顯示,只要通過 data.s('state') 修改節點狀態就可以實現如下效果:
使用一個定時器,不斷地改變節點的狀態值,相關代碼如下:
this._stateTimer = setInterval(() => { stateNodes.forEach(node => { this.stateAnimation(node); }); }, 180); //切換狀態 stateAnimation(node) { let stateIndex = (node.a('stateIndex') || 0) % stateEnum.length, state = stateEnum[stateIndex].value; node.s('state', state); node.a('stateIndex', ++stateIndex); }
流程圖動畫
流程圖中流動線同樣是使用 ht-flow.js 插件實現。由於圖紙上的線段比較多,我把不同的線段分組放在不同的 Block 下,遍歷其子節點設置樣式,代碼如下:
//設置流動屬性 setNodeFlow (data, value) { if (data instanceof ht.Block) { data.eachChild(child => { this.setNodeFlow(child, value); }); } else if (data.getDisplayName() === 'line'){ data.s({ 'flow': value, 'flow.element.max': 4, 'flow.element.count': 1, 'flow.count': 5, 'flow.step': 10 }); } } //設置虛線流動屬性 setNodeDashFlow(data, value) { if (data instanceof ht.Block) { data.eachChild(child => { this.setNodeDashFlow(child, value); }); } else if (data.getDisplayName() === 'border'){ if (value) { data.s({ 'shape.dash.flow': true, 'shape.dash': true }); } else { data.s({ 'shape.dash.flow': false, 'shape.dash': false }); } } }
為了使動畫看起來更順暢,我給一些節點加上透明度動畫,設置節點透明度的代碼如下:
//設置節點透明度 setNodeOpacity (data, value = 0.5) { if (data instanceof ht.Block) { data.eachChild(child => { this.setNodeOpacity(child, value); }); } else { data.s('opacity', value); } }
接下來只需要依次執行動畫:
//開始流程圖動畫 start() { let {eo, eoInput, eoLine1, eoKind, eoCalu} = this; //工況輸入透明度動畫 this.gv.enableFlow(30); this.setNodeOpacity(eo); this.setNodeFlow(eo, false); (new Promise((resolve, reject) => { this.animtion = startAnim({ frames: 16, interval: 5, finishFunc: () => {resolve()}, action: (v, t) => { this.setNodeOpacity(eoInput, 0.5 + 0.5 * v); } }); })).then(() => { //連線連線透明動畫,流動 return new Promise((resolve, reject) => { this.animtion = startAnim({ frames: 12, interval: 10, finishFunc: () => { this.setNodeFlow(eoLine1, true); this.timer = setTimeout(() => {resolve()}, 1500); }, action: (v, t) => { this.setNodeOpacity(eoLine1, 0.5 + 0.5 * v); } }); }) }).then(() => { //軟計算透明動畫 return new Promise(resolve => { this.animtion = startAnim({ frames: 16, interval: 5, finishFunc: () => {resolve()}, action: (v, t) => { this.setNodeOpacity(eoKind, 0.5 + 0.5 * v); this.setNodeOpacity(eoCalu, 0.5 + 0.5 * v); } }); }); }).then(() => { //軟計算透明虛線流動 return new Promise(resolve => { this.setNodeDashFlow(eoKind, true); this.setNodeDashFlow(eoCalu, true); this.timer = setTimeout(() => { this.setNodeDashFlow(eoKind, false); this.setNodeDashFlow(eoCalu, false); resolve(); }, 3000); }); }).then(() => { ...... }) }
智能物流
前面六個子系統均為 2D 界面,而智能物流頁面則是嵌入了一個 3D 場景。實現方式是通過定義 HT 矢量 JSON 的 renderHTML 函數屬性,可實現在 GraphView 拓撲圖上,嵌入任意第三方 HTML DOM 元素。不過這裡也要註意一點,HT 的圖紙是 Canvas 實現的,renderHTML 的 DOM 元素一定在 Canvas 之上,使用 renderHTML 的 DOM 與常規 Canvas 上繪製的圖元不可能有層級控制可能性。下麵展示一下 renderHTML 函數屬性里的代碼:
renderHTML : function (data, gv, cache) { // 避免重覆創建g3d if (!cache.g3d) { // 創建 3D 視圖組件 var g3d = cache.g3d = new ht.graph3d.Graph3dView(); // 佈局函數,根據圖元的位置信息擺放HTML元素 g3d.layoutHTML = function () { gv.layoutHTML(data, g3d, true); }; // 阻止事件冒泡 g3d.getView().addEventListener('mousedown', function (event) { event.stopPropagation(); }); g3d.getView().addEventListener('touchstart', function (event) { event.stopPropagation(); }); } // 獲取圖元自定義屬性sceneURL的值 var sceneURL = data.a('sceneURL'); // 獲取圖元自定義屬性onPostDeserialize的值 var onPostDeserialize = data.a('onPostDeserialize'); // 當圖元自定義屬性sceneURL改變時,清除舊dataModel,反序列化新的sceneURL if (cache.g3d.sceneURL !== sceneURL) { cache.g3d.dm().clear(); cache.g3d.sceneURL = sceneURL; if (sceneURL) { cache.g3d.deserialize(sceneURL, function (json, dm, g3d, datas) { // 在反序列化後的回調函數中,執行onPostDeserialize函數 onPostDeserialize && onPostDeserialize(json, dm, g3d, datas); }); } } return cache.g3d; }
3D場景嵌入後,接下來實現水泥廠內的車輛動畫。根據後臺傳來車輛進入工廠的數據,我們創建運載不同原料的車輛模型,讓它們沿著不同的路徑抵達對應的廠房。同樣是用 Shape 類型事先繪製好路徑,根據 Shape 的 Points 和 Segments 信息,實現車輛沿著路徑行駛動畫。相關代碼如下:
carAnimation(car, path, duration) { // 車輛行駛動畫 ht.Default.startAnim({ duration: duration, easing: Easing.easeNone, action: function (v, t) { // 設置偏移量 let offset = Math.floor(v * 100); // 根據偏移量得到在路徑上的點坐標 let position = ht.Default.getPercentPositionOnPoints(path.getPoints(), path.getSegments(), offset); // 根據偏移量得到在路徑上的點於路徑切線角度 let angle = ht.Default.getPercentAngle(path.getPoints(), path.getSegments(), offset); // 設置車輛位置坐標及旋轉角度 car.setX(position.x); car.setY(position.y); car.setRotationY(Math.PI / 2 - angle); }, }); }
總結
工業互聯網是工業發展的必經之路,我們國家是一個工業大國,正處在工業轉型升級的關鍵時刻,面臨著人工成本上升、原材料價格波動、貿易競爭日益加劇等問題,迫切需要提高效率、降低生產成本。只有堅定不移地推動工業互聯網落地,加快更多企業的數字化轉型和智能化改造,才有能讓在全球化競爭中立於不敗之地。可視化作為智能化數字化的最後一環,讓複雜抽象的數據變得真正可知可感,幫助決策者發現規律,洞悉未來,為企業提速增效。
還有更多的可視化案例可以參考:https://www.hightopo.com/demos/index.html