Building shapes in d3.js





The d3.js allows to draw shapes, that together build a graph. This document describe a few helpers function allowing to draw svg from data more efficiently.

Adding a circle with append("circle")


Here is how a circle would be drawn in pure svg, using a circle element. Three arguments are required: cx, cy and r for x position, y position and radius respectively.

<circle style="fill: #69b3a2" stroke="black" cx=100 cy=100 r=40></circle>

Now let's do it in javascript. It is basically the same process. Note that the code below expect a div with the id 'circle' somewhere in the html code.


// create svg element:
var svg = d3.select("#circle").append("svg").attr("width", 200).attr("height", 200)

// Add the path using this helper function
svg.append('circle')
  .attr('cx', 100)
  .attr('cy', 100)
  .attr('r', 50)
  .attr('stroke', 'black')
  .attr('fill', '#69a3b2');
  

Adding a rectangle with append("rect")


Here is how a rectangle would be drawn in pure svg, using a rect element. Four arguments are required: x, y, width and height.

<rect style="fill: #69b3a2" stroke="black" x=10 y=100, width=300 height=40></rect>

Now let's do it in javascript. It is basically the same process. Note that the code below expect a div with the id 'rect' somewhere in the html code.


// create svg element:
var svg = d3.select("#rect").append("svg").attr("width", 800).attr("height", 200)

// Add the path using this helper function
svg.append('rect')
  .attr('x', 10)
  .attr('y', 120)
  .attr('width', 600)
  .attr('height', 40)
  .attr('stroke', 'black')
  .attr('fill', '#69a3b2');

Adding a segment with append("line")


Here is how a segment would be drawn in pure svg, using a line element. Four arguments are required: x0, y0, x1 and y1.

<line stroke="red" x0=10 y0=10, x1=500 y1=100></line>

Now let's do it in javascript. It is basically the same process. Note that the code below expect a div with the id 'segment' somewhere in the html code.


// create svg element:
var svg = d3.select("#segment").append("svg").attr("width", 800).attr("height", 200)

// Add the path using this helper function
svg.append('line')
  .attr('x1', 10)
  .attr('y1', 10)
  .attr('x2', 700)
  .attr('y2', 100)
  .attr('stroke', 'red')

Adding text with append("text")


Here is how text would be drawn in pure svg, using a text element. Three arguments are required: x, y and text.

<text stroke="green" style="font-size: 19px" x=100 y=50>I'm a piece of text</text>
I'm a piece of text

Now let's do it in javascript. It is basically the same process. Note that the code below expect a div with the id 'text' somewhere in the html code.


// create svg element:
var svg = d3.select("#text").append("svg").attr("width", 800).attr("height", 200)

// Add the path using this helper function
svg.append('text')
  .attr('x', 100)
  .attr('y', 50)
  .attr('stroke', 'green')
  .style("font-size", 19)
  .text("I'm another piece of text")

Adding a line with d3.line()


Here is how a line would be drawn in pure svg, using a path element. You can learn more about the obscure syntax of the d argument here.

<path style="fill: none" stroke="black" d="M0 20 L150 150 L300 100 L450 20 L600 130"></path>

Fortunately, d3.js provides the d3.line() function, allowing to draw a line more efficiently. Basically it takes our data and convert it into the SVG Path we wrote above.

// create data
var data = [{x: 0, y: 20}, {x: 150, y: 150}, {x: 300, y: 100}, {x: 450, y: 20}, {x: 600, y: 130}]

// create svg element:
var svg = d3.select("#line").append("svg").attr("width", 800).attr("height", 200)

// prepare a helper function
var lineFunc = d3.line()
  .x(function(d) { return d.x })
  .y(function(d) { return d.y })

// Add the path using this helper function
svg.append('path')
  .attr('d', lineFunc(data))
  .attr('stroke', 'black')
  .attr('fill', 'none');

Going further: This page by dashingd3.js is awesome to go more in depth

Adding a curve with d3.line()


The d3.line() function has an option that allows to draw different line interpolations. Here is an example using a curve.

// create data
var data = [{x: 0, y: 20}, {x: 150, y: 150}, {x: 300, y: 100}, {x: 450, y: 20}, {x: 600, y: 130}]

// create svg element:
var svg = d3.select("#curve").append("svg").attr("width", 800).attr("height", 200)

// prepare a helper function
var curveFunc = d3.line()
  .curve(d3.curveBasis)              // This is where you define the type of curve. Try curveStep for instance.
  .x(function(d) { return d.x })
  .y(function(d) { return d.y })

// Add the path using this helper function
svg.append('path')
  .attr('d', curveFunc(data))
  .attr('stroke', 'black')
  .attr('fill', 'none');

Going further: Different type of curve are available: curve Basis, Linear, Step, StepBefore, StepAfter, Cardinal and more. See them all on this block.

Build an area with d3.area()


In pure svg, an area would also been drawn using a path element. You can learn more about the obscure syntax of the d argument here.

<path style="fill: #69b3a2" stroke="black" d="M0 200 L0 20 L150 150 L300 100 L450 20 L600 130 L600 200"></path>

Fortunately, d3.js provides the d3.area() function, allowing to draw an area more efficiently. Basically it takes our data and convert it into the SVG Path we wrote above. An area is defined by two bounding lines that often share the same X axis.

// create data
var data = [{x: 0, y: 20}, {x: 150, y: 150}, {x: 300, y: 100}, {x: 450, y: 20}, {x: 600, y: 130}]

// create svg element:
var svg = d3.select("#area").append("svg").attr("width", 800).attr("height", 200)

// prepare a helper function
var curveFunc = d3.area()
  .x(function(d) { return d.x })      // Position of both line breaks on the X axis
  .y1(function(d) { return d.y })     // Y position of top line breaks
  .y0(200)                            // Y position of bottom line breaks (200 = bottom of svg area)

// Add the path using this helper function
svg.append('path')
  .attr('d', curveFunc(data))
  .attr('stroke', 'black')
  .attr('fill', '#69b3a2');

Note: It is also possible to give specific X position for the bottom line. See the doc.

Draw arcs with d3.arc()


Let's see how drawing an arc in pure svg looks like:

<path style="fill: #69b3a2" stroke="black" transform="translate(400,200)" d="M0,149 A150,150,0,0,1,-0.47,-149.9 L-0.3,-99.9 A100,100,0,0,0,0.15,99.9Z"></path>

That was a bit tough. Now let's use the d3.arc() helper function to draw the same kind of shape. We need to provide 4 arguments: innerRadius, outerRadius, startAngle, endAngle. If you're not sure what these argument control, just play with the code below to figure it out.

// create svg element
var svg = d3.select("#arc").append("svg").attr("width", 1000).attr("height", 400)

// add an arc
svg
  .append("path")
  .attr("transform", "translate(400,200)")
  .attr("d", d3.arc()
    .innerRadius( 100 )
    .outerRadius( 150 )
    .startAngle( 3.14 )     // It's in radian, so Pi = 3.14 = bottom.
    .endAngle( 6.28 )       // 2*Pi = 6.28 = top
    )
  .attr('stroke', 'black')
  .attr('fill', '#69b3a2');

Note: It is of interest to note that with a innerRadius of 0, the shape looks like a part of a pie chart.