Check that text inside a table is overflowed

Hello,

I currently have a Table filled with Text on each column from an itemArray.
image

Is there a way I can check if a TextBlock inside this Table has ellipsis from
overflow: go.TextBlock.OverflowEllipsis or not?

Expected behavior:
If text inside the table is truncated with ellipsis I will add a tooltip that will show the whole text.
Otherwise, if no ellipsis - no tooltip.

Here’s an unsupported way of doing what you want, assuming only a single line of text:

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape,
      { fill: "white" },
      new go.Binding("fill", "color")),
    $(go.TextBlock,
      { name: "TB", margin: 8, width: 30, maxLines: 1, overflow: go.TextBlock.OverflowEllipsis },
      new go.Binding("text")),
    {
      toolTip:
        $("ToolTip",
          $(go.TextBlock,
            new go.Binding("text")),
          new go.Binding("visible", "adornedPart", node => {
            const m = node.findObject("TB").metrics;
            return m.arrText[0] && m.arrText[0].endsWith("...");
          }).ofObject()
        )
    }
  );

Thanks for responding.

Notes:

  1. panel.findObject(name) - “This does not recurse into the elements inside a Panel that holds elements for an itemArray.”
  2. findObject is evaluating to null here.

Question:

  1. Is there a different method I should be using for my specific use case?
  2. What would the code then look like?

Here is the TableRow + TextBlock code that I have:

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv");

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        $(go.Shape, { fill: "white" }),
        $(go.Panel, "Table",
          {
            name: "TABLE",
            margin: 4,
            itemTemplate:
              $(go.Panel, "TableRow",
                $(go.TextBlock,
                  { 
                    name: "NUMS",
                    column: 0,
                    width: 30,
                    margin: 2,
                    overflow: go.TextBlock.OverflowEllipsis,
                    wrap: go.TextBlock.None,
                    toolTip:
                        $("ToolTip",
                            $(go.TextBlock,
                                new go.Binding("text")),
                            new go.Binding("visible", "adornedPart", node => {
                                console.log(node.findObject("NUMS"))
                                const m = node.findObject("NUMS").metrics;
                                return m.arrText[0] && m.arrText[0].endsWith("...");
                            }).ofObject()
                        )
                },
                  new go.Binding("text", "name")),
              )
          },
          new go.Binding("itemArray", "items")
        )
      );

    myDiagram.model = new go.GraphLinksModel([
      { key: "Alpha", items: [
        { name: "one" },
        { name: "two" },
        { name: "three" },
        { name: "thirteen" },
        { name: "fourteen" },
        { name: "fifteen" },
        { name: "sixteen" },
        { name: "seventeen" }
      ]}
    ]);
  }

  </script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:400px"></div>
</body>
</html>

Try using “adornedObject” instead of “adornedPart”. Wait – you set the toolTip on the TextBlock, not on the item Panel. So that would make the Adornment.adornedObject the TextBlock, so you shouldn’t have to call Panel.findObject at all. The argument will be the textblock, not the node. But you do have to get its GraphObject.panel in order to get the Panel.data.

Thanks, this worked for me:

 new go.Binding("visible", "", function(adorn) {
       var x = adorn.adornedObject.metrics;
       console.log(x)

Hi Walter,

excuse me for hijacking a topic, that is already marked as solved, but I want to achieve a similar goal like @anon1, but the given solution does not work for me.

Depending on the overflow of a TextBlock, I want to hide or show another Shape.
I tried using the metrics property, but even though TextBlock contains text,
the metrics of the TextBlock do not.

The relevant code for the panel looks as follows:

$(go.Panel, 'Position',
    {
      ...
    },
    new go.Binding('opacity', '', (data, panel) => {
      const textBlock = panel.part.findObject('textBlock') as any;
      const metrics = textBlock.metrics;
      console.log(data.version, panel, textBlock, metrics);
      
      return 1;
    }),

    $(go.Shape,
      ...
    ),
  );

The output in the console looks as follows:

It can be seen, that the TextBlock Qg contains an array with the two lines, one with the ellipsis at the end. But the metrics object is an Array with size 0 and an empty text.

This is an example node, containing the TextBlock at the bottom center and the Shape at the bottom right:
Screenshot_2022-11-02_11-11-14

Can you help me with this? Thanks in advance!

Are you sure you have the right TextBlock? It isn’t shown in your template.

Oh, I am sorry. I just added the code of the Panel, that accesses the Part with the TextBlock.
Maybe a more fitting name for the variable, in which the TextBlock ist looked for, would be node.

Anyway. The Node is defined as follows (omitting the irrelevant parts):

  $(go.Node, 'Spot',
    ...
    $(go.Panel, 'Auto',
      {
        // ...
      },
      $(go.Shape, 'RoundedRectangle',
        // ...
      ),

      $(go.Panel, 'Table',
        // ...
        $(go.Panel, 'Auto',
            {
              alignment: go.Spot.Left,
              name: 'historyCommentPanel',
              padding: new go.Margin(2, 2, 0, 2),
              stretch: go.GraphObject.Fill,
            },

            $(go.TextBlock,
              {
                font: 'normal 8px Noto Sans',
                name: 'textBlock',
                overflow: go.TextBlock.OverflowEllipsis,
                textAlign: 'left',
              },
              new go.Binding('text', 'historyComment'),
            ),
        ),
        
        // ...

        $(go.Panel, 'Position',
          {
            // ...
          },
          new go.Binding('opacity', '', (data, panel) => {
              const textBlock = panel.part.findObject('textBlock') as any;
              const metrics = textBlock.metrics;
              console.log(data.version, panel, textBlock, metrics);

              return 1;
            }
          ),
          $(go.Shape,
            // ..
          ),
        )
      ),
    ),
    // ...
  );

I’m guessing that the binding is being evaluated too early for the TextBlock to have been measured and arranged yet.

Alright. But just to clarify:

How is it possible, that the correct info is already shown in the console output for the TextBlock?
Is it possible to access the information, that is displayed as attribute Wb, in another way?

I don’t think that information is available then. I suspect that your debugger is filling in that information at a later time when it does have those values.

My bad. You are right, of course. Sorry for bothering you.

I did not account for the fact, that the visibility of the tooltip is evaluated when the mouse is hovered over the GraphObject. At this time the TextBlock is already measured and arranged.

And you are also right regarding the debugger.

Thanks for your time.

I have sometimes wondered if there should be some event that is raised when a Part has finished being (panel-)laid-out, But that introduces all kinds of complications if the event handler makes changes to any of the GraphObjects in that Part that cause panel layouts to happen again.

That’s why there isn’t any such event. I suggest that you make changes “afterwards”, perhaps in a “LayoutCompleted” DiagramEvent listener. Try not to change the size of the node unless you also make sure that the diagram layout isn’t invalidated.

Yeah, that sounds more trouble than what it is worth.

Yes, this also came to my mind on my way to work. I will try that.
Thanks, again.