Problem with port placement

I’m trying to have my node’s links to wrap around the side they’re connected to. According to API spot go.Spot.LeftRightSides should do the trick (not perfect but close), but what I noticed is no matter what type of spot I choose it always connects to the same place (all links in one point). Even when I set the ports to go.Spot.Bottom nothing changes. The same when I delete the ports. Only thing that causes a change is moving ports to another object in the template - it changes accordingly.

So I guess for some reason my ports just won’t change. I think I’m missing something here.

Here’s my code:

    diagram.nodeTemplate =
      $(go.Node, "Vertical", go.Panel.Auto, {
          selectionObjectName: "TEXT"
        },
        new go.Binding("deletable", "deletable"),
        $(go.Shape, {
            figure: "RoundedRectangle",
            fill: "rgb(255,0,0)",
            portId: "",
            fromSpot: go.Spot.LeftRightSides,
            toSpot: go.Spot.LeftRightSides,
            strokeWidth: 0,
          },
          new go.Binding("stroke", "stroke"),
          new go.Binding("fill", "color"),

          new go.Binding("opacity", "depth", function (d) {
            return (d > 1) ? 0 : 1;
          }),
          
          new go.Binding("fill", "color")),
        new go.Binding("layerName", "stroke"),
        $(go.TextBlock, {
            name: "TEXT",
            minSize: new go.Size(30, 15),
            margin: new go.Margin(8, 15, 8, 15),
            stroke: "white",
            editable: true,
            isMultiline: false
          },
          new go.Binding("stroke", "stroke"),
          new go.Binding("margin", "depth", function (d) {
            return (d > 1) ? new go.Margin(8, 3, 8, 3) : new go.Margin(8, 15, 8, 15);
          }),

          new go.Binding("text", "text").makeTwoWay(),
          new go.Binding("scale", "scale").makeTwoWay(),
          new go.Binding("font", "font").makeTwoWay()),



        new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
        new go.Binding("locationSpot", "dir", function (d) {
          return spotConverter(d, false);
        }),
      );

Im using the Double Tree Layout.

Thanks for any help.

Do you have any small screenshots showing the current situation and sketches for what you want instead?

Yes wait a sec

First one is what I want
Second one is what I have

First, you need to turn off the link spots that TreeLayout normally assigns based on the direction of the layout. I suggest that you set TreeLayout.setsPortSpot to false.

Second, it seems that you want the links to come from a focus point that is not one of the sides of the node’s port. So I am curious what routing you wanted when there are just two children for a parent node.

1 Like

In case of 2 I think it just should be just a straight line and that I already have with the current setup. Thanks for help. I’ll try doing what you said.

It works thanks.
One more thing. How do I get those links to curve away from the middle? I have already set curve: go.Link.Bezier but this is the effect:

How would you want the link paths to go when there are four or five or more tree children?

Following this pattern

So basically stretching out further into the node

Well, if you don’t use spots at all, it gets a lot closer to what you want. And customizing how curvy each link is gets even closer results.

  // ES5 code for a custom go.Link class
  function CustomLink() {
    go.Link.call(this);
  }
  go.Diagram.inherit(CustomLink, go.Link);

  CustomLink.prototype.computeCurviness = function() {
    var floc = this.fromNode.location;
    var tloc = this.toNode.location;
    if (Math.abs(tloc.x-floc.x) < 100) return 0;
    return (tloc.y-floc.y)/(tloc.x-floc.x) * -50;
  }

  CustomLink.prototype.getLinkPoint = function(node, port, spot, from, ortho, othernode, otherport, result) {
    if (!from) {
      var ox = othernode.location.x;
      var tx = node.location.x;
      return port.getDocumentPoint((ox < tx) ? go.Spot.Left : go.Spot.Right, result);
    }
    // otherwise, normal behavior
    return go.Link.prototype.getLinkPoint.call(this, node, port, spot, from, ortho, othernode, otherport, result);
  }

  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          layout: $(go.TreeLayout, { setsPortSpot: false, setsChildPortSpot: false })
        });

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        { width: 150, height: 50 },
        $(go.Shape,
          { fill: "white" },
          new go.Binding("fill", "color")),
        $(go.TextBlock,
          new go.Binding("text"))
      );

    myDiagram.linkTemplate =
      $(CustomLink,
        { curve: go.Link.Bezier },
        $(go.Shape)
      );

    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" },
      { key: 3, text: "Gamma", color: "lightgreen" },
      { key: 4, text: "Delta", color: "pink" },
      { key: 5, text: "Epsilon", color: "lightgreen" },
      { key: 6, text: "Zeta", color: "pink" },
      { key: 7, text: "Eta", color: "lightblue" },
      { key: 8, text: "Theta", color: "orange" }
    ],
    [
      { from: 1, to: 2 },
      { from: 1, to: 3 },
      { from: 1, to: 4 },
      { from: 1, to: 5 },
      { from: 1, to: 6 },
      { from: 1, to: 7 },
      { from: 1, to: 8 }
    ]);
  }

produces:

Which isn’t exactly what you want, but close.

You can get exactly what you want by overriding Link.computePoints and computing the exact positions of the end points and the Bezier control points.

Amazing! Thank you

I have successfully implemented this and noticed that animations started going crazy when moving a node from side to side (between two trees). I see that the link wants to change sides by making a spiral. Is there a way to skip this part in the animation? Just starting with the link in the right way?

I don’t see how any link route can start “in the right way” when the nodes are moving. I have updated the CustomLink code slightly to reduce the effect.

Perhaps overriding computePoints is what you want, but I don’t have time now to work on that.

Okay i’ll look into that. Thanks. Your support is excelent

Try this:

  // ES5 code for a custom go.Link class
  function CustomLink() {
    go.Link.call(this);
    this.curviness = 0;
  }
  go.Diagram.inherit(CustomLink, go.Link);

  CustomLink.prototype.getLinkPoint = function(node, port, spot, from, ortho, othernode, otherport, result) {
    if (!from) {
      var ox = othernode.location.x;
      var tx = node.location.x;
      return port.getDocumentPoint((ox < tx) ? go.Spot.Left : go.Spot.Right, result);
    }
    // otherwise, normal behavior
    return go.Link.prototype.getLinkPoint.call(this, node, port, spot, from, ortho, othernode, otherport, result);
  }

  CustomLink.prototype.computePoints = function() {
    var result = go.Link.prototype.computePoints.call(this);
    if (result && this.pointsCount === 4) {
      var p0 = this.getPoint(0);
      var p3 = this.getPoint(3);
      this.setPoint(1, new go.Point(p0.x, (p0.y+p3.y)/2));
      this.setPoint(2, new go.Point((p0.x+p3.x)/2, p3.y));
    }
    return result;
  }