Placing labels at the center of nodes in d3.js

后端 未结 3 790
北荒
北荒 2020-12-04 23:08

I am starting with d3.js, and am trying to create a row of nodes each of which contains a centered number label.

I am able to produce the desired result visually, bu

相关标签:
3条回答
  • 2020-12-04 23:46

    The best answer came from the asker himself:

    just a further observation: with only .attr("text-anchor", "middle") for each text element, the label is at the middle horizontally but slightly off vertically. I fixed this by adding attr("y", ".3em") (borrowed from examples at d3.js website), which seems to work well even for arbitrary size of node circle. However, what exactly this additional attribute does eludes my understanding. Sure, it does something to the y-coordinate of each text element, but why .3em in particular? It seems almost magical to me...

    Just add .attr("text-anchor", "middle") to each text element.

    Example:

    node.append("text")
        .attr("x", 0)
        .attr("dy", ".35em")
        .attr("text-anchor", "middle")
        .text(function(d) { return d.name; });
    
    0 讨论(0)
  • 2020-12-05 00:02

    This page describes what's going on under the svg hood when it comes to text elements. Understanding the underlying machinery and data structures helped me get a better handle on how I had to modify my code to get it working.

    0 讨论(0)
  • 2020-12-05 00:10

    The text-anchor attribute works as expected on an svg element created by D3. However, you need to append the text and the circle into a common g element to ensure that the text and the circle are centered with one another.

    To do this, you can change your nodes variable to:

    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 + ")"; 
               });
    

    Note that the dataset is now a list of objects so that d.y and d.x can be used instead of just a list of strings.

    Then, replace your circle and text append code with the following:

    // 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;
          });
    

    Now, instead of changing the position of the circle you change the position of the g element which moves both the circle and the text.

    Here is a JSFiddle showing centered text on circles.

    If you want to have your text be in a separate g element so that it always appears on top, then use the d.x and d.y values set in the first g element's creation to transform the text.

    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 + ")"; 
        });
    
    0 讨论(0)
提交回复
热议问题