AUBREY

SOMETIMES LOVE JUST AIN'T ENOUGH

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

组合验证(Grouping validation)


当你想要限制用户添加到某个特定的group中的节点类型时,你可以为CommandHandler.memberValidation或者Group.memberValidation属性执行一个判断。在CommandHandler上设置属性会导致判断被应用到所有的Group中,但是在Group上设置属性会只应用到该group。

在下面的示例中,samePrefix 判断被用来决定一个Node是否应该被放入一个Group中。试着把下面的左侧的简单的文本节点拖拽到右侧的任意一个group中。只有当文本节点拖拽到group区域时,group的背景色变成绿色时,才表示这个文本节点可以被放入这个group中。你可以移动group来验证文本节点是否真的被加入到了该group中。

 // 如果两个节点的数据的key值是同一个字符开头的,则这个验证返回true
  function samePrefix(group, node) {
    if (group === null) return true;  // 如果把节点拖入背景时
    if (node instanceof go.Group) return false;  // 不能把Group添加到Group中
    return group.data.key.charAt(0) === node.data.key.charAt(0);
  };

  diagram.nodeTemplate =
    $(go.Node,      
      new go.Binding("location", "loc", go.Point.parse),
      $(go.TextBlock,        
       new go.Binding("text", "key"))
    );

  diagram.groupTemplate =
    $(go.Group, "Vertical",
      {        
        // 只允许有那些简单的与Group的数据里的key值前缀一样的节点
        memberValidation: samePrefix,        
        // 不需要在节点和连线上定义处理器
        handlesDragDropForMembers: true,        
        // 当Group允许放入一个节点时背景色会高亮为绿色
        mouseDragEnter: function(e, grp, prev) {
          // 这会调用samePrefix函数;如果节点的前缀与Group相同,则会返回true
          if (grp.canAddMembers(grp.diagram.selection)) {            
            var shape = grp.findObject("SHAPE");            
            if (shape) shape.fill = "green";
            grp.diagram.currentCursor = "";
          } else {
            grp.diagram.currentCursor = "not-allowed";
          }
        },
        mouseDragLeave: function(e, grp, next) {
          var shape = grp.findObject("SHAPE");          
          if (shape) shape.fill = "rgba(128,128,128,0.33)";
          grp.diagram.currentCursor = "";
        },        
        // 当拖入行为发生时允许增加新成员节点
        mouseDrop: function(e, grp) {
          if (grp.canAddMembers(grp.diagram.selection)) {            
            // 这样只会增加有相同前缀的成员节点
            grp.addMembers(grp.diagram.selection, true);
          } else {  // 否则的话取消拖入
            grp.diagram.currentTool.doCancel();
          }
        }
      },      
      // 确保所有的Group是在常规节点的底下
      { layerName: "Background" },      
      new go.Binding("location", "loc", go.Point.parse),
      $(go.TextBlock,
        { alignment: go.Spot.Left, font: "Bold 12pt Sans-Serif" },        
        new go.Binding("text", "key")),
      $(go.Shape,
        { name: "SHAPE", width: 100, height: 100,
          fill: "rgba(128,128,128,0.33)" })
    );

  diagram.mouseDrop = function(e) {
    // 如果拖到了图表的背景上则把该节点从所有的Group中删除
    diagram.commandHandler.addTopLevelParts(diagram.selection, true);
  };  
  
  var nodeDataArray = [
    { key: "A group", isGroup: true, loc: "100 10" },
    { key: "B group", isGroup: true, loc: "100 140" },
    { key: "A1", loc: "10 30" },  // A1和A2节点能被加入到 "A" group
    { key: "A2", loc: "10 60" },
    { key: "B1", loc: "10 90" },  // B1和B2节点能被加入到 "B" group
    { key: "B2", loc: "10 120" },
    { key: "C1", loc: "10 150" }  // C1节点不能被加入到任何group
  ];
  diagram.model = new go.GraphLinksModel(nodeDataArray, []);

image.png image.png

这两个group的尺寸是固定的——它们没有使用Placeholder。因此当把一个节点拖入其中时,group的尺寸并不会自动调整大小来包围它的成员节点。但这也有个好处,就是当把group中的成员节点拖出去的时候,group也不会变小。

当拖动group中已经存在的成员节点时,验证也会被调用。你可以看到,拖动时group的背景色也会变成绿色。当成员节点从group中被拖到图表的背景时,验证以null值作为“group”的参数被调用。

在这个示例中,将节点拖到整个图表的背景上永远都是可行的,但是拖到group中就不一定了。如果你需要不允许拖动到背景上,你可以在Diagram.mouseDrop事件处理器中调用myDiagram.currentTool.doCancel()。如果你想在在背景上拖动时获得反馈,你可以执行一个Diagram.mouseDragOver事件处理器,设置myDiagram.currentCursor = "not-allowed"。这样,你在背景上拖动节点时就会类似于在group中拖动节点,背景的填充颜色会高亮为绿色。

实践补充知识点:

要实现的功能是,group内部的节点不能与g包含他们的group连线

function checkLink(fromnode, fromport, tonode, toport){
   return fromnode.data.group != tonode.data.key;
}

var myDiagram = $$(go.Diagram, "myDiagramDiv",{
      initialContentAlignment: go.Spot.Center, //居中显示Diagram的内容
      "undoManager.isEnabled": true,  //打开Ctrl-Z撤销和Ctrl-Y重做功能
      maxSelectionCount: 1,// 用户一次只能选中一个Part
      layout: $$(go.TreeLayout, {angle: 90, layerSpacing: 35}),
      allowDrop: true,
      "linkingTool.linkValidation": checkLink,
      "relinkingTool.linkValidation": checkLink
   });

文本编辑验证


当用户在一个TextBlock上执行原地文本编辑时,你可以限制用户能输入什么文本。首先,要进行任何编辑,你都需要把TextBlock.editable设置为true。一个Part里可能会有好多textBlock,但是你可能只是需要限制某个特定的TextBlock的文本编辑。

正常情况下,用户输入的文本是没有限制的。如果你想要在用户完成编辑时提供一个验证来验证用户的输入。可以设置TextEditingTool.textValidation(验证会应用于所有的TextBlock)TextBlock.textValidation(为哪个TextBlock设置验证就会应用于哪个TextBlock)属性。

// 新的字符串如果最少有3个字母以及一个元音字母,则这个验证会返回true
  function okName(textblock, oldstr, newstr) {
    return newstr.length >= 3 && /[aeiouy]/i.test(newstr);
  };

  diagram.nodeTemplate =
    $(go.Node, "Auto",
      $(go.Shape, { fill: "lightyellow" }),
      $(go.Panel, "Vertical",
        { margin: 3 },
        $(go.TextBlock,
          { editable: true },  // 没有验证
          new go.Binding("text", "text1")),
        $(go.TextBlock,
          { editable: true,
            isMultiline: false,  // 不允许嵌入新行
            textValidation: okName },  // 新的字符必须是符合oKName这个验证函数的
          new go.Binding("text", "text2"))
      )
    );

  diagram.initialContentAlignment = go.Spot.Center;  
  
  var nodeDataArray = [
    { key: 1, text1: "Hello", text2: "Dolly!" },
    { key: 2, text1: "Goodbye", text2: "Mr. Chips" }
  ];
  diagram.model = new go.GraphLinksModel(nodeDataArray, []);

image.png image.png

注意,第一行文本可以接受输入的文本没有任何元音字母,但是第二行文本不接受并且会一直保持文本编辑框打开。


如果你想要在文本编辑完成后执行代码,可以通过调用Diagram.addDiagramListener来执行一个图表事件“TextEdited”。

发表评论

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