1 簡介
1.1產(chǎn)品介紹
mxGraph是一系列以不同技術(shù)開發(fā)的工具庫,旨在提供顯示交互式的 圖表和圖形的應(yīng)用程序的功能。 請注意,對于圖形,我們是指數(shù)學(xué)圖形, 不一定單單指圖表 (雖然有些圖形是圖表)。參見后面的章節(jié):“什么是圖形?”的細節(jié)描述。
作為一個開發(fā)庫,mxGraph沒有專門提供了一個現(xiàn)成的可以使用的應(yīng)用程序, 盡管其中的許多例子都接近可以直接使用。 mxGraph提供mxGraph樣式的 所有通常所需的繪畫功能,互動及關(guān)聯(lián)的圖表顯示環(huán)境。 mxGraph自帶有許多例子, 它們有助于解釋每種技術(shù)是如何被放在一起組成一個基本的應(yīng)用程序,并展示這個 工具庫的各項功能。
每本用戶手冊是針對某種特定的技術(shù),都具有通用的部分,如簡介和布局。開發(fā)人員會發(fā)現(xiàn),對于 在不同的技術(shù)實現(xiàn),在產(chǎn)品范圍內(nèi)的每個工具庫都共享相同的架構(gòu)和API。對于特定的技術(shù)領(lǐng)域, 事件處理和渲染的實現(xiàn)略有不同,但是從一個技術(shù)平臺整體移植到另一個平臺,mxGraph提供了 盡可能多的通用的接口。
開發(fā)人員在集成此工具庫到他們自己的應(yīng)用程序前,需要應(yīng)該閱讀的使用技術(shù)的先決條件。 參見下面的“先決條件”一節(jié)。鑒于mxGraph是您的應(yīng)用程序的組成部分,你必須了解應(yīng)用程序 使用的技術(shù),以及如何使用該技術(shù)進行編程。
mxGraph主要包含一個JavaScript文件,mxGraph的全部函數(shù)都在這個文件中。它需要被加載到一個瀏覽器的Web頁面的Javascript中并執(zhí)行在HTML容器中。它結(jié)構(gòu)簡單,只要一個web服務(wù)器來提供html頁面和一個支持JavaScript的瀏覽器就可以了。
它的優(yōu)點如下:
- 不需要第三方插件。也就少了對廠商的依賴。
- 涉及到的技術(shù)都是開源的并且有很多開放的實現(xiàn)。這就意味著一個廠商刪除它的一個產(chǎn)品或者技術(shù)不會導(dǎo)致你的程序無法工作。
- 標(biāo)準(zhǔn)化的技術(shù),意味著你的應(yīng)用可以部署在最大數(shù)量的瀏覽器上,用戶不需要在客戶端機器上添加額外的配置或進行安裝。大型企業(yè)的環(huán)境通常不允許個人安裝瀏覽器插件,也不允許改變所有機器的標(biāo)準(zhǔn)配置。

mxGraph組件關(guān)系
1.2 mxGraph可以被用在什么樣的產(chǎn)品上?
圖形可視化庫的應(yīng)用實例包括:過程圖、工作流和BPM的可視化圖表、流程圖、交通或水流量、 數(shù)據(jù)庫和WWW的可視化、網(wǎng)絡(luò)和電信顯示、映射應(yīng)用和地理信息系統(tǒng)、UML圖、電子線路、金融、 超大規(guī)模集成電路和社會網(wǎng)絡(luò)、數(shù)據(jù)挖掘、生化、生態(tài)循環(huán)、實體和因果關(guān)系和組織圖表。
1.3 怎樣部署mxGraph?
在典型的瘦客戶端環(huán)境中,mxGraph分為在客戶端的JavaScript庫和在服務(wù)器端兩種支持的語言之一的.NET或Java庫。 JavaScript庫作為一個更大的基于瀏覽器的web應(yīng)用程序的一部分,被一個標(biāo)準(zhǔn)web服務(wù)器分發(fā)到瀏覽器。所有的瀏覽器 需要開啟JavaScript能力才能運行這個應(yīng)用。
在本手冊的第三部分,您會看到一個嵌入了mxGraph庫的HTML頁面,以及一個簡單的調(diào)用了庫功能的應(yīng)用程序。
1.4 mxGraph的技術(shù)
mxGraph使用在瀏覽器上的客戶端的JavaScript功能。而在JavaScript代碼層面上,在瀏覽器中使用了基本的矢量圖形語言來顯示圖形,當(dāng)前SVG技術(shù)已經(jīng)被所有瀏覽器支持。 mxGraph還包括完全只使用HTML來呈現(xiàn)的功能, 這會限制可以使用的功能范圍,但可用于較簡單的圖表。
作為一名開發(fā)人員,您并不是被限制在瀏覽器相關(guān)的特定功能。如前所述,瀏覽器不同,所使用的矢量圖形語言也不同, 所以mxGraph的功能被抽象成一個共同的類。同樣,瀏覽器對于事件處理和DOM,兩大瀏覽器實施的功能也不盡相同。然而, mxGraph通過使用恒定的API來適用于所有瀏覽器,掩藏不同瀏覽器間的內(nèi)在差異。、
1.5 mxGraph 授權(quán)
mxGraph的JavaScript客戶端采用了Apache 2.0 license 許可證授權(quán),有關(guān)詳細的許可問題,請務(wù)必咨詢法律專業(yè)人士。
1.6 圖形是什么?
圖形可視化是建立于網(wǎng)絡(luò)、圖論的數(shù)學(xué)理論基礎(chǔ)上。如果您正在查找JavaScript的條形圖、餅圖、甘特圖, 可以參考Google Charts項目,或類似的信息。
一個圖是由頂點,也稱為節(jié)點,以及邊(節(jié)點之間的連接線)組成。圖論中沒有定義圖究竟如何來視覺呈現(xiàn)。本手冊中術(shù)語圖元用來描述圖形的構(gòu)成元素,無論是邊,節(jié)點或圖元組。

一張簡單的圖
圖論中有些額外的定義,為圖形處理提供 有用的背景,如果您感興趣的話,它們都列在附錄中。
1.6.1 圖形的可視化
可視化是創(chuàng)建一個有用的圖形可視化展現(xiàn)的過程??梢暬δ艿姆秶莔xGraphs的主要力量之一。 mxGraph支持范圍廣泛的功能,使圖元顯示僅限于開發(fā)人員的技術(shù)和平臺可用的功能。節(jié)點可以是圖形、圖像、矢量繪圖、動畫以及幾乎所有可以在瀏覽器中操作的圖形。您也可以在節(jié)點和邊使用HTML標(biāo)記。

交通系統(tǒng)的可視化圖 (c) Tourizm Maps2003, http://www.world-maps.co.uk
1.6.2 圖形交互
交互是指在一個使用mxGraph的應(yīng)用程序中,通過WEB應(yīng)用程序的GUI改變圖形模式。mxGraph支持拖動、復(fù)制圖元、重新調(diào)整大小、重新構(gòu)造,連接和斷開,從外部源的拖放和刪除,編輯圖元標(biāo)簽中的位置等等。 mxGraph的主要好處之一是通過編程來實現(xiàn)互動的靈活性。
許多復(fù)雜的圖形化Web應(yīng)用程序依賴于與服務(wù)器往返的通訊來顯示圖形,不僅是基本的顯示,還包括交互事件。雖然這就是通常所謂的AJAX功能,這種服務(wù)器的依賴對交互事件是不合適的。視覺反饋時間超過0.2秒在應(yīng)用程序中一般嚴(yán)重影響了實用性。mxGraph把所有的交互事件都放置在客戶端,提供了真實感覺的應(yīng)用程序,而不像一個啞巴的遠程終端。它還提供了脫機使用的可能性。

通過鼠標(biāo)拖動選擇一個區(qū)域時顯示陰影效果
1.6.3 圖像的布局
圖形圖元可以布置在一個簡單的應(yīng)用程序的任何地方,包括在彼此頂部。 某些應(yīng)用程序需要按照一般或特殊的順序結(jié)構(gòu)來顯示出示信息。 這可能涉及到確保圖元不重疊和至少彼此間留有一定的距離,或出現(xiàn)在相對于其他圖元的一個相對 位置,圖元通常是通過邊來連接。這個活動,被稱為布局的應(yīng)用,可以 通過多種方式,來協(xié)助用戶設(shè)置自己的圖形。 對于非編輯圖形,布局應(yīng)用是對圖元進行布局算法的過程。 對于交互式的圖形,即那些可以通過用戶界面進行編輯,布局應(yīng)用可能只 允許用戶對特定的圖元進行特定位置的修改,對每個修改重新布局,或 編輯完成后,重新布局。

使用水平流布局對工作流進行布局
mxGraph支持樹、有機排列和流向的布局,來滿足大多數(shù)布局的需求。后面的章節(jié)中會講述更多布局的信息。
在客戶端-服務(wù)器架構(gòu)中運行布局可以有兩個選項。JavaScript版提供了完全在客戶端布局的能力,如果需要的話,同樣的布局在服務(wù)器端的Java實現(xiàn)可以選擇卸載一些服務(wù)器的處理。
1.6.4 圖形的分析
圖形分析涉及到確定有關(guān)的圖形結(jié)構(gòu)的某些細節(jié)算法的應(yīng)用,例如, 確定所有路徑或兩個圖元之間的最短路徑。有些更復(fù)雜的圖形分析算法,往往被應(yīng)用于 指定域的任務(wù)。有些技術(shù),如聚合、分解、優(yōu)化等趨向某些針對性的科學(xué)領(lǐng)域的,目前包含在核心的mxGraph包中。

最短路徑分析
1.7 關(guān)于本手冊
1.7.1 mxGraph先決條件
要從本手冊中獲益匪淺,您需要對Web應(yīng)用程序和希望部署的服務(wù)器技術(shù)有一個合理的了解。部署的例子可以在每個服務(wù)器技術(shù)支持得到,熟悉該服務(wù)器的技術(shù)顯然是必需的。
對于修改描述顯示和行為方面的編輯器的配置文件,基本的XML知識是有用的。您需要理解和執(zhí)行JavaScript編碼,并熟悉面向?qū)ο缶幊淘砗同F(xiàn)代軟件設(shè)計。
您不需要底層的瀏覽器使用的矢量圖形的知識,如SVG或HTML的canvas。 mxGraph將可視化組件的描述抽象成一個API。
2 入門
2.1 mxGraph 包
2.1.1 獲取mxGraph
mxGraph可以從 github 項目上獲得,發(fā)布的版本號為"va.b.c",其中a,b和c版本號遵循了語義版本控制
每一個正式版本的.zip或者.tar.gz包也可以在mxGraph發(fā)布頁面獲得。
2.1.2 項目結(jié)構(gòu)和構(gòu)建選項
解壓縮后,你將在根目錄下獲得的一系列的文件和目錄。
| 目錄/文件 | 描述 |
|---|---|
| /doc | 文檔根目錄,包含本用戶手冊 |
| /docnet | .NET服務(wù)器端代碼 |
| /java | Java服務(wù)器端代碼 |
| /javascript | JavaScript客戶端功能 |
| /javascript/examples | mxGraph的HTML演示例子 |
| ChangeLog | 發(fā)布版本間差異詳情 |
| index.html | 庫的基本介紹 |
| license.txt | 使用庫的許可條款 |
項目目錄結(jié)構(gòu)表
2.1.3 npm
mxGraph同樣可以使用 npm 包管理獲得。使用mxgraph作為依賴,用 npm 安裝如下:
npm install mxgraph --save
這個模塊可以使用require()方法進行加載。它將返回一個接受對象作為選項的工廠函數(shù)。必須將mxBasePath選項提供給工廠函數(shù),而不是將其定義為一個全局變量。
var mxgraph = require("mxgraph")({
mxImageBasePath: "./src/images",
mxBasePath: "./src"
})
工廠函數(shù)返回一個“命名空間對象”,通過它可以訪問mxGraph包的所有對象。例如,mxEvent對象在mxgraph.mxEvent中可用。
var mxEvent = mxgraph.mxEvent;
mxEvent.disableContextMenu(container);
2.2 JavaScript和web應(yīng)用
Web應(yīng)用程序,特別是在網(wǎng)頁瀏覽器中使用JavaScript來試圖效仿桌面應(yīng)用程序, 仍然是一個相對較新的軟件工程領(lǐng)域。障礙JavaScript生產(chǎn)出高質(zhì)量應(yīng)用的主要 有三個問題:性能,缺乏原生性的桌面應(yīng)用程序功能以及瀏覽器之間API的不一致性。
相當(dāng)大的努力已經(jīng)被投入來開發(fā)框架庫,以解決功能和API這兩個問題。許多的開發(fā)庫 的設(shè)計需求就是由同時改善網(wǎng)站的設(shè)計和可用性,以及協(xié)助我們完成一般的應(yīng)用功能 (如菜單、窗口、對話框、持久性、事件處理等)的要求來驅(qū)動的。他們同時也提供了 某些在JavaScript中找不到的基本功能,如基本的數(shù)學(xué)和集合功能,而這些功能在桌面 的應(yīng)用程序開發(fā)中是與生俱來的。
許多這些JavaScript框架,通過原生支持或作為一個插件的支持,可以用時下流行IDE來開發(fā), 并支持所有的主流包含JavaScript調(diào)試器的瀏覽器。JavaScript沒有編譯過程(它是一種解釋語言), 因此,除非您的IDE具有語法檢查工具,打字錯誤通常只能在運行時刻才可以被捕獲。因此,世上沒有 一個能夠包羅萬象的工具包,您往往需要使用好幾個廠商的獨立組件,才能提供你開發(fā)JavaScript 應(yīng)用所需要的工具庫。
2.2.1 第三方JavaScript框架
2.2.1.1 原生JavaScript框架和庫
為了不用列表和比較每一個框架,請大家參閱維基百科的條目Web應(yīng)用程序框架和JavaScript庫比較。這個比較表不能被認(rèn)為是最權(quán)威的,而更象說明提供的功能類型,如提供事件處理、動畫、小工具、支持AJAX請求等。 這個網(wǎng)站(注:這個網(wǎng)站內(nèi)容已經(jīng)變了)也是一個有用的JavaScript庫名單,大多是基于開放/免費源許可。
請注意,很多框架添加了隱式的行為,使JavaScript的更像是一個面向?qū)ο蟮恼Z言, 并增加了語言的基本功能。在寫作的的布局mxGraph部分時,我們發(fā)現(xiàn),這種隱含的行為 使得調(diào)試一個例子變得非常困難。在選擇一個框架時,請留意它引入的隱式的行為,是否 會導(dǎo)致任何問題。
當(dāng)選擇了一個框架和/或工具庫時,考慮您會被綁定的某些特定功能,并尋找那些不同的,可以提供所需功能如動畫, 獨立的模塊,而無需在總體設(shè)計上被綁定。
2.2.1.2 mxGraph與其他JavaScript構(gòu)架的集成
這個部分經(jīng)常被誤解,簡單來講,并不需要集成。 Web應(yīng)用程序一般包括一個或多個 div元素, 可以被HTML用來放置包裝應(yīng)用程序的JavaScript。如果您創(chuàng)建一個div作為mxGraph的容器, 這就是一個可以為mxGraph應(yīng)用程序的獨立顯示。它可以與任何后端服務(wù)器通信本身,而并不依賴與這個div和頁面的其余部分,除了它們各自占的地方。這包括事件處理,mxGraph可以處理其容器的事件, 即便網(wǎng)頁的其余部分用一個完全不同的事件模型。只要mxGraph和頁面上的其他庫和框架不引入會打破 一個頁面作為整體的隱式行為,客戶端集成的問題根本就不需要考慮。
與mxGraph服務(wù)器端集成,我們會在后面的章節(jié)闡述。
2.2.1.3 mxGraph的JavaScript擴展
在JavaScript中,將語言結(jié)構(gòu)映射面向?qū)ο蠓妒接懈鞣N方式。mxGraph在整個項目中都使用一個特定的方法, 參見下面的默認(rèn)規(guī)則:
- 不要更改內(nèi)置的原型
- 不要試圖限制JavaScript語言的力量
在mxGraph中,有兩種類型的“類”:類classes和單例singletons (其中只有一個存在的類的實例)。單例被映射到全局對象而且變量名同類名是一樣的。 例如,mxConstants是一個定義了所有常量字段的對象實例。普通類映射到一個構(gòu)造函數(shù)和 定義了字段和方法的原型。例如,mxEditor是一個函數(shù)而mxEditor.prototype是mxEditor 函數(shù)創(chuàng)建對象時的原型。mx前綴是一種命名習(xí)慣,應(yīng)用于mxGraph包中的所有類,以避免 與其他對象在全局命名空間發(fā)生沖突。
為派生,父類必須提供一個構(gòu)造函數(shù),要么是無參數(shù)或者可以處理不帶參數(shù)的調(diào)用。 此外,特殊的構(gòu)造函數(shù)字段派生后的原型必須重新定義。例如,mxEditor派生于mxEventSource。 在JavaScript中,首先通過分配父類的一個實例到子類原型,來“繼承”從父類的所有字段和方法:
mxEditor.prototype = new mxEventSource()
并定義構(gòu)造函數(shù)字段:
mxEditor.prototype.constructor = mxEditor
后面的規(guī)則,使得可以通過使用構(gòu)造函數(shù)的名稱mxUtils.getFunctionName(obj.constructor)來檢索對象的類型。
構(gòu)造函數(shù)
在mxGraph中,對于派生的子類應(yīng)采用相同的機制。例如,mxGraph的派生子類,首先, 新類的構(gòu)造函數(shù)必須被定義。構(gòu)造函數(shù)調(diào)用的父類的構(gòu)造函數(shù),需要顯式傳入調(diào)用的 mxGraph對象的每一個參數(shù):
function MyGraph(container)
{
mxGraph.call(this, container);
}
MyGraph的portotype從mxGraph繼承如下。像往常一樣,子類的構(gòu)造函數(shù)在繼承后被重新定義:
MyGraph.prototype = new mxGraph();
MyGraph.prototype.constructor = MyGraph;
您可能需要在上述代碼之后定義與該類相關(guān)聯(lián)的編解碼器(參見I/O部分手冊)。該代碼將在類加載時執(zhí)行,并確保使用相同的編解碼器來編碼mxGraph和MyGraph的實例。
var codec = mxCodecRegistry.getCodec(mxGraph);
codec.template = new MyGraph();
mxCodecRegistry.register(codec);
方法
在MyGraph的prototype中,mxGraph的方法可如下擴展。
MyGraph.prototype.isSelectable = function(cell)
{
var selectable = mxGraph.prototype.isSelectable.apply(this, arguments);
var geo = this.model.getGeometry(cell);
return selectable &&(geo == null || !geo.relative);
}
在第一行中的supercall是可選的。這是使用apply方法通過傳入this及arguments這個變量作為參數(shù), 到mxGraph的protoype的isSelectable這個方法上。父類的方法只有在不被覆蓋的時候才可能被調(diào)用,這也是JavaScript中另一種“繼承”的方式。
mxGraph.prototype.isSelectable = function(cell)
{
var geo = this.model.getGeometry(cell);
return selectable && (geo == null || !geo.relative);
}
如果方法的定義需要被完全覆蓋,上述方案是有用的。
為了增加新的方法和字段,可以使用如下代碼。在下面的例子,示范了增加了一個返回圖模型的XML的新方法:
MyGraph.prototype.getXml = function()
{
var enc = new mxCodec();
return enc.encode(this.getModel());
}
字段
新的字段通過如下方式聲明和定義:
MyGraph.prototype.myField = ‘Hello, World!’;
需要注意的是myField的值只分配了一次,那就是說,所有MyGraph的實例共享相同的值。 如果您需要每個實例擁有自己的值,則該字段必須定義在構(gòu)造函數(shù)中。例如:
function MyGraph(container)
{
mxGraph.call(this, container);
this.myField = [];
}
最后,使用以下代碼將一個新的MyGraph實例,其中container是一個圖形視圖的容器的DOM節(jié)點:
var graph = new MyGraph(container);
2.2.2 JavaScript開發(fā)綜述
2.2.2.1 JavaScript混淆
默認(rèn)情況下,當(dāng)你向瀏覽器客戶端發(fā)送JavaScript時,發(fā)送都是JavaScript的全部源代碼。然后,JavaScript在瀏覽器上被解析并運行。在客戶端運行的時候,不可能在任何程度上加密JavaScript,因為JavaScript解析器必須理解和解釋JavaScript源碼,而且它不具有二進制的中間形式。
可以做到的是,在傳輸?shù)倪^程中,將JavaScript加密,在客戶端運行前解密,但客戶端仍然能夠訪問解密后的源代碼。
我們不做混淆,因為方法的名稱形成的公共的API和I/O,在通信的兩端都需要理解這樣的混淆。
2.2.2.2 命名空間
命名空間的概念在JavaScript中并不存在,所以在創(chuàng)建新的類名稱時要非常謹(jǐn)慎。 mxGraph中,所有的類都以“mx-”的前綴開始,以避免無意中沖突或覆蓋掉原型。
2.3 Hello World!
mxGraph中的Hello World,是一個簡單的客戶端的例子,顯示了兩個相連的“Hello”和“World”的節(jié)點標(biāo)簽。 這個例子演示了以下幾件事:
- 創(chuàng)建一個嵌入了mxGraph客戶端JavaScript的HTML頁面
- 創(chuàng)建了一個容器來裝載mxGraph
- 在圖形中加入了所需的元素
這個例子的源代碼,helloworld.html,可以在mxGraph的源代碼的示例目錄下找到。 在HTML源代碼包含兩個主要部分組成,head和body。建立一個基本的mxGraph 應(yīng)用程序的模板應(yīng)包含以下主要內(nèi)容:
mxBasePath: 這是一個JavaScript變量,用來定義CSS,圖片, 資源和js的使用的目錄。它是一段JavaScript代碼,并需要被放置在 script 標(biāo)簽內(nèi)。 它必須在加載mxClient.js之前,而且不應(yīng)該斜線。
mxClient.js: 這是mxGraph庫的路徑。如果HTML文件在本地執(zhí)行, 路徑可能是本地計算機路徑或公共互聯(lián)網(wǎng)的路徑。如果HTML頁面是從Web服務(wù)器上下載,這路徑 通常是一個公共的因特網(wǎng)路徑。
創(chuàng)建容器: 在body元素中底部的代碼,被定義為加載項 的方法(onload事件),加載網(wǎng)頁時會被調(diào)用。它通過在傳遞即下定義的一個div 容器作為參數(shù)。mxGraph組件將被放置在這個div容器中。在此示例中網(wǎng)格被添加作為背景, 這在圖表應(yīng)用程序中經(jīng)常用到。在容器創(chuàng)建時,其他視覺效果或者其他的背景和以及容器的 寬度和高度都沒有定義。
注意,如果你想不出現(xiàn)滾動條,overflow:hidden格式應(yīng)該一直被使用。
入口方法: 在這種情況下,該文件的主要代碼是在頁面加載時執(zhí)行。 這是JavaScript代碼,還必須在JavaScript的 script 標(biāo)簽當(dāng)中。任何mxGraph 應(yīng)用程序的第一行應(yīng)該檢查瀏覽器的支持,如果不支持應(yīng)該適當(dāng)退出。如果瀏覽器支持, mxGraph將在div容器內(nèi)被創(chuàng)建,在開始/結(jié)束更新調(diào)用之間,三個圖元被添加到圖中。

mxGraph的HelloWorld例子
<html>
<head>
<title>Hello, World! example for mxGraph</title>
<!-- Sets the basepath for the library if not in same directory -->
<script type="text/javascript">
mxBasePath = '../src';
</script>
<!-- Loads and initializes the library -->
<script type="text/javascript" src="../src/js/mxClient.js"></script>
<!-- Example code -->
<script type="text/javascript">
// Program starts here. Creates a sample graph in the
// DOM node with the specified ID. This function is invoked
// from the onLoad event handler of the document (see below).
function main(container)
{
// Checks if the browser is supported
if (!mxClient.isBrowserSupported())
{
mxUtils.error('Browser is not supported!', 200, false);
}
else
{
// Creates the graph inside the given container
var graph = new mxGraph(container);
// Enables rubberband selection
new mxRubberband(graph);
// Gets the default parent for inserting new cells. This
// is normally the first child of the root (ie. layer 0).
var parent = graph.getDefaultParent();
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try
{
var v1 = graph.insertVertex(parent, null,
'Hello,', 20, 20, 80, 30);
var v2 = graph.insertVertex(parent, null,
'World!', 200, 150, 80, 30);
var e1 = graph.insertEdge(parent, null, '', v1, v2);
}
finally
{
// Updates the display
graph.getModel().endUpdate();
}
}
};
</script>
</head>
<!-- Page passes the container for the graph to the program -->
<body onload="main(document.getElementById('graphContainer'))">
<!-- Creates a container for the graph with a grid wallpaper -->
<div id="graphContainer"
style="overflow:hidden;width:321px;height:241px;background:url('editors/images/grid.gif')">
</div>
</body>
</html>
這個例子中的重要概念有:
- mxClient.js是一個包含所有的mxGraph源代碼的JavaScript文件。從Web服務(wù)器下載時, 獲得包含所有的JavaScript的單個文件,要比分成多個獨立文件要快得多,這是由于每個文件 都具有獨立的請求/確認(rèn)開銷。無論服務(wù)器對于一個客戶的并行接口的能力差異有多大,速度的 提升通常至少是兩倍以上。
- 所有JavaScript代碼及所有的依賴都是放在head元素中
- 默認(rèn)情況下,Internet Explorer安全選項是開啟的,將導(dǎo)致試圖從本地文件系統(tǒng)中運行 JavaScript得到用戶提示。這可以在選項菜單中禁用,但請注意,從本地文件系統(tǒng)上運行, 不是通常的mxGraph部署場景,這只會發(fā)生在開發(fā)過程中遇到。
- 您的應(yīng)用程序可以寫在HTML文件中并鏈接到應(yīng)用程序,也可以寫在另外的JavaScript文件中,再被鏈接到HTML中,就像在本例中的mxClient.js文件使用的方式。
2.4 mxGraph部署和調(diào)試
mxclient.js文件有兩個版本,一個用于生產(chǎn)用途,另一個用于的開發(fā)/調(diào)試使用。javascript/src/js/mxClient.js 的是生產(chǎn)版, javascript/debug/js/mxClient.js 的是用于開發(fā)。第一個版本剝離了所有的換行符, 以確保該文件是最可能小的尺寸。這樣做的副作用,是破壞了JavaScript的調(diào)試器。在開發(fā)過程中, 我們建議您使用調(diào)試版本,其中有換行符,支持的在瀏覽器中啟用調(diào)試。
兩個mxClient.js文件是包含整個mxGraph的JavaScript源代碼,為減少文件大小,所有的空格和注釋都被刪除。 在調(diào)試過程中,如果您需要調(diào)試到mxGraph庫本身,使用單獨的源文件更加容易。在source.zip的 javascript/devel目錄中,包含完整的源代碼的文件。將它們解壓到mxBasePath,并除去加載完整版 的mxClient.js文件,會使得調(diào)試mxGraph更加容易。需要注意的是,源文件的zip文件中的mxclient.js文件, 會引導(dǎo)加載的所有其他JavaScript源代碼。
通過壓縮代碼,客戶端的程序的下載速度,可以進一步提高。所有的現(xiàn)代瀏覽器都支持傳輸在服務(wù)器端壓縮過的內(nèi)容, 而所有良好的網(wǎng)絡(luò)服務(wù)器可以檢測出不支持的瀏覽器,并發(fā)送未壓縮版本作為備用。
例如,在Apache Web服務(wù)器中有一個mod_deflate模塊,通過一個標(biāo)準(zhǔn)的搜索,可以了解其使用的細節(jié)。jgraph.com服務(wù)器一直在使用這個模塊,沒有發(fā)現(xiàn)有任何瀏覽器的支持問題。
通過使用壓縮,mxClient.js文件的大小從約600KB減少到只有130KB左右。對于使用最先進的網(wǎng)絡(luò)用戶而言, 區(qū)別并不明顯,但在某些情況下,傾向于使用較小的版本。
3 mxGraph的模型和圖元
3.1 mxGraph的核心架構(gòu)
3.1.1 mxGraph的模型
mxGraph模型是,描述了圖形結(jié)構(gòu)的核心的模型,被稱為mxGraphModel,可以在model包中發(fā)現(xiàn)。 另外,對圖形結(jié)構(gòu)的添加,更改和清除是通過圖模型API來完成的。該模型還提供了方法來確定圖形 的結(jié)構(gòu),以及提供方法來設(shè)置,如能見度、分組和樣式的視覺狀態(tài)。
然而,雖然對于模型進行的處理是被存儲在模型上的,mxGraph被設(shè)計成一種通過mxGraph類的主要公共API來使用的方式。 “添加該單元格到圖形”的概念,是一個比“添加單元到圖形的模型”的更自然的動作。它是直觀的,在模型上和單元上的方法被復(fù)制到了圖形類上,而這些圖形類上的方法被認(rèn)為是主要的公共API。本手冊的其余部分,這些關(guān)鍵的API方法都被以粉紅色的背景標(biāo)示(注:真實情況似乎是文字加粗):
anExampleCoreAPIMethod()
因此,盡管許多的主要API通過mxGraph類來調(diào)用,請注意,mxGraphModel是基本的對象,它存儲著圖形的數(shù)據(jù)結(jié)構(gòu)。
mxGraph使用事務(wù)處理系統(tǒng)來更新模型。在HelloWorld的例子里,我們看到如下代碼:
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try
{
var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
var v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
var e1 = graph.insertEdge(parent, null, '', v1, v2);
}
finally
{
// Updates the display
graph.getModel().endUpdate();
}
執(zhí)行2個節(jié)點和1條連線的插入。對于模型的每一個變化,請調(diào)用beginUpdate(),作出適當(dāng)?shù)恼{(diào)用更改模型,然后調(diào)用endUpate()方法來完成的變化,通知發(fā)送變化的事件出去。
關(guān)鍵API方法:
- mxGraphModel.beginUpdate() - 啟動一個事務(wù)或子事務(wù)處理。
- mxGraphModel.endUpdate() - 完成一個事務(wù)或子事務(wù)處理。
- mxGraph.addVertex() - 添加一個新節(jié)點到指定的父單元。
- mxGraph.addEdge() - 添加一個連線到指定的父單元。
注意 從技術(shù)上講,你不必用開始和結(jié)束調(diào)用來包圍著你的更改。此更新范圍之外所做的更改會立即生效,并立即發(fā)出通知。事實上,更新范圍內(nèi)的更改會立即在模型上立即實現(xiàn),更新范圍是控制事件通知的時間和連接。除非更新包裝導(dǎo)致代碼審美問題,否則值得使用它來避免事件和撤消粒度的可能問題。
請注意,這種將模型更改的包裝在try塊中,endUpdate()放在finally塊中的方式。即使模型的更改有錯誤,它依然確保了更新的完整性。
現(xiàn)在請先忽略parent圖元的引用,在本章節(jié)的后面再做解釋。
3.1.2 事務(wù)模型
以上藍色塊中的子事務(wù),是指事務(wù)可以被嵌套。也就是說,在模型中有這樣一個計數(shù)器,每次調(diào)用beginUpdate計數(shù)遞增,每次調(diào)用endUpdate計數(shù)遞減。在計數(shù)器增加超過1后,當(dāng)該計數(shù)再次達到0時,模型的事務(wù)被認(rèn)為是完成,模型的事件通知被觸發(fā)。
這意味著,每個子代碼的部分就可以(而且應(yīng)該)被開始/結(jié)束組合來包圍。在mxGraph中,這創(chuàng)建單獨的事務(wù),被用來作為“庫事務(wù)”的能力,能夠為創(chuàng)建復(fù)合改動,一系列事件的所有改動一起觸發(fā)并且只需要創(chuàng)建一個撤消。自動布局是說明這個功能必需性的很好的例子。
在自動布局中,在用戶通常通過用戶界面修改了圖形,應(yīng)用程序自動根據(jù)默認(rèn)規(guī)則定位結(jié)果。自動定位即布局,在開始/結(jié)束調(diào)用之間的獨立算法,它并不知道具體的變化內(nèi)容。因為所有的在開始/結(jié)束變化范圍內(nèi)的更新是由直接作用在圖形模型上,布局是根據(jù)模型的狀態(tài)的變化來進行。
需要重點區(qū)分的是,作用在圖形模型上的功能,是作為復(fù)合改動的一部分,還是原子態(tài)圖形的改動事件。在第一種情況下,如用于自動布局,該功能將模型就當(dāng)成那樣而作用于它。此方法只用于作為復(fù)合變化的一部分時使用。應(yīng)用程序的所有的其他部分,應(yīng)該依據(jù)模型的改變事件而作出反應(yīng)。
當(dāng)最后一個endUpdate調(diào)用將計數(shù)器還原到0并指示至少發(fā)生了一個原子圖更改時,會觸發(fā)模型更改事件。改變事件包含著完整的已改變信息(參見后面的部分Events更多詳細信息)。
3.1.2.1 模型改變方法
以下是更改圖形模型并應(yīng)直接或間接放置更新范圍的方法的列表:
add(parent, child, index)
remove(cell)
setCollapsed(cell, collapsed)
setGeometry(cell, geometry)
setRoot(root)
setStyle(cell, style)
setTerminal(cell, terminal, isSource)
setTerminals(edge,source,target)
setValue(cell, value)
setVisible(cell, visible)
最初,我們只關(guān)心添加和刪除,以及幾何和樣式編輯方法。請注意,這些方法不是核心API方法,像往常一樣,這些方法在mxGraph類中是適用的,他們執(zhí)行的是被封裝的更新。
設(shè)計背景 - 有些人對可視信息被存儲的模型中感到困惑。這些屬性包括圖元定位,可見性和折疊狀態(tài)。模型存儲了這些屬性的默認(rèn)值,提供一個共同的地方對每個單元進行設(shè)置,以及對每個視圖的單獨設(shè)置。模型是整個架構(gòu)中,第一個通用的地方可以以全局的方式設(shè)置這些屬性。請記住,這是一個圖形可視化庫,可視化的部分是核心功能。
插入圖元
在HelloWorld應(yīng)用程序中,創(chuàng)建的三個圖形單元包括兩個節(jié)點和一條連線。如果你不熟悉基本圖形理論和術(shù)語,請參閱 維基百科條目 。
你可以使用add()方法添加節(jié)點和連線到模型中。但是,考慮到日常使用庫的場景,請學(xué)習(xí)mxGrap.insertVertex()和mxGraph.insertEdge()這兩個添加圖元的核心公共API。
模型功能的要求,被添加的圖元必須已經(jīng)創(chuàng)建,而mxGraph.insertVertex()為你創(chuàng)建了圖元。
核心API方法:
mxGraph.insertVertex(parent, id, value, x, y, width, height, style) –在調(diào)用開始/結(jié)束更新中,創(chuàng)建并插入一個新的節(jié)點到模型中。
mxGraph.insertEdge(parent, id, value, source, target, style) –在調(diào)用開始/結(jié)束更新中,創(chuàng)建并插入一條新的連線到模型中。
mxGraph.insertVertex() 會創(chuàng)建一個mxCell對象并返回。方法的參數(shù)為:
parent – 組結(jié)構(gòu)中此圖元的直接父圖元。我們會很快談?wù)摰浇M結(jié)構(gòu),但現(xiàn)在我們直接使用graph.getDefaultParent();作為默認(rèn)的父圖元,就像在 HelloWorld 這個例子一樣。
id – 描述此單元的全局唯一身份號碼,總是一個字符串。主要用于外部對這單元的引用。如果你不想自己維護這些號碼,只需要傳入一個空參數(shù)并確保mxGraphModel.isCreateIds()返回真即可。這樣,模型就會管理這些號碼,并保證它們的唯一性。
value – 此單元的用戶對象。用戶對象只是一些對象,可以讓您把應(yīng)用程序的商務(wù)邏輯與mxGraph的可視化呈現(xiàn)相關(guān)聯(lián)。在手冊的后面有詳細地描述,這里我們就只用字符 串就好,并把它們顯示成節(jié)點和邊的標(biāo)簽。
x, y, width, height – 就像名字提到的,這是節(jié)點的左上角的 x 和 y 的位置以及它的寬度和高度。
style – 將被應(yīng)用到節(jié)點的樣式描述。關(guān)于樣式,很快會有更詳細的描述,簡單來講,就是一個特定格式的字符串。這個字符串有零個或多個樣式名字和一些鍵/值配對,用來覆蓋全局設(shè)置或者創(chuàng)立新的樣式。除非我們要創(chuàng)建自己的樣式,我們可以直接使用這些現(xiàn)有的設(shè)置。
添加連線的方法和添加節(jié)點的方法使用了同樣的參數(shù)。source和target參數(shù)定義了節(jié)點要連接的節(jié)點。注意,源節(jié)點 和目標(biāo)節(jié)點需要已經(jīng)被加入到模型中。
3.1.3 mxCell
mxCell是節(jié)點和連線的圖元對象。mxCell從模型那里復(fù)制了許多的方法。它們的主要差別在于,使用模型的方法會創(chuàng)建相關(guān)的事件通知以及撤銷方法,使用圖元的方法可以發(fā)生改變但不記錄它們。這對于臨時改變視覺效果,如動畫或鼠標(biāo)效果,是非常有用的。作為通用規(guī)則,一般使用模型的編輯API,除非您遇到什么特殊問題。
當(dāng)創(chuàng)建新的圖元時,構(gòu)造函數(shù)需要三部分參數(shù),值(用戶數(shù)據(jù)),幾何參數(shù)以及樣式。我們在回到討論圖元之前,先了解一下這三個概念。
3.1.3.1 樣式
樣式和樣式表的概念挺像CSS的樣式表,盡管你已經(jīng)注意到mxGraph中事實上使用的就是CSS,但CSS只是影響HTML的DOM的全局樣式。當(dāng)你使用編輯器打開 util.mxConstants.js 文件并查詢開頭皮匹配“STYLE_”,如果你向下滾動鼠標(biāo),將會看到很多帶有這個前綴的各種樣式定義字符串。一些樣式應(yīng)用到節(jié)點上,一些適用于節(jié)點,一些適用于連線,一些都適用。正如你所見,這些視覺屬性定義在它們操作的元素上。
mxStylesheet包含一個對象,樣式,則以一個散列表映射樣式名稱到一個樣式數(shù)組。

樣式集合中的樣式列表
上面藍框里的圖顯示了在mxStyleSheet里面的樣式表。字符串“defaultVertex”是真實樣式串/值配對列表中的鍵值。請注意,mxGraph創(chuàng)建兩組默認(rèn)樣式,一個給節(jié)點,一個給連線。如果你看回helloworld這個例子,作為可選參數(shù),沒有任何樣式值傳入insertVertex或insertEdge。這種情況下,默認(rèn)的樣式會被使用。
設(shè)置圖元的樣式
如果你希望給一個圖元指定非默認(rèn)的樣式,你必須在創(chuàng)建時傳入(mxGraph的insertVertex和insertEdge都有 為這個用途的可選參數(shù)),或者對這個圖元用model.setStyle()設(shè)定樣式。
你傳入的樣式有樣式名,請注意,樣式名和鍵/值配對可以按照任何順序排列。下面是這個概念的示例,使用我們在helloworld中看到的對insertVertex的調(diào)用:
- 創(chuàng)建一個叫'ROUNDED'的樣式,并應(yīng)用到一個節(jié)點上:
var v1 = graph.insertVertex(parent, null, 'Hello', 20, 20, 80, 30, 'ROUNDED');
- 用ROUNDED樣式創(chuàng)建一個新節(jié)點,覆蓋筆畫樣式和填充顏色:
var v1 = graph.insertVertex(parent, null, 'Hello', 20, 20, 80, 30, 'ROUNDED;strokeColor=red;fillColor=green');
- 創(chuàng)建一個沒有全局樣式,但有本地筆畫樣式和填充顏色:
var v1 = graph.insertVertex(parent, null, 'Hello', 20, 20, 80, 30, ';strokeColor=red;fillColor=green');
- 用默認(rèn)defaultVertex樣式,但本地填充顏色的節(jié)點:
var v1 = graph.insertVertex(parent, null, 'Hello', 20, 20, 80, 30, 'defaultVertex;fillColor=blue');
請注意,這種情況下,默認(rèn)樣式必須顯式的指明,在分號起始的字符串之后,沒有指明樣式名這個圖元即會 缺失全局樣式。如果沒有分號,則默認(rèn)樣式會被使用。
同樣,mxGraph在核心API中提供了工具方法來訪問和修改圖元的樣式:
核心API方法:
mxGraph.setCellStyle(style, cells) – 封裝在開始/結(jié)束的更新中,指定一組圖元的樣式。
mxGraph.getCellStyle(cell) – 返回指定單元的樣式,融合了這種單元類型,任何本地的和默認(rèn)全局的樣式。
創(chuàng)建新的全局樣式
要創(chuàng)建上述ROUNDED全局樣式,你可以按照這個模板來創(chuàng)建一個樣式,并將其注冊到mxStyleSheet上:
var style = new Object();
style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
style[mxConstants.STYLE_OPACITY] = 50;
style[mxConstants.STYLE_FONTCOLOR]= '#774400';
graph.getStylesheet().putCellStyle('ROUNDED',style);
3.1.3.2 幾何
在helloworld例子中,我們看到在調(diào)用insertVertex方法時,傳入了節(jié)點的位置及大小信息。在JavaScript的坐標(biāo)系統(tǒng)中,x是向右為正,y是向下為正,而對圖形而言,是相對mxGraph放置的容器的絕對位置。
有專門獨立的mxGeometry而不是簡單地用mxRectangle保存這個信息的原因,是因為連線也有相應(yīng)的幾何信息。
對于連線而言,寬帶和高度的值被忽略,而x和y對應(yīng)的是連線的標(biāo)簽位置。另外,連線還有控制點的概念。它們是沿邊的中間點位置,畫線時需要經(jīng)過??刂泣c的使用有時也被稱為邊緣路由。

一條由兩個控制點決定的邊
在幾何里面還有兩個重要的概念,相對位置和偏移。
相對位置
默認(rèn)情況下,一個節(jié)點的x和y位置是圖元本身的邊界矩形的左上角點與父圖元的邊界矩形的左上角點的偏移量。父圖元和組的概念將在本章的后面進行討論,這里就不深入細節(jié),如果一個圖元沒有父圖元, 那么為了定位,圖形容器就是它的父圖元。

非相對的節(jié)點位置
對于一條連線,在默認(rèn)的非相對模式中,連線的標(biāo)簽位置是對圖形原點的絕對位置。

非相對連線的標(biāo)簽位置
對于相對模式中的節(jié)點,(x,y)是沿父圖元(寬度,高度)的圖元的原點所在的比例。(0,0)是與父圖元 相同的原點,(1,1)是原點放在父圖元的右下角。兩個方向上,相對位置向0和1以上延伸。這有助于子圖元保持 對父圖元整體大小的固定。

相對節(jié)點位置
最后,在相對模式下的連線的標(biāo)簽位置,是根據(jù)連線的中心來確定。連線的x坐標(biāo)是相對位置,-1是連線的源端, 1是邊的目標(biāo)端。連線的y坐標(biāo)是了連線的正交像素偏移量。下圖顯示了在相對模式下的各種連線標(biāo)簽的x,y的值。 請注意,對于一條直線,計算是非常簡單的。對于有多個控制點的連線,連線是沿要跟蹤段(段結(jié)束點和/或 控制點之間的界線)來找到正確的沿連線的距離。 y值是到該段的正交偏移量。
對于連線的標(biāo)簽,切換到使用相對位置,是一種常見的應(yīng)用程序的偏好。導(dǎo)航到mxGraph的mxGraph.insertEdge() 方法中,你會看到createEdge()這樣的調(diào)用。在createEdge()中,幾何上設(shè)置為相對位置,是使用這個創(chuàng)建每一條連線的。在mxGraph中輔助方法有一定數(shù)量,是因為他們能夠很容易改變默認(rèn)行為。你應(yīng)該在應(yīng)用程序中, 嘗試盡可能多地使用mxGraph類中API,享受這項福利。
偏移
在mxGeometry中,偏移量字段是應(yīng)用到圖元標(biāo)簽的絕對x,y偏移量。在連線標(biāo)簽的情況下,該偏移量總是施加在邊標(biāo)簽已根據(jù)上面部分相對標(biāo)志計算好之后。
核心API方法:
- mxGraph.resizeCell(cell, bounds) - 在開始/結(jié)束的更新調(diào)用之間,改變指定圖元的大小到指定的邊框。
- mxGraph.resizeCells(cells, bounds) - 在開始/結(jié)束的更新調(diào)用之間,改變指定隊列中所有圖元的大小到指定的邊框。
3.1.3.3 用戶對象
用戶對象給了mxGraph一個環(huán)境,可以把業(yè)務(wù)邏輯與可視圖元相關(guān)聯(lián)。在HelloWorld的例子里,用戶對象只是一個字符串,只是簡單地用來呈現(xiàn)單元的標(biāo)簽。在更加復(fù)雜的應(yīng)用里,用戶對象可以是一個復(fù)雜的對象。這個對象的一些屬性可以用來作為圖元的顯示使用,而對象的其余部分可以用來描述應(yīng)用領(lǐng)域的邏輯關(guān)系。
用一個簡單的工作流或過程應(yīng)用程序來做例子,假定我們有以下的圖形(這個例子已在線,在任務(wù)窗口選擇泳道Swimlanes的例子):

一個簡單工作流
通常情況下,該工作流程將存在于某些應(yīng)用服務(wù)器和/或數(shù)據(jù)庫上。瀏覽器端用戶連接到該服務(wù)器,或者一些前端服務(wù)器連接到應(yīng)用程序服務(wù)器和用戶的Web應(yīng)用程序請求“訂購”的工作流。網(wǎng)站服務(wù)器取得該工作流中的數(shù)據(jù)并將其發(fā)送到客戶端。
mxGraph支持服務(wù)器端填充模型、發(fā)送到客戶端,然后再返回的過程。請參閱后面的章節(jié)關(guān)于“I/O和服務(wù)器之間的通信”。
數(shù)據(jù)的發(fā)送在視覺模型(圖中)和以及業(yè)務(wù)邏輯(主要是包含在用戶對象)都會發(fā)生??蛻舳藢⑹紫蕊@示如上圖。如果用戶有權(quán)限編輯工作流程,他們通常會做兩件事情:1)編輯圖表,添加和刪除節(jié)點,以及改變的連接,2)編輯圖元的用戶對象(節(jié)點和/或連線)。
在在線演示中,如果右鍵點擊菱形“Check Inventory”并選擇屬性,你會看到如下對話框:

節(jié)點的屬性
這些屬性展示了幾何數(shù)據(jù),標(biāo)簽,ID等,但一個對話框可以很容易地圖元的用戶對象。這有可能是在工作流引擎某個過程的引用,關(guān)于怎樣檢查庫存清單。這可能是一個用于特定應(yīng)用程序的機制,在服務(wù)器和客戶端為遠程方法調(diào)用分配一些識別標(biāo)志。另一種類型的值可能是調(diào)用過程的返回對象,也許是一個布爾值或整數(shù)(在這種情況下,表示庫存水平)。由于這個返回類型,它有可能可以加強對圖形的約束,并提供視覺化的提示,如,出口連線的決定檢查不符合返回的節(jié)點類型。
接下來,作為一個示例,發(fā)出的連線的用戶對象可能包含一個標(biāo)簽和一個布爾狀態(tài)。同樣,基于mxGraph的編輯器可能會提供更改布爾值的方法。在服務(wù)器端,當(dāng)執(zhí)行到該步驟時,它可能會跟隨對應(yīng)的決策的節(jié)點返回的布爾值的連線。
請記住,上述示例是非常具體的領(lǐng)域的,它用來解釋如何將用戶對象映射到應(yīng)用程序的業(yè)務(wù)邏輯。它展現(xiàn)了mxGraph如何創(chuàng)建我們所謂的上下文圖。這上下文是由節(jié)點之間的連接和用戶對象存儲的業(yè)務(wù)邏輯構(gòu)成的。一個典型的應(yīng)用程序從服務(wù)器接收可視化部分和業(yè)務(wù)邏輯,可能允許編輯它們,接著發(fā)送到服務(wù)器去持久化和/或執(zhí)行。
3.1.3.4 圖元類型
如前所述,mxGraph是使用這個庫時的主要API,同樣圖元也是。在圖上沒有暴露圖元的一個是節(jié)點還是連線的基本狀態(tài),這個調(diào)用可以在圖元上或在模型上找到。
在mxCell上有兩個標(biāo)志量,節(jié)點和邊,在一個圖元創(chuàng)建時,輔助函數(shù)將設(shè)置其中一個值為true,isVertex(), isEdge() 在 mxGraphModel中用來檢測一個圖元的類型,所以這兩種類型沒有分離的對象。從技術(shù)上講,在運行時可以隨便改一個圖元的類型,但是要注意在改變類型后無效的圖元狀態(tài)。同時,要留心幾何對象方法的參數(shù)在節(jié)點和連線上是不同的。通常,不建議在運行時修改一個圖元的類型的。
3.1.4 組結(jié)構(gòu)
在mxGraph中,分組的概念就是邏輯上將一個圖元與另一個進行關(guān)聯(lián)。在許多的圖形開發(fā)庫中,這通常被成為子圖。在圖形模型的數(shù)據(jù)結(jié)構(gòu)中,分組就是把一個或更多的連線或節(jié)點變成一個父節(jié)點或連線的子圖元。分組使得mxGraph擁有了更多的有用的特性:
- 子圖 一個邏輯上獨立的圖形的概念,在較高的層次圖中顯示為每個子圖的圖元。
- 展開和折疊 折疊是這樣的一種能力,它使用父圖元在視覺上來替換一組子圖元。展開則是與其相反的邏輯。通過單擊在線工作流程示例中泳道示例的組單元格左上角的小“ - ”可以看到此行為。這會在下面的 復(fù)雜性管理 章節(jié)中進行講解。
- 分層 層次的概念是指在圖形的顯示中,讓圖元以特定的順序顯示。
- 下鉆,遞升 這兩個概念是讓子圖可以當(dāng)作完整的圖形一樣可視化和編輯。在 用戶對象 章節(jié)我們看到 “check inventory” (檢查庫存)節(jié)點作為一個簡單圖元。舉個例子來說,一個開發(fā)人員正在描述流程中每一個節(jié)點作為軟件流程中執(zhí)行的任務(wù)。應(yīng)用程序中可能會有一個選項去下鉆到檢查庫存的節(jié)點。這將導(dǎo)致一個新的圖形出現(xiàn),詳細地描述了檢查庫存的細節(jié)。圖中可能會有一個標(biāo)題為“檢查庫存”的節(jié)點用以表示它是一個子圖,以及一個選項去遞升回到上一個級別。
在分組中,圖元都分配了一個父圖元。最簡單的情況是,所有的圖元都有一個默認(rèn)的父圖元作為他們的父圖元。這個父圖元是一個不可見的圖元,有著和整張圖相同的界限。這個圖元在 helloworld 例子中可以通過 graph.getDefaultParent() 返回。一個節(jié)點的x,y位置是相對它的父節(jié)點的,因此在默認(rèn)分組的情況下(所有的圖元共享默認(rèn)父圖元),圖元的定位也是圖形組件上的絕對坐標(biāo)。在所有的圖元都被添加到默認(rèn)根圖元的情況下,該組的結(jié)構(gòu)邏輯上的模樣,在hello world例子中,看起來如下圖所示。
注意添加了0層圖元,這是在組結(jié)構(gòu)中的默認(rèn)間接方式允許根據(jù)附加圖元的要求進行圖層的更改。我們將它包含在下面以便正確性,但在稍后的組圖中它將被省略。

helloworld例子中的組結(jié)構(gòu)
同時,請注意連線標(biāo)簽的位置(幾何上的x,y)是相對其父圖元的。
如果我們回頭去看用戶對象章節(jié)的簡單工作流例子,能看到組看起來是什么樣的。在這個例子中組圖元表示人,并且子節(jié)點表示分配給這些人的任務(wù)。在這個例子中,邏輯組結(jié)構(gòu)如下所示:

工作流示例的邏輯組結(jié)構(gòu)
工作流程操作節(jié)點是黃色的子節(jié)點,泳道組節(jié)點被標(biāo)記為藍色。
插入圖元的到組結(jié)構(gòu)是通過使用mxGraph類的insertVertex和insertEdge的parent參數(shù)方法。這些函數(shù)相應(yīng)地將父圖元格設(shè)置在子圖元上,而且重點是,會通知父圖元新子圖元的加入。
通過mxGraph.groupCells()和mxGraph.ungroupCells()函數(shù)來更改組結(jié)構(gòu)。
核心API方法
- mxGraph.groupCells(group, border, cells) – 添加指定的圖元到指定的組,在一個begin/end更新結(jié)構(gòu)中。
- mxGraph.ungroupCells(cells) – 從指定圖元的父圖元中移除它們,并將其加入到它們的父圖元的父圖元中。任何空的組在這個操作后將被刪除。這個操作需要在一個begin/end更新結(jié)構(gòu)中
3.1.5 復(fù)雜度管理
任何時候控制顯示圖元的個數(shù)主要有兩個原因。首先是性能,繪制越來越多的圖元在任何平臺上都將會在某個時間點達到性能的瓶頸。第二個原因是易用性,一個人只能理解一定量的信息。上面列出的與組相關(guān)的所有概念,能夠用來為用戶降低屏幕上信息的復(fù)雜度。
3.1.5.1 可折疊
可折疊是我們用來描述組展開和折疊一個集合名詞。我們可以將令一個圖元內(nèi)的子圖元不可見稱為折疊。有許多與此特性相關(guān)的方法:
核心API方法
- mxGraph.foldCells(collapse, recurse, cells) – 在一個begin/end更新結(jié)構(gòu)中,指定圖元的折疊狀態(tài)。
可折疊相關(guān)方法:
mxGraph.isCellFoldable(cell, collapse) – 對于有子圖元的圖元而言,默認(rèn)為真。
mxGraph.isCellCollapsed(cell) – 返回圖元的折疊狀態(tài)
當(dāng)一個組圖元折疊時,默認(rèn)發(fā)生三件事:
- 圖元的子圖變?yōu)椴豢梢?/li>
- 組圖元的邊界被使用。在mxgeometry中有一個alternativebounds字段,并且在組圖元中,默認(rèn)地分別存儲了展開和折疊狀態(tài)的邊界。這些實例之間的切換由mxgraph.swapbounds()調(diào)用,實際上這些是foldcells()調(diào)用過程中為你處理的。這允許折疊組能夠被改變大小,同時當(dāng)再次展開看起來和折疊前的尺寸一樣。
- 默認(rèn)情況下會發(fā)生連線提升。連線提升意味著去展現(xiàn)這樣的連線,它們連著子圖元通過折疊組圖元,組圖元同樣連著外面的折疊組圖元,通過使得這些子圖元消失而轉(zhuǎn)去連接折疊的父圖元。

展開泳道

折疊泳道
以上兩張圖片展示了這三個概念。在擴展?fàn)顟B(tài)下,上面的組圖元在左上角顯示一個小框,里面有一個“ - ”字符。這表示單擊此框會折疊組圖元。點擊后我們將獲得下面的圖片,圖中組圖元使用著它的折疊尺寸。沒有離開子節(jié)點和邊的圖元都是不可見的。最后,離開組圖元的連線被提升,表現(xiàn)為連接到折疊的組圖元。點擊框中現(xiàn)在出現(xiàn)的“+”字符展開組圖元,并將其返回到上面的那個張圖的原始狀態(tài)。
通過調(diào)用mxGraph.foldCells()方法,你可以通過編程獲得與單擊展開/折疊符號相同的結(jié)果。一個常見的用法是這樣的,當(dāng)應(yīng)用縮放到指定的數(shù)值,圖元群被分組并且組圖元折疊(往往不帶“-”框,因為應(yīng)用程序在控制折疊)。通過這種方式,用戶可以看到更少,更大的圖元,邏輯上每一個圖元都代表其子圖元。接著你可以提供一種機制去放大一個組,以在該過程中擴展它。你也可以提供下鉆/遞升,接下來就解釋一下。
3.1.5.2 子圖, 下鉆 / 遞升
有時候,作為一種展開/折疊方案的另一個選擇,或者可能與其結(jié)合使用,你的圖會由一組圖組成,嵌套到層次結(jié)構(gòu)中,下面我們看一個簡單的例子:

一個頂級工作流的例子
這個簡單的流程由三個高級別的步驟組成。顯然,單個步驟包含許多子步驟,我們將查看 Solve Bug 圖元的子圖。
在 Solve Bug 節(jié)點下,我們創(chuàng)建了一些子節(jié)點來呈現(xiàn)解決一個問題的流程的細節(jié),在這種情況下,解決了在企業(yè)號星艦(Starship Enterprise)上的一個問題。
在這個用GraphEditor的例子里,在上圖顯示的選中的菜單選項調(diào)用了mxGraph.enterGroup(cell),這是子圖相關(guān)的一個核心的API。
核心API方法:
- mxGraph.enterGroup(cell) – 使指定的圖元成為顯示區(qū)域的根圖元。
- mxGraph.exitGroup() - 使當(dāng)前圖元的父圖元(如果有)成為新的根圖元。
- mxGraph.home() - 離開所有組,使默認(rèn)父圖元成根圖元
到目前為止,圖的根圖元已經(jīng)是所有第一級圖元的默認(rèn)父節(jié)點。使用這些函數(shù)你能夠?qū)⑷魏谓M結(jié)構(gòu)內(nèi)的組圖元變成根圖元,這樣父圖元的子圖元就可以作為完整的圖形顯示出來。

下鉆到Solve Bug節(jié)點的結(jié)果
同樣的圖形如采用折疊方式會看起來如下:

退出組用 shape->exit group 選項,它會調(diào)用mxGraph.exitGroup,帶你回到原始的三個節(jié)點的最高一級的圖。
3.1.5.3 分層和過濾
在mxGraph里, 像其它圖形化應(yīng)用一樣,它也有z順序的概念。也就是說,你看向屏幕的方向就是對象的順序。對象可以位于其他對象的后面或前方,如果它們重疊且不透明,則最后面的對象將部分或完全遮蓋。讓我們回顧一下上面的HelloWorld圖的圖形結(jié)構(gòu)。子圖元以確定的順序被存儲在父圖元下(默認(rèn)情況下,是你添加它們的順序)
如果我們移動HelloWorld例子中的圖元,我們將看到如下的結(jié)果:

-重疊的節(jié)點-
可以看到World節(jié)點位于hello節(jié)點的前面。這是因為World節(jié)點比Hello節(jié)點有一個更高的子順序,它們分別在根圖元的有序子圖元集合中的位置1和0位置上。
改變順序我們可以用mxGraph.orderCells方法。
核心API方法:
- mxGraph.orderCells(back, cells) – 在開始/結(jié)束的更新調(diào)用之間,根據(jù)標(biāo)志位,移動一組圖元到它們的兄弟圖元的前面或者后面。
mxGraph中的兄弟圖元是指任何擁有相同父圖元的圖元。因此,對Hello節(jié)點執(zhí)行此方法,會使其覆蓋World節(jié)點。
排序和分組可以擴展成邏輯分層組。圖元通過深度優(yōu)先搜索被繪制。再次采用helloworld示例,設(shè)想一下,hello和world節(jié)點下面都有一些同層的子圖元。Hello節(jié)點及其子圖元會比World節(jié)點或其子圖元先繪制。如果Hello節(jié)點和World子點是不可見組圖元,那么你就會有兩個圖元層次結(jié)構(gòu),一個完全在另一個之前繪制。你還可以通過簡單地切換不可見組圖元的順序來切換層次結(jié)構(gòu)的順序。
layers.html示例演示了分層的概念。這里按鈕用于設(shè)置組圖層圖元的可見性。這個例子非常接近過濾的概念。
篩選具有一些特定的屬性的圖元來顯示。提供過濾功能的一種方法是在渲染圖元之前檢查某個狀態(tài)。另一種方法,如果過濾條件簡單且事先已知,則按組分配可過濾單元。執(zhí)行這個過濾操作時,可以顯示或隱藏這些組。
注:如果哪個地方翻譯的不對的地方,請以官方文檔為準(zhǔn)!