Get Node spot from part spot, for link target

Question: Given a named part being used as a port, how can I quickly set the node fromSpot to the port-part’s right hand edge ?

Scenario: As per the image below, I have nodes made of several parts. In each node two of the parts are ports (portId values set), shown as black and red in the image. I want to have links to/from the node connecting to these ports which the docs say I can do by setting the node.fromSpot and node.toSpot to the edge of the ports. The problem is how to know the node spot positions for the ports. The lowest node has a blue box to represent the node outline, and the red boxes represent panels within the node. The node’s main part is a panel.Table and the red boxes are panels with column values 0, 1 and 2. The overall aim is to get the links, currently linking to the edges of the node, to link across the text to the red and black circles. I have tried using

part.getDocumentPoint(go.Spot.MiddleLeft)

where part is, for example, the black circle port, to get the spot in document co-ordinates but I believe that I really need it in node co-ordinates. Any suggestions ?

I’m not sure I understand. It sounds like you really want the black circle and the red circle to be the two ports. If that’s the case, move the portId declaration from whatever they are now on to those two circle Shapes.

Yeah sorry, I was trying to be precise but realise it reads a bit heavy.

The red and black circle are already ports - I can click and drag a link out of them as I want, its more about where the links connect when I move the nodes around. If I understand correctly I need to alter the linking points for the node by setting the node.fromSpot & toSpot, as in the second example on the linked page…

  $(go.Node, "Auto",
      { fromSpot: go.Spot.Right,  // coming out from middle-right
        toSpot: go.Spot.Left },   // going into at middle-left
        ....

…but my issue is how to set those spots. I don’t know the width of the red rectangle to the left of the task bar - it’s just a panel with some text that auto-sizes to whatever text it holds, same for right hand text. Otherwise I could compute the spots myself. Hence looking at getDocumentPoint.

Oh, so you want to have the arrowhead at the black circle, but you also want the link shape’s route to extend towards the left far enough to include the full length (plus a little bit) of the textblock label? If so, I think you get that behavior automatically by setting the Link.routing to be AvoidsNodes.

But you’ll need to deal with either the link shape crossing over the text, thereby obscuring the text, or behind the node, thereby causing the link to mostly disappear there (assuming the node has transparent or no backgrounds).

By the way, most of those “from…” and “to…” properties have no effect except on GraphObjects whose portId has been set or bound to be non-null. So if the whole Node is not acting as a port, setting Node.fromSpot has no effect.

Hmm - just stripped out the node into a CodePen to play with it and it seems that I have a problem that makes the .getDocumentPoint(go.Spot.TopLeft) always return a (0,0) value.

I will strip my code back and see what causes the issue.

Re the AvoidsNodes etc, thanks for that, I will be able to make a decision on that and the text/link interference when I have links hitting the ports. I’ll let you know.

After looking further in to my case I discovered that because my model is detailed, the nodes being added in code via the model were not put in place on the diagram before I read their locations. The way I think about it a big model with a lot of diagram nodes & parts takes a few milliseconds to draw when refreshing, which makes sense. I modified my code to wait for the “LayoutCompleted” DiagramEvent and after that the positions were more sensible.

In the screen grab of my diagram below, the nodes that are the ‘task bars’ of the chart include the text on the left and right of the bar. The requirement was to have the links come from the red dot and go to the black dot. To achieve this I had hoped for a built-in function but ultimately had to do the math myself then set the node.fromSpot and node.toSpot values by computing the fractional distance of each dot as a proportion of the full node width.

The math involved using

var nodeX = node.getDocumentPoint(go.Spot.TopLeft).x  // get left edge of node on diagram.
var nodeW = node.actualBounds.width  // get node width
var portInX = portIn.getDocumentPoint(go.Spot.TopLeft).x // get left edge of inbound port on diagram.

then

node.toSpot = new go.Spot(  (portInX - nodeX) / nodeW, 0.5) 

and repeat for node.fromSpot for the port out.

I have further questions about modifying the link path to stop it covering the text, but will ask as another topic.

Hmmm. It appears that you are being inconsistent with your treatment of ports. You say that you have set the GraphObject.portId of the black circle and the red circle. Yet you are also setting the GraphObject.toSpot on the whole Node, implying that you are using the whole Node as a port element.

I suppose that might work out OK for your app, but I can imagine other circumstances where that could produce inconsistencies.

I’m wondering if it would be more sensible to have each label be a piece of the corresponding port. That would avoid the problem with having the link cross over the label text. And you could still have only the circle Shape be where the user can start drawing a new link by setting GraphObject.fromLinkable and GraphObject.toLinkable to false on the TextBlock within the new port, which would now be a Horizontal Panel.

I am connecting one shape to another through port but i want that port sholud be connect to shape boundary.
hence in shape’s style i mentioned portid="".But after that problem resolved.But whole shape considered as port.