Placer les étiquettes au centre des Noeuds en d3.js

je commence par d3.js, et j'essaye de créer une rangée de noeuds dont chacun contient un label de nombre centré.

je suis capable de produire le résultat désiré visuellement, mais la façon dont je l'ai fait est à peine optimale car il implique le codage dur les coordonnées x-y pour chaque élément de texte. Ci-dessous le code:

var svg_w = 800;
var svg_h = 400;
var svg = d3.select("body")
    .append("svg")
    .attr("width", svg_w)
    .attr("weight", svg_h);

var dataset = [];
for (var i = 0; i < 6; i++) {
    var datum = 10 + Math.round(Math.random() * 20);
    dataset.push(datum);
}

var nodes = svg.append("g")
               .attr("class", "nodes")
               .selectAll("circle")
               .data(dataset)
               .enter()
               .append("circle")
               .attr("class", "node")
               .attr("cx", function(d, i) {
                   return (i * 70) + 50;
               })
               .attr("cy", svg_h / 2)
               .attr("r", 20);

var labels = svg.append("g")
                .attr("class", "labels")
                .selectAll("text")
                .data(dataset)
                .enter()
                .append("text")
                .attr("dx", function(d, i) {
                    return (i * 70) + 42
                })
                .attr("dy", svg_h / 2 + 5)
                .text(function(d) {
                    return d;
                });

la classe node est la classe CSS personnalisée que j'ai définie séparément pour les éléments circle , tandis que les classes nodes et labels ne sont pas explicitement définis et ils sont empruntés à cette réponse .

comme vu, le positionnement de chaque étiquette de texte est codé dur de sorte qu'il apparaît au centre de chaque noeud. Évidemment, ce n'est pas la bonne solution.

ma question Est que comment devrais-je correctement associer chaque étiquette de texte avec chaque cercle de noeud dynamiquement de sorte que si le positionnement d'une étiquette change avec ce d'un cercle automatiquement. Une explication conceptuelle est la bienvenue avec un exemple de code.

51
demandé sur Community 2012-08-08 08:21:06

3 réponses

l'attribut text-anchor fonctionne comme prévu sur un élément svg créé par D3. Cependant, vous devez ajouter le text et le circle dans un élément commun g pour vous assurer que le text et le circle sont centrés l'un avec l'autre.

pour ce faire, vous pouvez changer votre variable nodes en:

var nodes = svg.append("g")
           .attr("class", "nodes")
           .selectAll("circle")
           .data(dataset)
           .enter()
           // Add one g element for each data node here.
           .append("g")
           // Position the g element like the circle element used to be.
           .attr("transform", function(d, i) {
             // Set d.x and d.y here so that other elements can use it. d is 
             // expected to be an object here.
             d.x = i * 70 + 50,
             d.y = svg_h / 2;
             return "translate(" + d.x + "," + d.y + ")"; 
           });

on Remarque que le dataset est maintenant une liste d'objets que d.y et d.x peuvent être utilisés au lieu d'une simple liste de chaînes.

alors, remplacer votre circle et text ajouter le code suivant:

// Add a circle element to the previously added g element.
nodes.append("circle")
      .attr("class", "node")
      .attr("r", 20);

// Add a text element to the previously added g element.
nodes.append("text")
     .attr("text-anchor", "middle")
     .text(function(d) {
       return d.name;
      });

maintenant, au lieu de changer la position du circle vous changez la position de l'élément g qui déplace à la fois le circle et le text .

voici un jsfiddle montrant texte centré sur les cercles.

si vous voulez que votre texte soit dans un élément séparé g de sorte qu'il apparaisse toujours en haut, alors utilisez les valeurs d.x et d.y définies dans le premier g création de l'élément à transform le texte.

var text = svg.append("svg:g").selectAll("g")
         .data(force.nodes())
         .enter().append("svg:g");

text.append("svg:text")
    .attr("text-anchor", "middle")
    .text(function(d) { return d.name; });

text.attr("transform",  function(d) {
      return "translate(" + d.x + "," + d.y + ")"; 
    });
62
répondu Brant Olsen 2013-05-18 01:30:01

La meilleure réponse le demandeur lui-même:

juste une autre observation: avec seulement .attr("texte d'ancre", "moyen") pour chaque élément de texte, l'étiquette est au milieu horizontalement mais légèrement en dehors de la verticale. J'ai corrigé ceci en ajoutant attr("y", ".3em") (emprunté à des exemples de d3.js site web), ce qui semble bien fonctionner même pour la taille arbitraire du cercle de noeud. Cependant, exactement ce que ce attribut supplémentaire n'échappe à ma compréhension. Bien sûr, il n' quelque chose à la coordonnée de chaque élément de texte, mais pourquoi .3em en particulier? Il semble presque magique pour moi...

il suffit d'ajouter .attr("text-anchor", "middle") à chaque élément de texte.

exemple:

node.append("text")
    .attr("x", 0)
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")
    .text(function(d) { return d.name; });
25
répondu tacone 2017-05-23 12:18:01

Cette page décrit ce qui se passe sous le svg hood quand il s'agit de les éléments de texte. La compréhension de la machinerie sous-jacente et des structures de données m'a aidé à mieux comprendre comment j'ai dû modifier mon code pour le faire fonctionner.

4
répondu MichaelGreene 2013-07-06 01:48:36