NxTIC/view/js/charts.js

410 lines
8.1 KiB
JavaScript

/* [1] Gestion du sociogramme
=========================================================*/
/* (0) On recupere les elements importants */
var SOCIOGRAM = {
container: document.getElementById('sociogram'),
sigma: null,
request: { path: 'charts/network_data' },
response: null,
nodes: null,
edges: null,
rad: 500,
nodeDistance: 100,
arrange: null
};
/* (0.5) Surcharge graph */
// On recupere les voisins d'un noeud
sigma.classes.graph.addMethod('nodeNeighbors', function(nodeId){
// On recupere les voisins du noeud courant
var neighbors = this.allNeighborsIndex[nodeId];
// Pile des voisins pour lesquels il faut chercher leurs voisins
var stack = [];
for( neighborId in neighbors ) stack.push(neighborId);
// Tant qu'il reste des voisins a trouver
while( stack.length > 0 ){
var subneighbors = this.allNeighborsIndex[stack[0]];
for( subId in subneighbors )
// Si le voisin est pas deja dans la liste/pile, on l'ajoute a la liste des voisins
if( neighbors[subId] == null ){
stack.push(subId); // On ajoute a la pile
neighbors[subId] = subneighbors[subId]; // On ajoute a la liste complete
}
stack.shift();
}
// On retourne le resultat
return neighbors;
});
// On recupere les voisins directs d'un noeud
sigma.classes.graph.addMethod('nodeDirectNeighbors', function(nodeId){
// On retourne les voisins directs
return this.allNeighborsIndex[nodeId];
});
/* (0.8) Initialisation de SIGMA */
SOCIOGRAM.sigma = new sigma({renderer: { container: SOCIOGRAM.container, 'type': 'canvas' }});
/* (1) On recupere les informations via l'API */
api.send(SOCIOGRAM.request, function(response){
console.log( response );
// Si erreur, on quitte
if( response.ModuleError != 0 ) return;
// Sinon on enregistre
SOCIOGRAM.response = response;
/* (2) Parametrage de SIGMA */
SOCIOGRAM.sigma.settings({
defaultNodeColor: '#348ed8',
defaultLabelSize: 14,
defaultLabelBGColor: "#ddd",
defaultHoverLabelBGColor: "#002147",
defaultLabelHoverColor: "#fff",
labelThreshold: 10,
defaultEdgeType: "line"
});
/* (3) On recupere la liste des noeuds */
SOCIOGRAM.nodes = [];
// Pour chaque alter
for( var i = 0 ; i < SOCIOGRAM.response.data.alter.length ; i++ ){
SOCIOGRAM.nodes.push({
'id': 'n-'+SOCIOGRAM.response.data.alter[i][0],
'label': SOCIOGRAM.response.data.alter[i][1],
'x': 0,
'y': 0,
'size': SOCIOGRAM.response.data.alter[i][2]
});
}
/* (4) On recupere la liste des liens */
SOCIOGRAM.edges = [];
for( var i = 0 ; i < SOCIOGRAM.response.data.inter.length ; i++ ){
SOCIOGRAM.edges.push({
'id': 'e-'+SOCIOGRAM.response.data.inter[i][0]+'-'+SOCIOGRAM.response.data.inter[i][1],
'source': 'n-'+SOCIOGRAM.response.data.inter[i][0],
'target': 'n-'+SOCIOGRAM.response.data.inter[i][1]
});
}
/* (5) On ajoute nos noeuds */
for( var i = 0 ; i < SOCIOGRAM.nodes.length ; i++)
SOCIOGRAM.sigma.graph.addNode(SOCIOGRAM.nodes[i]);
/* (6) On ajoute nos liens */
for( var i = 0 ; i < SOCIOGRAM.edges.length ; i++)
SOCIOGRAM.sigma.graph.addEdge(SOCIOGRAM.edges[i]);
/* (7) Gestion des interactions */
/* RETOURNE LA DISTANCE AVEC LE NOEUD LE PLUS PRES
*
* @x<float> Abscisse du point
* @y<float> Ordonnees du point
*
* @return distance<float> Retourne la distance du noeud le plus proche
*
*/
SOCIOGRAM.nodeAt = function(x, y){
var nodes = SOCIOGRAM.sigma.graph.nodes();
var minDistance = null;
for( nodeId in nodes ){
var distance = Math.sqrt( Math.pow(x-nodes[nodeId].x, 2) + Math.pow(y-nodes[nodeId].y, 2) );
if( minDistance == null || distance < minDistance )
minDistance = distance;
}
return minDistance;
};
/* POSITIONNE LES VOISINS AUTOUR DU NOEUD COURANT
*
* @nodeId<String> Id du noeud courant
* @pos<Object> Contient {x, y} position initiale, sinon la position actuelle du noeud
*
*/
SOCIOGRAM.arrange = function(nodeId, pos, alone){
var node = SOCIOGRAM.sigma.graph.nodes(nodeId);
// Si le noeud est deja place, on ne fais rien
if( node.x != 0 || node.y != 0 ) return;
var pos = (pos==null) ? {x: node.x, y: node.y} : pos; // On recupere la position
// Tant que le noeud est trop proche d'un autre, on l'eloigne
// UNIQUEMENT si alone n'est pas NULL
if( alone ){
while( SOCIOGRAM.nodeAt(pos.x, pos.y) < 2*SOCIOGRAM.nodeDistance ){
pos = {
x: pos.x + 2*SOCIOGRAM.nodeDistance*Math.cos(Math.random()*2*Math.PI),
y: pos.y + 2*SOCIOGRAM.nodeDistance*Math.sin(Math.random()*2*Math.PI)
};
}
}
// On recupere les voisins directs
var neighborsId = SOCIOGRAM.sigma.graph.nodeDirectNeighbors(nodeId);
var neighbors = {};
var neighborsCount = 0;
for( neighborId in neighborsId ){
neighbors[neighborId] = SOCIOGRAM.sigma.graph.nodes(neighborId);
neighborsCount++;
}
// On positionne le noeud
node.x = pos.x;
node.y = pos.y;
var angles = [];
// On positionne chaque voisin si c'est pas deja fait
for( neighborId in neighbors ){
var current = SOCIOGRAM.sigma.graph.nodes(neighborId);
// Si n'est pas deja positionne
if( current.x == 0 && current.y == 0 ){
// On cherche un angle tant qu'il est pas trop pres d'un deja pris
var angle, alreadyUsed = false;
do{
angle = Math.random()*2*Math.PI;
for( var i = 0 ; i < angles.length ; i++ )
if( Math.abs(angle-angles[i]) > Math.PI/10 ){
alreadyUsed = true;
break;
}
}while( alreadyUsed );
current.x = pos.x + SOCIOGRAM.nodeDistance*Math.cos(angle);
current.y = pos.y + SOCIOGRAM.nodeDistance*Math.sin(angle);
SOCIOGRAM.arrange(current.id);
}
}
SOCIOGRAM.sigma.refresh();
};
// On affiche que les voisins d'un noeud
SOCIOGRAM.sigma.bind('clickNode', function(e){
var nodeId = e.data.node.id;
// On recupere les voisins
var neighborNodes = SOCIOGRAM.sigma.graph.nodeNeighbors(nodeId);
neighborNodes[nodeId] = e.data.node; // on ajoute le noeud clique
SOCIOGRAM.sigma.graph.nodes().forEach(function(n) {
if( neighborNodes[n.id] != null ) n.color = n.originalColor;
else n.color = '#eee';
});
SOCIOGRAM.sigma.refresh();
});
// On affiche tous les noeuds quand on clique dans le vide
SOCIOGRAM.sigma.bind('clickStage', function(e){
SOCIOGRAM.sigma.graph.nodes().forEach(function(n){ n.color = n.originalColor; });
SOCIOGRAM.sigma.refresh();
});
/* (8) On affiche le graphique */
SOCIOGRAM.sigma.camera.ratio = 1.2;
// On repartit les noeuds
SOCIOGRAM.sigma.refresh();
SOCIOGRAM.sigma.graph.nodes().forEach(function(n){ SOCIOGRAM.arrange(n.id, null, true); });
SOCIOGRAM.sigma.refresh();
});
// var i,
// s,
// o,
// L = 10,
// N = 100,
// E = 500,
// g = {
// nodes: [],
// edges: []
// },
// step = 0;
// // Generate a random graph:
// for (i = 0; i < N; i++) {
// o = {
// id: 'n' + i,
// label: 'Node ' + i,
// circular_x: L * Math.cos(Math.PI * 2 * i / N - Math.PI / 2),
// circular_y: L * Math.sin(Math.PI * 2 * i / N - Math.PI / 2),
// circular_size: Math.random(),
// circular_color: '#' + (
// Math.floor(Math.random() * 16777215).toString(16) + '000000'
// ).substr(0, 6),
// grid_x: i % L,
// grid_y: Math.floor(i / L),
// grid_size: 1,
// grid_color: '#ccc'
// };
// ['x', 'y', 'size', 'color'].forEach(function(val) {
// o[val] = o['grid_' + val];
// });
// g.nodes.push(o);
// }
// for (i = 0; i < E; i++)
// g.edges.push({
// id: 'e' + i,
// source: 'n' + (Math.random() * N | 0),
// target: 'n' + (Math.random() * N | 0),
// });
// // Instantiate sigma:
// s = new sigma({
// graph: g,
// renderer: { container: document.getElementById('graph-container'), 'type': 'canvas' },
// settings: {
// animationsTime: 1000
// }
// });
// setInterval(function(){
// var prefix = ['grid_', 'circular_'][step = +!step];
// sigma.plugins.animate(
// s,
// {
// x: prefix + 'x',
// y: prefix + 'y',
// size: prefix + 'size',
// color: prefix + 'color'
// }
// );
// }, 10000);