Search code examples
cytoscape.js

How to save and restore layout of compound nodes using cytoscape.js


I'm using the JavaScript library cytoscape.js to draw some topology graph.

I could use the following snippet to save and restore layout for non-compound nodes case.

<button id="save" class="button">save</button>
<button id="reload" class="button">reload</button>

document.getElementById("save").addEventListener("click", function(){
    window.localStorage.setItem('savedlayout', JSON.stringify(cy.json()));
});

document.getElementById("reload").addEventListener("click", function(){
    cy.json(JSON.parse(window.localStorage.getItem('savedlayout')));
});

This solution seems not working for compound nodes case. I have downloaded some compound nodes demos and tried to add my above snippet, the layout can't be restored correctly.

Please see my demo. You could drag any nodes and click save button, then drag some nodes and click restore.

document.addEventListener('DOMContentLoaded', function(){

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

          ready: function(){
            this.nodes().forEach(function(node){
              let width = [30, 70, 110];
              let size = width[Math.floor(Math.random()*3)];
              node.css("width", size);
              node.css("height", size);
            });
            this.layout({name: 'cose-bilkent', animationDuration: 1000}).run();
          },
            
          style: [
            {
              selector: 'node',
              style: {
                'background-color': '#ad1a66'
              }
            },

            {
              selector: ':parent',
              style: {
                'background-opacity': 0.333
              }
            },

            {
              selector: 'edge',
              style: {
                'width': 3,
                'line-color': '#ad1a66'
              }
            }
          ],

            elements: [{ group:'nodes', data:{ id: 'n0'}},
                    { group:'nodes', data:{ id: 'n1'}},
                    { group:'nodes', data:{ id: 'n2'}},
                    { group:'nodes', data:{ id: 'n3'}},
                    { group:'nodes', data:{ id: 'n4', parent: 'n37'}},
                    { group:'nodes', data:{ id: 'n5'}},
                    { group:'nodes', data:{ id: 'n6'}},
                    { group:'nodes', data:{ id: 'n7', parent: 'n37'}},
                    { group:'nodes', data:{ id: 'n8', parent: 'n37'}},
                    { group:'nodes', data:{ id: 'n9', parent: 'n37'}},
                    { group:'nodes', data:{ id: 'n10', parent: 'n38'}},
                    { group:'nodes', data:{ id: 'n12'}},
                    { group:'nodes', data:{ id: 'n13'}},
                    { group:'nodes', data:{ id: 'n14'}},
                    { group:'nodes', data:{ id: 'n15'}},
                    { group:'nodes', data:{ id: 'n16'}},
                    { group:'nodes', data:{ id: 'n17'}},
                    { group:'nodes', data:{ id: 'n18'}},
                    { group:'nodes', data:{ id: 'n19'}},
                    { group:'nodes', data:{ id: 'n20'}},
                    { group:'nodes', data:{ id: 'n21'}},
                    { group:'nodes', data:{ id: 'n22'}},
                    { group:'nodes', data:{ id: 'n23'}},
                    { group:'nodes', data:{ id: 'n24', parent: 'n39'}},
                    { group:'nodes', data:{ id: 'n25', parent: 'n39'}},
                    { group:'nodes', data:{ id: 'n26', parent: 'n42'}},
                    { group:'nodes', data:{ id: 'n27', parent: 'n42'}},
                    { group:'nodes', data:{ id: 'n28', parent: 'n42'}},
                    { group:'nodes', data:{ id: 'n29', parent: 'n40'}},
                    { group:'nodes', data:{ id: 'n31', parent: 'n41'}},
                    { group:'nodes', data:{ id: 'n32', parent: 'n41'}},
                    { group:'nodes', data:{ id: 'n33', parent: 'n41'}},
                    { group:'nodes', data:{ id: 'n34', parent: 'n41'}},
                    { group:'nodes', data:{ id: 'n35', parent: 'n41'}},
                    { group:'nodes', data:{ id: 'n36', parent: 'n41'}},
                    { group:'nodes', data:{ id: 'n37'}},
                    { group:'nodes', data:{ id: 'n38'}},
                    { group:'nodes', data:{ id: 'n39', parent: 'n43'}},
                    { group:'nodes', data:{ id: 'n40', parent: 'n42'}},
                    { group:'nodes', data:{ id: 'n41', parent: 'n42'}},
                    { group:'nodes', data:{ id: 'n42', parent: 'n43'}},
                    { group:'nodes', data:{ id: 'n43'}},
                    { group:'edges', data:{ id: 'e0', source: 'n0', target: 'n1'} },
                    { group:'edges', data:{ id: 'e1', source: 'n1', target: 'n2'} },
                    { group:'edges', data:{ id: 'e2', source: 'n2', target: 'n3'} },
                    { group:'edges', data:{ id: 'e3', source: 'n0', target: 'n3'} },
                    { group:'edges', data:{ id: 'e4', source: 'n1', target: 'n4'} },
                    { group:'edges', data:{ id: 'e5', source: 'n2', target: 'n4'} },
                    { group:'edges', data:{ id: 'e6', source: 'n4', target: 'n5'} },
                    { group:'edges', data:{ id: 'e7', source: 'n5', target: 'n6'} },
                    { group:'edges', data:{ id: 'e8', source: 'n4', target: 'n6'} },
                    { group:'edges', data:{ id: 'e9', source: 'n4', target: 'n7'} },
                    { group:'edges', data:{ id: 'e10', source: 'n7', target: 'n8'} },
                    { group:'edges', data:{ id: 'e11', source: 'n8', target: 'n9'} },
                    { group:'edges', data:{ id: 'e12', source: 'n7', target: 'n9'} },
                    { group:'edges', data:{ id: 'e13', source: 'n13', target: 'n14'} },
                    { group:'edges', data:{ id: 'e14', source: 'n12', target: 'n14'} },
                    { group:'edges', data:{ id: 'e15', source: 'n14', target: 'n15'} },
                    { group:'edges', data:{ id: 'e16', source: 'n14', target: 'n16'} },
                    { group:'edges', data:{ id: 'e17', source: 'n15', target: 'n17'} },
                    { group:'edges', data:{ id: 'e18', source: 'n17', target: 'n18'} },
                    { group:'edges', data:{ id: 'e19', source: 'n18', target: 'n19'} },
                    { group:'edges', data:{ id: 'e20', source: 'n17', target: 'n20'} },
                    { group:'edges', data:{ id: 'e21', source: 'n19', target: 'n20'} },
                    { group:'edges', data:{ id: 'e22', source: 'n16', target: 'n20'} },
                    { group:'edges', data:{ id: 'e23', source: 'n20', target: 'n21'} },
                    { group:'edges', data:{ id: 'e25', source: 'n23', target: 'n24'} },
                    { group:'edges', data:{ id: 'e26', source: 'n24', target: 'n25'} },
                    { group:'edges', data:{ id: 'e27', source: 'n26', target: 'n38'} },
                    { group:'edges', data:{ id: 'e29', source: 'n26', target: 'n39'} },
                    { group:'edges', data:{ id: 'e30', source: 'n26', target: 'n27'} },
                    { group:'edges', data:{ id: 'e31', source: 'n26', target: 'n28'} },
                    { group:'edges', data:{ id: 'e33', source: 'n21', target: 'n31'} },
                    { group:'edges', data:{ id: 'e35', source: 'n31', target: 'n33'} },
                    { group:'edges', data:{ id: 'e36', source: 'n31', target: 'n34'} },
                    { group:'edges', data:{ id: 'e37', source: 'n33', target: 'n34'} },
                    { group:'edges', data:{ id: 'e38', source: 'n32', target: 'n35'} },
                    { group:'edges', data:{ id: 'e39', source: 'n32', target: 'n36'} },
                    { group:'edges', data:{ id: 'e40', source: 'n16', target: 'n40'} }
                   ],
                   elements1: [{ group:'nodes', data:{ id: 'n0'}},
                       { group:'nodes', data:{ id: 'n1'}},
                       { group:'nodes', data:{ id: 'n2'}},
                       { group:'nodes', data:{ id: 'n3'}},
                       { group:'nodes', data:{ id: 'n4', parent1: 'n37'}},
                       { group:'nodes', data:{ id: 'n5'}},
                       { group:'nodes', data:{ id: 'n6'}},
                       { group:'nodes', data:{ id: 'n7', parent1: 'n37'}},
                       { group:'nodes', data:{ id: 'n8', parent1: 'n37'}},
                       { group:'nodes', data:{ id: 'n9', parent1: 'n37'}},
                       { group:'nodes', data:{ id: 'n10', parent1: 'n38'}},
                       { group:'nodes', data:{ id: 'n12'}},
                       { group:'nodes', data:{ id: 'n13'}},
                       { group:'nodes', data:{ id: 'n14'}},
                       { group:'nodes', data:{ id: 'n15'}},
                       { group:'nodes', data:{ id: 'n16'}},
                       { group:'nodes', data:{ id: 'n17'}},
                       { group:'nodes', data:{ id: 'n18'}},
                       { group:'nodes', data:{ id: 'n19'}},
                       { group:'nodes', data:{ id: 'n20'}},
                       { group:'nodes', data:{ id: 'n21'}},
                       { group:'nodes', data:{ id: 'n22'}},
                       { group:'nodes', data:{ id: 'n23'}},
                       { group:'nodes', data:{ id: 'n24', parent1: 'n39'}},
                       { group:'nodes', data:{ id: 'n25', parent1: 'n39'}},
                       { group:'nodes', data:{ id: 'n26', parent1: 'n42'}},
                       { group:'nodes', data:{ id: 'n27', parent1: 'n42'}},
                       { group:'nodes', data:{ id: 'n28', parent1: 'n42'}},
                       { group:'nodes', data:{ id: 'n29', parent1: 'n40'}},
                       { group:'nodes', data:{ id: 'n31', parent1: 'n41'}},
                       { group:'nodes', data:{ id: 'n32', parent1: 'n41'}},
                       { group:'nodes', data:{ id: 'n33', parent1: 'n41'}},
                       { group:'nodes', data:{ id: 'n34', parent1: 'n41'}},
                       { group:'nodes', data:{ id: 'n35', parent1: 'n41'}},
                       { group:'nodes', data:{ id: 'n36', parent1: 'n41'}},
                       { group:'edges', data:{ id: 'e0', source: 'n0', target: 'n1'} },
                       { group:'edges', data:{ id: 'e1', source: 'n1', target: 'n2'} },
                       { group:'edges', data:{ id: 'e2', source: 'n2', target: 'n3'} },
                       { group:'edges', data:{ id: 'e3', source: 'n0', target: 'n3'} },
                       { group:'edges', data:{ id: 'e4', source: 'n1', target: 'n4'} },
                       { group:'edges', data:{ id: 'e5', source: 'n2', target: 'n4'} },
                       { group:'edges', data:{ id: 'e6', source: 'n4', target: 'n5'} },
                       { group:'edges', data:{ id: 'e7', source: 'n5', target: 'n6'} },
                       { group:'edges', data:{ id: 'e8', source: 'n4', target: 'n6'} },
                       { group:'edges', data:{ id: 'e9', source: 'n4', target: 'n7'} },
                       { group:'edges', data:{ id: 'e10', source: 'n7', target: 'n8'} },
                       { group:'edges', data:{ id: 'e11', source: 'n8', target: 'n9'} },
                       { group:'edges', data:{ id: 'e12', source: 'n7', target: 'n9'} },
                       { group:'edges', data:{ id: 'e13', source: 'n13', target: 'n14'} },
                       { group:'edges', data:{ id: 'e14', source: 'n12', target: 'n14'} },
                       { group:'edges', data:{ id: 'e15', source: 'n14', target: 'n15'} },
                       { group:'edges', data:{ id: 'e16', source: 'n14', target: 'n16'} },
                       { group:'edges', data:{ id: 'e17', source: 'n15', target: 'n17'} },
                       { group:'edges', data:{ id: 'e18', source: 'n17', target: 'n18'} },
                       { group:'edges', data:{ id: 'e19', source: 'n18', target: 'n19'} },
                       { group:'edges', data:{ id: 'e20', source: 'n17', target: 'n20'} },
                       { group:'edges', data:{ id: 'e21', source: 'n19', target: 'n20'} },
                       { group:'edges', data:{ id: 'e22', source: 'n16', target: 'n20'} },
                       { group:'edges', data:{ id: 'e23', source: 'n20', target: 'n21'} },
                       { group:'edges', data:{ id: 'e25', source: 'n23', target: 'n24'} },
                       { group:'edges', data:{ id: 'e26', source: 'n24', target: 'n25'} },
                       { group:'edges', data:{ id: 'e30', source: 'n26', target: 'n27'} },
                       { group:'edges', data:{ id: 'e31', source: 'n26', target: 'n28'} },
                       { group:'edges', data:{ id: 'e33', source: 'n21', target: 'n31'} },
                       { group:'edges', data:{ id: 'e35', source: 'n31', target: 'n33'} },
                       { group:'edges', data:{ id: 'e36', source: 'n31', target: 'n34'} },
                       { group:'edges', data:{ id: 'e37', source: 'n33', target: 'n34'} },
                       { group:'edges', data:{ id: 'e38', source: 'n32', target: 'n35'} },
                       { group:'edges', data:{ id: 'e39', source: 'n32', target: 'n36'} },
                      ]
        });
        document.getElementById("layoutButton").addEventListener("click", function(){
          var layout = cy.layout({
            name: 'cose-bilkent',
            animate: 'end',
            animationEasing: 'ease-out',
            animationDuration: 1000,
            randomize: true
          });

          layout.run();
        });
        document.getElementById("randomize").addEventListener("click", function(){
          var layout = cy.layout({
            name: 'random',
            animate: true,
            animationDuration: 1000,
            animationEasing: 'ease-out'
          });

          layout.run();
        });
        
        document.getElementById("save").addEventListener("click", function(){
	    	  window.localStorage.setItem('savedlayout', JSON.stringify(cy.json()));
	      });
	      
	      document.getElementById("reload").addEventListener("click", function(){
	    	  cy.json(JSON.parse(window.localStorage.getItem('savedlayout')));
	      });
      });
body {
  font-family: helvetica;
  font-size: 14px;
}

#cy {
  width: 100%;
  height: 90%;
  z-index: 999;
}

h1 {
  opacity: 0.5;
  font-size: 1em;
}

button {
  margin-right: 10px;
}
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<!--polyfills are needed for this extension for old browsers like IE -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/shim.min.js"></script>
<script src="https://unpkg.com/layout-base/layout-base.js"></script>
<script src="https://unpkg.com/cose-base/cose-base.js"></script>
<script src="https://unpkg.com/cytoscape-cose-bilkent/cytoscape-cose-bilkent.js"></script>
    
<button id="randomize" type="button">Randomize</button>
<button id="layoutButton" type="button">CoSE-Bilkent</button>
<button id="save" class="button">save</button>
<button id="reload" class="button">reload</button>
<div id="cy"></div>


Solution

  • EDIT: I tried this again, after @Ravenous pointed out the benefits of cy.json():

    Using cy.json() in this example works just fine, if you delete the other elements before adding the old ones.

    As long as you run the preset layout, the code can also look like this:

    document.getElementById("save").addEventListener("click", function () {
        window.localStorage.setItem("elements", JSON.stringify( cy.json() ));
    });
    
    document.getElementById("reload").addEventListener("click", function () {
        cy.elements().remove();
        cy.json({ elements: JSON.parse( window.localStorage.getItem("elements") ).elements }).layout({ name: 'preset' }).run();
    });
    

    or

    document.getElementById("save").addEventListener("click", function() {
        window.localStorage.setItem("elements", JSON.stringify({
          nodes: cy.nodes.jsons(),
          edges: cy.edges.jsons() 
        }));
    });
    
    document.getElementById("reload").addEventListener("click", function() {
        cy.elements().remove();
        cy.add( JSON.parse(window.localStorage.getItem("elements")) ).layout({ name: 'preset' }).run();  
    });
    


    Old answer:

    This problem has already been adressed here, but it took me some time to find it. Basically, you'll want to use cy.nodes().jsons() insted of just cy.json():

    var elements = {
        nodes: cy.nodes().jsons(),
        edges: cy.edges().jsons(),
    };
    

    This way you get the collection with every attribute in a JSON format. After that, you can save the elements.json to your local storage and get them back into the graph via cy.add(). I added a preset layout for the graph, that way the positions are not mixxed up after being reloaded:

    var elements1 = [{
        group: "nodes",
        data: {
          id: "n0"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n1"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n2"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n3"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n4",
          parent1: "n37"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n5"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n6"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n7",
          parent1: "n37"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n8",
          parent1: "n37"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n9",
          parent1: "n37"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n10",
          parent1: "n38"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n12"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n13"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n14"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n15"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n16"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n17"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n18"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n19"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n20"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n21"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n22"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n23"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n24",
          parent1: "n39"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n25",
          parent1: "n39"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n26",
          parent1: "n42"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n27",
          parent1: "n42"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n28",
          parent1: "n42"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n29",
          parent1: "n40"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n31",
          parent1: "n41"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n32",
          parent1: "n41"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n33",
          parent1: "n41"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n34",
          parent1: "n41"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n35",
          parent1: "n41"
        }
      },
      {
        group: "nodes",
        data: {
          id: "n36",
          parent1: "n41"
        }
      },
      {
        group: "edges",
        data: {
          id: "e0",
          source: "n0",
          target: "n1"
        }
      },
      {
        group: "edges",
        data: {
          id: "e1",
          source: "n1",
          target: "n2"
        }
      },
      {
        group: "edges",
        data: {
          id: "e2",
          source: "n2",
          target: "n3"
        }
      },
      {
        group: "edges",
        data: {
          id: "e3",
          source: "n0",
          target: "n3"
        }
      },
      {
        group: "edges",
        data: {
          id: "e4",
          source: "n1",
          target: "n4"
        }
      },
      {
        group: "edges",
        data: {
          id: "e5",
          source: "n2",
          target: "n4"
        }
      },
      {
        group: "edges",
        data: {
          id: "e6",
          source: "n4",
          target: "n5"
        }
      },
      {
        group: "edges",
        data: {
          id: "e7",
          source: "n5",
          target: "n6"
        }
      },
      {
        group: "edges",
        data: {
          id: "e8",
          source: "n4",
          target: "n6"
        }
      },
      {
        group: "edges",
        data: {
          id: "e9",
          source: "n4",
          target: "n7"
        }
      },
      {
        group: "edges",
        data: {
          id: "e10",
          source: "n7",
          target: "n8"
        }
      },
      {
        group: "edges",
        data: {
          id: "e11",
          source: "n8",
          target: "n9"
        }
      },
      {
        group: "edges",
        data: {
          id: "e12",
          source: "n7",
          target: "n9"
        }
      },
      {
        group: "edges",
        data: {
          id: "e13",
          source: "n13",
          target: "n14"
        }
      },
      {
        group: "edges",
        data: {
          id: "e14",
          source: "n12",
          target: "n14"
        }
      },
      {
        group: "edges",
        data: {
          id: "e15",
          source: "n14",
          target: "n15"
        }
      },
      {
        group: "edges",
        data: {
          id: "e16",
          source: "n14",
          target: "n16"
        }
      },
      {
        group: "edges",
        data: {
          id: "e17",
          source: "n15",
          target: "n17"
        }
      },
      {
        group: "edges",
        data: {
          id: "e18",
          source: "n17",
          target: "n18"
        }
      },
      {
        group: "edges",
        data: {
          id: "e19",
          source: "n18",
          target: "n19"
        }
      },
      {
        group: "edges",
        data: {
          id: "e20",
          source: "n17",
          target: "n20"
        }
      },
      {
        group: "edges",
        data: {
          id: "e21",
          source: "n19",
          target: "n20"
        }
      },
      {
        group: "edges",
        data: {
          id: "e22",
          source: "n16",
          target: "n20"
        }
      },
      {
        group: "edges",
        data: {
          id: "e23",
          source: "n20",
          target: "n21"
        }
      },
      {
        group: "edges",
        data: {
          id: "e25",
          source: "n23",
          target: "n24"
        }
      },
      {
        group: "edges",
        data: {
          id: "e26",
          source: "n24",
          target: "n25"
        }
      },
      {
        group: "edges",
        data: {
          id: "e30",
          source: "n26",
          target: "n27"
        }
      },
      {
        group: "edges",
        data: {
          id: "e31",
          source: "n26",
          target: "n28"
        }
      },
      {
        group: "edges",
        data: {
          id: "e33",
          source: "n21",
          target: "n31"
        }
      },
      {
        group: "edges",
        data: {
          id: "e35",
          source: "n31",
          target: "n33"
        }
      },
      {
        group: "edges",
        data: {
          id: "e36",
          source: "n31",
          target: "n34"
        }
      },
      {
        group: "edges",
        data: {
          id: "e37",
          source: "n33",
          target: "n34"
        }
      },
      {
        group: "edges",
        data: {
          id: "e38",
          source: "n32",
          target: "n35"
        }
      },
      {
        group: "edges",
        data: {
          id: "e39",
          source: "n32",
          target: "n36"
        }
      }
    ];
    
    document.addEventListener("DOMContentLoaded", function() {
      var cy = (window.cy = cytoscape({
        container: document.getElementById("cy"),
    
        ready: function() {
          this.nodes().forEach(function(node) {
            let width = [30, 70, 110];
            let size = width[Math.floor(Math.random() * 3)];
            node.css("width", size);
            node.css("height", size);
          });
          this.layout({
            name: "cose-bilkent",
            animationDuration: 1000
          }).run();
        },
    
        style: [{
            selector: "node",
            style: {
              'content': 'data(id)',
              'text-valign': 'center',
              'text-halign': 'center',
              'background-color': '#ad1a66'
            }
          },
    
          {
            selector: ":parent",
            style: {
              "background-opacity": 0.333
            }
          },
    
          {
            selector: "edge",
            style: {
              width: 3,
              "line-color": "#ad1a66"
            }
          }
        ],
    
        elements: [{
            group: "nodes",
            data: {
              id: "n0"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n1"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n2"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n3"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n4",
              parent: "n37"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n5"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n6"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n7",
              parent: "n37"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n8",
              parent: "n37"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n9",
              parent: "n37"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n10",
              parent: "n38"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n12"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n13"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n14"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n15"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n16"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n17"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n18"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n19"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n20"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n21"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n22"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n23"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n24",
              parent: "n39"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n25",
              parent: "n39"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n26",
              parent: "n42"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n27",
              parent: "n42"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n28",
              parent: "n42"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n29",
              parent: "n40"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n31",
              parent: "n41"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n32",
              parent: "n41"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n33",
              parent: "n41"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n34",
              parent: "n41"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n35",
              parent: "n41"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n36",
              parent: "n41"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n37"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n38"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n39",
              parent: "n43"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n40",
              parent: "n42"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n41",
              parent: "n42"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n42",
              parent: "n43"
            }
          },
          {
            group: "nodes",
            data: {
              id: "n43"
            }
          },
          {
            group: "edges",
            data: {
              id: "e0",
              source: "n0",
              target: "n1"
            }
          },
          {
            group: "edges",
            data: {
              id: "e1",
              source: "n1",
              target: "n2"
            }
          },
          {
            group: "edges",
            data: {
              id: "e2",
              source: "n2",
              target: "n3"
            }
          },
          {
            group: "edges",
            data: {
              id: "e3",
              source: "n0",
              target: "n3"
            }
          },
          {
            group: "edges",
            data: {
              id: "e4",
              source: "n1",
              target: "n4"
            }
          },
          {
            group: "edges",
            data: {
              id: "e5",
              source: "n2",
              target: "n4"
            }
          },
          {
            group: "edges",
            data: {
              id: "e6",
              source: "n4",
              target: "n5"
            }
          },
          {
            group: "edges",
            data: {
              id: "e7",
              source: "n5",
              target: "n6"
            }
          },
          {
            group: "edges",
            data: {
              id: "e8",
              source: "n4",
              target: "n6"
            }
          },
          {
            group: "edges",
            data: {
              id: "e9",
              source: "n4",
              target: "n7"
            }
          },
          {
            group: "edges",
            data: {
              id: "e10",
              source: "n7",
              target: "n8"
            }
          },
          {
            group: "edges",
            data: {
              id: "e11",
              source: "n8",
              target: "n9"
            }
          },
          {
            group: "edges",
            data: {
              id: "e12",
              source: "n7",
              target: "n9"
            }
          },
          {
            group: "edges",
            data: {
              id: "e13",
              source: "n13",
              target: "n14"
            }
          },
          {
            group: "edges",
            data: {
              id: "e14",
              source: "n12",
              target: "n14"
            }
          },
          {
            group: "edges",
            data: {
              id: "e15",
              source: "n14",
              target: "n15"
            }
          },
          {
            group: "edges",
            data: {
              id: "e16",
              source: "n14",
              target: "n16"
            }
          },
          {
            group: "edges",
            data: {
              id: "e17",
              source: "n15",
              target: "n17"
            }
          },
          {
            group: "edges",
            data: {
              id: "e18",
              source: "n17",
              target: "n18"
            }
          },
          {
            group: "edges",
            data: {
              id: "e19",
              source: "n18",
              target: "n19"
            }
          },
          {
            group: "edges",
            data: {
              id: "e20",
              source: "n17",
              target: "n20"
            }
          },
          {
            group: "edges",
            data: {
              id: "e21",
              source: "n19",
              target: "n20"
            }
          },
          {
            group: "edges",
            data: {
              id: "e22",
              source: "n16",
              target: "n20"
            }
          },
          {
            group: "edges",
            data: {
              id: "e23",
              source: "n20",
              target: "n21"
            }
          },
          {
            group: "edges",
            data: {
              id: "e25",
              source: "n23",
              target: "n24"
            }
          },
          {
            group: "edges",
            data: {
              id: "e26",
              source: "n24",
              target: "n25"
            }
          },
          {
            group: "edges",
            data: {
              id: "e27",
              source: "n26",
              target: "n38"
            }
          },
          {
            group: "edges",
            data: {
              id: "e29",
              source: "n26",
              target: "n39"
            }
          },
          {
            group: "edges",
            data: {
              id: "e30",
              source: "n26",
              target: "n27"
            }
          },
          {
            group: "edges",
            data: {
              id: "e31",
              source: "n26",
              target: "n28"
            }
          },
          {
            group: "edges",
            data: {
              id: "e33",
              source: "n21",
              target: "n31"
            }
          },
          {
            group: "edges",
            data: {
              id: "e35",
              source: "n31",
              target: "n33"
            }
          },
          {
            group: "edges",
            data: {
              id: "e36",
              source: "n31",
              target: "n34"
            }
          },
          {
            group: "edges",
            data: {
              id: "e37",
              source: "n33",
              target: "n34"
            }
          },
          {
            group: "edges",
            data: {
              id: "e38",
              source: "n32",
              target: "n35"
            }
          },
          {
            group: "edges",
            data: {
              id: "e39",
              source: "n32",
              target: "n36"
            }
          },
          {
            group: "edges",
            data: {
              id: "e40",
              source: "n16",
              target: "n40"
            }
          }
        ],
      }));
    
      document.getElementById("layoutButton").addEventListener("click", function() {
        var layout = cy.layout({
          name: "cose-bilkent",
          animate: "end",
          animationEasing: "ease-out",
          animationDuration: 1000,
          randomize: true
        });
    
        layout.run();
      });
      document.getElementById("randomize").addEventListener("click", function() {
        var layout = cy.layout({
          name: "random",
          animate: true,
          animationDuration: 1000,
          animationEasing: "ease-out"
        });
    
        layout.run();
      });
    
      document.getElementById("save").addEventListener("click", function() {
        window.localStorage.setItem("elements", JSON.stringify(cy.json()));
      });
    
      document.getElementById("reload").addEventListener("click", function() {
        cy.elements().remove();
        cy.json({
          elements: JSON.parse(window.localStorage.getItem("elements")).elements
        }).layout({
          name: 'preset'
        }).run();
        cy.fit();
        cy.center();
      });
    });
    body {
      font-family: helvetica;
      font-size: 14px;
    }
    
    #cy {
      height: 100%;
      width: 90%;
      position: absolute;
    }
    
    h1 {
      opacity: 0.5;
      font-size: 1em;
    }
    
    button {
      margin-right: 10px;
    }
    <script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
    
    <!--polyfills are needed for this extension for old browsers like IE -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/shim.min.js"></script>
    <script src="https://unpkg.com/layout-base/layout-base.js"></script>
    <script src="https://unpkg.com/cose-base/cose-base.js"></script>
    
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/cytoscape-cose-bilkent.min.js"></script>
    
    <body>
      <button id="randomize" type="button">Randomize</button>
      <button id="layoutButton" type="button">CoSE-Bilkent</button>
      <button id="save" class="button">save</button>
      <button id="reload" class="button">reload</button>
      <div id="cy"></div>
    
    </body>