Implementing a variation of Joachim Ungar's curved label placement method described here. The basic process is:

  1. Turn the shape into a polygon of evenly-spaced points.
  2. Generate a Voronoi diagram of those points.
  3. Clip the edges.
  4. Turn the edges into a graph.
  5. Find the "longest shortest path" between any pair of perimeter nodes.
  6. Smooth/simplify that path a bit.
  7. Place text along the smoothed centerline with a <textPath>.

A method for automatically finding the best eligible label position and font size for a label that's going to go along a path inside of an area, similar to this example but with two embellishments:

  • Using d3plus.polygonRayCast() to more accurately measure the vertical clearance available at a given x position with any rotation.
  • Avoiding label positions that would cause the text to be overlapped by another shape for a case like this bump chart.

The measurement gets thrown off a little bit by the curve function and the fact that text is rotated letter by letter instead of continuously, but the results seem good enough.

See also: Automatic label placement along a path Streamgraph label positions #2


A method for automatically finding the best eligible label position and size for a label that's going to go along a path inside of an area. This is potentially suitable for area charts where the area being labeled has a clear direction the text should "flow" in.

The basic approach is a crude one: test a center point at a certain font size, and work outwards to the left and right and disqualify it if you ever hit the side of the chart or run out of vertical space. If it fits, try a bigger size. If not, try a smaller size. Rinse/repeat until you've either found the largest size that will fit at that position or found that nothing will fit. Repeat with each possible center point until you've found the largest font size you can use, and where to put it.


  • This adds a small optimization of disqualifying any candidate points that involve a sharp angle turn, because text turning at a sharp angle can be pretty hard to read.
  • Another optimization that's omitted for brevity is to first try to use a flat label
View globalEconomyByGDP.json
"name": "world",
"children": [
"name": "Asia",
"color": "#f58321",
"children": [
{"name": "China", "weight": 14.84, "code": "CN"},
{"name": "Japan", "weight": 5.91, "code": "JP"},
{"name": "India", "weight": 2.83, "code": "IN"},

Click-to-zoom using projection.fitSize() to interpolate a projection's scale and translate instead of modifying the SVG transform. Has the advantage of leaving stroke-widths alone and the disadvantage of probably being a lot slower.

See also: click-to-zoom via transform


Converting an SVG animation to a video with the MediaRecorder API and a hidden canvas.

Drawing frames from img elements can introduce an extra delay, so this version generates all the frames upfront and then renders them in a loop with requestAnimationFrame().

See also: Canvas animation to video