Changing behavior of temporary link when drawing a new link

Hello Walter,

I am stuck with the diagram.toolManager.linkingTool.temporaryLink. It always starts the links in the center of the node. My custom Link class does what I want, but how can I use it for the temporaryLink ?

I want the temporarylink also to behave like my “final” link (i.e. use the shortest path at a given x-location, see the fat blue arrow).
image

Have you set LinkingTool.temporaryLink to an instance of your custom Link class?

  $(go.Diagram, . . .,
    { . . .,
      "linkingTool.temporaryLink":
          $(CustomLink, $(go.Shape, . . .), . . .),
      . . .
    })

Yes I did.
But I don´t see the temporary link any more, when I set it to an instance of my class:
image
There is only a small pink rectangle at the destination location:
image

Here is my CustomLink class, which works fine for final links. Am I missing something, which is required for the temporary link?

export class CustomLink extends go.Link {
    public getLinkPoint(node: go.Node, port: go.GraphObject, spot: go.Spot, from: boolean, ortho: boolean, othernode: go.Node, otherport: go.GraphObject): go.Point {
        let fromRect = new go.Rect(port.getDocumentPoint(go.Spot.TopLeft),
            port.getDocumentPoint(go.Spot.BottomRight));

        if (node.category === "process") {
            let pos = 2;
            if (from && node.findLinksInto(port.portId).next()) {
                pos = 1;
            } else if (!from && node.findLinksOutOf(port.portId).next()) {
                pos = 3;
            }
            return new go.Point(fromRect.x + fromRect.width * pos / 4, fromRect.bottom);
        } else if (node.category === "line") {
            let pos = 2;
            if (from && othernode.findLinksOutOf(otherport.portId).next()) {
                pos = 3;
            } else if (!from && othernode.findLinksInto(otherport.portId).next()) {
                pos = 1;
            }
            let toRect = new go.Rect(otherport.getDocumentPoint(go.Spot.TopLeft),
                otherport.getDocumentPoint(go.Spot.BottomRight));
            let x = Math.max(fromRect.x, Math.min(fromRect.right, toRect.x + toRect.width * pos / 4));
            return new go.Point(x, fromRect.bottom);
        } else {
            return fromRect.position;
        }
    }
    public getLinkDirection(node: go.Node, port: go.GraphObject, linkpoint: go.Point, spot: go.Spot, from: boolean, ortho: boolean, othernode: go.Node, otherport: go.GraphObject) {
        return node.category === "process" ? 90 : 270;
    }
}

I think you need to make sure the LinkingTool’s temporary nodes are of the desired categories.

I´m not sure what you mean by “temporary nodes are of desired categories”.
My data model nodes which can have links have two categories: “process” and “line”.

I have set

diagram.toolManager.linkingTool = new CustomLink(); 

But the getLinkPoint function is not executed as long as the temporary link is drawn.
The function is executed on mouse up for the first time, when the link is added to model.

If the category not “process” nor “line” getLinkPoint returns the left upper corner.

Btw, here is a code pen example which shows the missing temporary link:
codepen

I meant that you need to either need to set the category for LinkingBaseTool | GoJS API and LinkingBaseTool | GoJS API, or you need to make the Link.getLinkPoint override smarter to treat the temporary nodes used during the linking operation in the way that you want.

Sorry, but it´s still unclear to me:

If I set the

 diagram.toolManager.linkingTool.temporaryFromNode.category = "process"

during my initialization, I get the error:

Uncaught TypeError: Cannot read property 'mh' of undefined at H.<anonymous> (go-debug.js:1610) at ...
If I set the temporaryFromNode.category in the doActivate(), I also get the same error.
When / where should I set the category?

I could make Link.getLinkPoint smarter, but it is not executed while temporaryLink is drawn.

Ah, that statement does indeed cause an error in 1.8, but not in 2.0.

OK, so I suggest that you take the alternative approach and change the Link.getLinkPoint code to recognize the temporary linking nodes/ports as if they had the expected category.

But the function Link.getLinkPoint is not executed for temporaryLinks. So modifying it wont change anything.

If I define a CustomLink class that overrides Link.getLinkPoint, and if I replace the LinkingTool.temporaryLink instance:

    myDiagram.toolManager.linkingTool.temporaryLink =
      $(CustomLink,
        { routing: go.Link.Orthogonal },
        $(go.Shape, { stroke: "orange", strokeWidth: 2 }),
        $(go.Shape, { toArrow: "OpenTriangle", stroke: "orange", strokeWidth: 2 }));

I find that as a user when I am drawing a new link, it’s always an orange orthogonal link. And it’s clearly calling the CustomLink's override of getLinkPoint.

got it now. I use a linkTemplateMap.

If I only set a new instance of my Link class to temporaryLink, I don´t have a template.

Is it possible to “apply” a template from linkTemplateMap to the temporaryLink?

The LinkingBaseTool.temporaryLink isn’t a modeled Part – there is no Link.data and data Bindings won’t work.

But you could make a copy of any Link that is in the Diagram.linkTemplateMap and assign it to LinkingBaseTool.temporaryLink whenever the tool isn’t running. And maybe sometimes when it is – that wasn’t something that we designed for, so I don’t know when you can exchange it for another instance of Link.