web-dev-qa-db-fra.com

Comment dessiner un graphique ou une arborescence en JavaScript?

J'ai besoin de pouvoir dessiner des graphiques comme celui-ci en JavaScript:

crazy graph picture

Je connais la bibliothèque Raphael , mais c'est uniquement pour dessiner des formes arbitraires.

J'ai quelques types de nœuds prédéfinis (les nœuds colorés sur l'image) et du texte à proximité/à l'intérieur de chaque nœud. Cette bibliothèque ne semble pas gérer ce cas. Comment faire cela en JavaScript? Si cela a déjà été accompli par une autre bibliothèque, comment puis-je utiliser cette bibliothèque pour résoudre ce problème?

23
Alexey

Le Web est un monde en évolution rapide, et cette réponse était donc quelque peu dépassée. Dans cet esprit, j'ai rafraîchi cette réponse pour la rendre applicable en 2016.

  • D3.js - Ce serait toujours ma recommandation. Il est en développement actif et possède une communauté dynamique.
  • Vega - Un langage expressif (moins puissant que D3)
  • Cytoscape.js
  • Spring.js
  • cola.js

J'ajouterais que je n'ai utilisé que D3.js Dans cette nouvelle liste, sa puissance et sa flexibilité sont telles que je n'ai jamais eu besoin de trouver d'alternative. Voici un exemple d'implémentation d'un forcé dirigé .

var width = 960,
    height = 500;

var color = d3.scale.category20();

var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

d3.json("https://Gist.githubusercontent.com/mbostock/4062045/raw/4176c7d0c0c5ce15630d16072da0af67bb50eb6a/miserables.json", function(error, graph) {
  if (error) throw error;

  force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();

  var link = svg.selectAll(".link")
      .data(graph.links)
    .enter().append("line")
      .attr("class", "link")
      .style("stroke-width", function(d) { return Math.sqrt(d.value); });

  var node = svg.selectAll(".node")
      .data(graph.nodes)
    .enter().append("circle")
      .attr("class", "node")
      .attr("r", 5)
      .style("fill", function(d) { return color(d.group); })
      .call(force.drag);

  node.append("title")
      .text(function(d) { return d.name; });

  force.on("tick", function() {
    link.attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });

    node.attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  });
});
.node {
  stroke: #fff;
  stroke-width: 1.5px;
}

.link {
  stroke: #999;
  stroke-opacity: .6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Il existe un certain nombre de bibliothèques pour dessiner ce type de sortie dans un navigateur, vous avez mentionné Raphael, d'autres incluent:

  • Sigma.js
  • Processing.js
  • jit.js - Vendu à SenchaLabs. Le développeur solo a semblé arrêter de travailler dessus.
  • D3.js
  • Raphael.js - Semble avoir disparu, leur site principal a disparu

Personnellement, je recommanderais ce dernier, D3 selon le nombre d'éléments que vous souhaitez afficher et le support du navigateur dont vous avez besoin car il est bien documenté, puissant et facile à utiliser. Découvrez ceci projet Github pour un exemple de bibliothèque dirigée par la force .

Les changements que vous auriez besoin d'apporter pour accomplir la tâche que vous avez définie seraient les suivants:

1) Modifiez la provenance des données en modifiant la fonction suivante:

d3.json("flare.json", function(json) {
   root = json;
   root.fixed = true;
   root.x = w / 2;
   root.y = h / 2 - 80;
   update();
 });

Modifiez la d3.json("flare.json") pour pointer vers un autre fichier/URL sur votre serveur. Il est possible de faire la même chose avec jQuery si vous le souhaitez et d'utiliser une approche de rappel similaire.

2) Pour colorer vos nœuds en fonction de différentes catégories, vous souhaiterez modifier la section suivante:

// Update the nodes…
  node = vis.selectAll("circle.node")
      .data(nodes, function(d) { return d.id; })
      .style("fill", color);

Remplacez la .style("fill", color); par quelque chose comme:

.style("fill", function(d) { 
    switch(d.category) {
       case A: return "#FF0000";
       case B: return "#00FF00";
       default: return "#0000FF";
    }
});

Où catégorie est une propriété de l'objet de données JSON selon laquelle vous souhaitez varier.

39
Ian