上一篇咱們本身定義CPU和內存的展現界面效果,這篇咱們將繼續採用HT完畢一個新任務:實現一個能進行展開和合並切換動做的刀閘控件。對於電力SCADA和工業控制等領域的人機交互界面常需要提早定義一堆的行業標準控件。以便用戶能作可視化編輯器裏,經過拖拽方式高速搭建詳細電力網絡或工控環境的場景,並設置好設備相應後臺編號等參數信息。將拓撲圖形與圖元信息一併保存到後臺,實際執行環境中將打開編輯好的網絡拓撲圖信息,鏈接後臺實時數據庫,接下來就是接受實時數據庫發送過來的採集信息進行界面實時動態刷新。包含用戶經過client對設備進行的各類下發遙控等操做,發送到後臺終於實現對硬件設備的控制。這個過程就是典型的實時監控系統的基本架構流程。javascript
咱們今天僅僅作好小小螺絲釘工做,提供一個可控制的刀閘開關控件。html
詳細實現以前先看看咱們要達到的終於效果圖片和視頻前端
記得十多年前我剛畢業的第一份工做就是負責電力SCADA的人機界面交互模塊。當時大部分電力行業都是採用VC/MFC或QT來實現界面呈現,事實上至今也依舊如此,前端時間和老朋友聚會了解到他們還在用VC6編譯系統,如今的VS20**根本跑不動他們龐大的古老系統,固然或許他們沒配置好工具參數。但從一個側面你可以感覺到老系統遷移之重。大部分程序猿處於爲項目業務功能疲於奔命狀態,上百號人這麼多年在根本無力優化和重構的架子上不斷堆積功能,我記得當時一個mousedown函數居然堆了六千多行代碼,各類圖元類型的draw代碼也是長得不堪入目,這些老系統儘管很差維護但也考這麼多程序猿活生生的維護下來了,咱們天天能正常的用水用電用氣。背後都是靠着衆多程序猿的血汗維護着以如今眼光看全然不堪入目的爛代碼。不得不認可在中國能用是第一位。其它問題僅僅要堆人能解決的都不是問題。有點扯遠了,上幾張我曾經電力實現的圖庫工具:java
實現功能並不難。當時也實現了組合和分解圖元。能進行圖庫管理和用戶本身定義,我相信全世界確定不下幾百上千套畫圖軟件,剛開始我仍是很是興奮,天天學習不一樣的繪製API,就能搗鼓出新效果,我也不在意代碼架構,天天就是以學習掌握不少其它的龐大MFC庫爲榮,但當你掌握大部分畫圖技巧後,我發現本身天天維護這樣的龐大到沒法以我的力量進行大規模重構,又不得不持續維護天天堆積功能性體力活代碼時,我感受本身在浪費生命。因而跳槽到了另一家公司打算作電子商務,結果陰差陽錯又被安排到電力部門幹起來畫圖工具。還好此次我能換個新語言Java,沒有歷史包袱全然本身重頭設計圖形架構,因而地球上出現了第1001個畫圖工具:node
這一版設計上仍是有很是大的改進。圖形繪製邏輯,交互代碼以及界面佈局等都進行了較合理的分工設計,那個Java和設計模式很是火,人手一本Martin Fowler《Refactoring: Improving the Design of Existing Code》,宛如宗教信仰堅定運行一個函數不超過幾十行的時代。一個mousedown幾千行的代碼已經絕跡了,但我仍是很是不愜意,數據模型和界面繪製沒有很是好的有機結合機制,儘管電力要求界面有***的毫秒級響應,但大部分公司都是像遊戲刷新機制那樣不斷repaint界面,是的。當時的數據模型沒有不論什麼事件派發機制,就是內存中的一堆數據,你沒法知道哪一個數據何時change了,於是僅僅能不斷的repaint界面,刷新週期過短對於大的網絡拓撲圖根原本不及更新,更新週期太長又達不到響應要求,至於所謂的***毫秒級響應我僅僅能呵呵了,爲了上這個系統一堆兄弟在瀋陽某農村封閉了八個多月,我很是好奇那個老系統現在是否健在…數據庫
回到咱們的任務。一個刀閘最基本的就是可開閉的部分,其它部分都是裝飾物效果而已,所以我採用HT的矢量來描寫敘述整個刀閘外觀,當中需要開閉部分採用type爲shape的一個線段來描寫敘述。並將其的rotation旋轉參數經過func: ‘style@switch.angle’的描寫敘述來綁定到Node圖元的switch.angle樣式屬性上json
ht.Default.setImage('switch', { width: 100, height: 50, comps: [ { type: 'roundRect', rect: [0, 0, 100, 50], background: '#2C3E50', gradient: 'linear.north' }, { type: 'circle', rect: [10, 10, 10, 10], background: '#34495E', gradient: 'radial.center' }, { type: 'circle', rect: [80, 10, 10, 10], background: '#34495E', gradient: 'radial.center' }, { type: 'shape', points: [10, 40, 40, 40], borderWidth: 8, borderColor: '#40ACFF', border3d: true }, { type: 'shape', points: [60, 40, 90, 40], borderWidth: 8, borderColor: '#40ACFF', border3d: true }, { type: 'shape', points: [5, 40, 35, 40, 65, 40], segments: [1, 1, 2], borderWidth: 8, borderColor: '#40ACFF', border3d: true, borderCap: 'round', rotation: { value: -Math.PI/4, func: 'style@switch.angle' } }, { type: 'circle', rect: [30, 35, 10, 10], borderColor: 'red', borderWidth: 5, border3d: true }, { type: 'circle', rect: [60, 35, 10, 10], borderColor: 'red', borderWidth: 5, border3d: true } ] });
以上是在矢量編輯器中打開的效果圖,你可以清晰的看獲得咱們定義的幾個元素的位置大小演示等,這樣應用時僅僅要構建一個Node對象。將其image設置爲switch矢量,那麼未來僅僅需要調用node.setStyle(‘switch.angle’, Math.PI/6)就可以隨時隨地控制刀閘展開角度 。設計模式
這樣封裝還不夠完美,相應用着來講他們僅僅關心刀閘的打開和關閉的操做,他們並不關心旋轉角度。開和關是業務角度的理解,而旋轉角度是底層實現圖形上的參數。並且用戶還需要開關過程有動畫效果。因而咱們進行了進一步的封裝,設計了ht.Switch的類,提供了setExpanded的函數,在函數裏面操做底層綁定圖形的‘switch.angle’屬性,以及啓動動畫封裝網絡
ht.Switch = function(){ ht.Switch.superClass.constructor.call(this); this.s('switch.angle', 0); }; ht.Default.def('ht.Switch', ht.Node, { _image : 'switch', _icon: 'switch', toggle: function (anim) { this.setExpanded(!this.isExpanded(), anim); }, isExpanded: function () { return this.s('switch.angle') !== 0; }, setExpanded: function (expanded, anim) { if(anim == null){ anim = true; } var self = this, animation = self._animation, oldValue = self.isExpanded(); if(animation){ animation.stop(true); delete self._animation; } if (oldValue !== expanded) { var targetAngle = expanded ?-Math.PI/4 : 0; if(anim){ oldValue = self.s('switch.angle'); self._animation = ht.Default.startAnim({ action: function(t){ self.s('switch.angle', oldValue + (targetAngle-oldValue)*t); } }); }else{ self.s('switch.angle', targetAngle); } } } });架構
在咱們的視頻操做中你會發現經過屬性頁的拉條可以隨意控制刀閘張角。同一時候經過isExpanded/setExpanded的boolean類型屬性也可以勾選動畫切換刀閘的開與關,細心的程序猿你會發現不僅拓撲圖上的刀閘動起來了,連TreeView上的刀閘相應的icon圖標也是和矢量描寫敘述的效果同樣。更驚喜的是樹上的icon也是實時顯示刀閘的展開角度,這是傳統圖片做爲樹的icon圖片沒法實現的,這也是咱們一直強調的HT for Web整體架構已經爲矢量打下基礎,並非爲了拓撲才實現矢量。所有通用組件都享有矢量的功能特性,這個興許咱們會有不少其它的應用案例讓你們體會到這樣的結合的強大之處。固然可維護性已經不用我多說了。傳統的通用組件tree上本身定義renderer也能實現一個能動的icon,但你可以想一想工做量,咱們沒有寫一行繪製代碼,只經過定義一個json的矢量就把GraphView和TreeView的事都幹了,並且業務接口對上層應用人員來講就是一個node.setExpanded(true/false)之簡單。
這裏我僅僅是隨手搞了個很ugly的刀閘。你可以讓美工採用矢量畫圖工具可視化的繪製更美麗的效果,界面操做上你也可以經過graphView.mi監聽交互事件,好比監聽到雙擊刀閘時進行開關切換,甚至可以參考《透過WebGL 3D看動畫Easing函數本質》的章節採用更洋相的Easing動畫效果。
最後幾點設計控件的建議: