Getting final height in data binding function

i have a node template with a data binding function that is meant to calculate the node height using the existing height and model data.

however the only time this function is called the node hasn’t been fully drawn and the object’s actualBounds are incorrect. how can i get the final size of an object in the binding function? or do i have to use an event?

You cannot get the final height of the node when bindings are being evaluated.

Say there are several bindings in a node, and the first one wants to depend on the final actualBounds.height. But the next binding may have as a target the height of some element that will affect the height of the node, causing the first height value to be invalid. Clearly the height cannot be known until after the whole node has been measured and arranged.

I suggest that you design your node so that it naturally grows or shrinks to the height that you want. For example, in the Dynamic Ports sample, as the user keeps adding ports to either the left side or the right side of a node, the body of the node will expand in height so that there are never any ports hanging “in air”.

suggesting convoluted examples always feels like a cryptic way to answer these questions. what is the specific function that is causing the node to grow? is it the stretch parameter? is the node size somehow bound to the panels containing ports? a tiny bit of extra direction would go a long way, thanks.

Actually, I thought I was being very helpful in pointing you to an existing example of a node template that has a rectangle Shape whose height is determined by the maximum of the heights of two separate columns of ports. To me that fits the description of what you wanted.

If you want to learn more about how to determine the size of various objects in a node, please read the following Introduction pages that discuss this matter:

this behavior is precisely what i’m after. however there are over 400 lines of code in that sample of which i’m sure only 1 or 2 is relevant. furthermore, there is no computing of height anywhere. as such the mechanism for how the node’s size is variably attached to the internal panels is ambiguous. could you mention the specific part that handles this? thank you.

The node template is a “Table” Panel consisting of three rows and three columns. The main “body” is in the middle cell, with stretch: go.GraphObject.Fill. The main body is actually an “Auto” Panel with its own stuff in it. It could be arbitrarily complicated. It also has a minimum size because the “Auto” Panel’s main element has a minSize.

Each of the sides has either a “Vertical” Panel holding ports (columns 0 and 2) or a “Horizontal” Panel holding ports (rows 0 and 2).

Please read the Introduction pages about how Panels work, including the page about how objects get sizes in panels.

thanks - the stretch mechanism seems to be what i’m after. however this seems to be causing the inverted problem of stretching panels down when it shouldn’t. see what happens when only the center panel is stretched. it is stretching to the min height of the port panel instead of the center panel’s content height.

if i add stretch to the port panels also, then the port alignment defaults to the top which is also not desired behavior. i could not find a way to center the shapes within a stretched panel.

am i to assume that minSize is required on the center “Auto” panel to prevent stretching smaller than the content height? the challenge with this is that the content height of these panels is variable. the more i read and experiment the more it seems there’s no way to properly size the nodes without using some hard-coded values.

I’m not sure this embodies what you are looking for, but maybe something like this will work for you:

    myDiagram.nodeTemplate =
      $(go.Node, "Table",
        $(go.Shape, { column: 0, width: 10, height: 10 },
          new go.Binding("height", "heightL")),
        $(go.Shape, "RoundedRectangle",
          { column: 1, fill: "white", stretch: go.GraphObject.Fill }),
        $(go.Panel, "Vertical",
          { column: 1, margin: 4 },
          $(go.Shape, { width: 40, height: 40, fill: "yellow" }),
          $(go.TextBlock, new go.Binding("text"))
        $(go.Shape, { column: 2, width: 10, height: 10 },
          new go.Binding("height", "heightR"))

    myDiagram.model = new go.GraphLinksModel([
      { key: "Alpha", text: "Alpha", heightL: 10, heightR: 80 },
      { key: "Beta", text: "BetaBetaBeta" }

Note that for clarity and expediency I have replaced the Picture with a yellow Shape, and a table of ports with a single variable height Shape.

This results in:

it kinda works. but now this has introduced new problems. for one, there is now a shadow on the internal content of the node in addition to the whole node. secondly, some links go to ports and some go to the whole node. in the case of both there is overlap:

So your icon isn’t an image, OK. Set GraphObject | GoJS API.

Check your link data port identifiers. While routing a Link, it calls Node.findPort. If that returns null, it uses the default port instead.

in the above example the top link does not have a destination port. it is supposed to link directly to the node. i have specified the default port as the rounded rectangle using portId: "" on that shape. what i would like is for the link to attach above the port so there is no overlapping.

Sorry, using a “Side…” Spot only works for each individual port, not for multiple ports on a node somehow coordinating with each other. GoJS Link Connection Points on Nodes -- Northwoods Software

What you could do is have that second link connect to a regular port but have the width of that port be zero, with the regular height. That way it would appear that the link connects directly with the icon/body, yet its route would be sorted along with the rest of the links on that side.