流程圖控件GoJS教程:圖表布局
GoJS是一款功能強(qiáng)大,快速且輕量級(jí)的流程圖控件,可幫助你在JavaScript 和HTML5 Canvas程序中創(chuàng)建流程圖,且極大地簡(jiǎn)化您的JavaScript / Canvas 程序。
GoJS現(xiàn)已更新至最新版本2.1發(fā)布,修復(fù)了一些bug,增強(qiáng)用戶體驗(yàn),趕快下載試試吧~
圖表布局
一般而言,“布局”是確定對(duì)象集合大小和位置的一種方法。HTML的HTML元素具有自己的布局。在GoJS你已經(jīng)看到了面板布局的例子很多,如汽車(chē)或表,其大小和位置GraphObject一個(gè)內(nèi)小號(hào)面板。 GoJS還提供了Diagram布局,用于在Diagram或Group內(nèi)定位Node并路由Link。
自然,每個(gè)圖Layout的主要目的通常是通過(guò)調(diào)用Part.move來(lái)定位節(jié)點(diǎn)。但是,布局還可以通過(guò)在每個(gè)Link上設(shè)置屬性來(lái)導(dǎo)致自定義路由。例如,TreeLayout還通過(guò)根據(jù)TreeLayout.angle設(shè)置Link.fromSpot和Link.toSpot來(lái)確保按預(yù)期方向路由鏈接 。(但是,可以通過(guò)設(shè)置TreeLayout.setsPortSpot和TreeLayout.setsChildPortSpot來(lái)禁用該行為。對(duì)于其他一些布局也是如此。)
圖的布局可以通過(guò)幾種方式完成。手動(dòng)布局的出現(xiàn)是因?yàn)橛脩粢苿?dòng)了節(jié)點(diǎn),從而為這些節(jié)點(diǎn)建立了新的位置。這樣的布局可以以某種持久數(shù)據(jù)格式保存,然后使用數(shù)據(jù)綁定或代碼分配來(lái)加載。當(dāng)執(zhí)行某些代碼來(lái)設(shè)置零件位置或位置時(shí),就會(huì)發(fā)生程序化布局。自動(dòng)布局是由Layout類(lèi)或其子類(lèi)實(shí)現(xiàn)的程序化布局。
默認(rèn)布局
Diagram.layout的值默認(rèn)的實(shí)例布局。這種布局與所有其他布局子類(lèi)不同,因?yàn)樗鼉H設(shè)置尚未具有位置的節(jié)點(diǎn)的位置,即GraphObject.actualBounds的X或Y為NaN。它將保留位置已定義的所有節(jié)點(diǎn)不變,并忽略所有鏈接。
到目前為止,您看到的許多示例都未設(shè)置Diagram.layout,因此使用默認(rèn)布局。一些示例數(shù)據(jù)將Part.location或GraphObject.position綁定到數(shù)據(jù)屬性。這些示例基本上是使用手動(dòng)布局,但是節(jié)點(diǎn)位置來(lái)自節(jié)點(diǎn)數(shù)據(jù),而不是來(lái)自用戶的布置。
但是,許多示例僅允許Layout類(lèi)的標(biāo)準(zhǔn)行為將位置按節(jié)點(diǎn)在布局中可見(jiàn)的順序分配給節(jié)點(diǎn)。這些示例展示了自動(dòng)布局行為。
自動(dòng)版面
GoJS提供了幾種自動(dòng)布局,包括:
網(wǎng)格布局
樹(shù)形布局
ForceDirectedLayout
LayeredDigraphLayout
環(huán)形布局
這些布局中的每一個(gè)都有示例,展示了設(shè)置各種詳細(xì)布局屬性的效果:
GridLayout示例
TreeLayout示例
ForceDirectedLayout示例
LayeredDigraphLayout示例
CircularLayout示例
在介紹頁(yè)面和示例中,您將看到許多通過(guò)設(shè)置Diagram.layout屬性來(lái)利用自動(dòng)布局的示例。
布局用法
您可以在JavaScript語(yǔ)句中設(shè)置Diagram.layout:
diagram.layout = new go.ForceDirectedLayout();
或者,您可以使用GraphObject,make初始化該屬性:
var diagram = $(go.Diagram, "myDiagramDiv", { layout: $(go.TreeLayout, { angle: 90, nodeSpacing: 10, layerSpacing: 30 }) });
我們建議您盡可能使用GraphObject.make,因?yàn)闀?huì)對(duì)其屬性名稱(chēng)進(jìn)行錯(cuò)誤檢查。
網(wǎng)格布局
一個(gè)簡(jiǎn)單的布局,用于以類(lèi)似網(wǎng)格的形式放置節(jié)點(diǎn)。
樹(shù)布局
此布局將樹(shù)結(jié)構(gòu)圖的節(jié)點(diǎn)放置在層(行或列)中。
力導(dǎo)向布局
力導(dǎo)向布局將圖形視作是一個(gè)物理系統(tǒng),在其上以及它們之間作用有力。
分層的有向圖布局
這會(huì)將有向圖的節(jié)點(diǎn)排列成層(行或列)。
圓形布局
此布局將節(jié)點(diǎn)定位為圓形或橢圓形。
自定義布局
GoJS允許創(chuàng)建自定義布局。
布局無(wú)效
當(dāng)布局執(zhí)行完其節(jié)點(diǎn)的定位并可能路由了其鏈接時(shí),該布局被視為“有效”。但是,某些更改會(huì)導(dǎo)致布局變?yōu)椤盁o(wú)效”,從而使布局在不久的將來(lái)再次執(zhí)行。由于布局的計(jì)算量可能很大,因此,一旦布局無(wú)效,就不會(huì)立即執(zhí)行自動(dòng)布局。相反,它們通常在交易結(jié)束時(shí)執(zhí)行。
布局失效的最常見(jiàn)原因是:節(jié)點(diǎn)或鏈接已從布局負(fù)責(zé)的節(jié)點(diǎn)和鏈接的集合中添加或刪除,或者因?yàn)楣?jié)點(diǎn)或鏈接的可見(jiàn)性已更改,或者因?yàn)楣?jié)點(diǎn)的大小已更改。如果您不希望在發(fā)生這樣的更改時(shí)發(fā)生自動(dòng)布局,則將Layout.isOngoing設(shè)置為false 可能是最簡(jiǎn)單的。
另一種常見(jiàn)情況是,您已將Diagram.layout設(shè)置為某種布局,但您希望加載包含手動(dòng)定位或調(diào)整后的節(jié)點(diǎn)位置的圖(模型)。該綁定的Part.location到模型的數(shù)據(jù)是有效的,但是當(dāng)加載后立即進(jìn)行布局的位置都將丟失。通過(guò)將Layout.isInitial設(shè)置為false 可以避免這種情況 。在初始布局之后,除非您還將Layout.isOngoing設(shè)置為false ,否則通過(guò)添加或刪除或更改節(jié)點(diǎn)或鏈接的可見(jiàn)性或更改節(jié)點(diǎn)大小,布局可能仍然無(wú)效。當(dāng)Layout.isInitial和Layout.isOngoing都同時(shí)都是假的,你仍然可以明確地導(dǎo)致布局通過(guò)調(diào)用發(fā)生Layout.invalidateLayout或致電Diagram.layoutDiagram一個(gè)true說(shuō)法。
例如,在編輯器中,在Node.location上具有TwoWay綁定以保存手動(dòng)調(diào)整的節(jié)點(diǎn)位置是司空見(jiàn)慣的。這意味著保存的模型將為所有節(jié)點(diǎn)保存位置。但是,如果創(chuàng)建的所有節(jié)點(diǎn)數(shù)據(jù)對(duì)象都沒(méi)有真實(shí)位置的新模型,則希望在加載模型時(shí)首先執(zhí)行布局。您可以通過(guò)設(shè)置實(shí)現(xiàn)這一目標(biāo)Layout.isInitial為假(和可選Layout.isOngoing為false,如果這是你想要什么,當(dāng)用戶添加或刪除節(jié)點(diǎn)或鏈路),然后執(zhí)行一個(gè)“InitialLayoutCompleted” DiagramEvent偵聽(tīng)決定的布局是否需要。決定可能是查看添加到Model.modelData的標(biāo)志?;蛘?,您可以查看所有節(jié)點(diǎn)以確保其位置具有真實(shí)值:
$(go.Diagram, . . ., { . . ., layout: $(go.TreeLayout, { isInitial: false, isOngoing: false }, . . .), "InitialLayoutCompleted": function(e) { // if not all Nodes have real locations, force a layout to happen if (!e.diagram.nodes.all(function(n) { return n.location.isReal(); })) { e.diagram.layoutDiagram(true); } } })
但是,如果您不想更改特定的節(jié)點(diǎn)或鏈接以導(dǎo)致自動(dòng)布局,但又希望其他節(jié)點(diǎn)或鏈接無(wú)效,則可以將Part.layoutConditions屬性設(shè)置為部件 “布局...” 的組合符合您需求的標(biāo)志。最常見(jiàn)的是不希望為Part.LayoutNodeSized條件設(shè)置布局:
$(go.Node,.., { layoutConditions:go.Part.LayoutStandard&?go.Part.LayoutNodeSized}, .. )
保持不可見(jiàn)或位于Layer.isTemporary圖層中的零件也永遠(yuǎn)不會(huì)使任何布局無(wú)效。
最后,可以將Part.isLayoutPositioned設(shè)置為false,以使Layout完全忽略該P(yáng)art。但是您將必須確保Part確實(shí)具有真實(shí)的Part.location,因?yàn)闆](méi)有布局會(huì)為您設(shè)置它。沒(méi)有實(shí)際位置,該零件將在圖中的任何位置都不可見(jiàn)。此外,如果節(jié)點(diǎn)將isLayoutPositioned設(shè)置為false,則布局不僅會(huì)忽略該節(jié)點(diǎn),還會(huì)忽略與該節(jié)點(diǎn)連接的所有鏈接。因?yàn)楣?jié)點(diǎn)不會(huì)被布局移動(dòng),所以它可能與布局的節(jié)點(diǎn)和鏈接重疊。
====================================================