Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I can't get cytoscape.js to display my chart at all

Tags:

I built a chart in web webpage using the JavaScript chart program cytoscape.js. It does not display anything at all. But it doesn't' give syntax errors either, other than a warning about taking over the mouse for zooming purposes.

Here is the code:

     <style type="text/css">
        #cy {
            width: 90%;
            height: 300px;
            display: block;
        }
    </style>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.14.0/cytoscape.min.js"></script>
    <script type="text/javascript">
        var cy = cytoscape({

            container: document.getElementById('cy'), // container to render in


            style: [ // the stylesheet for the graph
                {
                    selector: 'node',
                    style: {
                        'background-color': '#666',
                        'label': 'data(id)'
                    }
                },

                {
                    selector: 'edge',
                    style: {
                        'width': 3,
                        'line-color': '#ccc',
                        'target-arrow-color': '#ccc',
                        'target-arrow-shape': 'triangle'
                    }
                }
            ],


            // initial viewport state:
            zoom: 1,
            pan: { x: 0, y: 0 },

            // interaction options:
            minZoom: 1e-50,
            maxZoom: 1e50,
            zoomingEnabled: true,
            userZoomingEnabled: true,
            panningEnabled: true,
            userPanningEnabled: true,
            boxSelectionEnabled: true,
            selectionType: 'single',
            touchTapThreshold: 8,
            desktopTapThreshold: 4,
            autolock: false,
            autoungrabify: false,
            autounselectify: false,

            // rendering options:
            headless: false,
            styleEnabled: true,
            hideEdgesOnViewport: false,
            textureOnViewport: false,
            motionBlur: false,
            motionBlurOpacity: 0.2,
            wheelSensitivity: 1,
            pixelRatio: 'auto'
        });
        let options = {
            name: 'breadthfirst',

            fit: true, // whether to fit the viewport to the graph
            directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
            padding: 30, // padding on fit
            circle: false, // put depths in concentric circles if true, put depths top down if false
            grid: false, // whether to create an even grid into which the DAG is placed (circle:false only)
            spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
            boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
            avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
            nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm
            roots: undefined, // the roots of the trees
            maximal: false, // whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only)
            animate: false, // whether to transition the node positions
            animationDuration: 500, // duration of animation in ms if enabled
            animationEasing: undefined, // easing of animation if enabled,
            animateFilter: function (node, i) { return true; }, // a function that determines whether the node should be animated.  All nodes animated by default on animate enabled.  Non-animated nodes are positioned immediately when the layout starts
            ready: undefined, // callback on layoutready
            stop: undefined, // callback on layoutstop
            transform: function (node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts
        };

        cy.layout(options);
var eles1 = cy.add([
{ group: 'nodes', data: { id: 'E1'} },
{ group: 'nodes', data: { id: 'E2'} },
{ group: 'nodes', data: { id: 'E3'} },
{ group: 'nodes', data: { id: 'E4'} },
{ group: 'nodes', data: { id: 'E5'} },
{ group: 'nodes', data: { id: 'E6'} },
{ group: 'nodes', data: { id: 'E7'} },
{ group: 'nodes', data: { id: 'E8'} }  ]);
var eles2 = cy.add([
{ group: 'nodes', data: { id: 'LH1'} },
{ group: 'nodes', data: { id: 'RH1'} },
{ group: 'nodes', data: { id: 'LH2'} },
{ group: 'nodes', data: { id: 'LH3'} },
{ group: 'nodes', data: { id: 'RH2'} },
{ group: 'nodes', data: { id: 'LH4'} },
{ group: 'nodes', data: { id: 'RH3'} },
{ group: 'nodes', data: { id: 'RH4'} } ]);
var eles4 = cy.add([
{ group: 'edges', data: { id: 'edge0', source: 'E4', target: 'E5' } },
{ group: 'edges', data: { id: 'edge1', source: 'E6', target: 'E7' } },
{ group: 'edges', data: { id: 'edge2', source: 'LH1', target: 'E1' } },
{ group: 'edges', data: { id: 'edge3', source: 'LH1', target: 'RH1' } },
{ group: 'edges', data: { id: 'edge4', source: 'LH2', target: 'E4' } },
{ group: 'edges', data: { id: 'edge5', source: 'LH3', target: 'E4' } },
{ group: 'edges', data: { id: 'edge6', source: 'LH4', target: 'E6' } },
{ group: 'edges', data: { id: 'edge7', source: 'RH1', target: 'E2' } },
{ group: 'edges', data: { id: 'edge8', source: 'RH1', target: 'E3' } },
{ group: 'edges', data: { id: 'edge9', source: 'RH2', target: 'E5' } },
{ group: 'edges', data: { id: 'edge10', source: 'RH3', target: 'E7' } },
{ group: 'edges', data: { id: 'edge11', source: 'RH4', target: 'E8' } }  ]);

</script>

    <center>

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

    </center>

My code is actually generated in an asp.net page, but that should not make a difference.

like image 295
Mark Springer Avatar asked Mar 16 '20 12:03

Mark Springer


1 Answers

You are adding the elements to the graph after the layout has been run. That's why all your nodes are piled up on the upper left corner.

You have two choices here:

  1. Supply both the layout at the elements on the constructor.
  2. Initialize the graph first, then add the elements (e.g. using cy.json()) and then tell cytoscape to run the layout with cy.layout(...).run().

Documentation for cy.layout() is here, and for cy.json() here.

The following snippet uses the first approach, but I have left the second one commented in case you cannot supply the elements on the constructor call (i.e. if you have to fetch them asynchronously).

var nodeArray = [
  { group: 'nodes', data: { id: 'E1'} },
  { group: 'nodes', data: { id: 'E2'} },
  { group: 'nodes', data: { id: 'E3'} },
  { group: 'nodes', data: { id: 'E4'} },
  { group: 'nodes', data: { id: 'E5'} },
  { group: 'nodes', data: { id: 'E6'} },
  { group: 'nodes', data: { id: 'E7'} },
  { group: 'nodes', data: { id: 'E8'} },
  { group: 'nodes', data: { id: 'LH1'} },
  { group: 'nodes', data: { id: 'RH1'} },
  { group: 'nodes', data: { id: 'LH2'} },
  { group: 'nodes', data: { id: 'LH3'} },
  { group: 'nodes', data: { id: 'RH2'} },
  { group: 'nodes', data: { id: 'LH4'} },
  { group: 'nodes', data: { id: 'RH3'} },
  { group: 'nodes', data: { id: 'RH4'} }
];

var edgeArray = [
  { group: 'edges', data: { id: 'edge0', source: 'E4', target: 'E5' } },
  { group: 'edges', data: { id: 'edge1', source: 'E6', target: 'E7' } },
  { group: 'edges', data: { id: 'edge2', source: 'LH1', target: 'E1' } },
  { group: 'edges', data: { id: 'edge3', source: 'LH1', target: 'RH1' } },
  { group: 'edges', data: { id: 'edge4', source: 'LH2', target: 'E4' } },
  { group: 'edges', data: { id: 'edge5', source: 'LH3', target: 'E4' } },
  { group: 'edges', data: { id: 'edge6', source: 'LH4', target: 'E6' } },
  { group: 'edges', data: { id: 'edge7', source: 'RH1', target: 'E2' } },
  { group: 'edges', data: { id: 'edge8', source: 'RH1', target: 'E3' } },
  { group: 'edges', data: { id: 'edge9', source: 'RH2', target: 'E5' } },
  { group: 'edges', data: { id: 'edge10', source: 'RH3', target: 'E7' } },
  { group: 'edges', data: { id: 'edge11', source: 'RH4', target: 'E8' } }
];

var stylesArray = [{
  selector: 'node',
  style: {
    'background-color': '#666',
    'label': 'data(id)'
  }
},{
  selector: 'edge',
  style: {
    'width': 3,
    'line-color': '#ccc',
    'target-arrow-color': '#ccc',
    'target-arrow-shape': 'triangle'
  }
}];

var layout = {name: 'breadthfirst'};

// You used mostly default options, there's no need to redefine them
var cy = cytoscape({
  container: document.getElementById('cy'),
  style: stylesArray,
  // If you want to apply the layout on the constructor
  // you must supply the elements too
  layout: layout,
  elements: {
    nodes: nodeArray,
    edges: edgeArray
  }
});

// Or add the elements afterwards, it's your choice
// But then you need to re-run the layout
/*
cy.json({
  elements: {
    nodes: nodeArray,
    edges: edgeArray
  }
});

// Tell cytoscape to apply the layout when ready
cy.ready(function () {
  cy.layout(layout).run();
});
*/
 #cy {
   width: 90%;
   height: 300px;
   display: block;
 }
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.14.0/cytoscape.min.js"></script>
<div id="cy"></div>
like image 158
vicpermir Avatar answered Oct 12 '22 22:10

vicpermir