Is it possible to put draggable Label inside group?

I have a requirement to add one draggable Panel inside group. is it possible to add panel inside group?

Can you explain what you mean, exactly? Only Nodes and other Groups can be placed “inside” (as members of) a Group.

Hi Simon,
I want to assign group name as label inside group. for that i am using this example. . but in this example one custom class is there NodeLabelDraggingTool.js. but this class only working for Spot in gojs. if i use Spot inside group. grouping is not working properly. please give me suggestion.

Yes, you can have a draggable label for a Group – it’s no different than how you would do it for a simple Node.

I started from the Grouping sample,, and modified the page to include NodeLabelDraggingTool.js and to initialize the diagram to make use of that new tool:

<script src="../extensions/NodeLabelDraggingTool.js"></script>
myDiagram.toolManager.mouseMoveTools.insertAt(0, new NodeLabelDraggingTool());

Then I modified the Group template so that it’s basically a “Spot” Panel holding the main pieces of the group, plus a label (in this case just a TextBlock) that is marked with _isNodeLabel so that the new tool knows what can be dragged around:

      myDiagram.groupTemplate =
        $(go.Group, "Spot",
          { // define the group's internal layout
            layout: $(go.TreeLayout,
                      { angle: 90, arrangement: go.TreeLayout.ArrangementHorizontal, isRealtime: false }),
            // the group begins unexpanded;
            // upon expansion, a Diagram Listener will generate contents for the group
            isSubGraphExpanded: false,
            // when a group is expanded, if it contains no parts, generate a subGraph inside of it
            subGraphExpandedChanged: function(group) {
              if (group.memberParts.count === 0) {
          // the main element of the "Spot" Panel
          $(go.Panel, "Auto",
            $(go.Shape, "Rectangle",
              // don't show this border when the group is collapsed
              new go.Binding("visible", "isSubGraphExpanded").ofObject(),
              { fill: "transparent", stroke: "gray", strokeWidth: 2 }),
            // create a placeholder to represent the area where the contents of the group are
            $(go.Placeholder, { padding: 12 }),
            // the SubGraphExpanderButton is a panel that functions as a button to expand or collapse the subGraph
            $("SubGraphExpanderButton", { alignment: go.Spot.TopLeft })
          // the element positioned by alignment and alignmentFocus relative to the main element
              _isNodeLabel: true,  // needed for NodeLabelDraggingTool to identify draggable label
              alignment: go.Spot.Top,
              alignmentFocus: go.Spot.Bottom,
              font: "Bold 18px Sans-Serif"
            new go.Binding("text", "key"))
        );  // end Group

Starting with:

Drag the label a bit to the left and down:

Expand the group and drag the label more to the left:

Move the label again, above the body and a bit towards the right:

Hi Walter,
I need Label as Groupname it is placed inside group. i have to drag label anywhere in group and put

and i have to show value of the group instead of it possible or not?

here Groupname is one textbox and value is one text box.i placed both in one node template.

I tried that draggable label example. but that label is coming outside of the group. is it possible to restrict that label inside group. i tried that example it is working like this.

Label is coming outside of the group. because of selection adorned it is showing like this. please help me to solve this.

Override NodeLabelDraggingTool.updateAlignment to limit where the label can go.

what about first approach?

Hi walter,
I want to put one Part inside group but it is giving this error “Cannot add a Part to a Panel:”.is there any solution?

What are you doing? You can either modify the diagram by setting Part.containingGroup or calling Group.addMembers, or you can modify the model by calling GraphLinksModel.setGroupKeyForNodeData.

As always, make all of your changes within a transaction. Events and overridable methods document whether or not a transaction is already ongoing at the time of the call.

Hi Walter,
I have 3 labels(groupname, subgroup,value). i want to put all these in one shape inside group.

OK, so what did you do? What happened and why was that not satisfactory?

this is my group template code

myDiagram.groupTemplate =
$(go.Group, “Spot”,{resizable:true},

      // the main element of the "Spot" Panel
      $(go.Panel, "Auto",
        $(go.Shape, "Rectangle",
          // don't show this border when the group is collapsed
          { fill: "transparent", stroke: "gray", strokeWidth: 2 }),

        // create a placeholder to represent the area where the contents of the group are
        $(go.Placeholder, { padding: 12 }),
        // the SubGraphExpanderButton is a panel that functions as a button to expand or collapse the subGraph
          _isNodeLabel: true,  // needed for NodeLabelDraggingTool to identify draggable label
         // alignment:new go.Spot(0.92, 0.1),
         alignmentFocus: go.Spot.TopLeft,
          font: "Bold 18px Sans-Serif"
     new go.Binding("text", "name").makeTwoWay()

if i make a group the label is going like .

Group name not coming inside but it is attaching to group. if i move group label is also moving.

Don’t you want to add TextBlocks for your other two labels?

Did you override NodeLabelDraggingTool.updateAlignment as I suggested?

yes. in my custom class i wrote like this
export class CustomBoundaryDraggingTool extends go.Tool {
public _originalAlignment:any=null;
public _originalCenter:any=null;
public label:any=null;
public _offset = new go.Point();

constructor() {
  super(); = "NodeLabelDragging";

public canStart(){
if (!super.canStart()) return false;
var diagram = this.diagram;
if (diagram === null) return false;
var e = diagram.lastInput;
console.log(“lastinput :”+e.left);
if (!e.left) return false;
if (!this.isBeyondDragSize()) return false;
return this.findLabel() !== null;

public isBeyondDragSize(){
return true;

public findLabel(){
var diagram = this.diagram;
var e = diagram.firstInput;
var elt:any = diagram.findObjectAt(e.documentPoint, null, null);
console.log(“elt :”+elt);
if (elt === null || !(elt.part instanceof go.Node)) return null;
while (elt.panel !== null) {
if (elt._isNodeLabel && elt.panel.type === go.Panel.Spot && elt.panel.findMainElement() !== elt) return elt;
elt = elt.panel;
return null;

public doActivate(){
this.startTransaction(“Shifted Label”);
this.label = this.findLabel();
if (this.label !== null) {
// compute the offset of the mouse-down point relative to the center of the label
this._offset = this.diagram.firstInput.documentPoint.copy().subtract(this.label.getDocumentPoint(go.Spot.Center));
this._originalAlignment = this.label.alignment.copy();
var main = this.label.panel.findMainElement();
this._originalCenter = main.getDocumentPoint(go.Spot.Center);

public doDeactivate(){


public doStop(){
this.label = null;

public doCancel(){
if (this.label !== null) {
this.label.alignment = this._originalAlignment;


    public doMouseMove(){
     if (!this.isActive) return;
    // public doMouseUp(){
    //   console.log("doMouseUp()");
    //   if (!this.isActive) return;
    //   this.updateAlignment();
    //   this.transactionResult = "Shifted Label";
    //   this.stopTool();
    // }
    public updateAlignment(){
      if (this.label === null) return;
      var last = this.diagram.lastInput.documentPoint;
      console.log("last :"+last);
      console.log("this._offset :"+this._offset);
      var cntr = this._originalCenter;
      this.label.alignment = new go.Spot(0.5, 0.5, last.x - this._offset.x - cntr.x, last.y - this._offset.y - cntr.y);

You haven’t taken my advice about customizing updateAlignment to limit how far the label can go.

Any limits on the Spot.offsetX and Spot.offsetY will limit how far the label can be dragged.