/* [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){ // 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 Abscisse du point * @y Ordonnees du point * * @return distance 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 Id du noeud courant * @pos 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);