Post

Introduction to D3.js

Contents


1. Introduction

D3.js (Data-Driven Documents) is a JavaScript library for visualizing data on the web using SVG, HTML, and CSS.
It allows you to bind data directly to the DOM, enabling charts, animations, and interactions.

SVG is a vector graphics standard for the web. Elements like <rect>, <circle>, or <path> can represent data.
For example, <path> is used to draw curves or complex shapes, which is useful for line charts or area charts.

With D3, once data is bound, SVG elements automatically reflect positions, sizes, and colors based on the data.
In this article, we will use below sample data to demonstrate D3 concepts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Sample data
var data = [
  {Country: "USA", Sales: 4800000},
  {Country: "China", Sales: 4200000},
  {Country: "Japan", Sales: 3100000},
  {Country: "Germany", Sales: 2900000},
  {Country: "India", Sales: 2500000},
  {Country: "UK", Sales: 2200000}
];

var margin = {top: 30, right: 30, bottom: 70, left: 60},
    width = 460 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;

function makeSvg(target) {
  return d3.select(target)
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
}

2. Basic Static Charts

The first step in D3 is usually creating static charts. You can turn a simple array of numbers into SVG bars.

Key ideas:

  • Use d3.select() to choose HTML or SVG elements.
  • Use .data() to bind data to elements.
  • Use .enter() to create new SVG elements for each data point.

Draw a static chart using the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
var svg1 = makeSvg("#chart-static");
var x1 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y1 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);

svg1.selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x", d => x1(d.Country))
    .attr("y", d => y1(d.Sales))
    .attr("width", x1.bandwidth())
    .attr("height", d => height - y1(d.Sales))
    .attr("fill", "gray");

Static charts are the foundation for more interactive visualizations.


3. Attributes and Styling

After binding data, D3 allows you to customize every element attribute:

  • .attr() changes SVG attributes like x, y, width, height, fill, etc.
  • .style() changes CSS properties like opacity, stroke, or font.
  • .text() changes text content (commonly used with <text> elements).

Add properties to the chart using the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var svg2 = makeSvg("#chart-attr");
var x2 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y2 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);

svg2.append("g").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x2));
svg2.append("g").call(d3.axisLeft(y2));

svg2.selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x", d => x2(d.Country))
    .attr("y", d => y2(d.Sales))
    .attr("width", x2.bandwidth())
    .attr("height", d => height - y2(d.Sales))
    .attr("fill", "#69b3a2")
    .attr("stroke", "black");

Combining these functions gives you full control over how data is displayed.


4. Hover and Value Display

D3 supports listening to events like mouseover and mouseout.
When users hover over a chart element, you can:

  • Highlight the element by changing color.
  • Show values directly above bars instead of using a tooltip.

The following code modifies the hover properties of the chart:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var svg3 = makeSvg("#chart-hover");
var x3 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y3 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);

svg3.append("g").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x3));
svg3.append("g").call(d3.axisLeft(y3));

// thêm label text (ẩn ban đầu)
var labels = svg3.selectAll(".label")
  .data(data)
  .enter()
  .append("text")
  .attr("x", d => x3(d.Country) + x3.bandwidth()/2)
  .attr("y", d => y3(d.Sales) - 5)
  .attr("text-anchor", "middle")
  .attr("fill", "#000")
  .style("font-size", "10px")
  .text("");

svg3.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("x", d => x3(d.Country))
  .attr("y", d => y3(d.Sales))
  .attr("width", x3.bandwidth())
  .attr("height", d => height - y3(d.Sales))
  .attr("fill", "#4CAF50")
  .on("mouseover", function(d, i) {
      d3.select(this).attr("fill", "#2E7D32");
      labels.filter((l, j) => i === j)
            .text("$" + d.Sales.toLocaleString());
  })
  .on("mouseout", function(d, i) {
      d3.select(this).attr("fill", "#4CAF50");
      labels.filter((l, j) => i === j)
            .text("");
  });

This method avoids tooltip issues on different themes or platforms while making charts more interactive.


5. Animation with Transitions

D3 provides animation via .transition() and .duration().
This allows effects like:

  • Bars “growing” when displayed.
  • Lines moving smoothly when data updates.
  • Colors gradually changing based on values.

The sample code below creates an animation for the chart:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var svg4 = makeSvg("#chart-anim");
var x4 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y4 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);

svg4.append("g").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x4));
svg4.append("g").call(d3.axisLeft(y4));

function drawAnimation() {
  svg4.selectAll("rect").remove();
  svg4.selectAll("rect")
      .data(data)
      .enter()
      .append("rect")
      .attr("x", d => x4(d.Country))
      .attr("y", y4(0))
      .attr("width", x4.bandwidth())
      .attr("height", height - y4(0))
      .attr("fill", "#2196F3")
      .transition()
      .duration(800)
      .attr("y", d => y4(d.Sales))
      .attr("height", d => height - y4(d.Sales))
      .delay((d,i) => i * 200);
}

// vẽ lần đầu
drawAnimation();

d3.select("#chart-anim")
  .append("button")
  .text("Replay")
  .style("margin-top", "10px")
  .on("click", drawAnimation);

Adding .delay() can create sequential animations, making charts feel more alive.


6. Chaining in D3

A key feature of D3 is chaining — methods can be called one after another in a single line.
For example, selecting elements → binding data → setting attributes → adding animation can all be linked.

This makes the code shorter, more readable, and clearly shows the data processing flow.


7. Conclusion

  • D3.js is a powerful tool for turning data into dynamic visualizations.
  • Starting from static charts, you can extend to interactive charts, animations, and more complex visualizations (line charts, scatter plots, networks, etc.).
  • Understanding data binding, enter-update-exit, attributes, and chaining is key to mastering D3.js.
  • This article provides only a basic overview. For deeper learning, refer to the official D3.js website or books “Interactive Data Visualization for the Web” by Scott Murray.
This post is licensed under CC BY 4.0 by the author.