[译] Using Models and Templates

全篇共 4365 字。按500字/分钟阅读速度,阅读完预计需要 8.7 分钟。

您可以以编程方式构建节点和链接图。但是GoJS提供了一种以更具声明性的方式构建图的方法。您仅需要提供图表和自动复制到图中的零件实例(即模板)所需的节点和链接数据(即模型)。这些模板可以通过节点和链接数据的属性进行参数化。

一般方法构建图表

让我们尝试构建两个节点,并通过链接将其连接。这是一种实现方法:

var node1 =
  $(go.Node, "Auto",
    $(go.Shape,
      { figure: "RoundedRectangle",
        fill: "lightblue" }),
    $(go.TextBlock,
      { text: "Alpha",
        margin: 5 })
  )
diagram.add(node1);

var node2 =
  $(go.Node, "Auto",
    $(go.Shape,
      { figure: "RoundedRectangle",
        fill: "pink" }),
    $(go.TextBlock,
      { text: "Beta",
        margin: 5 })
  );
diagram.add(node2);

diagram.add(
  $(go.Link,
    { fromNode: node1, toNode: node2 },
    $(go.Shape)
  ));

这将产生一个很好的简单图表。如果拖动节点之一,则将看到链接保持连接。

尽管这种构建图表的方法行得通,但在创建大型图表时无法很好地扩展。通常,您将需要数量可变的节点,每个节点与其他节点非常相似。最好共享节点的结构,但要在一些应该改变值的地方进行参数化。

一种可能的方法是将代码中的一个节点构建为一个函数,该函数返回一个完全构建的节点,包括其可视树中的所有面板和其他GraphObject。您可能需要对函数进行参数化,以提供所需的字符串,颜色,图形和图像URL。但是,这种方法是非常特殊的:系统很难知道如何自动调用这些函数以按需创建新节点或新链接。此外,随着应用程序数据动态变化,您将如何使用这些功能来更新现有节点和链接中现有对象的属性,而又不会低效地重新创建所有内容?而且,如果您希望任何事情/一切随着应用程序数据的更改而自动更新,系统将如何知道该怎么做?

这种建立图表的代码也比管理节点的引用要麻烦得多,以便您可以将它们链接起来。这类似于先前的问题,即在必须使用临时命名变量并在需要时引用它们的代码中构建节点的可视树时。

我们正在寻找的是将所有节点的外观,定义和构造与描述每个特定节点的独特方面所需的应用程序数据分开。即将节点数据与节点外观分离。

模型和模版

实现节点外观与节点数据分离的一种方法是使用数据模型和节点模板。模型基本上只是一个数据集合,其中包含每个节点和每个链接的基本信息。模板基本上只是一个可以复制的部分。您将具有用于节点和链接的不同模板。

实际上,图已经具有非常简单的节点和链接默认模板。如果要自定义图中节点的外观,可以通过设置Diagram.nodeTemplate来替换默认节点模板。

要自动使用模板,请为该图表提供一个模型,其中包含每个节点的数据和每个链接的数据。GraphLinksModel将节点数据和链接数据的集合(实际上是数组)保存为GraphLinksModel.nodeDataArray和GraphLinksModel.linkDataArray的值。然后,设置Diagram.model属性,以便该图可以为所有节点数据创建节点,并为所有链接数据创建链接。

模型解释并维护数据之间的引用。每个节点数据应具有唯一的键值,以便可以可靠地解析对节点数据的引用。模型还管理动态添加和删除数据。

模型中的节点数据和链接数据可以是任何JavaScript对象。您可以决定这些对象具有哪些属性——根据需要添加任意数量的应用程序。由于这是JavaScript,因此您甚至可以动态添加属性。GoJS模型假定数据上存在几个属性,例如“key”(在节点数据上)和“category”,“from”和“to”(后两个在链接数据上)。但是,可以通过设置名称以“…Property”结尾的模型属性来告诉模型使用不同的属性名称。

节点数据对象通常在“key”属性中具有其节点的唯一键值。当前,节点数据keys必须是字符串或数字。您可以通过Node.key属性或someNode.data.key获取节点的密钥。

让我们创建一个提供最少数量必要信息的图表。特定的节点数据已放入JavaScript对象数组中。我们在链接数据对象的单独数组中声明链接关系。每个链接数据都使用它们的键来保存对节点数据的引用。通常,引用是“from”和“to”属性的值。

var nodeDataArray = [
  { key: "Alpha"},
  { key: "Beta" }
];
var linkDataArray = [
  { from: "Alpha", to: "Beta" }
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

这会产生两个节点和一个链接,但是这些节点并没有按照我们想要的方式出现。因此,我们将节点模板定义为对上面所做的特定节点构造的概括。

diagram.nodeTemplate =  // 提供自定义节点外观
  $(go.Node, "Auto",
    $(go.Shape,
      { figure: "RoundedRectangle",
        fill: "white" }),
    $(go.TextBlock,
      { text: "hello!",
        margin: 5 })
  );

var nodeDataArray = [
  { key: "Alpha" },
  { key: "Beta" }
];
var linkDataArray = [
  { from: "Alpha", to: "Beta" }
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

现在,该图看起来更好,但是尚未对节点进行参数化-它们都是相同的!我们可以通过使用数据绑定来实现该参数化。

数据绑定参数化节点

数据绑定是一种声明性声明,其中应使用一个对象的属性值来设置另一个对象的属性值。

在这种情况下,我们要确保TextBlock.text属性获取相应节点数据的“key”值。并且我们要确保Shape.fill属性设置为相应节点数据的“color”属性值所给定的颜色/画笔。

我们可以通过创建Binding对象并将其与目标GraphObject关联来声明此类数据绑定。您可以通过编程方式通过调用GraphObject.bind来执行此操作。但是,当使用go.GraphObject.make时,在传递Binding时会自动发生。

diagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape,
      { figure: "RoundedRectangle",
        fill: "white" },  // default Shape.fill value
      new go.Binding("fill", "color")),  // binding to get fill from nodedata.color
    $(go.TextBlock,
      { margin: 5 },
      new go.Binding("text", "key"))  // binding to get TextBlock.text from nodedata.key
  );

var nodeDataArray = [
  { key: "Alpha", color: "lightblue" },  // note extra property for each node data: color
  { key: "Beta", color: "pink" }
];
var linkDataArray = [
  { from: "Alpha", to: "Beta" }
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

现在,我们得到了与以前相同的图表结果,但是它以更通用的方式实现。您可以轻松添加更多节点并链接数据以构建更大的图。而且,您可以轻松更改所有节点的外观,而无需修改数据。

实际上,您可能会注意到链接是不同的:它有一个箭头。当我们第一次使用代码构建此图表时,没有箭头。但是默认的Diagram.linkTemplate包含一个箭头,在此示例中,我们没有用自定义模板替换链接模板。

请注意,上面模板中的Shape.fill值获得了两次值。首先,将其设置为“白色”。然后,绑定将其设置为节点数据的“颜色”属性具有的任何值。如果节点数据不具有“ color”属性或在获取该值时出错,则能够指定保留的初始值可能会很有用。

在这一点上,我们还可以更加精确地了解模板是什么。模板是一个零件,它可能具有一些数据绑定,并且它本身并不是图中的一部分,但可以复制以创建添加到图中的零件。

模版定义

在Extensions目录的Templates.js中提供了所有预定义模板的实现。创建自己的模板时,您可能希望复制和修改这些定义。

这些定义可能不是GoJS中实际标准模板实现的最新描述。

模型种类

模型是一种将数据对象的集合解释为具有各种关系的抽象图的关系,该关系由数据属性和模型做出的假设决定。最简单的模型Model只能容纳“零件”,它们之间没有任何关系——没有链接或组。但是该模型类充当其他类型模型的基类。

GraphLinksModel

您在上面看到的那种模型GraphLinksModel实际上是最通用的一种。它为每个链接使用单独的链接数据对象来支持链接关系。链接可以连接的节点没有固有的限制,因此允许自反和重复链接。链接也可能导致图中的循环。但是,您可以通过设置各种属性(例如Diagram.validCycle)来阻止用户绘制此类链接。而且,如果您希望链接看起来像是通过链接而不是节点进行连接,则可以通过使属于链接并沿着链接路径排列的特殊节点(称为“标签节点”)成为可能。在链接上排列与文本标签相同的方式。

译者 » 陈帅华
发布日期 » 2020年6月16日 周二
更新日期 » 2020年7月1日 周三
上一篇 » [译] Building Parts with GraphObjects
下一篇 » 我读《你当像鸟飞往你的山》
:)记录此刻想法
请选择登录方式,开始记录你的想法。
授权微博登录
授权Github登录