AUBREY

SOMETIMES LOVE JUST AIN'T ENOUGH

GoJS 官方教程之:Validation(验证)(1)

英文官网链接:https://gojs.net/latest/intro/subgraphs.html

注:翻译仅供参考~ 所有“显示结果”都是截图,不可交互,要看交互效果请点击上面的官网链接

验证(Validation)


有些操作需要比前一节中讨论的二进制许可标志更复杂的控制。当用户试图绘制一条新的连线,或者重新连接一条已经存在的连线时,你的应用程序也许需要根据数据限制哪些连线可以被绘制。当用户试图为一个group增加一个node时,你的应用程序可能需要控制这个行为在该特定的的group里的特定node中是否被允许。当用户编辑某些文本时,你的应用程序可能会需要限制输入的字符类型。


尽管不完全是“验证”,你仍然可以通过设置Part的某些属性以及自定义DraggingTool来限制用户如何拖拽(移动或者复制)part。


Linking Validation(连线验证)


GraphObject对象有一些属性可以让你控制用户可以绘制或者重新绘制什么样的连线。这些属性适用于每一个端口元素并且影响了可能会与该端口连接的连线。


Linkable properties(可连接性属性)


最主要的属性是GraphObject.fromLinkableGraphObject.toLinkable。如果你没有一个fromLinkable属性为true的Node和另一个toLinkable为true的节点,那用户就不能在这两个节点间绘制一条新的连线。

diagram.nodeTemplate =
    $(go.Node, "Auto",      
    new go.Binding("location", "loc", go.Point.parse),
      $(go.Shape, "Ellipse",
        { fill: "green", portId: "", cursor: "pointer" },        
        new go.Binding("fromLinkable", "from"),        
        new go.Binding("toLinkable", "to")),
      $(go.TextBlock,
        { stroke: "white", margin: 3 },        
        new go.Binding("text", "key"))
    );  
  var nodeDataArray = [
    { key: "From1", loc: "0 0", from: true },
    { key: "From2", loc: "0 100", from: true },
    { key: "To1", loc: "150 0", to: true },
    { key: "To2", loc: "150 100", to: true }
  ];  
  var linkDataArray = [    
     
    // 最开始是没有连线的
  ];
  diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

image.png

鼠标移至绿色的椭圆上(当光标变为“手型”时)按下鼠标左键,然后拖动绘制一条新的连线。请注意,唯一允许的连线是从那些“From”的节点到“to”的节点连线。即便你从一个“to”节点出发拖拽绘制新连线,连线的方向也是正确的,会从“from”节点出发至“to”节点。


可连线属性的跨度(Span of Linkable properties)

由于上面的示例中的TextBlock(文本块)并没有被声明为一个端口(因为没有给文本块设置GraphObject.portId值),因此文本块上的鼠标事件并不会启动LinkingTool,只允许用户选择和移动节点以及任意数量的其他操作。


当然,你也可以声明一个Panel的GraphObject.fromLinkable或者GraphObject.toLinkable属性为true。这会使该panel内部的所有元素都表现得像一个端口的一部分,包括开始一个连线操作。有时候你会想要整个Node是可连线的。如果你仍然需要用户能够选择并且拖拽节点,你就需要在节点内部创建一些很容易被点击的但是不可连线的元素。你可以通过明确地设置GraphObject.fromLinkable 与/或 GraphObject.toLinkable属性为false来实现。这两个属性的默认值是null,意味着可连接性从包含该节点的panel中继承。


其他连线权限相关属性(Other linking permission properties)


仅仅因为你为某些端口对象设置了GraphObject.fromLinkableGraphObject.toLinkable属性为true并不意味着你想允许用户在每个这样的端口/节点与其余的端口/节点间创建连线。还有一些其他的GraphObject属性可以控制“from”出发点和“to”结束点的可连接性。


多重连线属性(LinkableDuplicates properties)


你之前应该已经注意到了一个限制,就是在同一对节点之间,同一个方向上,用户不能绘制第二条连线。下面的示例中把GraphObject.fromLinkableDuplicates或者GraphObject.toLinkableDuplicates设为了true,这样就允许在节点间绘制多重连线了。

diagram.nodeTemplate =
    $(go.Node, "Auto",      new go.Binding("location", "loc", go.Point.parse),
      $(go.Shape, "Ellipse",
        { fill: "green", portId: "", cursor: "pointer",
          //允许双重连线
          fromLinkableDuplicates: true, toLinkableDuplicates: true },        
          new go.Binding("fromLinkable", "from"),        
          new go.Binding("toLinkable", "to")),
      $(go.TextBlock,
        { stroke: "white", margin: 3 },        
        new go.Binding("text", "key"))
    );  
    
  var nodeDataArray = [
    { key: "From1", loc: "0 0", from: true },
    { key: "From2", loc: "0 100", from: true },
    { key: "To1", loc: "150 0", to: true },
    { key: "To2", loc: "150 100", to: true }
  ];  
  
  var linkDataArray = [    
    // 最开始是没有连线的
  ];
  diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

image.png image.png image.png

现在你可以试着在“From1”与“To1”之前绘制两条连线了。你会看到两条连线会自动分离。再试着拖拽连线两端的其中一个节点,你可以看到连线的路线也会自动变化。另外,你会发现,3、4、5……条连线也被支持。当连线的Link.curveLink.Bezier时,也会有类似的表现。


连接节点本身属性(LinkableSelfNode properties)


另一个标准的限制是,用户不能绘制一条从节点出发又连接了节点本身的连线。要移除这个限制也很简单:只需要把GraphObject.fromLinkableSelfNodeGraphObject.toLinkableSelfNode属性设置为true。请注意,前提是节点的这两个属性必须为true:GraphObject.fromLinkableGraphObject.toLinkable

diagram.nodeTemplate =
    $(go.Node, "Auto",      new go.Binding("location", "loc", go.Point.parse),
      $(go.Shape, "Ellipse",
        { fill: "green", portId: "", cursor: "pointer",
          fromLinkable: true, toLinkable: true,
          fromLinkableDuplicates: true, toLinkableDuplicates: true,
          //允许连线节点本身
          fromLinkableSelfNode: true, toLinkableSelfNode: true }),
      $(go.TextBlock,
        { stroke: "white", margin: 3 },        
        new go.Binding("text", "key"))
    );  
  
  var nodeDataArray = [
    { key: "Node1", loc: "0 0" },
    { key: "Node2", loc: "150 50" }
  ];  
  
  var linkDataArray = [    
    // 最开始是没有连线的
  ];
  diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

image.png image.png image.png

要绘制这样一条连接节点本身的反身连线,方法是:开始拖动鼠标绘制连线后,在靠近节点本身的地方放开鼠标。这个示例同时也设置了“多重连线”属性为true,所以你可以绘制多条反身连线。


在上面这些实例中,每个节点只有一个端口。当节点有多个端口时,这些限制实际上是应用于每个端口的,而不是每个节点。但是“LinkableSelfNode”属性的限制确实跨越了整个节点,因此它们必须被应用到节点的两个端口上,以便节点可以连接节点本身。


最多连线数属性(MaxLinks properties)


最后一个连线限制属性控制了一个节点/端口最多能几条连线连接。下面的示例将GraphObject.toMaxLinks属性设置为2,尽管GraphObject.toLinkableDuplicates属性的值为true,但是仍然限制了节点能够连接的连线的数量。

diagram.nodeTemplate =
    $(go.Node, "Auto",      
    new go.Binding("location", "loc", go.Point.parse),
      $(go.Shape, "Ellipse",
        { fill: "green", portId: "", cursor: "pointer",
          fromLinkableDuplicates: true, toLinkableDuplicates: true,
          toMaxLinks: 2 },  // 这个节点最多可以有两条连线
        new go.Binding("fromLinkable", "from"),        
        new go.Binding("toLinkable", "to")),
      $(go.TextBlock,
        { stroke: "white", margin: 3 },        
        new go.Binding("text", "key"))
    );  
    
  var nodeDataArray = [
    { key: "From1", loc: "0 0", from: true },
    { key: "From2", loc: "0 100", from: true },
    { key: "To1", loc: "150 0", to: true },
    { key: "To2", loc: "150 100", to: true }
  ];  
  var linkDataArray = [    
    // 最开始是没有连线的
  ];
  diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

image.png image.png

这个示例中没有对出发节点的连线数量做限制。


如果这个属性被设置,它通常被设置为1。当然,这取决于应用程序的性质。


注意,GraphObject.toMaxLinksGraphObject.fromMaxLinks是相互独立的。如果你想控制一个端口的最大连线总数,你需要同时设置这两个属性,而不是其中一个,然后你不能使用这两个属性,而应该设定你自己的连线验证判断,关于这点,下面会讨论。


循环图表(Cycles in graphs)


如果你想要确保你的用户创建的图形结构永远不会有任何的循环连线,或者图形总是树形结构的,GoJS可以简单地实现这个功能。只需要把Diagram.validCycle设置为Diagram.CycleNotDirected或者Diagram.CycleDestinationTree。默认值是Diagram.CycleAll,没有加任何限制——所有类型的循环连线都被允许。


下面的示例中的所有节点都是允许连线和被连线的。然而,由于配置了Diagram.validCycle,就会阻止用户连接一个节点两次,并且确保了用户无法绘制出循环连线。比如,下面的第二张图的Node5无法与Node1连接成一个循环连线。

image.png image.png

当你绘制更多的连线时,你可以看到潜在的连线目的地的集合是如何变得越来越小的。


一般连线验证(General linking validation)


可能会存在这种情况:你的应用程序的语义会导致用一种只能使用代码才能实现的方式:一个判断函数,使有效的连线目的地的集合是基于节点数据的(比如,在连接开始的节点和端口上,在可能的目的地节点/端口上)。(这里翻译得不准确,不知道说了啥~


通过设置LinkingBaseTool.linkValidationNode.linkValidation你可以实现这样一个特定领域的验证功能。这些判断,如果提供了,就会被连线工具考虑的每一对端口调用。如果判断返回false,连线就不会被绘制。设置LinkingToolRelinkingTool的这些属性会使判断被应用到所有的连线操作中,但是设置Node的这些属性只会使判断在关于这个节点的连线操作中被应用。只有当所有的标准连线验证通过时,这些判断才会被调用,基于上面讨论的属性。


在下面的示例中,有三种不同颜色的节点。LinkingToolRelinkingTool被自定义为使用一个函数,sameColor,来确保连线只会连接相同颜色的节点。在椭圆形上按下鼠标(当光标变成“手型”时)开始拖动绘制一条新的连线。你会看到唯一被允许的连线目的地是那些与出发节点颜色相同且还未被其他节点连线的节点。

diagram.nodeTemplate =
    $(go.Node, "Auto",
      $(go.Shape, "Ellipse",
        { cursor: "pointer", portId: "",
          fromLinkable: true, toLinkable: true },        
          new go.Binding("fill", "color")),
      $(go.TextBlock,
        { stroke: "white", margin: 3 },        
        new go.Binding("text", "key"))
    );

  diagram.linkTemplate =
    $(go.Link,
      // 连线的形状是贝塞尔曲线
      { curve: go.Link.Bezier, relinkableFrom: true, relinkableTo: true },
      $(go.Shape, { strokeWidth: 2 },        
        new go.Binding("stroke", "fromNode", function(n) { return n.data.color; })
            .ofObject()),
      $(go.Shape, { toArrow: "Standard", stroke: null},        
        new go.Binding("fill", "fromNode", function(n) { return n.data.color; })
            .ofObject())
    );  
    
  // 如果两个节点的颜色相同,这个判断函数会返回true
  function sameColor(fromnode, fromport, tonode, toport) {
    return fromnode.data.color === tonode.data.color;    
    // 也可以根据fromport.fill和 toport.fill来判断,
    // 因为Shape上面设置了PortId时,我们就可以假设Shape就是端口,
    // 并且Shape.fill上添加了数据绑定
  }  
  
  // 只允许在颜色相同的两个节点之间绘制新的连线
  diagram.toolManager.linkingTool.linkValidation = sameColor;  
  
  // 只允许重新连线到一个颜色相同的节点
  diagram.toolManager.relinkingTool.linkValidation = sameColor;  
  
  var nodeDataArray = [
    { key: "Red1", color: "red" },
    { key: "Blue1", color: "blue" },
    { key: "Green1", color: "green" },
    { key: "Green2", color: "green" },
    { key: "Red2", color: "red" },
    { key: "Blue2", color: "blue" },
    { key: "Red3", color: "red" },
    { key: "Green3", color: "green" },
    { key: "Blue3", color: "blue" }
  ];  
  
  var linkDataArray = [    
      // 最开始是没有连线的
  ];
  diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

image.pngimage.pngimage.png

为了强调颜色限制,连线的颜色与它们的出发节点的颜色节点数据绑定了。


限制一个节点上的总连线数量(Limiting total number of links connecting with a node)


我们可以通过设置GraphObject.toMaxLinks限制一个端口最多被几条连线连接。同样的,我们可以通过设置GraphObject.fromMaxLinks限制一个端口最多发出几条连线。但是,如果你想要限制一个端口上的总的连线数量呢?不管这些连线是从这个端口发出的,还是连接到这个端口的。这样的限制只能通过一个连线验证判断来实现。

当想要限制每个端口上的总连线数量时,我们可以使用Node.linkValidation判断:

$(go.Node, . . .,    
    {      
     linkValidation: function(fromnode, fromport, tonode, toport) {
        // 一个端口的总连线数被限制为 1:
        return fromnode.findLinksConnected(fromport.portId).count +
               tonode.findLinksConnected(toport.portId).count < 1;      
     }
    }, . . .

篇幅太长,分成两篇文章了,下一篇请见:GoJS 官方教程之:Validation(验证)(2)

2 thoughts on “GoJS 官方教程之:Validation(验证)(1)

shane进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注