拓撲圖形元件 ht.graph.GraphView (以下簡稱 GarphView)是 HT 框架中 2D功能最豐富的元件,其相關類庫都在 ht.graph包下。 GarphView 具有基本圖形的呈現和編輯功能,拓撲節點連線及自動佈局功能,電力和電信等行業預定義物件,具有動畫渲染等特效, 因此其應用面很廣泛,可作為監控領域的繪圖工具和人機介面,可作為一般性的圖形化編輯工具,可擴充套件成工作流和組織圖等企業應用。
HT 框架的元件指的是視覺化可互動的檢視控制元件,HT 框架基於 HTML5 技術,因此HT
元件的視覺化部分本質就是 HTML 的元素, 大部分 HT 元件與 DataModel 資料模型繫結,使用者通過操作純 js 的語言即可驅動視覺化元件,這樣遮蔽了 HTML 底層圖形技術複雜性。 HT 對 HTML5 技術封裝的目的在於提高開發效率和可維護性,但並不意味著不允許使用者直接操作 HTML 原生元素, 有 HTML5 開發經驗的程式設計師,在瞭解 HT 系統機制的前提下,大可運用各種 HTML5 的技術對 HT 元件做自定義擴充套件。
我們就是用 ht.graph.GraphView 元件作為場景的,具體程式碼只有兩行:
graphView = new ht.graph.GraphView(); graphView.addToDOM();
首先宣告變數,然後將這個元件例項變數新增進 body 體中。所有 HT 元件最根層都為一個 div 元件,可通過元件的 getView() 函式獲得, 預設和自定義互動事件監聽一般新增在該 div 上(getView().addEventListener(type, func, false)), 渲染層一般由 canvas 提供。 使用者可直接對根 div 和 canvas 層設定css背景等樣式, 也可以新增新的 HTML 元件到根 div 層上,作為 canvas 的兄弟元件一起呈現。 HT 元件一般都以設定 position 為 absolute 的絕對定位方式。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); }
接下來我們要引入“資料容器”的概念,顧名思義,就是裝載資料的容器,資料容器 ht.DataModel(以下簡稱 DataModel)作為承載 Data 資料的模型,管理著 Data 資料的增刪以及變化事件派發, HT 框架所有元件都是通過繫結 DataModel,以不同的形式呈現到使用者介面,可以通過 view.getDataModel() (簡寫為 view.dm())方式獲取資料容器;同時元件也會監聽 DataModel 模型的變化事件(view.getSelectionModel(),簡寫為 view.sm()), 實時同步更新介面資料資訊,掌握了 DataModel 的操作就掌握了所有元件的模型驅動方式。
我們要建立兩個節點 ht.Node(繼承於 ht.Data 類),一個伺服器,一個客戶端,中間連線兩條以及一條自環的連線,這些都是 Data 資料,都需要新增進 DataModel 資料容器中。但是我們得先建立這個資料節點,用 HT 只需要兩句話就能將節點新增進資料容器中了,方法跟上面建立拓撲元件的方法很像,拓撲元件是新增進 body 體中,而節點是新增進資料容器中:
var server = new ht.Node();//建立“伺服器”資料節點 graphView.dm().add(server);//將節點新增進資料容器 graphView.dm() 中
客戶端也是一樣的建立方式,節點名為 client。為了美觀,我給伺服器和客戶端的節點都設定了圖片,設定圖片有兩種方式:
- 直接將圖片相對或絕對路徑,設定到資料模型的相應屬性上,server.setImage('images/server.png')
- 先通過 ht.Default.setImage('server', 'images/server.png') 進行註冊,再將註冊名稱設定到模型上 server.setImage('server')
直接設定路徑方式開發方便,無需提前註冊圖片,但資料模型序列化時圖片路徑佔用記憶體較多,將來圖片路徑變化後不利於管理維護,兩種方式都是正確的使用方式,可根據專案情況選中不同方式或混合使用。 如果採用 url 的路徑方式 HT 內部會自動載入圖片,並在 onload 之後自動更新相應的檢視元件。
HT 的框架下圖片被賦予了更廣泛的含義,HT
提供了自定義 JSON 格式的向量描述形式,以 HT 標準定義的 JSON 向量格式, 也可以作為圖片進行註冊和使用,HT 的向量方式比傳統圖片格式更節省空間,縮放不失真,最強大之處在於向量的所有圖形引數, 皆可與 Data 模型上的資料動態繫結,具體說明參見向量手冊,現在我這邊的講解還沒到這個步驟,感興趣的可以自行了解。
接著是建立兩個節點之間的連線,ht.Edge 型別用於連線起始和目標兩個 Node 節點,兩個節點間可以有多條 Edge 存在,也允許起始和目標為同一節點。為同一節點的情況就是形成自環的情況啦~這裡有三條連線,由於有兩條類似,我就只將直線連線和自環的連線程式碼貼出來進行解釋:
var edge = new ht.Edge(server, client);//建立連線節點,引數為起始節點和目標節點 graphView.dm().add(edge);//將連線節點新增進資料容器中 var cirEdge = new ht.Edge(server, server);//這個連線的起始節點和目標節點都為同一個節點,形成自環 graphView.dm().add(cirEdge);
連線節點也繼承於 Data 類,所以新增進資料容器的方式也是一樣的。至於連線上面的字,則是通過 setStyle 方法來實現的。
HT 的資料 Data 可分為三種屬性型別:
- get/set 或 is/set型別,例如 getName(0/setName('ht') 和 isExpanded(),用於常用屬性操作
- attr 型別,通過 getAttr(name)和 setAttr(key, value) 存取,該型別是 HT 預留給使用者儲存業務資料
- style 型別,通過 getStyle(name)和 setStyle(key, value) 進行操作,GraphView 上圖元樣式由該型別屬性控制
這裡我是通過 style 型別來新增的文字說明,通過 ‘label’ 屬性設定顯示的文字:
edge.s({//setStyle 的簡寫 'label': '請求',//設定文字 'label.position': 3//設定文字位置 });
最終顯示文字由 GraphView.getLabel 函式決定:
getLabel: function (data) { var label = data.getStyle('label');//獲取 style 樣式中的 label 屬性的 value return label === undefined ? data.getName() : label; }
上面還有一個文字位置,是 HT 封裝的位置,具體顯示位置如下:
其中 17 為中心位置,大家可根據這個位置自行調整看看效果,位置的具體說明請參考 HT for Web 位置手冊。
至此,全部程式碼解析完畢,下一節我會給大家介紹如何新增連線中的流動哦,記得圍觀哦~