Several Issues regarding nodes, groups and links location in the graph


  1. I would like to allow the user to decide how he wants to view the graph - vertical or horizental. by default the graph is Vertical (groups and node) and the entites inside the groups are Vertical.

  2. The nodes that are inside the graph aren’t aligned to the center, and i can’t figure out what i’m missing. i’m using a placeholder in the groups.

This example is relevant for both issues:

  1. The links are overlapping each other, so i tried using the “fromSpot” ant “toSpot” to allow links to be spread the link drawing on the sides, but it’s not working.

in the example you can see that the label “Contains” of several links are merge with bad look.

Here is my code setup:

myDiagram =
$(go.Diagram, “myDiagramDiv”, // create a Diagram for the DIV HTML element
initialContentAlignment: go.Spot.Center,
initialAutoScale: go.Diagram.Uniform,
allowCopy: false,
allowGroup: false,
allowInsert: false,
allowLink: false,
allowTextEdit: false,
allowUngroup: false,
commandHandler: new DrawCommandHandler(),

  // more stuff...

myDiagram.nodeTemplate =
(go.Node, "Auto", { fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide, portId: "", cursor: "pointer", doubleClick: function(e, node) { doFilter(; }, }, (go.Shape, “RoundedRectangle”, { name: “ItemShape” },
new go.Binding(“fill”, “isExceptionEntity”, function(d) {
if (d == “true”) { return exceptionBackground; } else { return nodeBackground; }
(go.Panel, "Vertical", (go.Panel, “Auto”, { },
$(go.Picture, { desiredSize: new go.Size(24, 24) },
new go.Binding(“source”, “images”, function(e) { if (e[0]) return e[0]; else return “”})),

		$(go.Picture, { desiredSize: new go.Size(10, 10), alignment: go.Spot.BottomRight },
		new go.Binding("source", "images", function(e) { if (e[1]) return e[1]; else return ""}))
	$(go.TextBlock, { font: nodeFont, stroke: '#333', margin: 6, isMultiline: false, editable: false, stretch: go.GraphObject.Vertical }, 
	new go.Binding("text", "label"), 
	new go.Binding("stroke", "labelcolor"))
  contextMenu: partContextMenu


myDiagram.linkTemplate =
routing: go.Link.AvoidsNodes,
reshapable: true,
resegmentable: true,
adjusting: go.Link.Stretch,
corner: 4
new go.Binding(“key”, “key”),

$(go.Shape, { }, new go.Binding("stroke", "lineColor")),
$(go.Shape, { }, 
	new go.Binding("fill", "lineColor"),
	new go.Binding("toArrow", "showDirection", function(data) {
		if (data == "true") { return "Standard"; } else { return ""; }
	new go.Binding("fromArrow", "showDirection", function(data) {
		if (data == "true") { return "Standard"; } else { return ""; }
$(go.TextBlock, { 
	name: "LinkText",
	stroke: "#1e4373",
	textAlign: "center",
	segmentIndex: -1, segmentOffset: new go.Point(NaN, NaN),
	segmentOrientation: go.Link.OrientUpright,
	background: "transparent"
	new go.Binding("text", "typeName"))


myDiagram.groupTemplate =
$(go.Group, “Vertical”,
fromSpot: go.Spot.RightSide,
toSpot: go.Spot.LeftSide,
stretch: go.GraphObject.Vertical,
resizeObjectName: “GroupShape”,
selectionObjectName: “GroupShape”,
locationObjectName: “GroupShape”,
computesBoundsIncludingLinks: false,
computesBoundsIncludingLocation: true,

  layout: $(go.TreeLayout, { layerSpacing: 100, arrangementSpacing: new go.Size(60, 60) }),
  selectionChanged: function(node) {
	var shape = node.findObject("GroupShape");
	if (node.isSelected == true) {
		shape.fill = selectedBackground; 
		${onClick}(, false);
	} else {
		if ( == "true") {
			shape.fill = exceptionBackground;
		} else {
			shape.fill = nodeBackground;

$(go.Panel, "Vertical",  // title above Placeholder
  { cursor: "pointer" },
  $(go.Panel, "Horizontal",  // button next to TextBlock
	{ stretch: go.GraphObject.Horizontal, background: "#004280", padding: 4 },
	$(go.Picture, new go.Binding("source", "images", function(e) { return e[0]})),
	$(go.Picture, new go.Binding("source", "images", function(e) { return e[1]})),
	$(go.TextBlock, { alignment: go.Spot.Left, editable: false, isMultiline: false, margin: 5, font: groupFont, stroke: "white" }, new go.Binding("text", "label"))
  $(go.Panel, "Auto",
	 { opacity: 0.6, stretch: go.GraphObject.Fill },
	 // the rectangular shape around the members
	 $(go.Shape, "Rectangle", { name: "GroupShape", stroke: "#004280", strokeWidth: 1, stretch: go.GraphObject.Fill },
		new go.Binding("fill", "isExceptionEntity", function(d) {
			if (d == "true") { return exceptionBackground; } else { return groupBackground; }
	 ,$(go.Panel, "Vertical", { defaultAlignment: go.Spot.Center },
		 $(go.Placeholder, { margin: 10, alignment: go.Spot.Center, stretch: go.GraphObject.Fill  })  
),  // end Vertical Panel

This post is very confusing. I’m not sure exactly what your questions are. And you don’t include the Group template.

I think the basic answer for horizontally vs vertically oriented diagrams is the Group.layout that you use for each. One should grow horizontally and the other show grow vertically.

Thanks for the quick replay, i have updated my initial post with the Group template.

i will try to create a new button that will change the graph and groups layout from from Vertical to Horizontal.

Regarding the other issues:

  1. Links - i want to use “fromSpot: go.Spot.RightSide” to allow links to spread on the entire side of the groups and nodes, but it’s not working.
  2. i need to align group children to the center (and not aligned to the left). how can i do that?

Ah, OK – you are using a TreeLayout, so you want to change every Group.layout’s TreeLayout.angle from 0 to 90 or vice-versa.

myDiagram.nodes.each(function(g) {
  if (g instanceof go.Group) {
    var a = g.layout.angle;
    g.layout.angle = a ? 0 : 90;
myDiagram.commitTransaction("changed layout direction");

You appear to be correctly setting the fromSpot and toSpot on the port element (either the whole Node or the object with portId: ""), so that should be OK. And you haven’t set them to the wrong values on the Links, which would have superseded the values on the ports. So I don’t know what the problem is.

The TreeLayout by default has angle 0, which means it grows towards the right. But in your first screenshot there aren’t any links between the nodes, so they are all acting as “roots”. TreeLayout always lines up the nodes in each layer by the left position when the angle is zero.