流程图控件GoJS教程:验证方式(下)
GoJS是一款功能强大,快速且轻量级的流程图控件,可帮助你在JavaScript 和HTML5 Canvas程序中创建流程图,且极大地简化您的JavaScript / Canvas 程序。
常规链接验证
在某些情况下,您的应用程序的语义将导致有效链接目标集以某种方式取决于节点数据(即,链接从其开始的节点和端口以及可能的目标节点/端口)只能使用代码来实现:谓词函数。
您可以通过设置LinkingBaseTool.linkValidation或Node.linkValidation来实现此类特定于域的验证。这些谓词(如果提供)将为链接工具考虑的每对端口调用。如果谓词返回false,则可能无法建立链接。在LinkingTool或RelinkingTool上设置属性会使谓词应用于所有链接操作,而在Node上设置属性仅适用于涉及该节点的链接操作。根据上述属性,只有在所有标准链接检查均通过的情况下,才调用谓词。
在此示例中,存在三种不同颜色的节点。该LinkingTool和RelinkingTool自定义为使用的功能,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()) ); // this predicate is true if both nodes have the same color function sameColor(fromnode, fromport, tonode, toport) { return fromnode.data.color === tonode.data.color; // this could look at the fromport.fill and toport.fill instead, // assuming that the ports are Shapes, which they are because portID was set on them, // and that there is a data Binding on the Shape.fill } // only allow new links between ports of the same color diagram.toolManager.linkingTool.linkValidation = sameColor; // only allow reconnecting an existing link to a port of the same color 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 = [ // initially no links ]; diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
为了强调颜色限制,链接的颜色绑定到“ from”节点数据。
限制与节点连接的链接总数
可以通过设置GraphObject.toMaxLinks来限制进入端口的链接数。同样,可以通过设置GraphObject.fromMaxLinks来限制从端口出来的链接数。但是,如果要限制与端口连接的链接总数,而不管它们是进入端口还是离开端口,该怎么办?这样的约束只能通过链接验证谓词来实现。
当要限制任一方向上与每个端口连接的链路总数时,可以使用此Node.linkValidation谓词:
$(go.Node, . . ., { linkValidation: function(fromnode, fromport, tonode, toport) { // total number of links connecting with a port is limited to 1: return fromnode.findLinksConnected(fromport.portId).count + tonode.findLinksConnected(toport.portId).count < 1; } }, . . .当想要限制任一方向的链接总数,并为一个节点的所有端口连接时,可以使用此Node.linkValidation谓词:
$(go.Node, . . ., { linkValidation: function(fromnode, fromport, tonode, toport) { // total number of links connecting with all ports of a node is limited to 1: return fromnode.linksConnected.count + tonode.linksConnected.count < 1; } }, . . .
分组验证
当要限制用户可以添加到特定组的节点的类型时,可以将谓词实现为CommandHandler.memberValidation或Group.memberValidation属性。在CommandHandler上设置属性会使谓词应用于所有组,而在Group上设置属性仅适用于该组。
在此示例中,samePrefix谓词用于确定是否可以将节点放入组中。尝试将左侧的简单文本节点拖到右侧的任一组中。仅当将节点放到高亮“绿色”的组上时,该节点才被添加为该组的成员。您可以通过移动组以查看文本节点是否也移动来进行验证。
// this predicate is true if both node data keys start with the same letter function samePrefix(group, node) { if (group === null) return true; // when maybe dropping a node in the background if (node instanceof go.Group) return false; // don't add Groups to Groups 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", { // only allow those simple nodes that have the same data key prefix: memberValidation: samePrefix, // don't need to define handlers on member Nodes and Links handlesDragDropForMembers: true, // support highlighting of Groups when allowing a drop to add a member mouseDragEnter: function(e, grp, prev) { // this will call samePrefix; it is true if any node has the same key prefix 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 = ""; }, // actually add permitted new members when a drop occurs mouseDrop: function(e, grp) { if (grp.canAddMembers(grp.diagram.selection)) { // this will only add nodes with the same key prefix grp.addMembers(grp.diagram.selection, true); } else { // and otherwise cancel the drop grp.diagram.currentTool.doCancel(); } } }, // make sure all Groups are behind all regular Nodes { 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) { // dropping in diagram background removes nodes from any 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" }, // can be added to "A" group { key: "A2", loc: "10 60" }, { key: "B1", loc: "10 90" }, // can be added to "B" group { key: "B2", loc: "10 120" }, { key: "C1", loc: "10 150" } // cannot be added to either group ]; diagram.model = new go.GraphLinksModel(nodeDataArray, []);
这些组是固定大小的组-它们不使用Placeholder。因此,当将节点放入其中时,该组不会自动调整自身大小以包围其成员节点。但这在将节点拖出组时也是有好处的。
拖动已经是组成员的节点时,也会调用验证谓词。您可以看到将节点放入其现有的包含组是如何可接受的。当将其拖动到组的外部到图的背景中时,谓词将以null作为“组”参数被调用。
在此示例中,将节点放到图的背景中而不是放到一个组中总是可以的。如果要禁止在后台拖放,可以myDiagram.currentTool.doCancel() 在Diagram.mouseDrop事件处理程序中调用。如果要在后台拖动过程中显示反馈,则可以实现一个set 的Diagram.mouseDragOver事件处理程序 myDiagram.currentCursor = "not-allowed"。当在“组”中拖动时,此行为将类似于上面实现的行为。
文字编辑验证
您还可以限制用户在对TextBlock进行就地文本编辑时输入的文本。首先,要完全启用任何编辑,您需要将TextBlock.editable设置为true。零件中可能有许多TextBlock,但是您可能希望将文本编辑限制为特定的TextBlock。
通常,用户可以输入什么文字没有限制。如果要提供断言以在用户完成编辑时批准输入,请设置TextEditingTool.textValidation或TextBlock.textValidation属性。在TextEditingTool上设置属性会使谓词应用于所有TextBlock,而在TextBlock上设置属性仅应用于该文本对象。
// this predicate is true if the new string has at least three characters // and has a vowel in it 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 }, // no validation predicate new go.Binding("text", "text1")), $(go.TextBlock, { editable: true, isMultiline: false, // don't allow embedded newlines textValidation: okName }, // new string must be an OK name new go.Binding("text", "text2")) ) ); var nodeDataArray = [ { key: 1, text1: "Hello", text2: "Dolly!" }, { key: 2, text1: "Goodbye", text2: "Mr. Chips" } ]; diagram.model = new go.GraphLinksModel(nodeDataArray, []);
请注意,如何编辑顶部的TextBlock如何接受不带任何元音的文本,但是底部的TextBlock不接受它,而是使文本编辑器处于打开状态。
如果要在文本编辑完成后执行代码,请通过调用Diagram.addDiagramListener来实现“ TextEdited” DiagramEvent侦听器。
====================================================
想要购买GoJS正版授权的朋友可以
有关产品的最新消息和最新资讯,欢迎扫描关注下方微信公众号