La gestion des évènements

Dans cette partie nous allons parler du paramétrage des évènements et des interactions avec le graphe. L’avantage d’avoir un graphe dynamique en javascript est bien de pouvoir interagir avec lui, afin d’afficher des informations supplémentaires, de rediriger l’utilisateur vers une autre page et plein d’autre choses ;)

La capture des évènements

Il est très simple d’écouter les évènements de VisNetwork, pour cela il suffit d’ajouter des écouteurs à notre réseau comme ceci :

network.on("nomEvenement", mafunction);

Il existe un large choix d’évènements pour visnetwork, voici une petite liste de ceux que j’estime intéressants, vous pouvez retrouver les autres dans la doc :

  • click : Clic gauche de la souris sur la zone d’affichage du graphe
  • doubleClick : Double clic sur la zone d’affichage du graphe.
  • oncontext : Clic droit de la souris sur la zone d’affichage du graphe.
  • dragStart : Évènement déclenché lors du déclenchement du déplacement d’un noeud.
  • dragging : Évènement déclenché lors du déplacement d’un noeud.
  • dragEnd : Évènement déclenché lors de l’arrêt du déplacement d’un noeud.
  • zoom : Déclenché lors de l’action de zoom et de dezoom (molette de la souris).
  • selectNode : Déclenché lors de la sélection d’un noeud.
  • selectEdge : Déclenché lors de la sélection d’un lien.
  • deselectNode : Déclenché lors de la dé-sélection d’un noeud.
  • deselectEdge : Déclenché lors de la dé-sélection d’un lien.

Clic et double-clic

Avant de commencer la présentation des exemples, je vous fournis le code JavaScript utilisé afin que vous puissiez reproduire les exemples chez vous.

let nodes = new vis.DataSet([]);
let edges = new vis.DataSet([]);

let container = document.getElementById('graphe');

let data = {
  nodes: nodes,
  edges: edges
};
let options = {
    interaction:{hover:true}
};

// Initialisation de l'instance de VisNetwork
let network = new vis.Network(container, data, options);

// Ajout de nos deux noeuds
nodes.add(
    [
        {
            id: 1,
            label: "N1"
        },
        {
            id: 2,
            label: "N2"
        }
    ]
);

// Ajout du lien entre nos deux noeuds
edges.add(
    [
        {
            from: 1,
            to: 2,
            label: "E1",
        }
    ]
);

Nous allons écouter l’action de clic du notre graphe, elle se déclenche lorsque l’utilisateur clique sur la zone d’affichage du graphe.

network.on("click", function(data)
{
  if(data.nodes.length > 0)
  {
    alert(data.nodes[0]);
  }
});

Le paramètre data contient un tableau de tout les identifiants des noeuds et un tableau de tout les identifiants des liens dans la zone du clic. Dans notre exemple on vérifie qu’il y a bien un noeud dans la zone du clic et l’on affiche l’identifiant de ce noeud dans un pop-up.

Voici un second exemple pour vous montrer comment récupérer les labels des noeuds et des liens sélectionnés.

network.on("doubleClick", function(data)
{
  if(data.nodes.length > 0)
  {
    var selectedNode = nodes.get(data.nodes[0]);
      
    var label = selectedNode.label;
    
    alert(label);
  }
  else if(data.edges.length > 0)
  {
    var selectedEdges = edges.get(data.edges[0]);
      
    var label = selectedEdges.label;
    
    alert(label);
  }
});

La méthode nodes.get(id) nous permet de récupérer toutes les informations du noeud sur lequel on a cliqué, on récupère ensuite le label du noeud ou du lien, puis on l’affiche.

Au clic un pop-up avec le label du noeud ou du lien s'affiche à l'écran.
Au clic un pop-up avec le label du noeud ou du lien s'affiche à l'écran.

Zoom/Dézoom

Dans cet exemple on va afficher le niveau de zoom actuel dans une zone de texte.

Les paramètres de l’action de zoom ne sont pas les mêmes que les autres actions, ces paramètres sont :

  • direction : égale à + ou -.
  • scale : échelle actuelle du zoom (Nombre).
  • pointer : {x : position de la souris en x, y : position de la souris en y}.

Voici un exemple d’affichage du zoom actuel à chaque action de zoom ou de dézoom.

// Code Javascript
function zoom(data)
{
    document.getElementById("infos").innerHTML = data.scale;
}

network.on("zoom", zoom);

Il faut également ajouter une balise HTML qui contiendra nos informations : <div id="infos"></div>

Le niveau de zoom est affiché en bas de l'écran
Le niveau de zoom est affiché en bas de l'écran

Exercice

Je vous propose un petit exercice pour mettre en pratique les évènements, à partir du drag and drop (déplacement d’un noeud).

Le but est lors du déplacement d’un noeud de mesurer et d’afficher la valeur de son déplacement, pour cela on va utiliser les évènements dragStart, dragging et dragEnd.

Petite Astuce : Pour récupérer la position d’un noeud il faut utiliser la méthode network.getPositions(idNoeud)[idNoeud]

Procédure à suivre :

  • Lors de l’action dragStart, stocker la position du noeud.
  • Lors de l’action dragging, afficher la valeur actuelle du déplacement par rapport à la position initiale du noeud.
  • Lors de l’action dragEnd, afficher la valeur du déplacement qui vient de se terminer (ex: Dernier déplacement : X : 215 || Y : 17).
Vous devriez obtenir ce résultat lorsque vous avez terminé un déplacement.
Vous devriez obtenir ce résultat lorsque vous avez terminé un déplacement.

Bon courage ;)

Si vous n’y arrivez pas, vous pouvez retrouver la solution ci dessous :

Code HTML :

<!doctype html>
<html>
 <head>
   <title>Tuto VisNetwork</title>

   <style>
     #graphe
     {
       display: inline-block;
       width: 800px;
       height: 600px;

       background-color: #f0f0f0;
     }
   </style>

   <script type="text/javascript" src="vis.min.js"></script>

 </head>
 <body>

   <div id="graphe"></div>
   <div id="infos"></div>

   <script type="text/javascript" src="graph.js"></script>

 </body>
</html>

Code Javascript :

let nodes = new vis.DataSet([]);
let edges = new vis.DataSet([]);

let container = document.getElementById('graphe');

let data = {
  nodes: nodes,
  edges: edges
};
let options = {
    interaction:{hover:true}
};

// Initialisation de l'instance de VisNetwork
let network = new vis.Network(container, data, options);

// Ajout de nos deux noeuds
nodes.add(
    [
        {
            id: 1,
            label: "N1"
        },
        {
            id: 2,
            label: "N2"
        }
    ]
);

// Ajout du lien entre nos deux noeuds
edges.add(
    [
        {
            from: 1,
            to: 2,
            label: "E1",
        }
    ]
);

// Stockage de la position de départ
let startPos = {};

// Fonction appelé lors du lancement du déplacement
function dragStart(data)
{
    if(data.nodes.length > 0)
    {
        // Récupération des informations du noeud en cours de déplacement
        let selectedNode = nodes.get(data.nodes[0]);
        
        // Mise à jour de la variable stockant la position de départ
        startPos = network.getPositions(data.nodes[0])[data.nodes[0]];
    }
}

// Fonction s'exécutant en continu au cours du déplacement
function dragging(data)
{
    let text = "";
    
    if(data.nodes.length > 0)
    {
        // Récupération des informations du noeud en cours de déplacement
        let selectedNode = nodes.get(data.nodes[0]);
        
        // Récupération de la position du noeud
        let pos = network.getPositions(data.nodes[0])[data.nodes[0]];
        
        // Calcul de la différence de position entre la position actuel du noeud et sa position au debut de déplacement
        let posDiffX = pos.x - startPos.x;
        let posDiffY = pos.y - startPos.y;
        
        // Affichage du différenciel de position
        text += "X:" + posDiffX + " || Y:" + posDiffY;
    }
    
    document.getElementById("infos").innerHTML = text; 
}

// Fonction s’exécutant à la fin de l'action de déplacement (au relâchement de la souris)
function dragEnd(data)
{
    let text = "";
    
    if(data.nodes.length > 0)
    {
        // Récupération des informations du noeud
        let selectedNode = nodes.get(data.nodes[0]);
        
        // Récupération de la position du noeud
        let endPos = network.getPositions(data.nodes[0])[data.nodes[0]];
        
        // Calcul de la différence de position entre la position actuel du noeud et sa position au début de déplacement
        let posDiffX = endPos.x - startPos.x;
        let posDiffY = endPos.y - startPos.y;
        
        // Affichage du différentiel de position
        text += "Dernier déplacement : X:" + posDiffX + " || Y:" + posDiffY;
    }
    
    document.getElementById("infos").innerHTML = text; 
}

// Déclenchement des évènements
network.on("dragStart", dragStart);
network.on("dragging", dragging);
network.on("dragEnd", dragEnd);

Ce chapitre sur les évènements est maintenant terminé, si vous voulez connaître d’autres évènements rendez vous sur la doc où vous retrouverez une description en anglais de chaque évènements.

Dans la prochaine partie, je vous ferait découvrir les hierarchicals layouts permettant d’ordonnancer les noeuds et le clustering permettant de regrouper les noeuds.