OliviaHarmon
OliviaHarmon

Reputation: 81

In D3, how does one place text inside shapes that already have text attached to them?

I am currently working on the following d3 example where I'd like to place text inside of the arcs, similar to this example. However, whenever I try to append text to anything, the text just doesn't display. I've looked at the developer console, and it appears to be there, but it won't visually display on the screen. I used all the code provided in the first example, except I tried to add the following the the arc elements:

("the d3 element").enter().append("svg:text").text("???")

("the d3 element").enter().append("text").text("???")

("the d3 element").append("svg:text").text("???")

("the d3 element").append("text").text("???")

Aside from cutting off some of the styling changes, it seems like no matter where I put any of this code, it just doesn't want to work for me. I would appreciate and help!

Upvotes: 2

Views: 778

Answers (1)

Andrew Reid
Andrew Reid

Reputation: 38151

"whenever I try to append text to anything, the text just doesn't display": Text cannot be appended to most svg elements. You can append text to the svg itself or a g, but you cannot append it to a path, rect, circle, etc.

One of the most common methods of dealing with this is to use g elements to place a shape and text while binding data to the g. Using a transform on theg will translate shape and text - great for things like circles and rectangles.

There are several other approaches you can use to overlay text on svg elements:

  • Use the positioning attributes of an element to set the x and y attributes of text so that you can place text over top of an element.
  • Use a path as a text path to place text (as in your example)
  • Use utility methods such as centroid (for arcs or geopaths for example)
  • Find the bounding box of elements and place elements using this information.

These options help place, but won't make sure that the text falls within the bounds of a shape - that is different complication.

For arcs, one option is to use a circular path as a text-path where the circle has a radius between that of the inner and outer radius of your arc - then place the text using a text offset that reflects the start angle - or make an arc for each piece of text. The general mechanism is shown below (note it can't use a circle element as svg textPaths must follow paths):

var svg=d3.select("body")
  .append("svg")
  .attr("height",400)
  .attr("width",400)
  .attr("transform","translate(200,200)")
  
var arc = d3.arc()
  .innerRadius(50)
  .outerRadius(100)
  .startAngle(0)
  .endAngle(2);
  
var arcText = d3.arc()
  .innerRadius(75)
  .outerRadius(75)
  .startAngle(0)
  .endAngle(2);
  
var arc = svg.append("path")
  .attr("d",arc)
  .attr("fill","steelblue")
  
var textPath = svg.append("path")
  .attr("d",arcText)
  .attr("id","textpath")
  .attr("fill","none")
  .attr("stroke","black");
  
var text = svg.append("text")
  .append("textPath")
  .attr("xlink:href","#textpath")
  .text("title")
  .attr("startOffset", "25%")  // the bottom of the arc is from 50%-100%, the top from 0 to 50%
  .style("text-anchor","middle")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

The above mechanism is very similar to the example you link to - it appends text using the arcs as text paths. The example you reference uses text paths of the visible arc(donut) segments themselves - and offsets the x,y positions to move the text into the arc itself (as opposed to on the arc).

Note that I've used v4, as opposed to v3 as in the linked example.

Upvotes: 3

Related Questions