Gojs + 2 scrolling table inside card giving wrong thumb for one scroller

Hi Guys ,

in my card there are 2 sections with data inside it and 2 sections are scrollable , one top sections has given a max height of 200 , and the other one with no height ( meaning it can take the height given for the parent node)


So here the first scrolling table normally have 3-4 cards , but the thumb in scroller indicating it have 100+items, that much small thumb .whereas when we try to click , thumb takes the actual height, whereas the other scrolling table thumb is behaving fine

Imagining my first table have only 4 items (its a scrollable table) and my 2nd table is having 50 items.

see above picture first table thumb height indicating it have more than 25 items , but actually 4 items , now when i touch the table , see the height of thumb changes


it clearly indicating number of items are less than 5

its not anything with data, but not sure. Can you help me if you understood what i am trying to achieve
Happy to explain if you need more details

Thanks

I’d like to make clear that the thumb size is based on the number of items that are visible relative to the total number of items. Their actual heights are not considered. Nor can you scroll so that only part of the top item is visible.

Does the problem happen when there is only one scrolling table? You aren’t nesting scrolling tables, are you?

I can experiment with this later today to see if there’s a bug with having two scrolling tables in a panel.

I know that the thumb does not update automatically as the number of items changes. That feature is unimplemented.

@walter yeah , thumb size is based on number of items , but thats not working when we have 2 scrolling tables in a panel. Am not nesting scrolling tables.

Just a layout of my code look like this

 $(
        go.Panel,
        'Vertical',
        $(
          go.Panel,
          'Auto',
        $(
          go.Panel,
          'Table',

        $(
          //go.Panel,
          'ScrollingTable',
          {
new go.Binding('TABLE.itemArray', 'carsOptions'),
          // new go.Binding('desiredSize', 'size').makeTwoWay(),
          {
            'TABLE.itemTemplate': $(
              go.Panel,
              'TableRow',
 ),
}
),
$(
          go.Panel,
          'Table',

        $(
          //go.Panel,
          'ScrollingTable',
          {
new go.Binding('TABLE.itemArray', 'carsSizes'),
          // new go.Binding('desiredSize', 'size').makeTwoWay(),
          {
            'TABLE.itemTemplate': $(
              go.Panel,
              'TableRow',
 ),
}
),

Can you pls experiment with this later today to see if there’s a bug with having two scrolling tables in a panel.

Thankyou

Two “ScrollingTables” in a Panel seems to work. The “thumb” isn’t always sized correctly, though.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>

  <script src="go.js"></script>
  <script src="../extensions/ScrollingTable.js"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  $(go.Diagram, "myDiagramDiv", { "undoManager.isEnabled": true });

myDiagram.nodeTemplate =
  $(go.Node, "Vertical",
    {
      selectionObjectName: "BODY",
      resizable: true, resizeObjectName: "BODY"
    },
    $(go.TextBlock, { font: "bold 12pt sans-serif" },
      new go.Binding("text")),
    $(go.Panel, "Auto",
      { name: "BODY", width: 200, height: 200 },
      $(go.Shape,
        { fill: "white" },
        new go.Binding("fill", "color")),
      $(go.Panel, "Table",
        { stretch: go.GraphObject.Fill, defaultStretch: go.GraphObject.Horizontal },
        $("ScrollingTable",
          {
            name: "SCROLLER1",
            row: 0,
            maxSize: new go.Size(NaN, 50),
            alignment: go.Spot.Top,
            defaultStretch: go.GraphObject.Horizontal,
            defaultColumnSeparatorStroke: "gray",
            defaultColumnSeparatorStrokeWidth: 0.5
          },
          new go.Binding("TABLE.itemArray", "items1"),
          new go.Binding("TABLE.column", "left", function(left) { return left ? 2 : 0; }),
          {
            "TABLE.itemTemplate":
              $(go.Panel, "TableRow",
                {
                  defaultStretch: go.GraphObject.Horizontal,
                  fromSpot: go.Spot.LeftRightSides, toSpot: go.Spot.LeftRightSides,
                  fromLinkable: true, toLinkable: true
                },
                new go.Binding("portId", "name"),
                $(go.TextBlock, { column: 0 }, new go.Binding("text", "name")),
                $(go.TextBlock, { column: 1 }, new go.Binding("text", "value"))
              ),
            "TABLE.defaultColumnSeparatorStroke": "gray",
            "TABLE.defaultColumnSeparatorStrokeWidth": 0.5,
            "TABLE.defaultRowSeparatorStroke": "gray",
            "TABLE.defaultRowSeparatorStrokeWidth": 0.5,
            "TABLE.defaultSeparatorPadding": new go.Margin(1, 3, 0, 3)
          }
        ),
        $(go.RowColumnDefinition, { row: 1, sizing: go.RowColumnDefinition.None }),
        $(go.Shape, "LineH", { row: 1, height: 0, stretch: go.GraphObject.Horizontal }),
        $("ScrollingTable",
          {
            name: "SCROLLER2",
            row: 2,
            stretch: go.GraphObject.Fill,
            defaultStretch: go.GraphObject.Horizontal,
            defaultColumnSeparatorStroke: "gray",
            defaultColumnSeparatorStrokeWidth: 0.5
          },
          new go.Binding("TABLE.itemArray", "items2"),
          new go.Binding("TABLE.column", "left", function(left) { return left ? 2 : 0; }),
          {
            "TABLE.itemTemplate":
              $(go.Panel, "TableRow",
                {
                  defaultStretch: go.GraphObject.Horizontal,
                  fromSpot: go.Spot.LeftRightSides, toSpot: go.Spot.LeftRightSides,
                  fromLinkable: true, toLinkable: true
                },
                new go.Binding("portId", "name"),
                $(go.TextBlock, { column: 0 }, new go.Binding("text", "name")),
                $(go.TextBlock, { column: 1 }, new go.Binding("text", "value"))
              ),
            "TABLE.defaultColumnSeparatorStroke": "gray",
            "TABLE.defaultColumnSeparatorStrokeWidth": 0.5,
            "TABLE.defaultRowSeparatorStroke": "gray",
            "TABLE.defaultRowSeparatorStrokeWidth": 0.5,
            "TABLE.defaultSeparatorPadding": new go.Margin(1, 3, 0, 3)
          }
        )
      )
    )
  );

const alpha = { key: 1, text: "Alpha", items1: [], items2: [] };
for (let i = 0; i < 4; i++) alpha.items1.push({ name: i.toString(), value: "item " + i});
for (let i = 100; i < 130; i++) alpha.items2.push({ name: i.toString(), value: "item " + i});

const beta = { key: 2, text: "Beta", items1: [], items2: [] };
for (let i = 0; i < 4; i++) beta.items1.push({ name: i.toString(), value: "item " + i});
for (let i = 100; i < 130; i++) beta.items2.push({ name: i.toString(), value: "item " + i});

myDiagram.model = new go.GraphLinksModel({
  linkFromPortIdProperty: "fpid",
  linkToPortIdProperty: "tpid",
  nodeDataArray: [
    alpha,
    beta
  ],
  linkDataArray: [
    { from: 1, fpid: "112", to: 2, tpid: "103" }
  ]
});
  </script>
</body>
</html>

@walter yeah The “thumb” isn’t always sized correctly, though., thats what i was trying to say . is there any help to achieve same ?

This isn’t quite right, but I think it’s better. Maybe it will help.

"use strict";
/*
*  Copyright (C) 1998-2022 by Northwoods Software Corporation. All Rights Reserved.
*/

// A "ScrollingTable" Panel

// This defines an "AutoRepeatButton" Panel,
// which is used by the scrollbar in the "ScrollingTable" Panel.

// It is basically a custom "Button" that automatically repeats its click
// action when the user holds down the mouse.
// The first optional argument may be a number indicating the number of milliseconds
// to wait between calls to the click function.  Default is 50.
// The second optional argument may be a number indicating the number of milliseconds
// to delay before starting calls to the click function.  Default is 500.

// Example:
//   $("AutoRepeatButton", 150,  // slower than the default 50 milliseconds between calls
//     {
//       click: function(e, button) { doSomething(button.part); }
//     },
//     $(go.Shape, "Circle", { width: 8, height: 8 })
//   )
go.GraphObject.defineBuilder("AutoRepeatButton", function(args) {
  var repeat = go.GraphObject.takeBuilderArgument(args, 50, function(x) { return typeof x === "number"; });
  var delay = go.GraphObject.takeBuilderArgument(args, 500, function(x) { return typeof x === "number"; });
  var $ = go.GraphObject.make;
  // some internal helper functions for auto-repeating
  function delayClicking(e, obj) {
    endClicking(e, obj);
    if (obj.click) {
      // wait milliseconds before starting clicks
      obj._timer = setTimeout(function() { repeatClicking(e, obj); }, delay);  
    }
  }
  function repeatClicking(e, obj) {
    if (obj._timer) clearTimeout(obj._timer);
    if (obj.click) {
      obj._timer =
        setTimeout(function() {
                     if (obj.click) {
                       (obj.click)(e, obj);
                       repeatClicking(e, obj);
                     }
                   },
                   repeat);  // milliseconds between clicks
    }
  }
  function endClicking(e, obj) {
    if (obj._timer) {
      clearTimeout(obj._timer);
      obj._timer = undefined;
    }
  }

  var button = $("Button",
           {
             "ButtonBorder.figure": "Rectangle",
             "ButtonBorder.fill": "transparent",
             "ButtonBorder.stroke": null,
             "_buttonFillOver": "rgba(0, 0, 0, .25)",
             "_buttonStrokeOver": null,
             cursor: "auto"
           });
  // override the normal button actions
  var btndown = button.actionDown;
  var btnup = button.actionUp;
  var btncancel = button.actionCancel;
  button.actionDown = function(e, btn) {
    delayClicking(e, btn);
    if (btndown) btndown(e, btn);
  };
  button.actionUp = function(e, btn) {
    endClicking(e, btn);
    if (btnup) btnup(e, btn);
  };
  button.actionCancel = function(e, btn) {
    endClicking(e, btn);
    if (btncancel) btncancel(e, btn);
  };
  return button;
});


// Create a "Table" Panel that supports scrolling.
// This creates a Panel that contains the "Table" Panel whose topIndex is modified plus a scroll bar panel.
// That "Table" Panel is given a name that is given as the optional first argument.
// If not given the name defaults to "TABLE".

// The scroll bar panel is named "SCROLLBAR".
// It has three pieces, the "UP" "AutoRepeatButton", the "THUMB", and the "DOWN" "AutoRepeatButton".
// The scroll bar can be on either side of the "Table" Panel; it defaults to being on the right side.
// The side is controlled by whether the column of the "Table" Panel is 0 (the default) or 2.

// Example use:
//   $("ScrollingTable", "TABLE",
//     new go.Binding("TABLE.itemArray", "someArrayProperty"),
//     ...)

// Note that if you have more than one of these in a Part,
// you'll want to make sure each one has a unique name.
go.GraphObject.defineBuilder("ScrollingTable", function(args) {
  var $ = go.GraphObject.make;
  var tablename = go.GraphObject.takeBuilderArgument(args, "TABLE");

  // an internal helper function used by the THUMB for scrolling to a Y-axis point in local coordinates
  function setScrollIndexLocal(bar, y) {
    // may be called with the "SCROLLBAR" panel or any element within it
    while (bar && bar.name !== "SCROLLBAR") bar = bar.panel;
    if (!bar) return;
    var table = bar.panel.findObject(tablename);
    if (!table) return;

    var up = bar.findObject("UP");
    var uph = up ? up.actualBounds.height : 0;

    var down = bar.findObject("DOWN");
    var downh = down ? down.actualBounds.height : 0;

    var tabh = bar.actualBounds.height;
    var idx = Math.round(Math.max(0, Math.min(1, (y - uph) / (tabh - uph - downh))) * table.rowCount);
    incrTableIndex(bar, idx - table.topIndex);
  }

  // an internal helper function used by the UP and DOWN buttons for relative scrolling
  // the OBJ may be the "SCROLLBAR" panel or any element within it
  function incrTableIndex(obj, i) {
    var diagram = obj.diagram;
    var table = obj;
    while (table && table.name !== "SCROLLBAR") table = table.panel;
    if (table) table = table.panel.findObject(tablename);
    if (!table) return;
    if (i === +Infinity || i === -Infinity) {  // page up or down
      var tabh = table.actualBounds.height;
      var rowh = table.elt(table.topIndex).actualBounds.height;  // assume each row has same height?
      if (i === +Infinity) {
        i = Math.max(1, Math.ceil(tabh / rowh) - 1);
      } else {
        i = -Math.max(1, Math.ceil(tabh / rowh) - 1);
      }
    }
    var idx = table.topIndex + i;
    if (idx >= table.rowCount - 1) idx = table.rowCount - 1;
    if (idx < 0) idx = 0;
    if (table.topIndex !== idx) {
      if (diagram !== null) diagram.startTransaction("scroll");
      table.topIndex = idx;
      var node = table.part;  // may need to reroute links if the table contains any ports
      if (node instanceof go.Node) node.invalidateConnectedLinks();
      updateScrollBar(table);
      if (diagram !== null) diagram.commitTransaction("scroll");
    }
  }

  // must be passed either the "ScrollingTable" Panel, or the "Table" Panel that holds the rows
  // that are scrolled (i.e. adjusting topIndex), or the "SCROLLBAR" Panel
  function updateScrollBar(table) {
    if (!(table instanceof go.Panel) || table.type !== go.Panel.Table) return;
    if (table.part) table.part.ensureBounds();
    if (table.name !== tablename) {
      while (table && !table._updateScrollBar) table = table.panel;
      if (!table) return;
      table = table.findObject(tablename);
    }

    // the scrollbar is a sibling of the table
    var bar = table.panel.findObject("SCROLLBAR");
    if (!bar) return;
    var idx = table.topIndex;

    var up = bar.findObject("UP");
    var uph = 0;
    if (up) {
      up.opacity = (idx > 0) ? 1.0 : 0.3;
      uph = up.actualBounds.height;
    }

    var down = bar.findObject("DOWN");
    var downh = 0;
    if (down) {
      down.opacity = (idx < table.rowCount - 1) ? 1.0 : 0.3;
      downh = down.actualBounds.height;
    }

    var thumb = bar.findObject("THUMB");
    var tabh = bar.actualBounds.height;
    var availh = Math.max(0, (tabh - uph - downh));
    if (table.rowCount <= 0) {
      if (thumb) thumb.height = Math.min(availh, 10);
      return;
    }
    var rows = 0;
    var rowh = 1;
    var last = idx;
    for (var i = idx; i < table.rowCount; i++) {
      var h = table.elt(i).actualBounds.height;
      if (h > 0) { rows++; rowh += h; last = i; }
    }
    var needed = idx > 0 || last < table.rowCount-1;
    bar.opacity = needed ? 1.0 : 0.5;
    if (thumb) {
      thumb.height = Math.max((rows / table.rowCount) * availh, Math.min(availh, 10));
      thumb.alignment = new go.Spot(0.5, (Math.min(table.rowCount, (idx+0.5)) / table.rowCount), 0, 0);
    }
  }

  // must be called with the "SCROLLBAR" panel
  function showScrollButtons(bar, show) {
    if (!bar || bar.name !== "SCROLLBAR") return;
    var table = bar.panel.findObject(tablename);
    if (!table) return;
    var idx = table.topIndex;

    var up = bar.findObject("UP");
    if (up) up.opacity = show ? ((idx > 0) ? 1.0 : 0.3) : 0.0;

    var down = bar.findObject("DOWN");
    if (down) down.opacity = show ? ((idx < table.rowCount - 1) ? 1.0 : 0.3) : 0.0;

    var thumb = bar.findObject("THUMB");
    if (thumb) thumb.opacity = table.rowCount > 0 ? 1 : 0;
  }

  return $(go.Panel, "Table",
      { // in case external code wants to update the scrollbar
        _updateScrollBar: updateScrollBar,
        mouseEnter: function(e, table) { table._updateScrollBar(table); }
      },

      // this actually holds the item elements
      $(go.Panel, "Table",
        {
          name: tablename,
          column: 0,
          stretch: go.GraphObject.Fill,
          background: "whitesmoke",
          rowSizing: go.RowColumnDefinition.None,
          defaultAlignment: go.Spot.Top
        }),

      // this is the scrollbar
      $(go.RowColumnDefinition,
        { column: 1, sizing: go.RowColumnDefinition.None }),
      $(go.Panel, "Table",
        { name: "SCROLLBAR", column: 1, stretch: go.GraphObject.Vertical, background: "#DDDDDD",
          mouseEnter: function(e, bar) { showScrollButtons(bar, true); },
          mouseLeave: function(e, bar) { showScrollButtons(bar, false); }
        },

        // the scroll up button
        $("AutoRepeatButton",
          { name: "UP", row: 0, opacity: 0,
            click: function(e, obj) { e.handled = true; incrTableIndex(obj, -1); }
          },
          $(go.Shape, "TriangleUp",
            { stroke: null, desiredSize: new go.Size(6, 6) })),
        $(go.RowColumnDefinition, { row: 0, sizing: go.RowColumnDefinition.None }),

        { // clicking in the bar scrolls directly to that point in the list of items
          click: function(e, bar) {
            e.handled = true;
            var local = bar.getLocalPoint(e.documentPoint);
            setScrollIndexLocal(bar, local.y);
          }
        },

        // the scroll thumb, gets all available extra height
        $(go.Shape,
          { name: "THUMB", row: 1,
            stretch: go.GraphObject.Horizontal, height: 10,
            margin: new go.Margin(0, 2),
            fill: "gray", stroke: "transparent",
            alignment: go.Spot.Top, alignmentFocus: go.Spot.Top,
            mouseEnter: function(e, thumb) { thumb.stroke = "gray"; },
            mouseLeave: function(e, thumb) { thumb.stroke = "transparent"; },
            isActionable: true,
            actionMove: function(e, thumb) {
              var local = thumb.panel.getLocalPoint(e.documentPoint);
              setScrollIndexLocal(thumb, local.y);
            },
          }),
        $(go.RowColumnDefinition, { row: 1, stretch: go.GraphObject.Vertical }),

        // the scroll down button
        $("AutoRepeatButton",
          { name: "DOWN", row: 2, opacity: 0,
            click: function(e, obj) { e.handled = true; incrTableIndex(obj, +1); }
          },
          $(go.Shape, "TriangleDown",
            { stroke: null, desiredSize: new go.Size(6, 6) })),
        $(go.RowColumnDefinition, { row: 2, sizing: go.RowColumnDefinition.None })
      )
    );
});

There’s also a TypeScript version, if you want. These changes will be in the next release.

@walter Sorry for the delay in coming back to this . was stuck with some other issues.
I have couple of issues in introducing the scroll bar

  1. Can we show this scrollbar only when mouse enters in to that particular ScrollingTable panel. if no mouse enters it wont show the scrollbar or even the trackpad, only will be visible when it enters to that particular section

2.Also when introduced ScrollingTable , also introduced mouse wheel scroll up and down , when move up and down using scrollbar ,white space getting appended on the bottom of the scrolling table.so keep on moving up and down will increase the height of the table ? if need i can share the code

  1. Sure, just control its opacity in mouseEnter and mouseLeave event handlers. But remember that those events aren’t too useful on touch devices.

  2. It’s unclear what you are trying to say. You can disable that mouse wheel event handling if you like. I don’t see the height of the panel changing as I scroll up and down in the sample: Scrolling Table

@walter Do need mouse wheel scroll up and down feature , but each time when i scroll up and down using mouse wheel , that height of particular node increases.
Note am using 2 scrolling table in my nodes.is that the issue , second scrolling table always increases its height when we do up and down using mouse wheel

    diagram.toolManager.doMouseWheel = function () {
      // method override
      let e = this.diagram.lastInput;
      let tab = this.diagram.findObjectAt(e.documentPoint);
      while (tab !== null && !tab._updateScrollBar) tab = tab.panel;
      if (tab !== null) {
        let table = tab.findObject('TABLE');
        if (table) {
          let delta = e.delta;
          let incr = e.shift ? 5 : 1;
          if (delta > 0) {
            table.topIndex = Math.max(0, table.topIndex - incr);
          } else if (delta < 0) {
            table.topIndex = Math.min(table.topIndex + incr, table.rowCount - 1);
          }
        }
        tab._updateScrollBar(table);
        e.handled = true;
        return;
      }
      go.ToolManager.prototype.doMouseWheel.call(this);
    };

and my scrolling table look like

$(
          //go.Panel,
          'ScrollingTable',
          {
            name: 'PROPERTIES',
            stretch: go.GraphObject.Fill,
            defaultAlignment: go.Spot.Left,
            defaultColumnSeparatorStroke: 'gray',
            defaultRowSeparatorStroke: 'gray',
            width: 271,
            margin: new go.Margin(0, 0, 5, 0),
          },
          new go.Binding('visible', 'properties', (arr) => arr.length > 0),
          new go.Binding('TABLE.itemArray', 'properties'),
          {
            'TABLE.itemTemplate': $(
              go.Panel,
              'TableRow',
              // this Panel is a row in the containing Table
              new go.Binding('portId', 'id'), // this Panel is a "port"
              {
                fromSpot: go.Spot.LeftRightSides,
                toSpot: go.Spot.LeftRightSides,
                // allow drawing links from or to this port:
                fromLinkable: true,
                toLinkable: true,
                fromLinkableDuplicates: true,
              },
              $(
                go.Panel,
                'Vertical',
                $(
                  go.Panel,
                  'Horizontal',
                  { stretch: go.GraphObject.Horizontal },
                  $(
                    go.Panel,
                    'Horizontal',
                  ),
                  $(
                    go.TextBlock,
                    { stretch: go.GraphObject.Horizontal },
                    {
                      column: 1,
                      stroke: '#161616',
                      alignment: go.Spot.Left,
                      margin: new go.Margin(15, 5, 5, 18),
                    },
                    new go.Binding('text', 'name'),

                  )
                ),
                $(
                  go.TextBlock,
                  { stretch: go.GraphObject.Horizontal },
                  {
                    column: 2,
                    stroke: '#525252',
                    alignment: go.Spot.Left,
                    margin: new go.Margin(-1, 5, 5, 18),
                  },
                  new go.Binding('width', 'desiredSize').makeTwoWay(),
                  new go.Binding('text', '', function (data) {
                    return data.value
                  }),
 
                )
              )
            )

@walter also to hide scrollbar on mouse out and show on mouse enter. where we need to give the opacity property. As above you can see my code , will be helpful if you can tell where to hide trackpad and up/down arrows

That looks OK, but I thought you said you had two "ScrollingTable"s.

I’m surprised you didn’t post before-and-after screenshots of the behavior that you didn’t like.

@walter i can share the screenshot in a while . between would you mind to help with code to hide/show the mouse trackpad on mouse enter and leave on above code , if you dont mind

It’s quite straight-forward. What have you tried, and how did it not work the way that you wanted?

@walter was wondering whether we need to make change in scrollingtable.js or not

It probably isn’t required. What did you do, and what was the problem?

@walter may be i am wrong but what i am trying to give is

$(
          //go.Panel,
          'ScrollingTable',
          {
          name:'PROPERTIES',
          mouseEnter: function (e, node) {
          node.findObject('SCROLLBAR').opacity = '1.0'; 

        },
          mouseLeave: function (e, node) {
          node.findObject('SCROLLBAR').opacity = '0.0'; 

        },


Not sure this is what we intended to do , but thought to ask you guys before implementing>
BUt i can ee the scroll section visible even if i do this , only the track gets hidden, i need to remove that space that is offered for trackpad and when you mouse over , everything has to be visible

opacity must be a number from 0 to 1, inclusive: GraphObject | GoJS API

But you could try changing its visible property true or false. However that will cause the panel to change size, which may have other side-effects.

infact both give same effect , but my question is am seeing the rectangle vertical section ,i mean the vertical rectangle section is visible with no thumb

See the above screenshot is with opacity 0 , but here i can see vertical rectangle section , can we hide that , no longer need that


This is with opacity 1 , behaving as expected.
Also on initial page load am seeing thumb as well, thats not expected
What i am expecting is a scrollbar that float on the content when you mouse over

if it cause the panel to change its width and causes some other issues , then i will park it for sometime.
Can we look the other issue , which is bit problematic , 2 scrolling table inside a panel causes the second scrolling table to increase its height when you do mouse wheel up and down.

here in the screenshot if you can check the second scroll section , you can see 6 dark rectangle section and it fit to height

Now i keep on scrolling up and down white space after sixth cards get accumulated. so height increases dynamically for no reason.

I BELIEVE you will encounter when you have 2 scrolling tables inside a card and issue is with second scrolling table. can you please check and help on same
@walter help will be highly helpful

How have you defined the Panel that holds the two "ScrollingTable"s?

Here’s what I tried:

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>

  <script src="https://unpkg.com/gojs"></script>
  <script src="https://unpkg.com/gojs/extensions/ScrollingTable.js"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      "PartResized": e => {
        const table = e.subject.findObject("SCROLLER2");
        if (table && table._updateScrollBar) table._updateScrollBar(table);
      },
      "undoManager.isEnabled": true
    });

myDiagram.nodeTemplate =
  $(go.Node, "Vertical",
    {
      selectionObjectName: "BODY",
      resizable: true, resizeObjectName: "BODY"
    },
    $(go.TextBlock, { font: "bold 12pt sans-serif" },
      new go.Binding("text")),
    $(go.Panel, "Auto",
      { name: "BODY", width: 200, height: 200 },
      $(go.Shape,
        { fill: "white" },
        new go.Binding("fill", "color")),
      $(go.Panel, "Table",
        { stretch: go.GraphObject.Fill, defaultStretch: go.GraphObject.Horizontal },
        $("ScrollingTable",
          {
            name: "SCROLLER1",
            row: 0,
            maxSize: new go.Size(NaN, 50),
            alignment: go.Spot.Top,
            defaultStretch: go.GraphObject.Horizontal,
            defaultColumnSeparatorStroke: "gray",
            defaultColumnSeparatorStrokeWidth: 0.5
          },
          new go.Binding("TABLE.itemArray", "items1"),
          new go.Binding("TABLE.column", "left", function(left) { return left ? 2 : 0; }),
          {
            "TABLE.itemTemplate":
              $(go.Panel, "TableRow",
                {
                  defaultStretch: go.GraphObject.Horizontal,
                  fromSpot: go.Spot.LeftRightSides, toSpot: go.Spot.LeftRightSides,
                  fromLinkable: true, toLinkable: true
                },
                new go.Binding("portId", "name"),
                $(go.TextBlock, { column: 0 }, new go.Binding("text", "name")),
                $(go.TextBlock, { column: 1 }, new go.Binding("text", "value"))
              ),
            "TABLE.defaultColumnSeparatorStroke": "gray",
            "TABLE.defaultColumnSeparatorStrokeWidth": 0.5,
            "TABLE.defaultRowSeparatorStroke": "gray",
            "TABLE.defaultRowSeparatorStrokeWidth": 0.5,
            "TABLE.defaultSeparatorPadding": new go.Margin(1, 3, 0, 3)
          }
        ),
        $(go.RowColumnDefinition, { row: 1, sizing: go.RowColumnDefinition.None }),
        $(go.Shape, "LineH", { row: 1, height: 0, stretch: go.GraphObject.Horizontal }),
        $("ScrollingTable",
          {
            name: "SCROLLER2",
            row: 2,
            stretch: go.GraphObject.Fill,
            defaultStretch: go.GraphObject.Horizontal,
            defaultColumnSeparatorStroke: "gray",
            defaultColumnSeparatorStrokeWidth: 0.5
          },
          new go.Binding("TABLE.itemArray", "items2"),
          new go.Binding("TABLE.column", "left", function(left) { return left ? 2 : 0; }),
          {
            "TABLE.itemTemplate":
              $(go.Panel, "TableRow",
                {
                  defaultStretch: go.GraphObject.Horizontal,
                  fromSpot: go.Spot.LeftRightSides, toSpot: go.Spot.LeftRightSides,
                  fromLinkable: true, toLinkable: true
                },
                new go.Binding("portId", "name"),
                $(go.TextBlock, { column: 0 }, new go.Binding("text", "name")),
                $(go.TextBlock, { column: 1 }, new go.Binding("text", "value"))
              ),
            "TABLE.defaultColumnSeparatorStroke": "gray",
            "TABLE.defaultColumnSeparatorStrokeWidth": 0.5,
            "TABLE.defaultRowSeparatorStroke": "gray",
            "TABLE.defaultRowSeparatorStrokeWidth": 0.5,
            "TABLE.defaultSeparatorPadding": new go.Margin(1, 3, 0, 3)
          }
        )
      )
    )
  );

const alpha = { key: 1, text: "Alpha", items1: [], items2: [] };
for (let i = 0; i < 4; i++) alpha.items1.push({ name: i.toString(), value: "item " + i});
for (let i = 100; i < 130; i++) alpha.items2.push({ name: i.toString(), value: "item " + i});

const beta = { key: 2, text: "Beta", items1: [], items2: [] };
for (let i = 0; i < 4; i++) beta.items1.push({ name: i.toString(), value: "item " + i});
for (let i = 100; i < 130; i++) beta.items2.push({ name: i.toString(), value: "item " + i});

myDiagram.model = new go.GraphLinksModel({
  linkFromPortIdProperty: "fpid",
  linkToPortIdProperty: "tpid",
  nodeDataArray: [
    alpha,
    beta
  ],
  linkDataArray: [
    { from: 1, fpid: "112", to: 2, tpid: "103" }
  ]
});
  </script>
</body>
</html>