You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
11 KiB
290 lines
11 KiB
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>GoJS Ports in Nodes-- Northwoods Software</title>
|
|
<!-- Copyright 1998-2019 by Northwoods Software Corporation. -->
|
|
<script src="../release/go.js"></script>
|
|
<script src="goIntro.js"></script>
|
|
</head>
|
|
<body onload="goIntro()">
|
|
<div id="container" class="container-fluid">
|
|
<div id="content">
|
|
|
|
<h1>Ports in Nodes</h1>
|
|
<p>
|
|
Although you have some control over where links will connect at a node (at a particular spot, along one or
|
|
more sides, or at the intersection with the edge), there are times when you want to have different logical
|
|
and graphical places at which links should connect. The elements at which a link may connect are called
|
|
<i>ports</i>. There may be any number of ports in a node. By default there is just one port, the whole node,
|
|
which results in the effect of having the whole node act as the port, as you have seen in all of the previous examples.
|
|
</p>
|
|
<p>
|
|
To declare that a particular element in a <a>Node</a> is a port, set the <a>GraphObject.portId</a> property to a string.
|
|
Note that the port-or-link-related properties may apply to any element in the visual tree of the node,
|
|
which is why they are properties of <a>GraphObject</a> rather than <a>Node</a>.
|
|
</p>
|
|
<p>
|
|
Port-like GraphObjects can only be in <a>Node</a>s or <a>Group</a>s, not in <a>Link</a>s or <a>Adornment</a>s or simple <a>Part</a>s.
|
|
So there is no reason to try to set <a>GraphObject.portId</a> on any object in a Link.
|
|
</p>
|
|
<p>
|
|
<p>
|
|
See samples that make use of ports in the <a href="../samples/index.html#ports">samples index</a>.
|
|
</p>
|
|
</p>
|
|
|
|
<h2 id="SinglePorts">Single Ports</h2>
|
|
<p>
|
|
In many situations you want to consider links logically related to the node as a whole but you don't want links
|
|
connecting to the whole node.
|
|
In this case each node has only one port, but you do not want the whole node to act as the one port.
|
|
</p>
|
|
<p>
|
|
For example, consider how links connect to the nodes when the whole node is acting as a port in one common manner.
|
|
The <a>GraphObject.fromSpot</a> and <a>GraphObject.toSpot</a> are at the middles of the sides.
|
|
Because the height of the whole node includes the text label,
|
|
the middle of the side is not the middle of the "icon", which in this case is a circle.
|
|
</p>
|
|
<pre class="lang-js" id="defaultPort">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Vertical",
|
|
{ fromSpot: go.Spot.Right, toSpot: go.Spot.Left }, // port properties on the node
|
|
$(go.Shape, "Ellipse",
|
|
{ width: 30, height: 30, fill: "green" }),
|
|
$(go.TextBlock,
|
|
{ font: "20px sans-serif" },
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
var nodeDataArray = [
|
|
{ key: "Alpha" },
|
|
{ key: "Beta" }
|
|
];
|
|
var linkDataArray = [
|
|
{ from: "Alpha", to: "Beta" }
|
|
];
|
|
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
|
|
</pre>
|
|
<script>goCode("defaultPort", 600, 100)</script>
|
|
<p>
|
|
This appearance does not look or behave quite right.
|
|
Really we want links to connect to the circular <a>Shape</a>.
|
|
</p>
|
|
|
|
<p>
|
|
If you want a particular element to act as the port rather than the whole node,
|
|
just set its <a>GraphObject.portId</a> to the empty string.
|
|
The empty string is the name of the default port.
|
|
</p>
|
|
<p>
|
|
In this example, we set <a>GraphObject.portId</a> on the circular shape.
|
|
Note that we move the other port-related properties, such as the port spots, to that object too.
|
|
</p>
|
|
<pre class="lang-js" id="singlePort">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Vertical",
|
|
$(go.Shape, "Ellipse",
|
|
{ width: 30, height: 30, fill: "green",
|
|
portId: "", // now the Shape is the port, not the whole Node
|
|
fromSpot: go.Spot.Right, // port properties go on the port!
|
|
toSpot: go.Spot.Left
|
|
}),
|
|
$(go.TextBlock,
|
|
{ font: "20px sans-serif" },
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
var nodeDataArray = [
|
|
{ key: "Alpha" },
|
|
{ key: "Beta" }
|
|
];
|
|
var linkDataArray = [
|
|
{ from: "Alpha", to: "Beta" }
|
|
];
|
|
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
|
|
</pre>
|
|
<script>goCode("singlePort", 600, 100)</script>
|
|
<p>
|
|
Notice how the links nicely connect the circular shapes by ignoring the text labels.
|
|
</p>
|
|
|
|
<h2 id="GeneralPorts">General Ports</h2>
|
|
<p>
|
|
It is also common to have diagrams where you want more than one port in a node.
|
|
The number of ports might even vary dynamically.
|
|
</p>
|
|
<p>
|
|
In order for a link data object to distinguish which port the link should connect to,
|
|
the <a>GraphLinksModel</a> supports two additional data properties that identify the names of the ports in the nodes
|
|
at both ends of the link.
|
|
<a>GraphLinksModel.getToKeyForLinkData</a> identifies the node to connect to;
|
|
<a>GraphLinksModel.getToPortIdForLinkData</a> identifies the port within the node.
|
|
Similarly, <a>GraphLinksModel.getFromKeyForLinkData</a> and <a>GraphLinksModel.getFromPortIdForLinkData</a> identify the node and its port.
|
|
</p>
|
|
<p>
|
|
Normally a <a>GraphLinksModel</a> assumes that there is no need to recognize port information on link data.
|
|
If you want to support port identifiers on link data, you need to set <a>GraphLinksModel.linkToPortIdProperty</a>
|
|
and <a>GraphLinksModel.linkFromPortIdProperty</a> to be the names of the link data properties.
|
|
If you do not set these properties, all port identifiers are assumed to be the empty string,
|
|
which is the name of the one default port for a node.
|
|
</p>
|
|
<p class="box bg-danger">
|
|
If you have set or bound <a>GraphObject.portId</a> on any element to be a non-empty string,
|
|
you will need to use a <a>GraphLinksModel</a> and set <a>GraphLinksModel.linkToPortIdProperty</a>
|
|
and <a>GraphLinksModel.linkFromPortIdProperty</a> to be the names of two properties on your link data,
|
|
or you will need to hard code the portId names in the link template(s)
|
|
(i.e. <a>Link.fromPortId</a> and <a>Link.toPortId</a>),
|
|
in order for the user to be able to link with those ports.
|
|
</p>
|
|
<pre class="lang-js" id="ports">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.Panel, "Table",
|
|
$(go.RowColumnDefinition,
|
|
{ column: 0, alignment: go.Spot.Left}),
|
|
$(go.RowColumnDefinition,
|
|
{ column: 2, alignment: go.Spot.Right }),
|
|
$(go.TextBlock, // the node title
|
|
{ column: 0, row: 0, columnSpan: 3, alignment: go.Spot.Center,
|
|
font: "bold 10pt sans-serif", margin: new go.Margin(4, 2) },
|
|
new go.Binding("text", "key")),
|
|
$(go.Panel, "Horizontal",
|
|
{ column: 0, row: 1 },
|
|
$(go.Shape, // the "A" port
|
|
{ width: 6, height: 6, portId: "A", toSpot: go.Spot.Left }),
|
|
$(go.TextBlock, "A") // "A" port label
|
|
),
|
|
$(go.Panel, "Horizontal",
|
|
{ column: 0, row: 2 },
|
|
$(go.Shape, // the "B" port
|
|
{ width: 6, height: 6, portId: "B", toSpot: go.Spot.Left }),
|
|
$(go.TextBlock, "B") // "B" port label
|
|
),
|
|
$(go.Panel, "Horizontal",
|
|
{ column: 2, row: 1, rowSpan: 2 },
|
|
$(go.TextBlock, "Out"), // "Out" port label
|
|
$(go.Shape, // the "Out" port
|
|
{ width: 6, height: 6, portId: "Out", fromSpot: go.Spot.Right })
|
|
)
|
|
)
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
{ routing: go.Link.Orthogonal, corner: 3 },
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
diagram.layout = $(go.LayeredDigraphLayout, { columnSpacing: 10 });
|
|
|
|
diagram.model =
|
|
$(go.GraphLinksModel,
|
|
{ linkFromPortIdProperty: "fromPort", // required information:
|
|
linkToPortIdProperty: "toPort", // identifies data property names
|
|
nodeDataArray: [
|
|
{ key: "Add1" },
|
|
{ key: "Add2" },
|
|
{ key: "Subtract1" }
|
|
],
|
|
linkDataArray: [
|
|
{ from: "Add1", fromPort: "Out", to: "Subtract1", toPort: "A" },
|
|
{ from: "Add2", fromPort: "Out", to: "Subtract1", toPort: "B" }
|
|
] });
|
|
</pre>
|
|
<script>goCode("ports", 600, 150)</script>
|
|
|
|
<h2 id="DrawingNewLinks">Drawing new Links</h2>
|
|
<p>
|
|
Setting either or both of the <a>GraphObject.fromLinkable</a> and <a>GraphObject.toLinkable</a>
|
|
properties to true allows users to interactively draw new links between ports.
|
|
</p>
|
|
<p>
|
|
To draw a new link, mouse down on an "Out" port, move (drag) to nearby an input port,
|
|
and then mouse-up to complete the link.
|
|
</p>
|
|
<pre class="lang-js" id="linkablePorts">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.Panel, "Table",
|
|
$(go.RowColumnDefinition,
|
|
{ column: 0, alignment: go.Spot.Left}),
|
|
$(go.RowColumnDefinition,
|
|
{ column: 2, alignment: go.Spot.Right }),
|
|
$(go.TextBlock, // the node title
|
|
{ column: 0, row: 0, columnSpan: 3, alignment: go.Spot.Center,
|
|
font: "bold 10pt sans-serif", margin: new go.Margin(4, 2) },
|
|
new go.Binding("text", "key")),
|
|
$(go.Panel, "Horizontal",
|
|
{ column: 0, row: 1 },
|
|
$(go.Shape, // the "A" port
|
|
{ width: 6, height: 6, portId: "A", toSpot: go.Spot.Left,
|
|
toLinkable: true, toMaxLinks: 1 }), // allow user-drawn links from here
|
|
$(go.TextBlock, "A") // "A" port label
|
|
),
|
|
$(go.Panel, "Horizontal",
|
|
{ column: 0, row: 2 },
|
|
$(go.Shape, // the "B" port
|
|
{ width: 6, height: 6, portId: "B", toSpot: go.Spot.Left,
|
|
toLinkable: true, toMaxLinks: 1 }), // allow user-drawn links from here
|
|
$(go.TextBlock, "B") // "B" port label
|
|
),
|
|
$(go.Panel, "Horizontal",
|
|
{ column: 2, row: 1, rowSpan: 2 },
|
|
$(go.TextBlock, "Out"), // "Out" port label
|
|
$(go.Shape, // the "Out" port
|
|
{ width: 6, height: 6, portId: "Out", fromSpot: go.Spot.Right,
|
|
fromLinkable: true }) // allow user-drawn links to here
|
|
)
|
|
)
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
{ routing: go.Link.Orthogonal, corner: 3 },
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
diagram.layout = $(go.LayeredDigraphLayout, { columnSpacing: 10 });
|
|
|
|
diagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal;
|
|
|
|
diagram.model =
|
|
$(go.GraphLinksModel,
|
|
{ linkFromPortIdProperty: "fromPort", // required information:
|
|
linkToPortIdProperty: "toPort", // identifies data property names
|
|
nodeDataArray: [
|
|
{ key: "Add1" },
|
|
{ key: "Add2" },
|
|
{ key: "Subtract1" }
|
|
],
|
|
linkDataArray: [
|
|
// no predeclared links
|
|
] });
|
|
</pre>
|
|
<script>goCode("linkablePorts", 600, 250)</script>
|
|
<p>
|
|
By default the user may not draw more than one link in the same direction between any pair of ports,
|
|
nor may the user draw a link connecting a node with itself.
|
|
Please read a general discussion of <a href="validation.html">Linking Validation</a>.
|
|
</p>
|
|
<p>
|
|
By setting <a>GraphObject.toMaxLinks</a> to 1, as shown in this example, the user may draw at most one link going into that port.
|
|
And because <a>GraphObject.fromLinkable</a> is false for that port element, the user will not be able to connect any links coming out of that port.
|
|
</p>
|
|
<p>
|
|
If you want to prevent the user from connecting any more than one Link with a Node, regardless of direction,
|
|
you will need to implement a <a>LinkingBaseTool.linkValidation</a> or a <a>Node.linkValidation</a> predicate.
|
|
See the discussion about <a href="validation.html#GeneralLinkingValidation">General Linking Validation</a>
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|