Treelayout for PlaceHolder with scrollbar

Hi walter,

Please find group Template and scrollingtablelayout code. i am expecting to have a TreeLayout for nodes in placeholder with scrolling Bar?

myDiagram.groupTemplate =
            $$(go.Group, "Auto",
                    {
                        //layout: makeLayout(false),
                        background: "transparent",
                        selectionObjectName: "SIZED",
       resizable: true, resizeObjectName: "SIZED",
       layout: $$(ScrollingGroupLayout),

                        ungroupable: true,
                    },
//                                new go.Binding("layout", "horiz", makeLayout), // Uncomment this for TreeLayout in PlaceHolder
                    new go.Binding("isSubGraphExpanded", "isSubGraphExpanded"),
                    $$(go.Shape, "RoundedRectangle", {
                        portId: "",
                        fromSpot: go.Spot.Right,
                        toSpot: go.Spot.Left
//                        ,height:100
                    },
                            {fill: null, stroke: defaultColor(false), strokeWidth: 2},
                            new go.Binding("stroke", "horiz", defaultColor),
                            new go.Binding("stroke", "color"))
                    , $$(go.Panel, "Vertical",{name: "SIZED"}, new go.Binding("background", "horiz", backgroundColor),
                            $$(go.Panel, "Horizontal",
                                    {stretch: go.GraphObject.Horizontal, background: defaultColor(false)},
                                    new go.Binding("background", "horiz", defaultColor),
                                  //  new go.Binding("height", "horiz", defaultHeight),
                                    new go.Binding("background", "color"),
                                    $$("SubGraphExpanderButton",
                                            {alignment: go.Spot.Right, margin: 5}),
                                    $$(go.TextBlock,
                                            {
                                                alignment: go.Spot.Left,
                                                editable: true,
                                                margin: 5,
                                                font: defaultFont(false),
                                                opacity: 0.75,
                                            },
                                            new go.Binding("stroke", "horiz", fontColor),
                                            new go.Binding("font", "horiz", defaultFont),
                                            new go.Binding("text", "text").makeTwoWay())
                                    ),
                                    $$(go.Panel, "Horizontal",
     {

       desiredSize: new go.Size(NaN, 200),
       minSize: new go.Size(0, 0)
     },

     $$(go.Placeholder,
          ),
             $$("AutoRepeatButton",
               { name: "UP", alignment: go.Spot.TopRight },
               $$(go.Shape, "TriangleUp", { width: 6, height: 6 }),
               {
                 click: function(e, button) {
                   var group = button.part;
                   var lay = group.layout;
                   if (lay.lastIndex < lay.count - 1) {
                     lay.topIndex++;
                   }
                 }
               }),
             $$("AutoRepeatButton",
               { name: "DOWN", alignment: go.Spot.BottomRight },
               $$(go.Shape, "TriangleDown", { width: 6, height: 6 }),
               {
                 click: function(e, button) {
                   var group = button.part;
                   var lay = group.layout;
                   if (lay.topIndex > 0) {
                     lay.topIndex--;
                   }
                 }
               })
),

   )

                    );

Find the scrollinggrouplayout:

function ScrollingGroupLayout() {
   go.Layout.call(this);
   this._topIndex = 0;
   this._spacing = 10;
   this._count = 0;
   this._lastIndex = 0;
 }
 go.Diagram.inherit(ScrollingGroupLayout, go.TreeLayout);

 ScrollingGroupLayout.prototype.cloneProtected = function(copy) {
   go.Layout.prototype.cloneProtected.call(this, copy);
   copy._topIndex = this._topIndex;
   copy._spacing = this._spacing;
 };

 Object.defineProperty(ScrollingGroupLayout.prototype, "topIndex", {
   get: function() { return this._topIndex; },
   set: function(val) {
     if (typeof val !== "number") throw new Error("new value for ScrollingGroupLayout.topIndex is not a number: " + val);
     if (this._topIndex !== val) {
       this._topIndex = val;
       this.invalidateLayout();
     }
   }
 });

 Object.defineProperty(ScrollingGroupLayout.prototype, "spacing", {
   get: function() { return this._spacing; },
   set: function(val) {
     if (typeof val !== "number") throw new Error("new value for ScrollingGroupLayout.spacing is not a number: " + val);
     if (this._spacing !== val) {
       this._spacing = val;
       this.invalidateLayout();
     }
   }
 });

 Object.defineProperty(ScrollingGroupLayout.prototype, "count", {
   get: function() { return this._count; }
 });

 Object.defineProperty(ScrollingGroupLayout.prototype, "lastIndex", {
   get: function() { return this._lastIndex; }
 });

 ScrollingGroupLayout.prototype.doLayout = function(coll) {
   var diagram = this.diagram;
   var group = this.group;
   if (group === null) throw new Error("ScrollingGroupLayout must be a Group.layout, not a Diagram.layout");

   if (diagram !== null) diagram.startTransaction("Scrolling Group Layout");
   this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin);
   var arr = [];
   // can't use Layout.collectParts here, because we're intentionally making some
   // member nodes not visible, which would normally prevent them from being laid out
   var it = group.memberParts.iterator;
   while (it.next()) {
     var part = it.value;
     if (part instanceof go.Link) continue;
     part.ensureBounds();
     arr.push(part);
   }
   this._count = arr.length;
   //?? ought to support custom sort ordering
   var x = this.arrangementOrigin.x;
   var y = this.arrangementOrigin.y;
   var maxy = y + group.resizeObject.height - group.placeholder.padding.bottom;
   var i = 0;
   var last = -1;
   while (i < arr.length && i < this.topIndex) {
     var part = arr[i++];
     part.visible = false;
     part.moveTo(x, y);
   }
   while (i < arr.length && y < maxy) {
     var part = arr[i++];
     part.moveTo(x, y);
     if (y + part.actualBounds.height < maxy) {
       part.visible = true;
       y += part.actualBounds.height + this.spacing;
       last = i - 1;
     } else {
       part.visible = false;
       break;
     }
   }
   while (i < arr.length) {
     var part = arr[i++];
     part.visible = false;
     part.moveTo(x, y);
   }
   this._lastIndex = last;
   var up = group.findObject("UP");
   if (up !== null) up.visible = this.lastIndex < this.count - 1;
   var down = group.findObject("DOWN");
   if (down !== null) down.visible = this.topIndex > 0;
   if (diagram !== null) diagram.commitTransaction("Scrolling Group Layout");
 };

The implementation in Scrolling Groups just depends on there being a (vertical) list of Nodes. The ScrollingGroupLayout just makes Nodes that are above the ScrollingGroupLayout.topIndex and below the ScrollingGroupLayout.lastIndex not visible.

I think the only real difference between what that offers and what you want is that you need to indent Nodes based on where they are in the tree. You can adapt the ScrollingGroupLayout.doLayout method, instead of using a fixed value for the x coordinate of the point to which it moves the node, to using an x value that depends on how deep the node should be in the tree.