Node size lower than 100px

goJS is an awesome tools bu I dont understand why it’s so complicated to do a node template… My node template is like :

The corresponding code is :

this.go(go.Node, 'Table',
  {
    locationSpot: go.Spot.Center,
    background: '#00FFF0',
    padding: 5,
  },

  this.go(go.Shape, 'RoundedRectangle', {
    spot1: go.Spot.TopLeft,
    spot2: go.Spot.BottomRight,
    rowSpan: 999,
    columnSpan: 999,
    margin: new go.Margin(0, 0),
    stretch: go.GraphObject.Fill,
    strokeWidth: 1,
    stroke: scheme.ui.input.normal.border.color,
    fill: this.go(go.Brush, 'Linear', {
      0:   '#F2F2F2',
      0.1: '#FFFFFF',
      0.9: '#FFFFFF',
      1:   '#EEEEEE',
    }),
  }),

  this.go(go.Panel, 'Vertical',
    {
      column: 0,
      defaultAlignment: go.Spot.Left,
      itemTemplate: this.getPortTemplate(go.Spot.Left, this.properties),
    },
  ),

  this.go(go.Panel, 'Vertical',
    {
      column: 2,
      defaultAlignment: go.Spot.Right,
      itemTemplate: this.getPortTemplate(go.Spot.Right, this.properties),
    },
  ),

  this.go(go.Panel, 'Horizontal',
    {
      column: 1,
      stretch: go.GraphObject.Fill,
      background: '#0000FF',
    },

  this.go(go.TextBlock, 'Un autre',
  {
     verticalAlignment: go.Spot.Center,
     font: '700 12pt "SourceSansPro", sans-serif',
     stroke: this.props.scheme.ui.input.normal.forecolor,
     textAlign: 'center',
     wrap: go.TextBlock.None,
     angle: 270,
     margin: new go.Margin(10, 0),
     stretch: go.GraphObject.Fill,
     minSize: new go.Size(30, 50),
   },
  ),

With this item template :

getPortTemplate(alignment, properties, pinColor = this.props.scheme.ui.input.normal.border.color) {
   const { portSize, portMargin } = this.props;

   let geo;
   if (alignment === go.Spot.Left) {
     geo = 'F M11.3 0H0v14h11.3c3.8 0 7-3 7-7s-3.2-7-7-7z';
   } else {
     geo = 'F M7 14h11.3V0H7C3 0 0 3 0 7s3 7 7 7z';
   }

   const circle = this.go(go.Shape, 'Circle',
     {
       strokeWidth: 0,
       desiredSize: new go.Size(portSize - (portSize / 2), portSize - (portSize / 2)),
       cursor: 'pointer',
       fromSpot: alignment,
       toSpot: alignment,
    },
  );

  const pin = this.go(go.Panel, 'Auto', 
    {
      background: '#FF0000',
    },

    this.go(go.Shape, {
      geometryString: geo,
      margin: new go.Margin(0, 0.5),
      strokeWidth: 0,
      fill: pinColor,
      desiredSize: new go.Size(portSize * 1.1, portSize),
    }),
    circle,
  );

  const label = properties.display.portDisplayType !== types.PortDisplayType.None ?
     this.go(go.TextBlock,
      {
        background: '#00FF00',
        font: '9pt "SourceSansPro", sans-serif',
        stroke: '#888888',
        margin: new go.Margin(2, 8, 0, 8),
        verticalAlignment: go.Spot.MiddleLeft,
      },
  ) : null;

  const panel = this.go(go.Panel, 'Horizontal',
    {
      background: '#FFF000',
      alignment,
      margin: new go.Margin(portMargin / 2, 0),
    },
  );

  if (alignment === go.Spot.Left) {
    panel.add(pin);
    if (label !== null) panel.add(label);
  } else {
    if (label !== null) panel.add(label);
    panel.add(pin);
  }

  return panel;
}

Q1. Without port text, the final width of the node template is lower than 100px but it’s seem the node object as a default width of 100px I cant delete. How to correct this size ? That doesn’t work with minSize = new go.Size(NaN, …)

Q2. I add two new panel (column 0, row 0 and column 0, row 2) on the left colum, how to center the content of the column 0, row 1 ? A stretch fill/vertical doesn’t work.

EDIT : Work with a rowSpan 3 and a margin top/bottom. Is this the only solution ?

Try defining your template as an Auto Panel with the outer RoundedRectangle as the main shape. The structure would be something like this:

$(go.Node, "Auto",
  { locationSpot: go.Spot.Center },
  $(go.Shape, "RoundedRectangle",
    {
      spot1: go.Spot.TopLeft,
      spot2: go.Spot.BottomRight,
      ...
    }
  ),
  $(go.Panel, "Table",
    { margin: new go.Margin(3, 0) },
    $(go.Panel, "Vertical", ...), // column 0, left side ports
    $(go.Panel, ...), // column 1, middle text
    $(go.Panel, "Vertical", ...) // column 2, right side ports
  )
)

You were on the right track, and I think an Auto Panel will get you what you want. Try implementing this, and if you need more detail, let us know.

It was my previous layout but I have change to the current way because I need to add two panels on the left column (+ and - buttons).

With your layout the size is correct but not the overflow :

Another idea ?

Depending on how you’re defining the +/- buttons, you could wrap the whole Auto panel in a Spot panel and place those buttons near to top left and bottom left.

http://gojs.net/latest/intro/nodes.html

Like my screenshoot between the background shape and the background node…

 A GraphObject can only be added to a Panel, not to: Spot(0,0)

It’s definitively too complicated to create complex layout with goJS and it’s really a big problem. Each time I want to make a layout I spent a lot of time to find a way to make what I want.

From your original design, we found there is probably a bug in the way the Table panel is stretching the RoundedRectangle element where it’s not properly accounting for the angle of the Addition text. We’re working on a fix.

As for the solution of using a Spot/Auto panel, it would look something like this:

$(go.Node, "Spot",
  $(go.Panel, "Auto"
    { locationSpot: go.Spot.Center },   
    $(go.Shape, "RoundedRectangle",
      {
        spot1: go.Spot.TopLeft,
        spot2: go.Spot.BottomRight,
        ...
      }
    ),
    $(go.Panel, "Table",
      { margin: new go.Margin(3, 0) },
      $(go.Panel, "Vertical", ...), // column 0, left side ports
      $(go.Panel, ...), // column 1, middle text
      $(go.Panel, "Vertical", ...) // column 2, right side ports
    )
  ),
  $(go.Shape, "Circle", // circle representing "+" button
    { desiredSize: new go.Size(10, 10), alignment: go.Spot.TopLeft }
  ),
  $(go.Shape, "Circle", // circle representing "-" button
    { desiredSize: new go.Size(10, 10), alignment: go.Spot.BottomLeft }
  )
)

I tried with Spot (it’s probably like your solution) :

return this.go(go.Node, 'Spot',
  {
    locationSpot: go.Spot.Center,
  },

  this.go(go.Panel, 'Auto',
    {
      background: '#00FFF0',
    },

    this.go(go.Shape, 'RoundedRectangle', {
      spot1: go.Spot.TopLeft,
      spot2: go.Spot.BottomRight,
      stretch: go.GraphObject.Fill,
      strokeWidth: 1,
      stroke: scheme.ui.input.normal.border.color,
      name: 'SHAPE',
      fill: this.go(go.Brush, 'Linear', {
        0:   '#F2F2F2',
        0.1: '#FFFFFF',
        0.9: '#FFFFFF',
        1:   '#EEEEEE',
      }),
    }),

    this.go(go.Panel, 'Table',

      this.go(go.Panel, 'Vertical',
        {
          row: 1,
          column: 0,
          rowSpan: 3,
          alignment: go.Spot.Center,
          background: '#FF00FF',
          margin: new go.Margin(14, 0),
        },
        this.go(go.Panel, 'Vertical',
          this.getPortsData(types.PortType.In, this),
          {
            defaultAlignment: go.Spot.Left,
            itemTemplate: this.getPortTemplate(go.Spot.Left, this.properties),
          },
        ),
      ),

      this.go(go.Panel, 'Horizontal',
        {
          row: 1,
          column: 1,
          rowSpan: 3,
          stretch: go.GraphObject.Fill,
          background: '#0000FF',
          margin: new go.Margin(6, 0),
        },
        this.renderText(this.properties.display.text),
      ),

      this.go(go.Panel, 'Vertical',
        {
          row: 1,
          column: 2,
          rowSpan: 3,
          defaultAlignment: go.Spot.Right,
          itemTemplate: this.getPortTemplate(go.Spot.Right, this.properties),
        },
      ),
    ),
  ),

  this.go(go.Panel, 'Spot',
    {
      alignment: new go.Spot(0, 0, 20, 0),
      alignmentFocus: go.Spot.LeftCenter,
    },
    this.renderVariableParameters(true),
  ),

  this.go(go.Panel, 'Spot',
    {
      alignment: new go.Spot(0, 1, 20, 0),
      alignmentFocus: go.Spot.LeftCenter,
    },
    this.renderVariableParameters(false),
  ),

But in this case “+/-” are notre center on the left column :

Ok make a sense. But strange because on the two below there are no text :

In fact each node as 4 templates (I use the spacebar to swap templates). As you can see on the three last, the size is incorrect and allways the same :

Ok, if you need the buttons to dynamically change location based on the size of column 1 of the Table panel, using the Spot panel solution won’t work.

To clarify, the bug we’re fixing isn’t related to just text, it is related to any element of a table panel that is stretching and also has row/columnSpan, which should resolve all your examples.

Ok I wait your fix :):):)

Hi!, have you had time to found a fix about my issue ? I can’t continue always it’s not corrected… I have find another strange issue but I open a new topic about this.

Yes, I believe we have just fixed it internally; we could do another release later this week.

I suppose I should put out a beta (i.e. at GoJS - Build Interactive Diagrams for the Web) so that you can try it. It should be there in twenty minutes or so.

Thanks Walter. With 1.7.17 (it’s probably not the latest beta you tell) I have an error :

Error: Non-real measuredBounds has been set. Object TextBlock(""), measuredBounds: Rect(0,0,30,NaN)

I double check my code…

EDIT : This error is raised when the row property is biggest than other rows values. I can do a codepen if you want to reproduce it.

Yes, I think it would help us to see an example. It’s not clear how you’re defining your templates at this point since you’ve made many changes.

Please include your full templates, including any +/- buttons, labels, etc. It’s hard to debug the issues when we don’t know the full scope of all the problems you’re encountering.

I understand and you are right. Below a complete template like I use (I use many databinding/methods I have remove to simplify the code). You can set the “display” variable with “icon”, “text”, “normal” and “detail”. Only the detail view (and the right node in “normal” view) is correct and “push” the width to the correct value.

Ok, here you go:

This seems to cover all your cases. A summary of the changes I made:

  • Top action moved to row 0
  • Icon moved to Viewbox panel (as discussed in the other topic)
  • Lines set to stretch vertically (since they don’t need to increase horizontally)
  • Outer RoundedRectangle set to row 0
  • rowSpan removed from Vertical panels holding ports
  • Horizontal panel moved to row 0 and set to stretch vertically

Some background: In GoJS, when an object (such as a Shape) has infinite space to measure into, it will give itself a size of 100.

I changed the second column (the Horizontal panel) to stretch Vertical is because the size of the spanning RoundedRectangle wants to be as wide as needed since it’s stretching across columns. When the Horizontal panel (middle column) also stretches horizontally, it doesn’t provide a size. The RoundedRectangle that spans all 3 columns then has infinite space to stretch, so it gives itself a width of 100. At the end of Table panel measuring, it gives that “extra space” that the spanning object asked for (by becoming 100 wide) to the final column, which is why the third column was large. So the stretch = Vertical on the middle column is to stop that RoundedRectangle from having infinite width to stretch into.

Jonathan,

Firstly thank you (you and walter),

It was because I forgot the little “Icon” on the top right.

Ok but a developer cannot guess this :) Why in this case you dont resize to the largest inner container (in my case a table) ? Or please add a note in the documentation about this problem :)

I have made some changes in the case where an itemArray (the left or the right) is empty. Do you think it’s possible to be simplier ?

I think the changes you’ve made are suitable. Using bindings on the arrays is a good solution.

As for the documentation, yes it might be useful. But also consider it is an extremely specific case (in fact, this is the first time this has ever come up), and we don’t necessarily want to overload users with unneeded information.