<div id="myDiagramDiv"
     style="width:600px; height:600px; background-color: #DAE4E4;"></div>
console.clear();

const portText = { None: 'none', 'Abbrv': 'abbrv', 'Normal': 'normal' }

// Display only the icon
const icon = { lines: false, text: false, icon: true, portText: portText.None };
// Display only the text
const text = { lines: false, text: true, icon: false, portText: portText.None };
// Display text and port text (abbrv = 2 chars maximum)
const normal = { lines: true, text: true, icon: false, portText: portText.Abbrv }
// Display text and port text (long)
const detail = { lines: true, text: true, icon: false, portText: portText.Normal }

const displayActions = true; // Show/hide actions (grey circles)
const display = normal; // icon, text, normal or detail


var $ = go.GraphObject.make;
var myDiagram = $(go.Diagram, "myDiagramDiv", { initialContentAlignment: go.Spot.Center });

// ------------------------------------------------------------
// PORT TEMPLATE
// ------------------------------------------------------------

function getPortTemplate(alignment) {
  const circle = $(go.Shape, 'Circle', {
    strokeWidth: 0,
    desiredSize: new go.Size(8, 8),
    cursor: 'pointer',
    fill: '#FFFFFF',
    fromSpot: alignment,
    toSpot: alignment
  });

  const pin = $(go.Panel, 'Auto',
    $(go.Shape, 
      {
        strokeWidth: 0,
        geometryString: alignment === go.Spot.Left ? 'F M11.3 0H0v14h11.3c3.8 0 7-3 7-7s-3.2-7-7-7z' : 'F M7 14h11.3V0H7C3 0 0 3 0 7s3 7 7 7z',
        fill: '#DDDDDD', 
        desiredSize: new go.Size(16 * 1.1, 16),
        margin: new go.Margin(0, 0)
      },
    ),
    circle,
  );

  const label = display.portText !== portText.None ?
    $(go.TextBlock, 
      {
        font: '9pt "Verdana", sans-serif',
        stroke: '#888888',
        margin: new go.Margin(2, 8, 0, 8),
        verticalAlignment: go.Spot.Left
      },
      new go.Binding('text', display.portText === portText.Abbrv ? 'id' : 'name')
   ) : null;
  
  const panel = $(go.Panel, 'Horizontal', {
    alignment,
    margin: new go.Margin(4, 1)
  });

  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;
}

// ------------------------------------------------------------
// ACTIONS TEMPLATES (GREY CIRCLES)
// ------------------------------------------------------------

function getActions(top) {
  if (!displayActions) return {};
  return $(go.Panel, 'Auto',
    {
      width: 14,
      height: 14,
      row: top ? 0 : 2,
      column: 0,
      alignment: top ? go.Spot.Top : go.Spot.Bottom,
      margin: new go.Margin(0, 0, 0, 0),
      cursor: 'pointer'
    },
    new go.Binding("column", "", (value, target) => {
      return (value.items.length !== 0 ? 0 : 1);
    }),
    $(go.Shape, 'Circle', {
      name: 'SHAPE',
      fill: '#888888',
      strokeWidth: 0
    }),
    $(go.TextBlock, 'Z', {
      textAlign: 'center',
      verticalAlignment: go.Spot.Center,
      font: '700 6pt "Verdana", sans-serif',
      stroke: '#FFFFFF'
    })
  );
}

// ------------------------------------------------------------
// IF ICON IS RENDERED
// ------------------------------------------------------------

function renderIcon() {
  if (!display.icon) return {};
  const icon =
    $(go.Panel, "Viewbox",
      {
        desiredSize: new go.Size(20, 20),
        margin: new go.Margin(5, 5)
      },
      $(go.Shape,
        {
          strokeWidth: 0,
          fill: '#009ABD'
        },
        new go.Binding("geometryString", "icon")
      )
    );
  return icon;
}

// ------------------------------------------------------------
// IF LINE IS RENDERED
// ------------------------------------------------------------

function renderLine(left) {
  if (!display.lines) return {};
  return $(go.Shape, 'LineV', 
    {
      stroke: '#CCCCCC',
      desiredSize: new go.Size(1, NaN),
      margin: new go.Margin(0, 0),
      stretch: go.GraphObject.Vertical
    },
    new go.Binding("visible", "", (value) => {
     return (left && value.items.length !== 0 || !left && value.items2.length !== 0) ? true : false;
    }),
  );
}

// ------------------------------------------------------------
// IF TEXT IS RENDERED
// ------------------------------------------------------------

function renderText() {
  if (!display.text) return {};
  return $(go.TextBlock, 'Text', {
      verticalAlignment: go.Spot.Center,
      font: '700 12pt "Verdana", sans-serif',
      stroke: '#CCCCCC',
      textAlign: 'center',
      wrap: go.TextBlock.None,
      margin: new go.Margin(10, 0),
      stretch: go.GraphObject.Fill,
      minSize: new go.Size(30, 50),
      angle: 270
 });
}

// ------------------------------------------------------------
// NODE TEMPLATE
// ------------------------------------------------------------

myDiagram.nodeTemplate = $(go.Node, 'Table',
    {
      locationSpot: go.Spot.Center,
      selectionAdorned: false
    },
    $(go.Shape, 'RoundedRectangle', {
      spot1: go.Spot.TopLeft,
      spot2: go.Spot.BottomRight,
      row: 0,
      rowSpan: 3,
      margin: new go.Margin(5, 0),
      stretch: go.GraphObject.Fill,
      strokeWidth: 1,
      stroke: '#CCCCCC',
      name: 'SHAPE',
      fill: $(go.Brush, 'Linear', {
        0:   '#F2F2F2',
        0.1: '#FFFFFF',
        0.9: '#FFFFFF',
        1:   '#EEEEEE'
      })
    },
      new go.Binding("columnSpan", "", (value) => {
        return 1 + (value.items.length !== 0 ? 1 : 0) + (value.items2.length !== 0 ? 1 : 0);
      }),
      new go.Binding("column", "items", (value) => {
        return (value.length !== 0 ? 0 : 1);
      }),
     ),
    $(go.Panel, 'Vertical',
      {
        row: 1,
        column: 0,
        alignment: go.Spot.Center,
        margin: new go.Margin(14, 0)
      },
      $(go.Panel, 'Vertical',
        {
          defaultAlignment: go.Spot.Left,
          itemTemplate: getPortTemplate(go.Spot.Left)
        },
        new go.Binding("itemArray", "items")
      )
    ),
    getActions(true),
    getActions(false),
    $(go.Panel, 'Horizontal',
      {
        row: 0,
        column: 1,
        rowSpan: 3,
        stretch: go.GraphObject.Vertical,
        margin: new go.Margin(6, 0)
      },
      renderLine(true),
      renderText(),
      renderIcon(),
      renderLine(false)
    ),
    $(go.Panel, 'Vertical',
      {
        row: 1,
        column: 2,
        alignment: go.Spot.Center,
        margin: new go.Margin(14, 0)
      },
      $(go.Panel, 'Vertical',
        {
          defaultAlignment: go.Spot.Right,
          itemTemplate: getPortTemplate(go.Spot.Right)
        },
        new go.Binding("itemArray", "items2"),
      )
    ) 
);

var myModel = $(go.Model);

myModel.nodeDataArray = [
  { key: 'Test 1', icon: 'F M33 21.2l-3.7-2.6.2-1.8v-1.5l3.6-2.6c.6-.3.7-1 .4-1.5L30 5.7c-.3-.5-1-.6-1.5-.3l-3.4 2c-1-1-2-1.6-3.3-2L21.5 1c0-.5-.5-1-1-1h-6.6c-.6 0-1 .5-1 1l-.3 4c-1.3.6-2.5 1.3-3.6 2.2l-3.5-2C5 4.7 4.3 5 4 5.4L.6 11c-.3.5 0 1 .3 1.4L4.6 15v3.3L1 21c-.5.3-.7 1-.4 1.4L4 28c.3.4 1 .6 1.5.2l3.5-2c1 1 2.2 1.7 3.5 2.2l.2 4.6c0 .5.5 1 1 1h6.6c.5 0 1-.5 1-1l.3-4.6c1.2-.5 2.3-1.2 3.3-2l3.5 2c.5.4 1.2.2 1.5-.3l3.4-5.4c.3-.5.2-1-.3-1.4z', items: [ { id: "A", name: "Alpha" }, { id: "B", name: "Beta" }, { id: "G", name: "Gamma" } ], items2: [] },
  { key: 'Test 1', icon: 'F M30 15c0 1.6-1.3 2.8-3 2.8H2.8C1.3 17.8 0 16.6 0 15s1.3-2.8 3-2.8h24c1.7 0 3 1.3 3 2.8z', items: [ { id: "Al", name: "Alpha" } , { id: "Be", name: "Beta" }, { id: "Ga", name: "Gamma" }, { id: "De", name : "Delta" }, ], items2: [ { id: "Al", name: "Alpha" } , { id: "Be", name: "Beta" }, { id: "Ga", name: "Gamma" }, { id: "De", name : "Delta" }, ], },
{ key: 'Test 3', icon: 'F M30 15c0 1.6-1.3 2.8-3 2.8H2.8C1.3 17.8 0 16.6 0 15s1.3-2.8 3-2.8h24c1.7 0 3 1.3 3 2.8z', items: [ ], items2: [ { id: "Al", name: "Alpha" } , { id: "Be", name: "Beta" }, { id: "Ga", name: "Gamma" }, { id: "De", name : "Delta" }, ], },
];

myDiagram.model = myModel;
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. http://gojs.net/beta/release/go.js