基於 HTML5 Canvas 的 Web SCADA 組態電機控制面板


前言

HT For Web 提供完整的基於 HTML5 圖形界面組件庫。您可以輕松構建現代化的,跨桌面和移動終端的企業應用,無需擔憂跨平台兼容性,及觸屏手勢交互等棘手問題。也可用於快速創建和部署,高度可定制化,並具有強大交互功能的拓撲圖形及表盤圖表等應用。HT for Web 非常適用於實時監控系統的界面呈現,廣泛應用於電信網絡拓撲和設備管理,以及電力、燃氣等工業自動化 ( HMI / SCADA ) 領域。HT for Web 還有提供了一套一套強大的基於 WebGL 技術的 3D 圖形引擎,獨特的 WebGL 層抽象,將 Model – View – Presenter ( MVP ) 的設計模型延伸應用到了 3D 圖形領域。使用 HT for Web 您可更關注於業務邏輯功能,不必將精力投入復雜 3D 渲染和數學等非業務核心的技術細節。( http://www.hightopo.com )

作為剛入門的小白(大家可以叫我老鄭),我嘗試着一步一步的做這個面板,用這篇文章來記錄自己的一些收獲(畢竟我還是個菜鳥)以及代碼的實現,希望能夠幫到一些朋友。當然,如果有什么意見可以直接跟我說,大家一起交流才會進步!

效果圖

代碼實現

話不多說,上代碼。整體是一個 2D 的面板,那么要引入我們必須需要用到的 HT 核心庫:ht.js 。

首先,要創建數據容器和拓撲圖形組件。DateModel 作為承載 Data 數據的模型,管理着Data數據的增刪以及變化事件派發, HT 框架所有組件都是通過綁定 DataModel,以不同的形式呈現到用戶界面;同時組件也會監聽 DataModel 模型的變化事件, 實時同步更新界面數據信息,掌握了 DataModel 的操作就掌握了所有組件的模型驅動方式;拓撲圖形組件 ht.graph.GraphView 是 HT 框架中 2D 功能最豐富的組件,其相關類庫都在 ht.graph 包下。GraphView 具有基本圖形的呈現和編輯、拓撲節點連線及自動布局功能。

var dataModel = new ht.DataModel(); var graphView = new ht.graph.GraphView(dataModel);

通過以下代碼來進行一些基礎操作上的設置:

// 禁止平移
graphView.setPannable(false);
// 將其重載為空函數,禁止滾動 graphView.handleScroll = function() {};
// 禁用touch上雙指操作縮放 graphView.handlePinch = function() {};
// 禁止拓撲上框選操作 graphView.setRectSelectable(false);
// 通過過濾器設置禁止拖動 graphView.setMovableFunc(function(data) { return false; });
// 后將組件加入到指定的 DOM 元素底下,不指定則加入到 document.body 下 graphView.addToDOM(); window.addEventListener('resize', function(e) { graphView.fitContent(); }, false);

接下來通過請求把圖紙(json 文件)的 url 寫好拿到我們精心設計的面板。先還原成 JSON 字符串,然后將其反序列化並加入 dataModal 然后就可以操作數據了。

var json = ht.Default.parse(text); dataModel.deserialize(json);

然后,我們來實現其中的一些小效果。第一,我想讓 Alarm 的 4 個小燈每 2s 交替變化一次。那么,讓咱們來寫一個函數來控制它們:

var flag = true; setInterval(function () {   changeAlarmColor(dataModel, 'Alarm1', flag);   changeAlarmColor(dataModel, 'Alarm2', flag);   changeAlarmColor(dataModel, 'Alarm3', flag);   changeAlarmColor(dataModel, 'Alarm4', flag);   flag = !flag; }, 2000);
function changeAlarmColor(dataModel, tag, flag) { var tag = dataModel.getDataByTag(tag); if(flag) { tag.a('backgroundColor', 'rgb(138,40,18)'); tag.a('progressiveColor', 'rgb(232,97,56)'); } else { tag.a('backgroundColor', 'rgb(34,168,38)'); tag.a('progressiveColor', 'rgb(82,222,133)'); } }

因為我之前在 2D 編輯器中已經對它們的 tag 和屬性名進行了設置,所以我在這里直接通過尋找 tag 值來返回指定標示的 Data 對象。接着只需要改變它們的屬性值就可以產生想要的效果了。(.a 是獲取或設置 attr 屬性的簡寫,僅有一個參數時相當於getAttr,有兩個參數時相當於setAttr)怎么樣,是不是很簡單。同理,我們再將 PUMP 中每個部分的文字和顏色每 2.5s 變化一次。

setInterval(function () {   changePumpState(dataModel, 'pump1');   changePumpState(dataModel, 'pump2');   changePumpState(dataModel, 'pump3'); }, 2500);
function changePumpState(dataModel, tag) {   var tag = dataModel.getDataByTag(tag);   var num = Math.floor(Math.random() * 3 + 1);   tag.a('status', num); }

到這里,細心的朋友可能看出我換了寫法,用了一個 status 屬性。因為我們以后會遇到更多的屬性需要根據需求同時變化,那么我們逐一去操作會寫出大量的代碼。對比一下“笨方法”:

function changePumpState(dataModel, tag) {   var tag = dataModel.getDataByTag(tag);   var changeArr = [     {       instruction: 'Stopped',       instructionColor: 'rgb(234,0,0)',       backgroundColor: 'rgb(138,40,18)',       progressiveColor: 'rgb(232,97,56)',       status: 'FAULT'     },     {       instruction: 'Need to Run',       instructionColor: 'rgb(221,181,0)',       backgroundColor: 'rgb(29,143,32)',       progressiveColor: 'rgb(82,222,133)',       status: 'NO FAULT'     },     {       instruction: 'Running',       instructionColor: 'rgb(92,137,34)',       backgroundColor: 'rgb(29,143,32)',       progressiveColor: 'rgb(82,222,133)',       status: 'NO FAULT'     }   ];   i = Math.floor(Math.random() * (changeArr.length - 1 + 1));   tag.a('instruction', changeArr[i].instruction);   tag.a('instructionColor', changeArr[i].instructionColor);   tag.a('backgroundColor', changeArr[i].backgroundColor);   tag.a('progressiveColor', changeArr[i].progressiveColor);   tag.a('status', changeArr[i].status); }

所以,我在圖標里自己聲明了一個屬性,並通過改變 status 值來控制我在編輯器中綁定在一起的屬性以達到同時變換。哦對了,大家在做點擊圖標產生變化的時候別忘記在 2D 編輯器中選中“可交互”!下面我們再做一個 TANK 進度條每 3s 隨機變化一次的動畫效果。

  

setInterval(function () {   var tag = dataModel.getDataByTag('tank');   var num = Math.random() * 1;   ht.Default.startAnim({     duration: 500,     action: function(v, t){       tag.a('progress', num * v);     }   }); }, 3000);

這里我們用到了動畫。在 HT 的數據模型驅動圖形組件的設計架構下,動畫可理解為將某些屬性由起始值逐漸變到目標值的過程, HT 提供了 ht.Default.startAnim 的動畫函數。它支持 Frame-Based 和 Time-Based 兩種方式的動畫,Frame-Based方式是用戶通過指定 frames 動畫幀數,以及 interval 動畫幀間隔參數控制動畫效果。

我用的是 Time-Based 方式,該方式用戶只需要指定 duration 的動畫周期的毫秒數即可,HT 將在指定的時間周期內完成動畫, 不同於 Frame-Based 方式有明確固定的幀數,即 action 函數被調用多少次,Time-Based 方式幀數或 action 函數被調用次數取決於系統環境, 一般來說系統配置更好的機器,更高效的瀏覽器則調用幀數越多,動畫過程更平滑。由於 js 語言無法精確控制 interval 時間間隔, 采用 Frame-Based 不能精確控制動畫時間周期,即使相同的 frames 和 interval 參數在不同的環境,可能會出現動畫周期差異較大的問題, 因此 HT 默認采用 Time-Based 的方式,如果不設置 duration 和 frames 參數,則 duration 參數將被系統自動設置為 ht.Default.animDuration 值。action 函數就是實現動畫過程中的屬性變化(變化參數和進度)。

好了,如果你們還想改變其 HT 系統默認屬性,可以通過全局的 htconfig 變量名指定,HT 系統只在初始化時讀取 htconfig 的配置信息, 因此該屬性必須在引入 ht.js 包之前初始化好,運行狀態時修改 htconfig 變量不會再起作用。示例代碼如下:

<script>
  htconfig = {     Color: {       label: '#000',       labelSelect: '#FFF'     },     Default: {       toolTipDelay: 100,       toolTipContinual: true     },     Style: {       'select.color': '#E74C3C',       'select.width': 0// 去掉默認選中樣式(綠框)     }   }; </script> <script src="ht.js"></script>

總結

剛開始做的時候很費勁,之前沒有接觸過,不過用上編輯器之后發現一切都沒有想象的那么難,雖然花了些時間,但是總的來說收獲還是很大的,成長了很多,人都是要不斷進步嘛~

通過這個 demo 的實現,你也將會慢慢聯想到很多東西。互聯網+ 的概念在新興產業上能夠很好地運營,同時在傳統行業中利用得當同樣能夠產生非常大的效益,比如智慧城市建設,智慧能源管理,智慧工廠,甚至是地鐵、隧道監管等等都可以結合互聯網+ 的模式來運作,在一定程度上節省了非常多的人力和時間成本!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM