Node ports on Tree Layout

http://codepen.io/anon/pen/kkxEwp is the code I am working on its taken from the TreeMapper sample. How do I modify such that a port for each node appears along the edge of the template. That would mean that the tree on the left has ports on the right edge and tree on the right would have ports on the left edge.

Can you explain what you want a little more? Do you want links to just connect to the whole Group, instead of some object inside of the Group? Or something else?

The image you attached does not seem to be from the sample that you linked.

I want the links for each object in treeNode to start and end at the edges of group.


Above image is a sample of how I want the links to look like.

I see. That won’t be easy with the setup you have.

You are going to have to rework your code so that all nodes have the same position.x value, and are all the same width, so they start and end at the same points. This is a problem when using tree layout since part of its function is to indent them, and you still want some visual indication of indentation.

I’m not sure if there’s an “easy” way to do what you want to do. I’ll give it some thought and let you know if I think of a good way.

Actually, that is pretty easy to implement. We’ll need a custom Link class which decides where it should terminate – at the Node.containingGroup’s boundary rather than at the normal Node boundary.

So add this class:

    function MappingLink() {
      go.Link.call(this);
      this.isTreeLink = false;
      this.isLayoutPositioned = false;
    }
    go.Diagram.inherit(MappingLink, go.Link);

    MappingLink.prototype.getLinkPoint = function(node, port, spot, from, ortho, othernode, otherport) {
      var r = new go.Rect(port.getDocumentPoint(go.Spot.TopLeft),
                          port.getDocumentPoint(go.Spot.BottomRight));
      var group = node.containingGroup;
      var b = (group !== null) ? group.actualBounds : node.actualBounds;
      var op = othernode.getDocumentPoint(go.Spot.Center);
      var x = (op.x > r.centerX) ? b.right : b.left;
      return new go.Point(x, r.centerY);
    };
    // end MappingLink

And use this class in your Link template for mapping links (not for links within the tree structure):

      myDiagram.linkTemplateMap.add("Mapping",
        $(MappingLink,
          { layerName: "Foreground" },
          . . .

We’ll also need to add an event handler when the user collapses or expands a subtree, because that will cause the Group to change size.

    function TreeNode() {
      go.Node.call(this);
      this.treeExpandedChanged = function(node) {
        if (node.containingGroup !== null) {
          node.containingGroup.findExternalLinksConnected().each(function(l) { l.invalidateRoute(); });
        }
      };
    }
    go.Diagram.inherit(TreeNode, go.Node);

If Nodes can change size, you’ll need to do something similar then, as well.

The result is:

I think I’ll make this change to the TreeMapper sample itself.

Nice but I was hoping that we would be able to draw a node’s links from group boundary rather than the node itself and the boundary would have a hook for each node (like in the picture I attached) to represent the link’s potential starting or endpoint.

Well, you could add “Triangle” arrowheads on the mapping links.

      myDiagram.linkTemplateMap.add("Mapping",
        $(MappingLink,
          { layerName: "Foreground" },
          { fromSpot: go.Spot.Right, toSpot: go.Spot.Left },
          { relinkableFrom: true, relinkableTo: true },
          $(go.Shape, { stroke: "blue", strokeWidth: 2 }),
          $(go.Shape, { toArrow: "Triangle", fill: "blue", strokeWidth: 0 }),
          $(go.Shape, { fromArrow: "Triangle", fill: "blue", strokeWidth: 0 })
        ));

If you also shift the end points inward, computed by MappingLink.getLinkPoint, you’ll get this:

But that doesn’t help with allowing the user to start dragging a new link anywhere in the horizontal area occupied by each node. If you wanted that, I suppose one could customize the LinkingTool to accomplish that.