Cytoscape simple directive – angularJs

Cytoscape sample

Sorry but this sample uses old version of the Cytoscope.js and it isn’t maintained

I needed a mind-map chart for Angular and found the amazing Cytoscape.js project.
Check Cytoscape’s project site you’ll find lots of information about customizing the charts object.

Note: In this article I’ll show a simple directive sample that wraps it and connects it to a controller. I have used here a simple $broadcast method and just kept the data in a controller. It is not the recommended way and just used to simplify the sample without adding a service and more complex ways to interact with the directive.

Check out the sample @

Download source files @

HTML part of the directive

< cytoscape cy-data="mapData" cy-edges="edgeData" cy-click="doClick(value)"></cytoscape>

cytoscape – the directive’s element
cy-data – object name that contains the Nodes data
cy-edges – object name that contains the Edges data
cy-click – function to be called in the Controller, when clicking on a Node.

Basic element’s CSS

This CSS shapes the Cytoscape element in display.

#cy {
    height: 400px;
    width: 80%;
    border: 2px solid #662244;
    position: relative;
    clear: both;

The controller

Holding two objects – one for the nodes and one for the edges (the connecting lines between nodes) . It can use just one, more complex, object for both, but I wrote it like that to be easier to read and understand.

The controller also holds functions to add nodes and edges from the sample form.

The $scope.objTypes object just holds types of grouping data. I used the available shapes of Cytoscape as types for the sample.

angular.module('cytoscapeSample').controller('CytoscapeCtrl',function($scope, $rootScope){
    // container objects
    $scope.mapData = [];
    $scope.edgeData = [];
    // data types/groups object - used Cytoscape's shapes just to make it more clear
    $scope.objTypes = ['ellipse','triangle','rectangle','roundrectangle','pentagon','octagon','hexagon','heptagon','star'];

    // add object from the form then broadcast event which triggers the directive redrawing of the chart
    // you can pass values and add them without redrawing the entire chart, but this is the simplest way
    $scope.addObj = function(){
        // collecting data from the form
        var newObj = $;
        var newObjType = $scope.form.obj.objTypes;
        // building the new Node object
        // using the array length to generate an id for the sample (you can do it any other way)
        var newNode = {id:'n'+($scope.mapData.length), name:newObj, type:newObjType};
        // adding the new Node to the nodes array
        // broadcasting the event
        // resetting the form
        $scope.form.obj = '';

    // add Edges to the edges object, then broadcast the change event
    $scope.addEdge = function(){
        // collecting the data from the form
        var edge1 = $;
        var edge2 = $;
        // building the new Edge object from the data
        // using the array length to generate an id for the sample (you can do it any other way)
        var newEdge = {id:'e'+($scope.edgeData.length), source: edge1, target: edge2};
        // adding the new edge object to the adges array
        // broadcasting the event
        // resetting the form
        $scope.formEdges = '';

    // sample function to be called when clicking on an object in the chart
    $scope.doClick = function(value)
        // sample just passes the object's ID then output it to the console and to an alert

The directive

This is a simple sample directive.

angular.module('cytoscapeSample').directive('cytoscape', function($rootScope) {
    // graph visualisation by -
    return {
        restrict: 'E',
        template :'<div id="cy"></div>',
        replace: true,
        scope: {
            // data objects to be passed as an attributes - for nodes and edges
            cyData: '=',
            cyEdges: '=',
            // controller function to be triggered when clicking on a node
        link: function(scope, element, attrs, fn) {
            // dictionary of colors by types. Just to show some design options
            scope.typeColors = {

            // graph  build
            scope.doCy = function(){ // will be triggered on an event broadcast
                // initialize data object
                scope.elements = {};
                scope.elements.nodes = [];
                scope.elements.edges = [];

                // parse edges
                // you can build a complete object in the controller and pass it without rebuilding it in the directive.
                // doing it like that allows you to add options, design or what needed to the objects
                // doing it like that is also good if your data object/s has a different structure
                for (i=0; i<scope.cyEdges.length; i++)
                    // get edge source
                    var eSource = scope.cyEdges[i].source;
                    // get edge target
                    var eTarget = scope.cyEdges[i].target;
                    // get edge id
                    var eId = scope.cyEdges[i].id;
                    // build the edge object
                    var edgeObj = {
                    // adding the edge object to the edges array

                // parse data and create the Nodes array
                // object type - is the object's group
                for (i=0; i<scope.cyData.length; i++)
                    // get id, name and type  from the object
                    var dId = scope.cyData[i].id;
                    var dName = scope.cyData[i].name;
                    var dType = scope.cyData[i].type;
                    // get color from the object-color dictionary
                    var typeColor = scope.typeColors[Otype];
                    // build the object, add or change properties as you need - just have a name and id
                    var elementObj = {
                    // add new object to the Nodes array

                // graph  initialization
                // use object's properties as properties using: data(propertyName)
                // check Cytoscapes site for much more data, options, designs etc
                // here are just some basic options
                    layout: {
                        name: 'circle',
                        fit: true, // whether to fit the viewport to the graph
                        ready: undefined, // callback on layoutready
                        stop: undefined, // callback on layoutstop
                        padding: 5 // the padding on fit
                    style: cytoscape.stylesheet()
                            'shape': 'data(typeShape)',
                            'width': '120',
                            'height': '90',
                            'background-color': 'data(typeColor)',
                            'content': 'data(name)',
                            'text-valign': 'center',
                            'color': 'white',
                            'text-outline-width': 2,
                            'text-outline-color': 'data(typeColor)'
                            'width': '10',
                            'target-arrow-shape': 'triangle',
                            'source-arrow-shape': 'triangle'
                            'background-color': 'black',
                            'line-color': 'black',
                            'target-arrow-color': 'black',
                            'source-arrow-color': 'black'
                            'opacity': 0.65,
                            'text-opacity': 0.65
                        ready: function(){
               = this;

                        // giddy up...

                        // Event listeners
                        // with sample calling to the controller function as passed as an attribute
                        cy.on('tap', 'node', function(e){
                            var evtTarget = e.cyTarget;
                            var nodeId =;

                        // load the objects array
                        // use cy.add() / cy.remove() with passed data to add or remove nodes and edges without rebuilding the graph
                        // sample use can be adding a passed variable which will be broadcast on change

            }; // end doCy()

            // When the app object changed = redraw the graph
            // you can use it to pass data to be added or removed from the object without redrawing it
            // using cy.remove() / cy.add()
            $rootScope.$on('appChanged', function(){

Check out the sample @

Download source files @

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *