6

I am creating a graph using cytoscape.js and I have compounded nodes which are inside the parent node. I would like to have the title of the main/parent node at the top of the node but inside the node. Is that possible in cytoscape?

I have tried using using halign and valign. Whenever I use top value, it shows outside the box.

Is there a extension or a plugin that lets us do it?

Example with child node: https://stackblitz.com/edit/cytoscape-call-method-child-efmbaj?file=src%2Fapp%2FstylesheetObject.ts

Learn AspNet
  • 1,192
  • 3
  • 34
  • 74

2 Answers2

5

As you can read here, you can only place labels inside a node with the center option, a good configuration (label inside at the top) requires a margin to be added to your label:

.selector(':parent')
  .css({
    'text-valign': 'center',
    // the next line moves the parents label up to the top of the node and 5px down to create a padding 
    'text-margin-y': function (node) { return -node.height() + 5 }
})

Here is a working example:

var cy = cytoscape({
  container: document.getElementById('cy'),

  style: cytoscape.stylesheet()
    .selector(':parent')
    .css({
      'text-valign': 'center',
      'text-margin-y': function(node) {
        return -node.height() + 5
      }
    })
    .selector('node')
    .css({
      'height': 'data(size)',
      'width': 'data(size)',
      'border-color': '#000',
      'border-width': '1',
      'content': 'data(name)'
    })
    .selector('edge')
    .css({
      'width': 'data(strength)'
    })
    .selector('#1')
    .css({
      'background-color': 'red'
    })
    .selector('#4')
    .css({
      'background-color': 'green'
    }),

  elements: {
    nodes: [{
        data: {
          id: '1',
          size: 50,
          name: 'a'
        }
      },
      {
        data: {
          id: '2',
          size: 20,
          name: 'b',
          parent: '1'
        }
      },
      {
        data: {
          id: '3',
          size: 40,
          name: 'c',
          parent: '1'
        }
      },
      {
        data: {
          id: '4',
          size: 50,
          name: 'd'
        }
      },
      {
        data: {
          id: '5',
          size: 20,
          name: 'e',
          parent: '4'
        }
      },
      {
        data: {
          id: '6',
          size: 40,
          name: 'f',
          parent: '4'
        }
      }
    ],
  },
});
body {
  font: 14px helvetica neue, helvetica, arial, sans-serif;
}

#cy {
  height: 100%;
  width: 75%;
  position: absolute;
  left: 0;
  top: 0;
  float: left;
}
<html>

<head>
  <meta charset=utf-8 />
  <meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js"></script>
  <script src="https://unpkg.com/jquery@3.3.1/dist/jquery.js"></script>
</head>

<body>
  <div id="cy"></div>
</body>

</html>
Stephan T.
  • 5,843
  • 3
  • 20
  • 42
  • 1
    This is not working if you have a node inside a node. The child node does not go down and make space for the title. The title just goes behind the child node – Learn AspNet Jun 25 '21 at 18:25
  • 1
    Here is a simple example: https://stackblitz.com/edit/cytoscape-call-method-child-efmbaj?file=src%2Fapp%2FstylesheetObject.ts – Learn AspNet Jun 25 '21 at 18:41
  • 3
    If I set this ```{ selector: 'node[type="parent"]', style: { shape: 'rectangle', 'background-color': 'grey', width: 300, height: 100, 'font-size': 25.5, 'font-family': 'Lato, Helvetica Neue, Helvetica, Arial, sans-serif', color: 'black', 'text-valign': 'top', 'text-halign': 'center', 'text-margin-y': function(node) { return '40px'; } } },``` I see the labels are behind the child node – canbax Jun 27 '21 at 09:03
  • @canbax does this mean that this is not possible with cytoscape currently? – Learn AspNet Jun 29 '21 at 16:30
  • 2
    @LearnAspNet it might be impossible, not sure. I couldn't find a way. You might want to check issues in cytoscape.js repository. Also you might want to play with styles like `z-compound-depth` and `z-index`, `background-opacity`, `opacity` etc.. Logically if you want your child node to be visible, it should be rendered on top of its parent. So parent's z-index should be lower. So then its label should also be rendered before child. I think it is contradictory. – canbax Jun 29 '21 at 20:40
  • 2
    If z-index of parent is greater then you can not see its children – canbax Jun 29 '21 at 20:41
4

What I understand is that you want to put the parent label inside the box above child? apologies if I'm wrong

enter image description here

If so, My solution will be to add a padding and then apply margin for alignment.

Modified your example

Styles updated:

  1. 'padding-top':60

    selector: 'node',
    css: {
      content: 'data(label)',
      'text-valign': 'center',
      'text-halign': 'center',
      'font-size': 28,
      'padding-top':60
    }
    
  2. 'text-valign': 'top', and 'text-margin-y': function(node) { return node.height() - 10; }

    selector: 'node[type="parent"]',
    style: {
      shape: 'rectangle',
      'background-color': 'grey',
      width: 300,
      height: 100,
      'font-size': 25.5,
      'font-family': 'Lato, Helvetica Neue, Helvetica, Arial, sans-serif',
      color: 'black',
      'text-valign': 'top',
      'text-halign': 'center',
      'text-margin-y': function(node) {
        return node.height() - 10;
      }
    }
    
Abhi
  • 995
  • 1
  • 8
  • 12
  • 1
    This is working. The only thing, when I add padding top it does not just add padding at the top, it adds padding everywhere and makes the node of different size. Do you know a way of adding a space at the top like a margin instead of padding? – Learn AspNet Jun 30 '21 at 17:55
  • Try adding 'padding-top' to specific selector like 'node[type="parent"]' – Abhi Jul 05 '21 at 07:52
  • I am adding padding top to selector like 'node[type="parent"]' It still adds padding everywhere so the node size increases – Learn AspNet Jul 06 '21 at 14:04