基於 WebGL 的 HTML5 3D 棉花加工監控系統
前言
現在的棉花加工行業還停留在傳統的反應式維護模式當中,當棉花加下廠的裝置突然出現故障時,控制程式需要更換。這種情況下,首先需要客戶向裝置生產廠家請求派出技術人員進行維護,然後生產廠家才能根據情況再派人到現場進行處理。由於棉花加工裝置分佈在中國各地乃至出口到世界各地,從客戶反應問題到廠家派人到達現場的時間週期就會很長,少則 一天,個別偏遠的地方可能會需要幾天,不同程度地影響到企業生產活動的繼續進行。傳統的反應式維護存在以下缺點:售後服務響應速度慢;維護成本高;生產效率低下;停車率高;管理成本高;無法應對合格工程師不足的情況。
遠端監控系統主要是通過分佈於棉花加工生產線各種裝置的感測器、開關訊號、視訊監控裝置、 PLC 控制器等裝置,通過智慧聯網裝置整合到網際網路和區域網上面,實現對生產、運營情況的隨時掌握,建立網路範圍內的監控資料和網上知識資源庫,根據現場採集的裝置執行資料進行遠端診斷和線上維修。
http://www.hightopo.com/demo/Plucker/
程式碼實現
建立場景
首先是建立一個三維場景( https://hightopo.com/guide/guide/core/3d/ht-3d-guide.html ) ,通過將場景中的元素新增到儲存資料的資料容器( http://www.hightopo.com/guide/guide/core/datamodel/ht-datamodel-guide.html ) 中即可:
var dm = new ht.DataModel(); // 資料容器
var g3d = new ht.graph3d.Graph3dView(dm); // 三維元件
g3d.addToDOM(); // 將三維元件新增到 body 體中
上面程式碼中出現的 addToDOM 方法是將呼叫此方法的元件通過 getView 方法獲取到此元件的底層 div,隨後將此 div 新增到 body 體中。HT 的元件一般都會嵌入 BorderPane、SplitView 和 TabView 等容器中使用,而最外層的HT元件則需要使用者手工將 getView() 返回的底層 div 元素新增到頁面的 DOM 元素中,這裡需要注意的是,當父容器大小變化時,如果父容器是 BorderPane 和 SplitView 等這些HT預定義的容器元件,則HT的容器會自動遞迴呼叫孩子元件 invalidate 函式通知更新。但如果父容器是原生的 html 元素, 則 HT 元件無法獲知需要更新,因此最外層的 HT 元件一般需要監聽 window 的視窗大小變化事件,呼叫最外層元件 invalidate 函式進行更新。
為了最外層元件載入填充滿視窗的方便性,HT 的所有元件都有 addToDOM 函式,其實現邏輯如下,其中 iv 是 invalidate 的簡寫:
addToDOM = function(){
var self = this,
view = self.getView(), //獲取元件的底層 div
style = view.style;
document.body.appendChild(view); //將元件底層 div 新增進 body 中
style.left = '0'; //ht 預設將所有的元件的 position 都設定為 absolute 絕對定位
style.right = '0';
style.top = '0';
style.bottom = '0';
window.addEventListener('resize', function () { self.iv(); }, false); //視窗大小改變事件,呼叫重新整理函式
}
整個大環境搭建好了後,我們需要向場景中新增 3D 模型,並進行位置的擺放,這裡採用的是將整個場景的模型以及模型的擺放放在一個 JSON 格式的檔案中,然後通過將這個 JSON 檔案反序列化到資料容器 DataModel 中,即可呈現 JSON 檔案中的場景內容以及模型的擺放位置:
ht.Default.xhrLoad('scenes/抓棉機.json', function(text) { // 載入 JSON 檔案
dm.deserialize(text); // 將 JSON 反序列化到資料容器中
});
上面出現的 ht.Default.xhrLoad 方法是一個封裝好的非同步載入檔案的函式,可以通過這種方法來載入 JSON 檔案,因為此方法為非同步載入,所以如果要操作此函式反序列化後的資料容器中的元素,需要在此函式中進行後續的操作。
場景動畫
因為整個場景中的元素都是從此 JSON 檔案中反序列化出來的,此 JSON 檔案中儲存的只有場景的內容,並不包括動畫以及互動,對於不同部分的元素的動畫也不同,我們需要單獨將這些元素取出來,這裡通過 dm.getDataByTag(tag) 方法實現(https://hightopo.com/guide/guide/core/datamodel/ht-datamodel-guide.html#ref_datamodel),此方法通過 tag 唯一標識來獲取節點的資訊:
var equipment = dm.getDataByTag('equipment'); // 獲取軋棉機的節點
var hand = dm.getDataByTag('hand'); // 獲取軋棉機“手”節點
var light = dm.getDataByTag('light'); // 獲取軋棉機頂部的指示燈的節點
獲取到這些需要做動畫的節點後,這裡我用的是動畫外掛 setAnimation (https://hightopo.com/guide/guide/plugin/animation/ht-animation-guide.html)方法來做的,動畫外掛更進一步對動畫進行封裝,使用者只需用描述性的說明 HT 即可自動實現動畫過程,動畫外掛可以將圖元的一個或多個屬性值 (如 width、height、opacity 等)從一個值平滑的緩動至另一個值,同時提供了豐富的緩動方式用於實現各種效果。但是使用這個外掛前得先引入 ht-animation.js 檔案:
<script src="ht.js"></script> <!--先引入ht.js-->
<script src="ht-animation.js"></script>
這裡總共有三個部分有動畫,採用的方法大致相同,這裡僅對整個軋棉機的機身的左右移動的動畫進行說明。
equipment.setAnimation({ // 動畫呼叫方法
moveDown: { // 定義了一個名為 moveDown 的動畫過程,這個動畫過程改變圖元的 x 軸座標,將其從 623 變化至 -256
from: 623, // 動畫開始時的屬性值
to: -256, // 動畫結束時的屬性值
interval: equipInterval, // 動畫間隔,單位ms
next: ["moveUp"], // 字串型別,指定當前動畫完成之後,要執行的下個動畫,可將多個動畫融合
onUpdate: function(value) { // 回撥函式,動畫的每一幀都會回撥此函式
this.setX(value); // 設定該節點的 x 軸的值為當前動畫 from 到 to 的值
formPane.getItemById('xValue').element = value.toFixed(2); // 獲取 form 表單上的 xValue 元素,同時改變此值
formPane.iv(); // 表單內容變化後要通知表單進行重新整理變化
}
},
moveUp: { // 定義了一個名為 moveUp 的動畫過程,這個動畫過程改變圖元的 x 軸座標,將其從 -256 變化至 623
from: -256,
to: 623,
interval: equipInterval,
next: ["moveDown"],
onUpdate: function(value) {
this.setX(value);
formPane.getItemById('xValue').element = value.toFixed(2);
formPane.iv();
}
},
start: ['moveDown'] // start是一個陣列,用於指定要啟動的一個或多個動畫
});
注意,要使用動畫,首先您需要呼叫 ht.DataModel#enableAnimation(interval) 啟動全域性動畫定時器,預設 interval 為 16ms,如果不設定此引數值,則 DataModel 定時器每隔 16ms 左右就會遍歷自己所有的 Data,根據 Data 的 animation 配置執行動畫。
dm.enableAnimation();
表單建立
前面程式碼中出現的 form 表單(https://hightopo.com/guide/guide/plugin/form/ht-form-guide.html),是通過 createForm 方法建立的,此方法定義如下(PS:由於 form 表單的列表稍長,這裡就選取幾個比較有代表性的表單元素進行說明):
// 建立 form 表單
function createForm() {
var fp = new ht.widget.FormPane(); // 建立表單元件例項
fp.setWidth(200); // 設定表單元件的寬度
fp.setHeight(250); // 設定表單元件的高度
fp.getView().style.top = '8%'; // 設定表單元件的樣式
fp.getView().style.right = 0;
fp.getView().style.background = 'rgba(255, 255, 255, 0.3)';
document.body.appendChild(fp.getView()); // 將表單元件的底層 div 新增到 body 體中
var equipment = dm.getDataByTag('equipment'); // 通過 tag 唯一標識獲取元素
var hand = dm.getDataByTag('hand');
fp.setLabelAlign('right'); // 設定表單的文字對齊方式
fp.addRow([ // 向表單中新增一行 此方法的引數一為元素陣列,可在一行中新增多個元素
{ // 元素一 顯示文字內容為 “機器號”
element: '機器號',
color: '#fff'
},
{ // 元素二 顯示文字內容為 “Machine”
element: 'Machine',
color: '#fff'
}
], [0.1, 0.1]); // 引數二為每個元素寬度資訊陣列,寬度值大於1代表固定絕對值,小於等於1代表相對值,也可為80+0.3的組合
fp.addRow([ // 向表單中新增一行 此方法的引數為一個陣列,可在一行中新增多個元素
{ // 元素一 顯示文字內容為 “機器號”
element: '抓棉機動畫',
color: '#fff'
},
{ // 元素二 顯示文字內容為 一個按鈕元素
button: {
label: '開始',
onClicked: function() { // 按鈕點選觸發事件,啟動軋棉機左右移動動畫
dm.enableAnimation(); // 啟動全域性動畫定時器
var light = dm.getDataByTag('light');
if (!light) return;
lightColor(light);
colorTimer = setInterval(function() {
lightColor(light);
}, 1000);
}
}
},
{
button: {
label: '停止',
onClicked: function() { // 按鈕點選觸發事件,關閉軋棉機左右移動動畫
dm.disableAnimation(); // 停止全域性動畫定時器
clearInterval(colorTimer);
var light = dm.getDataByTag('light');
if (light) light.s('all.color', 'rgba(0,0,255,0.51)');
}
}
}
], [0.2, 0.1, 0.1]); // 將一行中的三個元素都分配寬度進行顯示
fp.addRow([ // 向表單中新增一行 此方法的引數為一個陣列,可在一行中新增多個元素
{ // 元素一 顯示文字內容為“小車行走速度”
element: '小車行走速度',
color: '#fff'
},
{ // 元素二 顯示文字內容為一個 滑動條
id: 'slide',
slider: { // 滑動條
value: equipInterval, // slider 當前值
min: 0, // slider 最小值
max: 300, // slider 最大值
step: 20, // slider 每移動一步的值
onValueChanged: function() { // slider 值變化觸發事件
var anim = dm.getDataAnimation(equipment); // 獲得引數data的動畫配置
anim.moveDown.interval = this.getValue(); // 設定 moveDown 動畫的 interval 內容
anim.moveUp.interval = this.getValue(); // 設定 moveUp 動畫的 interval 內容
}
}
}
], [0.1, 0.1]);
fp.addRow([ // 向表單中新增一行 此方法的引數為一個陣列,可在一行中新增多個元素
{
element: 'X 軸',
color: '#fff'
},
{
id: 'xValue',
element: equipment.getX().toFixed(2), // 獲取軋棉機當前 x 軸值
color: '#fff'
}
], [0.1, 0.1]);
return fp;
}
有趣的部分就說這麼多,如果有什麼建議和意見,歡迎留言或者私信~或者上官網查閱相關資料(https://hightopo.com/)
總結
以前對 animation 動畫用的比較少,這次也是特地用它仔細研究一下 animation 的機制,就 animation 設定的動畫能夠以一種“平和”的方式進行值的變化,動畫也看起來比較有條理一些;當然還有能夠設定下一次動畫需要做什麼的操作,這個設計也非常的人性化;同時還能通過 getDataAnimation 獲取物件的動畫配置,並通過此方法對物件的動畫進行重新配置,這些優點都是值得拿出來跟大家分享的。
相關文章
- 基於 HTML5 WebGL 的 3D 棉花加工監控系統HTMLWeb3D
- 基於 WebGL 的 HTML5 3D 智慧樓宇監控系統WebHTML3D
- 基於 HTML5 的 WebGL 3D 智慧樓宇監控系統HTMLWeb3D
- 基於 HTML5 的 WebGL 3D 隧道監控HTMLWeb3D
- 基於 HTML5 WebGL 的 智慧樓宇能源監控系統HTMLWeb
- 基於 HTML5 WebGL 的低碳工業園區監控系統HTMLWeb
- 基於 WebGL 的 HTML5 低碳工業園區監控系統WebHTML
- 基於 HTML5 WebGL 的 3D 工控裙房系統HTMLWeb3D
- 基於 WebGL 的 HTML5 3D 工控裙房系統WebHTML3D
- 基於 HTML5 的 WebGL 樓宇自控 3D 視覺化監控HTMLWeb3D視覺化
- 基於 WebGL 的 HTML5 樓宇自控 3D 視覺化監控WebHTML3D視覺化
- 基於 HTML5 的 WebGL 自定義 3D 攝像頭監控模型HTMLWeb3D模型
- 基於 HTML5 WebGL 的加油站 3D 視覺化監控HTMLWeb3D視覺化
- 基於 HTML5 WebGL 的故宮人流量動態監控系統HTMLWeb
- 於 HTML5 WebGL 的民航客機飛行監控系統HTMLWeb
- 基於 HTML5 + WebGL 的太陽系 3D 展示系統HTMLWeb3D
- 基於 WebGL 的 HTML5 3D SCADA 主站系統WebHTML3D
- 基於 HTML5 + WebGL 的太陽系 3D 視覺化系統HTMLWeb3D視覺化
- 基於 HTML5 WebGL 的 3D 風機視覺化系統HTMLWeb3D視覺化
- 基於 WebGL 的 HTML5 3D 工控隧道視覺化系統WebHTML3D視覺化
- 基於 HTML5 的 WebGL 3D 地鐵站視覺化系統HTMLWeb3D視覺化
- 基於 HTML5 + WebGL 的無人機 3D 視覺化系統HTMLWeb無人機3D視覺化
- 基於 HTML5 WebGL 的發動機 3D 視覺化系統HTMLWeb3D視覺化
- 基於 HTML5 WebGL 的地鐵站 3D 視覺化系統HTMLWeb3D視覺化
- 基於 HTML5 WebGL 的 3D 機房HTMLWeb3D
- 基於 HTML5 WebGL 的 3D 挖掘機HTMLWeb3D
- 基於 HTML5 WebGL 的垃圾分類系統HTMLWeb
- 基於 WebGL 3D 的 HTML5檔案館視覺化管理系統Web3DHTML視覺化
- 基於 HTML5 的 WebGL 3D 檔案館視覺化管理系統HTMLWeb3D視覺化
- 基於 HTML5 WebGL 的 3D 渲染引擎構建工廠運作系統HTMLWeb3D
- 基於 HTML5 WebGL 的 3D 科幻風機HTMLWeb3D
- 基於 HTML5 + WebGL 的 3D 風力發電場視覺化系統HTMLWeb3D視覺化
- 基於 HTML5 WebGL 的計量站三維視覺化監控系統 Web 組態工控應用HTMLWeb視覺化
- 基於 HTML5 WebGL 的 3D 模型斜面生成HTMLWeb3D模型
- 基於 WebGL HTML5 的 3D 模型分離控制WebHTML3D模型
- 基於 HTML5 WebGL + WebVR 的 3D 虛實現實視覺化培訓系統HTMLWebVR3D視覺化
- 基於 WebGl HTML5 的 3D 視覺化機房WebHTML3D視覺化
- 基於 HTML5 WebGL 的 3D 網路拓撲圖HTMLWeb3D