Self loop link shape


I have been trying to change the look of Self looping which is used in our application. In our case, the self loop looks like a straight line when drawn

During the self loop draw, the link positions itself perfectly,

But after I release the mouse the link draws itself like this

But we wanted to have the link to look same like the previous one even after I release the mouse.

Can you let me know how can we solve this problem.

I don’t see what the problem is. I just tried a simple app:

    myDiagram.nodeTemplate =
      $(go.Node, "Spot",
        $(go.Panel, "Auto", { width: 100, height: 40 },
          $(go.Shape, "RoundedRectangle", { fill: "gold" }),
          $(go.TextBlock, new go.Binding("text", "key"))
        $(go.Shape, {
          width: 10, height: 10, fill: "transparent",
          alignment: go.Spot.Top, alignmentFocus: go.Spot.Top,
          portId: "in", toSpot: go.Spot.Top,
          toLinkable: true, toLinkableSelfNode: true
        $(go.Shape, {
          width: 10, height: 10, fill: "transparent",
          alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Bottom,
          portId: "out", fromSpot: go.Spot.Bottom,
          fromLinkable: true, fromLinkableSelfNode: true

    myDiagram.linkTemplate =
        { routing: go.Link.Orthogonal, fromPortId: "out", toPortId: "in", corner: 10 },
        $(go.Shape, { toArrow: "OpenTriangle" })

    myDiagram.model = $(go.GraphLinksModel,
        linkFromPortIdProperty: "out",
        linkToPortIdProperty: "in",
            { key: "Beta" }

Running this and drawing a new link from the bottom port to the top port results in:

If you want the temporary Link that the user modifies during the LinkingTool operation, you can do things such as:

myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal;

Read more at GoJS Tools -- Northwoods Software

Yes, I have the same code. Is there any setting which removes extra points from the link ?

I was debugging the code in browser and found this line is the problem.

After this line is executed, the link is converted to straight line. Any help would help me save time.

The code that produces the link is :

` this.graph.linkTemplate = this.diagram(go.Link,
          routing: go.Link.AvoidsNodes,  // may be either Orthogonal or AvoidsNodes
          curve: go.Link.JumpOver,
          corner: 5, 
          relinkableFrom: true,
          relinkableTo: true,
          reshapable: true,
          resegmentable: true

      this.diagram(go.Shape, { toArrow: "Standard" })
    this.graph.toolManager.linkingTool.temporaryLink.routing = go.Link.AvoidsNodes;
    this.graph.toolManager.relinkingTool.temporaryLink.routing = go.Link.AvoidsNodes;`

I’m sorry, but I tried with your link template in both 1.6 and 1.7, and I was unable to reproduce any routing problem with drawing a new link.


I was trying to do the same, but somehow could not find the issue where it might be doing this. I can assure that no code written by us is doing this.

You can check the deployed version here :

If you just create a self loop for Get / Process, it will show you the link as per intended, but it will straighten after it opens the popup.

Can you please help if there is a configuration or so which does this ?

I believe that the line that you executed (beginning with a.Ca("LinkDrawn",h))...) raises the “LinkDrawn” DiagramEvent, which calls your linkUpdate function, in which you nicely provided a debugger; breakpoint. After that it stops the LinkingTool.

But I don’t understand how your code is working at all. In that linkUpdate function:
var currentLink = myGraph.getCurrentlink();
could be better written:
var currentLink =;

Then the next two lines are not only extremely inefficient, but they could be causing identity problems.
In var linkDataArray = JSON.parse(myGraph.getModelJson()).linkDataArray; you really should not be re-parsing a string to get a new Array of link data objects. You can get the real Array via e.diagram.model.linkDataArray. No parsing or allocation needed. Same goes for the next line.

Then this: var fromNode = getNode(nodeDataArray, currentLink.from); could be more efficiently and more correctly be done with: var fromNode = e.diagram.model.findNodeDataForKey(currentLink.from);. Same goes for the next line.

I’m concerned that your Diagram is not working with the model data objects for Nodes and Links that you think it is working with. I’m not sure that that answers your question, but it’s suspicious.

Thanks for letting me know. We were not having much of idea about the API, will surely be optimizing the code for sure.

The line where it actually removes the point is here :

I have commented out the whole thing inside LinkDrawn function from WorkflowNew.js but it still does the same thing.

You can see the latest code here :

I found the problem. Your ports are not at or sufficently near to the top and bottom edges of the node. Apparently if the ports are “inside” the node by some margin, the routing will be different.

So a work-around is to change your node template so that the top ports are at the top of the node and that the bottom ports are at the bottom of the node.

An easier work-around, and maybe the right solution anyway, is to increase the GraphObject.fromEndSegmentLength on “out” ports and GraphObject.toEndSegmentLength on “in” ports so that the point of the end segment (either the first segment or the last segment) is sufficiently outside of the node’s bounds. The default values are 10. I don’t know how much your ports are inset into the nodes, but if you increased the values to 12 it might be enough.

Wohoo… You have solved one of the long pain area. The problem is solved by just adding 12 to those two properties on the port. Thank you so much.

BTW, few days back I was thinking to shift the ports to an Adornment layer where the nodes will be outside the nodes, do you think it would be right approach to go, or the template we are using is fine .?

Port elements need to be in the visual tree of their Nodes. So they really cannot belong to other Parts, including Adornments.

Keep things as simple as they can be. If some standard feature isn’t simple when using GoJS, maybe you’re doing the wrong thing. Probably you just need to use properties or methods you didn’t know about.

Thank you walter. :)