流程圖控件GoJS教程:數(shù)據(jù)綁定(下)
GoJS是一款功能強(qiáng)大,快速且輕量級(jí)的流程圖控件,可幫助你在JavaScript 和HTML5 Canvas程序中創(chuàng)建流程圖,且極大地簡(jiǎn)化您的JavaScript / Canvas 程序。
GoJS現(xiàn)已更新至最新版本2.0.16發(fā)布,修復(fù)了一些bug,增強(qiáng)用戶體驗(yàn),趕快下載試試吧~
更改數(shù)據(jù)值
以上所有示例均取決于 創(chuàng)建部件并將部件Panel.data屬性設(shè)置為引用相應(yīng)的節(jié)點(diǎn)或鏈接數(shù)據(jù)時(shí)要評(píng)估的數(shù)據(jù)綁定。這些動(dòng)作發(fā)生時(shí)自動(dòng)圖表用于在設(shè)定模型的數(shù)據(jù)創(chuàng)建圖份Diagram.model。
但是,GoJS不知道何時(shí)修改了任意JavaScript對(duì)象的data屬性。如果要更改模型中的某些數(shù)據(jù)對(duì)象并自動(dòng)更新圖表,則應(yīng)執(zhí)行的操作取決于所更改屬性的性質(zhì)。
對(duì)于大多數(shù)數(shù)據(jù)屬性,模型不會(huì)對(duì)其進(jìn)行特殊處理,但它們是數(shù)據(jù)綁定的,您只需調(diào)用Model.setDataProperty即可。在此示例中,我們修改節(jié)點(diǎn)數(shù)據(jù)對(duì)象上的“ highlight”值。此修改大約每秒發(fā)生兩次。
diagram.nodeTemplate = $(go.Node, "Auto", { locationSpot: go.Spot.Center }, $(go.Shape, "RoundedRectangle", { // default values if the data.highlight is undefined: fill: "yellow", stroke: "orange", strokeWidth: 2 }, new go.Binding("fill", "highlight", function(v) { return v ? "pink" : "lightblue"; }), new go.Binding("stroke", "highlight", function(v) { return v ? "red" : "blue"; }), new go.Binding("strokeWidth", "highlight", function(v) { return v ? 3 : 1; })), $(go.TextBlock, { margin: 5 }, new go.Binding("text", "key")) ); diagram.model.nodeDataArray = [ { key: "Alpha", highlight: false } // just one node, and no links ]; function flash() { // all model changes should happen in a transaction diagram.model.commit(function(m) { var data = m.nodeDataArray[0]; // get the first node data m.set(data, "highlight", !data.highlight); }, "flash"); } function loop() { setTimeout(function() { flash(); loop(); }, 500); } loop();
改變圖結(jié)構(gòu)
對(duì)于模型知道的數(shù)據(jù)屬性,例如鏈接數(shù)據(jù)的“到”或“從”,必須調(diào)用適當(dāng)?shù)哪P头椒ú拍苄薷臄?shù)據(jù)屬性。直接修改數(shù)據(jù)屬性而不調(diào)用適當(dāng)?shù)哪P头椒赡軙?huì)導(dǎo)致不一致或不確定的行為。
對(duì)于節(jié)點(diǎn)數(shù)據(jù),模型方法是 Model.setCategoryForNodeData, Model.setKeyForNodeData, GraphLinksModel.setGroupKeyForNodeData, TreeModel.setParentKeyForNodeData和 TreeModel.setParentLinkCategoryForNodeData。對(duì)于鏈接數(shù)據(jù),模型方法為GraphLinksModel.setCategoryForLinkData, GraphLinksModel.setFromKeyForLinkData, GraphLinksModel.setFromPortIdForLinkData, GraphLinksModel.setToKeyForLinkData, GraphLinksModel.setToPortIdForLinkData和GraphLinksModel.setLabelKeysForLinkData。
本示例更改鏈接數(shù)據(jù)的“ to”屬性,從而使鏈接連接到其他節(jié)點(diǎn)。
diagram.nodeTemplate = $(go.Node, "Auto", { locationSpot: go.Spot.Center }, $(go.Shape, "RoundedRectangle", { fill: "yellow", stroke: "orange", strokeWidth: 2 }), $(go.TextBlock, { margin: 5 }, new go.Binding("text", "key")) ); var nodeDataArray = [ { key: "Alpha" }, { key: "Beta" }, { key: "Gamma" } ]; var linkDataArray = [ { from: "Alpha", to: "Beta" } ]; diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray); function switchTo() { // all model changes should happen in a transaction diagram.model.commit(function(m) { var data = m.linkDataArray[0]; // get the first link data if (m.getToKeyForLinkData(data) === "Beta") m.setToKeyForLinkData(data, "Gamma"); else m.setToKeyForLinkData(data, "Beta"); }, "reconnect link"); } function loop() { setTimeout(function() { switchTo(); loop(); }, 1000); } loop();
綁定到GraphObject源
綁定源對(duì)象不必是圖模型中保存的普通JavaScript數(shù)據(jù)對(duì)象。相反,源對(duì)象可以是同一Part中的一個(gè)命名GraphObject。source屬性必須是該類的可設(shè)置屬性。當(dāng)屬性設(shè)置為新值時(shí),將評(píng)估綁定。
這種綁定的一種常見用法是當(dāng)Part.isSelected時(shí)更改Part的外觀。調(diào)用Binding.ofObject以使Binding使用其GraphObject.name是給定名稱的對(duì)象。使用空字符串“”或不使用參數(shù)來(lái)引用整個(gè)Part本身。這是一種方便,因此您無(wú)需命名整個(gè)零件?!?ofObject”實(shí)際上表示“名為...的GraphObject的”,如存在字符串參數(shù)時(shí)由Panel.findObject找到的。
在下面的示例中,Shape.fill綁定到Part.isSelected屬性。當(dāng)選擇或取消選擇節(jié)點(diǎn)時(shí),Part.isSelected屬性將更改值,因此將對(duì)綁定進(jìn)行評(píng)估。轉(zhuǎn)換函數(shù)獲取布爾值,并返回所需的筆刷顏色以用作形狀的填充。此示例還關(guān)閉了選擇裝飾,因此,唯一的可視方法(即形狀的填充顏色)是表明已選擇節(jié)點(diǎn)的方法。
diagram.nodeTemplate = $(go.Node, "Auto", { selectionAdorned: false }, // no blue selection handle! $(go.Shape, "RoundedRectangle", // bind Shape.fill to Node.isSelected converted to a color new go.Binding("fill", "isSelected", function(sel) { return sel ? "dodgerblue" : "lightgray"; }).ofObject()), // no name means bind to the whole Part $(go.TextBlock, { margin: 5 }, new go.Binding("text", "descr")) ); diagram.model.nodeDataArray = [ { descr: "Select me!" }, { descr: "I turn blue when selected." } ];
注意:請(qǐng)勿聲明綁定依賴項(xiàng)的循環(huán)-這將導(dǎo)致未定義的行為。 GraphObject綁定源還要求將Part綁定到數(shù)據(jù)(即Part.data必須為非null)。GraphObject上的屬性必須是可設(shè)置的,因此它不適用于只讀屬性,例如那些返回計(jì)算值(例如Part.isTopLevel)或迭代器(例如Node.linksConnected)的屬性。
綁定到共享的Model.modelData源
除了Panel.data或面板中的某些GraphObject之外,綁定源對(duì)象可能是第三種來(lái)源。也可以是JavaScript對(duì)象,它是共享的Model.modelData對(duì)象。這允許將節(jié)點(diǎn)或鏈接元素屬性綁定到模型中將存在的共享屬性,即使模型中不存在節(jié)點(diǎn)或鏈接也可以對(duì)其進(jìn)行修改。
在下面的示例中,Shape.fill綁定到Model.modelData對(duì)象上的“ color”屬性。單擊按鈕時(shí),該changeColor函數(shù)modelData通過調(diào)用Model.setDataProperty修改對(duì)象。
diagram.nodeTemplate = $(go.Node, "Auto", $(go.Shape, "RoundedRectangle", { fill: "white" }, // the default value if there is no modelData.color property new go.Binding("fill", "color").ofModel()), // meaning a property of Model.modelData $(go.TextBlock, { margin: 5 }, new go.Binding("text")) ); // start all nodes yellow diagram.model.modelData.color = "yellow"; diagram.model.nodeDataArray = [ { text: "Alpha" }, { text: "Beta" } ]; diagram.undoManager.isEnabled = true; changeColor = function() { // define a function named "changeColor" callable by button.onclick diagram.model.commit(function(m) { // alternate between lightblue and lightgreen colors var oldcolor = m.modelData.color; var newcolor = (oldcolor === "lightblue" ? "lightgreen" : "lightblue"); m.set(m.modelData, "color", newcolor); }, "changed shared color"); }
雙向數(shù)據(jù)綁定
上面的所有綁定僅將值從源數(shù)據(jù)傳輸?shù)侥繕?biāo)屬性。但是有時(shí)您希望能夠?qū)raphObject的值傳輸回模型數(shù)據(jù),以使模型數(shù)據(jù)與圖保持最新。這可以通過使用TwoWay Binding來(lái)實(shí)現(xiàn),該方法不僅可以將值從源傳遞到目標(biāo),還可以將目標(biāo)對(duì)象中的值傳遞回源數(shù)據(jù)。
diagram.nodeTemplate = $(go.Node, "Auto", { locationSpot: go.Spot.Center }, new go.Binding("location", "loc").makeTwoWay(), // TwoWay Binding $(go.Shape, "RoundedRectangle", { fill: "lightblue", stroke: "blue", strokeWidth: 2 }), $(go.TextBlock, { margin: 5 }, new go.Binding("text", "key")) ); var nodeDataArray = [ { key: "Alpha", loc: new go.Point(0, 0) } ]; diagram.model = new go.GraphLinksModel(nodeDataArray); shiftNode = (function() { // define a function named "shiftNode" callable by button.onclick // all model changes should happen in a transaction diagram.commit(function(d) { var data = d.model.nodeDataArray[0]; // get the first node data var node = d.findNodeForData(data); // find the corresponding Node var p = node.location.copy(); // make a copy of the location, a Point p.x += 10; if (p.x > 200) p.x = 0; // changing the Node.location also changes the data.loc property due to TwoWay binding node.location = p; // show the updated location held by the "loc" property of the node data document.getElementById("bindTwoWayData").textContent = data.loc.toString(); }, "shift node"); }); shiftNode(); // initialize everything
單擊按鈕以移動(dòng)節(jié)點(diǎn)。效果基本上就是用戶拖動(dòng)節(jié)點(diǎn)時(shí)發(fā)生的情況。在此示例中,在Node.location上的雙向綁定將更新作為Node的Part.data的節(jié)點(diǎn)數(shù)據(jù)的“ loc”屬性。
正如從源到目標(biāo)時(shí)可以使用轉(zhuǎn)換函數(shù)一樣,可以為Binding.makeTwoWay提供從目標(biāo)到源去轉(zhuǎn)換函數(shù)。例如,在模型數(shù)據(jù)中以字符串而不是Point表示位置:
// storage representation of Points/Sizes/Rects/Margins/Spots is as strings, not objects:new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify)
但是,您不能在作為“鍵”屬性的節(jié)點(diǎn)數(shù)據(jù)屬性上具有TwoWay綁定。(默認(rèn)為名稱“鍵”,但實(shí)際上是Model.nodeKeyProperty的值。)該屬性值在模型內(nèi)的所有節(jié)點(diǎn)數(shù)據(jù)中必須始終是唯一的,并且模型可以識(shí)別。雙向綁定可能會(huì)更改該值,從而導(dǎo)致許多問題。同樣,Node.key屬性是只讀的,以防止意外更改鍵值。
雙向綁定的原因
在可設(shè)置的屬性上 使用雙向綁定的基本原因是要確保對(duì)該屬性的任何更改都將被復(fù)制到相應(yīng)的模型數(shù)據(jù)中。通過確保模型是最新的,您只需保存模型即可輕松地“保存圖”,而“加載圖”只需將模型加載到內(nèi)存中并設(shè)置Diagram.model即可。如果您僅在模型數(shù)據(jù)中保留JSON可序列化的數(shù)據(jù),則可以使用Model.toJson和Model.fromJson方法在模型和文本表示之間進(jìn)行轉(zhuǎn)換。
大多數(shù)綁定不需要是TwoWay。 出于性能原因,除非您確實(shí)需要將更改傳播回?cái)?shù)據(jù),否則不應(yīng)將Binding設(shè)為TwoWay。大多數(shù)可設(shè)置的屬性僅在初始化時(shí)設(shè)置,然后永不更改。
可設(shè)置屬性僅在某些代碼對(duì)其進(jìn)行設(shè)置時(shí)才更改值。該代碼可能在您作為應(yīng)用程序一部分編寫的代碼中?;蛘咚赡茉诿罨蚬ぞ咧小_@是一個(gè)可能存在雙向綁定的屬性列表,因?yàn)轭A(yù)定義的命令或工具之一對(duì)其進(jìn)行了修改:
Part.location,通過DraggingTool如果已啟用
Link.points,通過LinkReshapingTool(如果已啟用)
GraphObject.desiredSize,由ResizingTool啟用(如果已啟用)
GraphObject.angle,由RotatingTool啟用(如果已啟用)
TextBlock.text,如果已啟用,則由TextEditingTool進(jìn)行
Part.isSelected,通過許多工具和命令
Node.isTreeExpanded和Node.wasTreeExpanded,通過CommandHandler.collapseTree和CommandHandler.expandTree,由“TreeExpanderButton”之稱
Group.isSubGraphExpanded和Group.wasSubGraphExpanded,通過CommandHandler.collapseSubGraph和CommandHandler.expandSubGraph,由“SubGraphExpanderButton”之稱
如果修改屬性的工具無(wú)法運(yùn)行,或者修改屬性的命令無(wú)法調(diào)用,則無(wú)需在屬性上使用TwoWay綁定。除非編寫代碼來(lái)修改它們,否則您可能不需要任何其他屬性的TwoWay綁定。即使這樣,有時(shí)還是最好通過直接調(diào)用Model.setDataProperty來(lái)編寫代碼來(lái)修改模型數(shù)據(jù),這取決于OneWay綁定來(lái)更新GraphObject屬性。
如果源是GraphObject而不是模型數(shù)據(jù),也可以使用TwoWay綁定。當(dāng)您不希望將狀態(tài)存儲(chǔ)在模型中,但又想在同一零件中同步GraphObjects的屬性時(shí),則不需要這樣做。 謹(jǐn)慎使用TwoWay綁定。
=====================================================
想要購(gòu)買GoJS正版授權(quán)的朋友可以咨詢慧都官方客服。
更多精彩內(nèi)容,歡迎關(guān)注下方的微信公眾號(hào),及時(shí)獲取產(chǎn)品最新資訊▼▼▼