Skip to content

Instantly share code, notes, and snippets.

@maxkfranz
Last active July 5, 2017 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save maxkfranz/a1aea574f0e248b2b38e to your computer and use it in GitHub Desktop.
Save maxkfranz/a1aea574f0e248b2b38e to your computer and use it in GitHub Desktop.
Cytoscape.js & Angular
// a very simple example of angular/cytoscape.js integration
// context (rightclick/2finger) drag to resize in graph
// use text boxes to resize in angular
var app = angular.module('app', []);
// use a factory instead of a directive, because cy.js is not just for visualisation; you need access to the graph model and events etc
app.factory('peopleGraph', [ '$q', function( $q ){
var cy;
var peopleGraph = function(people){
var deferred = $q.defer();
// put people model in cy.js
var eles = [];
for( var i = 0; i < people.length; i++ ){
eles.push({
group: 'nodes',
data: {
id: people[i].id,
weight: people[i].weight,
name: people[i].name
}
});
}
$(function(){ // on dom ready
cy = cytoscape({
container: $('#cy')[0],
style: cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(name)',
'height': 80,
'width': 'mapData(weight, 1, 200, 1, 200)',
'text-valign': 'center',
'color': 'white',
'text-outline-width': 2,
'text-outline-color': '#888'
})
.selector('edge')
.css({
'target-arrow-shape': 'triangle'
})
.selector(':selected')
.css({
'background-color': 'black',
'line-color': 'black',
'target-arrow-color': 'black',
'source-arrow-color': 'black',
'text-outline-color': 'black'
}),
layout: {
name: 'cose',
padding: 10
},
elements: eles,
ready: function(){
deferred.resolve( this );
cy.on('cxtdrag', 'node', function(e){
var node = this;
var dy = Math.abs( e.cyPosition.x - node.position().x );
var weight = Math.round( dy*2 );
node.data('weight', weight);
fire('onWeightChange', [ node.id(), node.data('weight') ]);
});
}
});
}); // on dom ready
return deferred.promise;
};
peopleGraph.listeners = {};
function fire(e, args){
var listeners = peopleGraph.listeners[e];
for( var i = 0; listeners && i < listeners.length; i++ ){
var fn = listeners[i];
fn.apply( fn, args );
}
}
function listen(e, fn){
var listeners = peopleGraph.listeners[e] = peopleGraph.listeners[e] || [];
listeners.push(fn);
}
peopleGraph.setPersonWeight = function(id, weight){
cy.$('#' + id).data('weight', weight);
};
peopleGraph.onWeightChange = function(fn){
listen('onWeightChange', fn);
};
return peopleGraph;
} ]);
app.controller('PeopleCtrl', [ '$scope', 'peopleGraph', function( $scope, peopleGraph ){
var cy; // maybe you want a ref to cy
// (usually better to have the srv as intermediary)
$scope.people = [
{ id: 'l', name: 'Laurel', weight: 65 },
{ id: 'h', name: 'Hardy', weight: 110 }
];
var peopleById = {};
for( var i = 0; i < $scope.people.length; i++ ){
var p = $scope.people[i];
peopleById[ p.id ] = p;
}
// you would probably want some ui to prevent use of PeopleCtrl until cy is loaded
peopleGraph( $scope.people ).then(function( peopleCy ){
cy = peopleCy;
// use this variable to hide ui until cy loaded if you want
$scope.cyLoaded = true;
});
$scope.onWeightChange = function(person){
peopleGraph.setPersonWeight( person.id, person.weight );
};
peopleGraph.onWeightChange(function(id, weight){
peopleById[id].weight = weight;
$scope.$apply();
});
} ]);
<!DOCTYPE html>
<html>
<head>
<link href="style.css" rel="stylesheet" />
<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">
<title>AngularJS example</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://cytoscape.github.io/cytoscape.js/api/cytoscape.js-latest/cytoscape.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script src="code.js"></script>
</head>
<body ng-app="app">
<div id="logo"></div>
<div id="cy"></div>
<table id="people-table" ng-controller="PeopleCtrl">
<tbody>
<tr>
<th>Name</th>
<th>Weight</th>
</tr>
<tr ng-repeat="person in people">
<td>{{person.name}}</td>
<td><input type="number" min="1" ng-model="person.weight" ng-change="onWeightChange(person)" /></td>
</tr>
</tbody>
</table>
</body>
</html>
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#logo {
position: absolute;
left: 0;
top: 0;
background-image: url('https://raw.githubusercontent.com/angular/angular.js/master/images/logo/AngularJS-Shield.exports/AngularJS-Shield-medium.png');
background-size: contain;
background-repeat: no-repeat;
width: 33%;
height: 33%;
z-index: -1;
opacity: 0.5;
pointer-events: none;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
#people-table {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 999;
background: rgba(255, 200, 200, 0.5);
}
th {
text-align: left;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment