1

I'm new to d3.js and I'm creating a simple horizontal bar chart with two bars. I want to put text labels on the two bars. The code below looks correct according to my research, but no text shows on the screen. From the dev console, it looks like the text elements are not being added.

Here's the javascript code:

var dataArray = [23, 13];

var svg = d3.select("svg.d3svg")
  .attr("height", "20%")
  .attr("width", "100%")
  .selectAll("rect")
  .data(dataArray)
  .enter().append("rect")
  .attr("height", "7")
  .attr("width", "250")
  .attr("y", function(d, i) {return (i * 40) + 50 })
  .attr("x", "0")
  .attr("class", "d3bar");

  svg.selectAll("text")
  .data(dataArray)
  .enter().append("text")
  .attr("class", "text-svg")
  .text(function(d) {return d})
  .attr("x", "0")
  .attr("y", function(d, i) {return (i * 40) + 50});

The text-svg class contains only:

.text-svg {
  fill: white;
  font-family: sans-serif;
}

This correctly code targets the svg element on the html page because the bars are placed where I want them, but I haven't been able to get the text to show.

Thanks for any help.

ksav
  • 20,015
  • 6
  • 46
  • 66
RTC222
  • 2,025
  • 1
  • 20
  • 53
  • 1
    `text` is not an allowed child tag of `rect`. Use a `g` and put `rect` and `text` to the `g`, or make the `text` a sibling of the `rect` – rioV8 Sep 25 '18 at 21:19
  • Thanks for the comment. I suspected it might be something like that. I'm working it out now. – RTC222 Sep 25 '18 at 21:34

1 Answers1

1

As per the comment from @rioV8, you need to restructure so that your text and rect nodes are children of a g like so:

var dataArray = [23, 13];

var svg = d3.select("svg")
  .attr("height", "20%")
  .attr("width", "100%")

var bar = svg.selectAll("g")
  .data(dataArray)
  .enter().append("g")

var rect = bar.append('rect')
  .attr("height", "7")
  .attr("width", "250")
  .attr("y", function(d, i) {
    return (i * 40) + 50
  })
  .attr("x", "0")
  .attr("class", "d3bar");

var text = bar.append('text')
  .attr("class", "text-svg")
  .text(function(d) {
    return d
  })
  .attr("x", "0")
  .attr("y", function(d, i) {
    return (i * 40) + 45
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg></svg>

This would give you a valid SVG structure like this:

<svg height="20%" width="100%">
    <g>
        <rect height="7" width="250" y="50" x="0" class="d3bar"></rect>
        <text class="text-svg" x="0" y="50">23</text>
    </g>
    <g>
        <rect height="7" width="250" y="90" x="0" class="d3bar"></rect>
        <text class="text-svg" x="0" y="90">13</text>
    </g>
</svg>

Have a look a look at the docs for SVG rect. It says:

Permitted content: Any number of the following elements, in any order: Animation elements, Descriptive elements


Now have a look at the docs for SVG g. It says:

Permitted content: Any number of the following elements, in any order: Animation elements, Descriptive elements, Shape elements, Structural elements, Gradient elements


From these usage notes we get exactly what @rioV8 commented: text is not an allowed child tag of rect.

Codepen

ksav
  • 20,015
  • 6
  • 46
  • 66
  • 1
    Thanks very much for a wonderfully detailed answer. Your solution works perfectly for me. Thanks so much. – RTC222 Sep 25 '18 at 22:29