logo GoJS教程 2019 我也要发布文档

数据绑定(下)


GoJS是一款功能强大,快速且轻量级的流程图控件,可帮助你在JavaScript 和HTML5 Canvas程序中创建流程图,且极大地简化您的JavaScript / Canvas 程序。

GoJS现已更新至最新版本2.0.16发布,修复了一些bug,增强用户体验,赶快下载试试吧~

点击下载GoJS最新试用版

更改数据值

以上所有示例均取决于 创建部件并将部件Panel.data属性设置为引用相应的节点或链接数据时要评估的数据绑定。这些动作发生时自动图表用于在设定模型的数据创建图份Diagram.model。

但是,GoJS不知道何时修改了任意JavaScript对象的data属性。如果要更改模型中的某些数据对象并自动更新图表,则应执行的操作取决于所更改属性的性质。

对于大多数数据属性,模型不会对其进行特殊处理,但它们是数据绑定的,您只需调用Model.setDataProperty即可。在此示例中,我们修改节点数据对象上的“ highlight”值。此修改大约每秒发生两次。

 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();

流程图控件GoJS教程:数据绑定(下)

改变图结构

对于模型知道的数据属性,例如链接数据的“到”或“从”,必须调用适当的模型方法才能修改数据属性。直接修改数据属性而不调用适当的模型方法可能会导致不一致或不确定的行为。

对于节点数据,模型方法是 Model.setCategoryForNodeData, Model.setKeyForNodeData, GraphLinksModel.setGroupKeyForNodeData, TreeModel.setParentKeyForNodeData和 TreeModel.setParentLinkCategoryForNodeData。对于链接数据,模型方法为GraphLinksModel.setCategoryForLinkData, GraphLinksModel.setFromKeyForLinkData, GraphLinksModel.setFromPortIdForLinkData, GraphLinksModel.setToKeyForLinkData, GraphLinksModel.setToPortIdForLinkData和GraphLinksModel.setLabelKeysForLinkData。

本示例更改链接数据的“ to”属性,从而使链接连接到其他节点。

  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();

流程图控件GoJS教程:数据绑定(下)

绑定到GraphObject源

绑定源对象不必是图模型中保存的普通JavaScript数据对象。相反,源对象可以是同一Part中的一个命名GraphObject。source属性必须是该类的可设置属性。当属性设置为新值时,将评估绑定。

这种绑定的一种常见用法是当Part.isSelected时更改Part的外观。调用Binding.ofObject以使Binding使用其GraphObject.name是给定名称的对象。使用空字符串“”或不使用参数来引用整个Part本身。这是一种方便,因此您无需命名整个零件。“ ofObject”实际上表示“名为...的GraphObject的”,如存在字符串参数时由Panel.findObject找到的。

在下面的示例中,Shape.fill绑定到Part.isSelected属性。当选择或取消选择节点时,Part.isSelected属性将更改值,因此将对绑定进行评估。转换函数获取布尔值,并返回所需的笔刷颜色以用作形状的填充。此示例还关闭了选择装饰,因此,唯一的可视方法(即形状的填充颜色)是表明已选择节点的方法。

  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." }
  ];

8.png

注意:请勿声明绑定依赖项的循环-这将导致未定义的行为。 GraphObject绑定源还要求将Part绑定到数据(即Part.data必须为非null)。GraphObject上的属性必须是可设置的,因此它不适用于只读属性,例如那些返回计算值(例如Part.isTopLevel)或迭代器(例如Node.linksConnected)的属性。

绑定到共享的Model.modelData源

除了Panel.data或面板中的某些GraphObject之外,绑定源对象可能是第三种来源。也可以是JavaScript对象,它是共享的Model.modelData对象。这允许将节点或链接元素属性绑定到模型中将存在的共享属性,即使模型中不存在节点或链接也可以对其进行修改。

在下面的示例中,Shape.fill绑定到Model.modelData对象上的“ color”属性。单击按钮时,该changeColor函数modelData通过调用Model.setDataProperty修改对象。

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");
}

9.png

双向数据绑定

上面的所有绑定仅将值从源数据传输到目标属性。但是有时您希望能够将GraphObject的值传输回模型数据,以使模型数据与图保持最新。这可以通过使用TwoWay Binding来实现,该方法不仅可以将值从源传递到目标,还可以将目标对象中的值传递回源数据。

 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

单击按钮以移动节点。效果基本上就是用户拖动节点时发生的情况。在此示例中,在Node.location上的双向绑定将更新作为Node的Part.data的节点数据的“ loc”属性。

10.png

正如从源到目标时可以使用转换函数一样,可以为Binding.makeTwoWay提供从目标到源去转换函数。例如,在模型数据中以字符串而不是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)

但是,您不能在作为“键”属性的节点数据属性上具有TwoWay绑定。(默认为名称“键”,但实际上是Model.nodeKeyProperty的值。)该属性值在模型内的所有节点数据中必须始终是唯一的,并且模型可以识别。双向绑定可能会更改该值,从而导致许多问题。同样,Node.key属性是只读的,以防止意外更改键值。

双向绑定的原因

在可设置的属性上 使用双向绑定的基本原因是要确保对该属性的任何更改都将被复制到相应的模型数据中。通过确保模型是最新的,您只需保存模型即可轻松地“保存图”,而“加载图”只需将模型加载到内存中并设置Diagram.model即可。如果您仅在模型数据中保留JSON可序列化的数据,则可以使用Model.toJson和Model.fromJson方法在模型和文本表示之间进行转换。

大多数绑定不需要是TwoWay。 出于性能原因,除非您确实需要将更改传播回数据,否则不应将Binding设为TwoWay。大多数可设置的属性仅在初始化时设置,然后永不更改。

可设置属性仅在某些代码对其进行设置时才更改值。该代码可能在您作为应用程序一部分编写的代码中。或者它可能在命令或工具中。这是一个可能存在双向绑定的属性列表,因为预定义的命令或工具之一对其进行了修改:

  • Part.location,通过DraggingTool如果已启用

  • Link.points,通过LinkReshapingTool(如果已启用)

  • GraphObject.desiredSize,由ResizingTool启用(如果已启用)

  • GraphObject.angle,由RotatingTool启用(如果已启用)

  • TextBlock.text,如果已启用,则由TextEditingTool进行

  • Part.isSelected,通过许多工具和命令

  • Node.isTreeExpanded和Node.wasTreeExpanded,通过CommandHandler.collapseTree和CommandHandler.expandTree,由“TreeExpanderButton”之称

  • Group.isSubGraphExpanded和Group.wasSubGraphExpanded,通过CommandHandler.collapseSubGraph和CommandHandler.expandSubGraph,由“SubGraphExpanderButton”之称

如果修改属性的工具无法运行,或者修改属性的命令无法调用,则无需在属性上使用TwoWay绑定。除非编写代码来修改它们,否则您可能不需要任何其他属性的TwoWay绑定。即使这样,有时还是最好通过直接调用Model.setDataProperty来编写代码来修改模型数据,这取决于OneWay绑定来更新GraphObject属性。

如果源是GraphObject而不是模型数据,也可以使用TwoWay绑定。当您不希望将状态存储在模型中,但又想在同一零件中同步GraphObjects的属性时,则不需要这样做。 谨慎使用TwoWay绑定。

=====================================================

想要购买GoJS正版授权的朋友可以咨询慧都官方客服

更多精彩内容,欢迎关注下方的微信公众号,及时获取产品最新资讯▼▼▼

图片2.jpg