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