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.
410 lines
14 KiB
410 lines
14 KiB
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>GoJS Link Connection Points on Nodes -- Northwoods Software</title>
|
|
<!-- Copyright 1998-2019 by Northwoods Software Corporation. -->
|
|
<script src="../release/go.js"></script>
|
|
<script src="../extensions/Figures.js"></script>
|
|
<script src="goIntro.js"></script>
|
|
</head>
|
|
<body onload="goIntro()">
|
|
<div id="container" class="container-fluid">
|
|
<div id="content">
|
|
|
|
<h1>Link Connection Points on Nodes</h1>
|
|
<p>
|
|
There is flexibility in controlling exactly how and where a link connects to a node.
|
|
In the previous examples the link has always ended at the edge of the node.
|
|
But you can specify the <a>Spot</a> on a node at which a link terminates.
|
|
</p>
|
|
|
|
<h2 id="NonRectangularNodes">Non-rectangular Nodes</h2>
|
|
<p>
|
|
When a <a>Node</a> does not have a rectangular shape, by default links will end
|
|
where the line toward the center of the node intersects with the edge of the node.
|
|
</p>
|
|
<p>
|
|
Here is a demonstration of that -- drag one of the nodes around and watch how the link always
|
|
connects to the nearest intersection or to the center of the node.
|
|
This example includes arrowheads at both ends of the link, to make it clear that the link route
|
|
really ends right at the edge of the node.
|
|
</p>
|
|
<pre class="lang-js" id="nonRectangular">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
{ width: 90, height: 90,
|
|
selectionAdorned: false },
|
|
new go.Binding("location", "loc", go.Point.parse),
|
|
$(go.Shape, "FivePointedStar", { fill: "lightgray" }),
|
|
$(go.TextBlock,
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
$(go.Shape),
|
|
$(go.Shape, // the "from" end arrowhead
|
|
{ fromArrow: "Chevron" }),
|
|
$(go.Shape, // the "to" end arrowhead
|
|
{ toArrow: "StretchedDiamond", fill: "red" })
|
|
);
|
|
|
|
var nodeDataArray = [
|
|
{ key: "Alpha", loc: "0 0" },
|
|
{ key: "Beta", loc: "100 50" }
|
|
];
|
|
var linkDataArray = [
|
|
{ from: "Alpha", to: "Beta" }
|
|
];
|
|
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
|
|
</pre>
|
|
<script>goCode("nonRectangular", 600, 150)</script>
|
|
|
|
<h2 id="ToSpotAndFromSpot">ToSpot and FromSpot</h2>
|
|
<p>
|
|
You can easily require links to end at a particular point within the bounds of the node,
|
|
rather than at the nearest edge intersection.
|
|
Set the <a>GraphObject.toSpot</a> to a <a>Spot</a> value other than <a>Spot,None</a>
|
|
to cause links coming into the node to end at that spot within the node, with a direction
|
|
that is appropriate for the side that the spot is at.
|
|
Similarly, set the <a>GraphObject.fromSpot</a> for the ends of links coming out of the node.
|
|
</p>
|
|
|
|
<p>
|
|
The following examples all display the same graph but use different templates
|
|
to demonstrate how links can connect to nodes.
|
|
They all call this common function to define some nodes and links.
|
|
</p>
|
|
<pre class="lang-js" id="makeGraph">
|
|
function makeGraph(diagram) {
|
|
var $ = go.GraphObject.make;
|
|
|
|
diagram.layout =
|
|
$(go.LayeredDigraphLayout, // this will be discussed in a later section
|
|
{ columnSpacing: 5,
|
|
setsPortSpots: false });
|
|
|
|
var nodeDataArray = [
|
|
{ key: "Alpha" }, { key: "Beta" }, { key: "Gamma" }, { key: "Delta" },
|
|
{ key: "Epsilon" }, { key: "Zeta" }, { key: "Eta" }, { key: "Theta" }
|
|
];
|
|
var linkDataArray = [
|
|
{ from: "Beta", to: "Alpha" },
|
|
{ from: "Gamma", to: "Alpha" },
|
|
{ from: "Delta", to: "Alpha" },
|
|
{ from: "Alpha", to: "Epsilon" },
|
|
{ from: "Alpha", to: "Zeta" },
|
|
{ from: "Alpha", to: "Eta" },
|
|
{ from: "Alpha", to: "Theta" }
|
|
];
|
|
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
|
|
}
|
|
</pre>
|
|
<script>eval(document.getElementById("makeGraph").textContent)</script>
|
|
|
|
<p>
|
|
Let us specify that links coming into a node connect at the middle of the left side, and that links going out
|
|
of a node connect at the middle of the right side. Such a convention is appropriate for diagrams that have
|
|
a general sense of direction to them, such as the following one which goes from left to right.
|
|
</p>
|
|
<pre class="lang-js" id="leftright">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
{ fromSpot: go.Spot.Right, // coming out from middle-right
|
|
toSpot: go.Spot.Left }, // going into at middle-left
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.TextBlock,
|
|
{ margin: 5},
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
makeGraph(diagram);
|
|
</pre>
|
|
<script>goCode("leftright", 600, 150)</script>
|
|
|
|
<p>
|
|
You can also specify that the links go into a node not at a single spot but spread out along one side.
|
|
Instead of <a>Spot,Right</a> use <a>Spot,RightSide</a>, and similarly for the left side.
|
|
</p>
|
|
<pre class="lang-js" id="leftrightSides">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
{ fromSpot: go.Spot.RightSide, // coming out from right side
|
|
toSpot: go.Spot.LeftSide }, // going into at left side
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.TextBlock,
|
|
{ margin: 5},
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
makeGraph(diagram);
|
|
</pre>
|
|
<script>goCode("leftrightSides", 600, 150)</script>
|
|
<p>
|
|
Of course this only looks good when the nodes are basically rectangular.
|
|
</p>
|
|
|
|
<p>
|
|
You can use a different kind of <a>Link.routing</a>:
|
|
</p>
|
|
<pre class="lang-js" id="leftrightSidesOrthogonal">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
{ fromSpot: go.Spot.RightSide, // coming out from right side
|
|
toSpot: go.Spot.LeftSide }, // going into at left side
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.TextBlock,
|
|
{ margin: 5},
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
{ routing: go.Link.Orthogonal, // Orthogonal routing
|
|
corner: 10 }, // with rounded corners
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
makeGraph(diagram);
|
|
</pre>
|
|
<script>goCode("leftrightSidesOrthogonal", 600, 150)</script>
|
|
|
|
<p>
|
|
Or you can use a different kind of <a>Link.curve</a>:
|
|
</p>
|
|
<pre class="lang-js" id="leftrightSidesBezier">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
{ fromSpot: go.Spot.RightSide, // coming out from right side
|
|
toSpot: go.Spot.LeftSide }, // going into at left side
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.TextBlock,
|
|
{ margin: 5},
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
{ curve: go.Link.Bezier }, // Bezier curve
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
makeGraph(diagram);
|
|
</pre>
|
|
<script> goCode("leftrightSidesBezier", 600, 150)</script>
|
|
|
|
<p>
|
|
But you need to be careful to specify sensible spots for how the graph is arranged.
|
|
</p>
|
|
<pre class="lang-js" id="leftrightSidesBad">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
{ fromSpot: go.Spot.TopSide, // coming out from top side -- BAD!
|
|
toSpot: go.Spot.RightSide }, // going into at right side -- BAD!
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.TextBlock,
|
|
{ margin: 5},
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
makeGraph(diagram);
|
|
|
|
diagram.add($(go.Part, // this is just a comment
|
|
{ location: new go.Point(300, 50) },
|
|
$(go.TextBlock, "Bad Spots",
|
|
{ font: "16pt bold", stroke: "red" })
|
|
));
|
|
</pre>
|
|
<script>goCode("leftrightSidesBad", 600, 150)</script>
|
|
|
|
<h3 id="UndirectedSpots">Undirected Spots</h3>
|
|
<p>
|
|
When no spot is specified for the <a>GraphObject.fromSpot</a> or <a>GraphObject.toSpot</a>,
|
|
the route computation will compute the furthest point on the route of the link from the center of the port to the other port
|
|
that is an intersection of an edge of the port.
|
|
This was demonstrated above in <a href="#NonRectangularNodes">Non-rectangular Nodes</a> and is again demonstrated here.
|
|
</p>
|
|
<pre class="lang-js" id="noSpotFocus0">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Vertical",
|
|
new go.Binding("location", "loc", go.Point.parse),
|
|
$(go.Shape, "YinYang",
|
|
{
|
|
fill: "white", portId: ""
|
|
},
|
|
new go.Binding("fill", "color")),
|
|
$(go.TextBlock,
|
|
{ margin: 8 },
|
|
new go.Binding("text"))
|
|
);
|
|
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: 1, text: "Alpha", color: "lightblue", loc: "0 50" },
|
|
{ key: 2, text: "Beta", color: "orange", loc: "150 0" },
|
|
{ key: 3, text: "Gamma", color: "lightgreen", loc: "300 50" }
|
|
],
|
|
[
|
|
{ from: 1, to: 2 },
|
|
{ from: 2, to: 3 }
|
|
]);
|
|
</pre>
|
|
<script>goCode("noSpotFocus0", 600, 250)</script>
|
|
|
|
<p>
|
|
However it is possible to specify a focus point that is different from the center of the port.
|
|
Use a <a>Spot</a> value that has <a>Spot.x</a> and <a>Spot.y</a> equal to 0.5 but with <a>Spot.offsetX</a> and <a>Spot.offsetY</a>
|
|
values that specify where you want links to focus towards, relative to the center of the port.
|
|
</p>
|
|
<pre class="lang-js" id="noSpotFocus1">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Vertical",
|
|
new go.Binding("location", "loc", go.Point.parse),
|
|
$(go.Shape, "YinYang",
|
|
{
|
|
fill: "white", portId: "",
|
|
fromSpot: new go.Spot(0.5, 0.5, 0, -25), toSpot: new go.Spot(0.5, 0.5, 0, 25)
|
|
},
|
|
new go.Binding("fill", "color")),
|
|
$(go.TextBlock,
|
|
{ margin: 8 },
|
|
new go.Binding("text"))
|
|
);
|
|
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: 1, text: "Alpha", color: "lightblue", loc: "0 50" },
|
|
{ key: 2, text: "Beta", color: "orange", loc: "150 0" },
|
|
{ key: 3, text: "Gamma", color: "lightgreen", loc: "300 50" }
|
|
],
|
|
[
|
|
{ from: 1, to: 2 },
|
|
{ from: 2, to: 3 }
|
|
]);
|
|
</pre>
|
|
<script>goCode("noSpotFocus1", 600, 250)</script>
|
|
<p>
|
|
In this example, links always appear to be coming from the hole near the top of the "YinYang" figure
|
|
towards the dot near the bottom of the figure.
|
|
Try moving the nodes to see this behavior.
|
|
Note that the <a>Spot.x</a> and <a>Spot.y</a> values are both 0.5, with fixed offsets from the center of the port.
|
|
</p>
|
|
|
|
<p>
|
|
It is also possible to have links go directly to particular spots within a port.
|
|
Use regular <a>Spot</a> values, but set the Link's end segment length to zero,
|
|
<a>Link.fromEndSegmentLength</a> or <a>Link.toEndSegmentLength</a>.
|
|
</p>
|
|
<pre class="lang-js" id="noSpotFocus2">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Vertical",
|
|
new go.Binding("location", "loc", go.Point.parse),
|
|
$(go.Shape, "YinYang",
|
|
{
|
|
fill: "white", portId: "",
|
|
fromSpot: new go.Spot(0.5, 0.25), toSpot: new go.Spot(0.5, 0.75),
|
|
fromEndSegmentLength: 0, toEndSegmentLength: 0
|
|
},
|
|
new go.Binding("fill", "color")),
|
|
$(go.TextBlock,
|
|
{ margin: 8 },
|
|
new go.Binding("text"))
|
|
);
|
|
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: 1, text: "Alpha", color: "lightblue", loc: "0 50" },
|
|
{ key: 2, text: "Beta", color: "orange", loc: "150 0" },
|
|
{ key: 3, text: "Gamma", color: "lightgreen", loc: "300 50" }
|
|
],
|
|
[
|
|
{ from: 1, to: 2 },
|
|
{ from: 2, to: 3 }
|
|
]);
|
|
</pre>
|
|
<script>goCode("noSpotFocus2", 600, 250)</script>
|
|
<p>
|
|
Again, links always appear to be coming from the hole near the top of the "YinYang" figure
|
|
towards the dot near the bottom of the figure, but now they go all the way rather than stop at the edge.
|
|
Note that the <a>Spot.x</a> and <a>Spot.y</a> values are <i>not</i> both 0.5,
|
|
and that the Link end segment lengths are zero.
|
|
</p>
|
|
|
|
<h2 id="SpotsForIndividualLinks">Spots for Individual Links</h2>
|
|
<p>
|
|
Setting the <a>GraphObject.fromSpot</a> and <a>GraphObject.toSpot</a> properties specifies
|
|
the default link connection point for all links connected to the node.
|
|
What if you want some links to go to the middle-top spot but some other links to go to the middle-left spot of the same node?
|
|
You can achieve this by setting the <a>Link.fromSpot</a> and <a>Link.toSpot</a> properties,
|
|
which take precedence over the correspondingly named properties of what the link connects with.
|
|
</p>
|
|
<pre class="lang-js" id="customSpots">
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Auto",
|
|
$(go.Shape, "Rectangle", { fill: "lightgray" }),
|
|
$(go.TextBlock,
|
|
{ margin: 5},
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
// get the link spots from the link data
|
|
new go.Binding("fromSpot", "fromSpot", go.Spot.parse),
|
|
new go.Binding("toSpot", "toSpot", go.Spot.parse),
|
|
$(go.Shape),
|
|
$(go.Shape, { toArrow: "Standard" })
|
|
);
|
|
|
|
var nodeDataArray = [
|
|
{ key: "Alpha" }, { key: "Beta" }, { key: "Gamma" }, { key: "Delta" }
|
|
];
|
|
var linkDataArray = [
|
|
{ from: "Alpha", to: "Beta", fromSpot: "TopRight", toSpot: "Left" },
|
|
{ from: "Alpha", to: "Gamma", fromSpot: "Left", toSpot: "Left" },
|
|
{ from: "Alpha", to: "Delta", fromSpot: "None", toSpot: "Top" }
|
|
];
|
|
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
|
|
</pre>
|
|
<script>goCode("customSpots", 600, 150)</script>
|
|
|
|
<h3 id="SomeLayoutsSetLinkSpots">Some Layouts set Link Spots</h3>
|
|
<p>
|
|
Some of the predefined <a>Layout</a>s automatically set <a>Link.fromSpot</a> and <a>Link.toSpot</a>
|
|
when the nature of the layout implies a natural direction.
|
|
So, for example, a <a>TreeLayout</a> with a <a>TreeLayout.angle</a> <code>== 90</code> will set each Link's
|
|
fromSpot to be <a>Spot,Bottom</a> and each Link's toSpot to be <a>Spot,Top</a>.
|
|
</p>
|
|
<p>
|
|
You can disable the setting of Link spots for TreeLayout by setting <a>TreeLayout.setsPortSpot</a> and/or <a>TreeLayout.setsChildPortSpot</a> to false.
|
|
For LayeredDigraphLayout, set <a>LayeredDigraphLayout.setsPortSpots</a> to false.
|
|
For ForceDirectedLayout, set <a>ForceDirectedLayout.setsPortSpots</a> to false, although this is rarely needed.
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|