Strange behaviour in the link path

Hi,

I’m experiencing some strange behaviour when reshaping a link that goes from and to the same node. The link gets strange curves when it is reshaped, this is not happening when the link is between two different nodes.

The above screenshot is produced in the polylinelinking example

Is this expected behaviour? and how do i make sure the link follows the exact link points?

Thanks,
Tim

PS: the model that is used in the upper example

{ “class”: “go.GraphLinksModel”,
“nodeDataArray”: [
{“key”:1, “text”:“Node 1”, “fill”:“blueviolet”, “loc”:“100 100”}
],
“linkDataArray”: [ {“from”:1, “to”:1, “points”:[150.5,140.54744525547446,237,210,231,285,114,332,-49,279,57.963687150838,150.5]} ]}

This looks like a bug. We’ll investigate.

FYI, each Bezier curve segment requires 3 points, but the existing resegmenting code does not add 3 points.

That seems to be the issue. Self-connecting links are made to be bezier curves, so if you make them with 3, 6, 9, etc points, they will work. But any other number and you’ll have curves missing points.

Thanks, for the quick replies. I understand this works as designed then. Is there any way to have all links behave in the same way? We would like our users to be able to draw links like in the image below, but we don’t want to force the link.Orthogonal routing

You could force self-links to be non-bezier and non-ortho by overriding Link.computeCurve:

go.Link.prototype.computeCurve = function() { return go.Link.None; }

This will make all of the links in the sample straight/Link.None links. You may need more nuance in your override, depending on your app.

See: Link | GoJS API

Hi Simon,

Overriding the function does work, but i’m still running in to some other problems that only occur with self-linking links.
a) the direction of a self-linking link is different than that of a ‘regular’ link. as you can see in the screenshot below.
b) when i drag on of the self-linking links end points (i’ve implemented the linkshiftingtool extension) the link is fully redrawn, but it should only redraw it from the last point, because the adjusting is set to go.Link.End. Again the behaviour is different than that of ‘regular’ links.

Instead of having the self-linking links and ‘regular’ links behave differently, i would really like the two to behave in the exact same way. How should i do this?

This seems to be because Link.computePoints will clear the points of any self loop link when it needs computing. If you want, you could override computePoints in order to do something different when its a self-link. You’d need something like:

/**
* @constructor
* @extends Link
* @class
*/
function CustomLink() {
  go.Link.call(this);
}
go.Diagram.inherit(CustomLink, go.Link);

// previously discussed, stop self-links from being orthogonal or bezier:
CustomLink.prototype.computeCurve = function() { return go.Link.None; }

// general routing computation
CustomLink.prototype.computePoints = function() { 
  var selfloop = (this.fromPort === this.toPort && this.fromPort !== null);
  // do the default functionality if you don't have a self link
  if (!selfloop) {
    go.Link.prototype.computePoints.call(this);
  } else {
    //todo:
    // compute points differently for self links
  }
}

Hi Simon,

Thanks for your reply. Your example points me in the right direction to have the link computed properly as i want. But now i have to write a function which computes the points in the same way the points are computed for ‘regular’ links, which sounds like reinventing the wheel. So it would be really helpful to be able to simply have selflinking links behave in the exact same way as all other links, instead of overriding all functionality that make them behave differently.

I don’t think we really understand what behavior you want.

But try an override of Link.computePoints that is like:

  CustomLink.prototype.computePoints = function() {
    var fromport = this.fromPort;
    var toport = this.toPort;
    var num = this.pointsCount;
    if (fromport === toport && fromport !== null && num >= 4) {
      var oldpts = this.points;
      var ortho = false;
      var fromnode = this.fromNode;
      var fromspot = this.computeSpot(true);
      var tonode = this.toNode;
      var tospot = this.computeSpot(false);

      var fromPoint = this.getLinkPoint(fromnode, fromport, fromspot, true, ortho, tonode, toport);
      var fromDir = this.getLinkDirection(fromnode, fromport, fromPoint, fromspot, true, ortho, tonode, toport);
      var fromSeg = this.computeEndSegmentLength(fromnode, fromport, fromspot, true);
      var toPoint = this.getLinkPoint(tonode, toport, tospot, false, ortho, fromnode, fromport);
      var toDir = this.getLinkDirection(tonode, toport, toPoint, tospot, false, ortho, fromnode, fromport);
      var toSeg = this.computeEndSegmentLength(tonode, toport, tospot, false);

      var Bx = fromSeg * Math.cos(fromDir * Math.PI / 180);
      var By = fromSeg * Math.sin(fromDir * Math.PI / 180);
      var Cx = toSeg * Math.cos(toDir * Math.PI / 180);
      var Cy = toSeg * Math.sin(toDir * Math.PI / 180);
      var b = new go.Point(fromPoint.x + Bx, fromPoint.y + By);
      var c = new go.Point(toPoint.x + Cx, toPoint.y + Cy);
      this.adjustPoints(1, b, num - 2, c);
      this.setPoint(0, fromPoint);
      this.setPoint(num - 1, toPoint);
      return true;
    } else {
      return go.Link.prototype.computePoints.call(this);
    }
  };

You may need to improve the code to match your expectations.

Hi Walter,

Thanks for the code excerpt. This fixed the problem i had.

I’m sorry if it’s not clear what the problem is, so i’ll try to explain again.

We want our links to run in a straight line between two points. Like this:


Users must be able to add points to the links to reshape them as they please, like so:

With links between two different nodes this works as expected, but the links act differently when it is drawn between the same node. It is curved:

And when its reshaped it behaves very differently than links that are drawn between two nodes. it is still curved

But i want it to look like this

So with the overriding of computeCurve() and computeLinkPoints() i’m able to have self linking links behave this way, but imo it seems a bit strange to have to override these functions, because i simply want all the links to behave in the same manner, for self linking links and links that are drawn between to nodes.

I hope it is a little more clear now.
Thanks a lot for the help and the code excerpt. If i had to write it myself it would have taken me quite some time.