Search code examples
javascriptcytoscape.jscytoscape

Cytoscape.js all nodes are on top of each other when created in a loop


I'm displaying a flowchart with values from a JSON file.

When I create my element in a static way, like this :

elements: {
      nodes: [
        { data: { id: 'INIT' } },
        { data: { id: 'BUSINESS_RULES_1' } },
        { data: { id: 'EXPORT_STC' } },
        { data: { id: 'EXPORT_SPEC' } },
        { data: { id: 'COPY' } },
        { data: { id: 'MERGE' } },
        { data: { id: 'BUSINESS_RULES_2' } },
        { data: { id: 'TRANSFORM_ARP' } },
        { data: { id: 'TRANSFORM_APS' } },
        { data: { id: 'PUBLISH_APS' } },
        { data: { id: 'PUBLISH_ARP' } },
        { data: { id: 'ARCHIVE' } }
      ],
      edges: [
        { data: { source: 'INIT', target: 'BUSINESS_RULES_1' } },
        { data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_SPEC' } },
        { data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_STC' } },
        { data: { source: 'EXPORT_STC', target: 'COPY' } },
        { data: { source: 'EXPORT_SPEC', target: 'COPY' } },
        { data: { source: 'COPY', target: 'MERGE' } },
        { data: { source: 'MERGE', target: 'BUSINESS_RULES_2' } },
        { data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_APS' } },
        { data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_ARP' } },
        { data: { source: 'TRANSFORM_ARP', target: 'PUBLISH_ARP' } },
        { data: { source: 'TRANSFORM_APS', target: 'PUBLISH_APS' } },
        { data: { source: 'PUBLISH_APS', target: 'ARCHIVE' } },
        { data: { source: 'PUBLISH_ARP', target: 'ARCHIVE' } }
      ]
    }

It is well displayed as you can see : Chart well displayed

But when I create the element in a dynamic way, like this :

// Fill array with nodes and edges
var arrayNodesAndEdges = [];
for (var i = 0; i < myJSONdata.length; i++) {
    if(i < myJSONdata.length - 1 && (myJSONdata[i].OPERATION_NAME != myJSONdata[i+1].OPERATION_NAME)) {
      console.log(i + " " +myJSONdata[i].OPERATION_NAME);
      arrayNodesAndEdges.push({
        group: "nodes",
        data: { 
          id: myJSONdata[i].OPERATION_NAME
        }
      });
    } else if(i == myJSONdata.length - 1) {
      console.log(i + " " +myJSONdata[i].OPERATION_NAME);
      arrayNodesAndEdges.push({
        group: "nodes",
        data: { 
          id: myJSONdata[i].OPERATION_NAME
        }
      });
    }
}

for (var i = 0; i < myJSONdata.length; i++) {
  var source = myJSONdata[i].OPERATION_NAME;
  if(myJSONdata[i].NEXT_OPERATION_NAME !== "" && myJSONdata[i].NEXT_OPERATION_NAME !== null) {
    console.log("Source: " + myJSONdata[i].OPERATION_NAME + ", " + "Target: " +myJSONdata[i].NEXT_OPERATION_NAME);
    arrayNodesAndEdges.push({
        group: "edges",
        data: {
            id: "e"+i,
            source: source,
            target: myJSONdata[i].NEXT_OPERATION_NAME
        }
      });
  }
}
cy.add(arrayNodesAndEdges);

It is bad displayed, all nodes are on top of each other, as you can see: Chart bad displayed

(I moved some to explain how they are positionned, but they are all on top of each other)

Here's the console log, you can see this is the same structure in static or dynamic way :

NODES
0 INIT
2 BUSINESS_RULES_1
3 EXPORT_STC
4 EXPORT_SPEC
5 COPY
6 MERGE
8 BUSINESS_RULES_2
9 TRANSFORM_ARP
10 TRANSFORM_APS
11 PUBLISH_APS
12 PUBLISH_ARP
13 ARCHIVE

EDGES
Source: INIT, Target: BUSINESS_RULES_1
Source: BUSINESS_RULES_1, Target: EXPORT_SPEC
Source: BUSINESS_RULES_1, Target: EXPORT_STC
Source: EXPORT_STC, Target: COPY
Source: EXPORT_SPEC, Target: COPY
Source: COPY, Target: MERGE
Source: MERGE, Target: BUSINESS_RULES_2
Source: BUSINESS_RULES_2, Target: TRANSFORM_APS
Source: BUSINESS_RULES_2, Target: TRANSFORM_ARP
Source: TRANSFORM_ARP, Target: PUBLISH_ARP
Source: TRANSFORM_APS, Target: PUBLISH_APS
Source: PUBLISH_APS, Target: ARCHIVE
Source: PUBLISH_ARP, Target: ARCHIVE

I can't understand what I'm doing wrong ? Thank you

EDIT ---------- This is my whole code :

var myJSONdata = data;
var cy = window.cy = cytoscape({
  container: document.getElementById('cy'),

  boxSelectionEnabled: true,
  autounselectify: true,
  layout: {
    name: 'dagre',
    rankDir: 'LR' // 'TB' for top to bottom flow, 'LR' for left to right. default is undefined, making it plot top-bottom
  },

  style: [
    {
      selector: 'node',
      style: {
        'content': 'data(id)',
        'width': 200,
        'height': 50,
        'text-opacity': 1,
        'text-valign': 'center',
        'text-halign': 'center',
        'shape': 'square',
        'label': 'data(id)',
        'background-color': '#11479e',
        'color': 'white'
      }
    },
    {
      selector: 'edge',
      style: {
        'width': 7,
        'target-arrow-color': '#ccc',
        'target-arrow-shape': 'triangle',
        'curve-style': 'bezier',
        'line-color': '#9dbaea'
      }
    },
      {
        selector: ':selected',
        style: {
          'background-color': 'yellow',
          'line-color': 'yellow',
          'target-arrow-color': 'yellow',
          'source-arrow-color': 'yellow',
        }
      }
    ]
    /*,elements: {
      nodes: [
        { data: { id: 'INIT' } },
        { data: { id: 'BUSINESS_RULES_1' } },
        { data: { id: 'EXPORT_STC' } },
        { data: { id: 'EXPORT_SPEC' } },
        { data: { id: 'COPY' } },
        { data: { id: 'MERGE' } },
        { data: { id: 'BUSINESS_RULES_2' } },
        { data: { id: 'TRANSFORM_ARP' } },
        { data: { id: 'TRANSFORM_APS' } },
        { data: { id: 'PUBLISH_APS' } },
        { data: { id: 'PUBLISH_ARP' } },
        { data: { id: 'ARCHIVE' } }
      ],
      edges: [
        { data: { source: 'INIT', target: 'BUSINESS_RULES_1' } },
        { data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_SPEC' } },
        { data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_STC' } },
        { data: { source: 'EXPORT_STC', target: 'COPY' } },
        { data: { source: 'EXPORT_SPEC', target: 'COPY' } },
        { data: { source: 'COPY', target: 'MERGE' } },
        { data: { source: 'MERGE', target: 'BUSINESS_RULES_2' } },
        { data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_APS' } },
        { data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_ARP' } },
        { data: { source: 'TRANSFORM_ARP', target: 'PUBLISH_ARP' } },
        { data: { source: 'TRANSFORM_APS', target: 'PUBLISH_APS' } },
        { data: { source: 'PUBLISH_APS', target: 'ARCHIVE' } },
        { data: { source: 'PUBLISH_ARP', target: 'ARCHIVE' } }
      ]
    }*/
});



// Fill array with nodes and edges
var arrayNodesAndEdges = [];
for (var i = 0; i < myJSONdata.length; i++) {
    if(i < myJSONdata.length - 1 && (myJSONdata[i].OPERATION_NAME != myJSONdata[i+1].OPERATION_NAME)) {
      console.log(i + " " +myJSONdata[i].OPERATION_NAME);
      arrayNodesAndEdges.push({
        group: "nodes",
        data: { 
          id: myJSONdata[i].OPERATION_NAME
        }
      });
    } else if(i == myJSONdata.length - 1) {
      console.log(i + " " +myJSONdata[i].OPERATION_NAME);
      arrayNodesAndEdges.push({
        group: "nodes",
        data: { 
          id: myJSONdata[i].OPERATION_NAME
        }
      });
    }
}

for (var i = 0; i < myJSONdata.length; i++) {
  var source = myJSONdata[i].OPERATION_NAME;
  if(myJSONdata[i].NEXT_OPERATION_NAME !== "" && myJSONdata[i].NEXT_OPERATION_NAME !== null) {
    console.log("Source: " + myJSONdata[i].OPERATION_NAME + ", " + "Target: " +myJSONdata[i].NEXT_OPERATION_NAME);
    arrayNodesAndEdges.push({
        group: "edges",
        data: {
            id: "e"+i,
            source: source,
            target: myJSONdata[i].NEXT_OPERATION_NAME
        }
      });
  }
}
cy.add(arrayNodesAndEdges);

Solution

  • I finally manage to solve it thanks to this post right here I created the array at the beginning and add them to the "element" property. But I still do not know why it was not working in the previous version.

    This is my final code :

    var myJSONdata = data;
    
    // Fill array with nodes and edges
    var arrayNodes = [];
    for (var i = 0; i < myJSONdata.length; i++) {
        if(i < myJSONdata.length - 1 && (myJSONdata[i].OPERATION_NAME != myJSONdata[i+1].OPERATION_NAME)) {
          console.log(i + " " +myJSONdata[i].OPERATION_NAME);
          arrayNodes.push({
            group: "nodes",
            data: { 
              id: myJSONdata[i].OPERATION_NAME
            }
          });
        } else if(i == myJSONdata.length - 1) {
          console.log(i + " " +myJSONdata[i].OPERATION_NAME);
          arrayNodes.push({
            group: "nodes",
            data: { 
              id: myJSONdata[i].OPERATION_NAME
            }
          });
        }
    }
    
    var arrayEdges = [];
    for (var i = 0; i < myJSONdata.length; i++) {
      var source = myJSONdata[i].OPERATION_NAME;
      if(myJSONdata[i].NEXT_OPERATION_NAME !== "" && myJSONdata[i].NEXT_OPERATION_NAME !== null) {
        console.log("Source: " + myJSONdata[i].OPERATION_NAME + ", " + "Target: " +myJSONdata[i].NEXT_OPERATION_NAME);
        arrayEdges.push({
            group: "edges",
            data: {
                id: "e"+i,
                source: source,
                target: myJSONdata[i].NEXT_OPERATION_NAME
            }
          });
      }
    }
    
    
    var cy = window.cy = cytoscape({
      container: document.getElementById('cy'),
    
      boxSelectionEnabled: true,
      autounselectify: true,
      layout: {
        name: 'dagre',
        rankDir: 'LR' // 'TB' for top to bottom flow, 'LR' for left to right. default is undefined, making it plot top-bottom
      },
    
      style: [
        {
          selector: 'node',
          style: {
            'content': 'data(id)',
            'width': 200,
            'height': 50,
            'text-opacity': 1,
            'text-valign': 'center',
            'text-halign': 'center',
            'shape': 'square',
            'label': 'data(id)',
            'background-color': '#11479e',
            'color': 'white'
          }
        },
        {
          selector: 'edge',
          style: {
            'width': 7,
            'target-arrow-color': '#ccc',
            'target-arrow-shape': 'triangle',
            'curve-style': 'bezier',
            'line-color': '#9dbaea'
          }
        },
          {
            selector: ':selected',
            style: {
              'background-color': 'yellow',
              'line-color': 'yellow',
              'target-arrow-color': 'yellow',
              'source-arrow-color': 'yellow',
            }
          }
        ]
        ,elements: {
          nodes: arrayNodes,
          edges: arrayEdges
        }
    });