Thư viện D3.js là một trong những công cụ mạnh mẽ nhất để trực quan hóa dữ liệu trên web. Trong kỷ nguyên dữ liệu lớn, việc trình bày dữ liệu trực quan trở thành kỹ năng quan trọng với sinh viên CNTT.
Thay vì bảng số liệu khô khan, biểu đồ giúp dễ dàng phát hiện xu hướng và insight ẩn. Với D3.js, bạn có thể xây dựng biểu đồ tương tác linh hoạt và tích hợp trực tiếp vào giao diện web.

Giới thiệu về thư viện D3.js
D3.js (Data-Driven Documents) là thư viện JavaScript mạnh mẽ dùng để trực quan hóa dữ liệu. Thư viện kết hợp HTML, CSS và SVG để tạo biểu đồ tương tác.
D3.js giúp biến dữ liệu thô thành các biểu đồ sinh động. Ví dụ như như cột, đường, bản đồ hay dashboard phức tạp. Điểm nổi bật là khả năng liên kết dữ liệu trực tiếp với phần tử web. Khi dữ liệu thay đổi, giao diện sẽ tự động cập nhật.
Thư viện được phát triển bởi Mike Bostock và giới thiệu năm 2011. D3.js dựa trên nguyên lý gắn dữ liệu vào DOM. Thay vì tạo giao diện trước, D3.js lấy dữ liệu làm trung tâm để xây dựng biểu đồ động.
Hiện nay, D3.js được sử dụng rộng rãi trong dashboard, phân tích dữ liệu, trí tuệ nhân tạo và tài chính. Để học D3.js, bạn cần nắm vững JavaScript, HTML và CSS.
Nhúng D3 vào trang web
Việc nhúng D3.js vào trang rất đơn giản. Chỉ cần thêm một dòng mã vào file HTML:
<script src="https://d3js.org/d3.v7.min.js"></script>
Sau đó, bạn đã có thể sử dụng toàn bộ thư viện D3.js trong dự án của mình mà không cần cài đặt phức tạp.
Ví dụ đơn giản cách dùng D3
Đây là một ví dụ đơn giản để minh họa cách D3.js hiển thị dữ liệu:
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
const data = [10, 20, 30];
d3.select("body")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("background", "steelblue")
.style("margin", "5px")
.style("height", "20px")
.style("width", d => d * 10 + "px")
.text(d => d);
</script>
</body>
</html>
Đoạn code trên sẽ hiển thị các giá trị trong mảng dữ liệu ra màn hình dưới dạng các đoạn văn bản. Đây là ví dụ cơ bản nhất, nhưng từ đó có thể phát triển thành các biểu đồ phức tạp hơn.
Các tính năng trong D3.js
Data binding
Một trong những ý tưởng cốt lõi nhất của D3.js là data binding, tức là gắn dữ liệu vào các phần tử HTML. Theo đó, lập trình viên đưa dữ liệu vào và D3 sẽ sinh ra các phần tử trên trang web tương ứng với dữ liệu.
Điểm mạnh của data binding là khi dữ liệu thay đổi, giao diện cũng có thể cập nhật theo. Đây là nền tảng giúp D3.js trở nên rất linh hoạt khi xây dựng các biểu đồ động, dashboard tương tác hay các giao diện thay đổi theo dữ liệu người dùng chọn.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div id="output"></div>
</body>
</html>
<script>
const data = [10, 20, 30];
d3.select("#output")
.selectAll("p")
.data(data)
.join("p")
.text(d => "Giá trị: " + d);
</script>
Giải thích: mảng dữ liệu data gồm các giá trị 10, 20, 30 sẽ lần lượt được gắn vào các thẻ <p>. Kết quả tạo ra 3 dòng văn bản trên trang. Đây chính là cách D3 biến dữ liệu thành giao diện.

Scale (linear, band…)
Trong trực quan hóa dữ liệu, dữ liệu thường nằm ở dạng số hoặc nhãn, còn màn hình lại được tính bằng pixel. Để chuyển dữ liệu thành vị trí, chiều cao, chiều rộng hoặc màu sắc trên biểu đồ, D3 sử dụng khái niệm scale.
Scale có thể hiểu đơn giản là phép biến đổi từ miền dữ liệu sang miền hiển thị. Chẳng hạn, giá trị từ 0 đến 100 có thể được ánh xạ thành chiều cao từ 0 đến 300 pixel. Nhờ scale, biểu đồ giữ được tỷ lệ chính xác và dễ đọc.
Một số loại scale phổ biến gồm:
- scaleLinear(): dùng cho dữ liệu số liên tục, ví dụ trục tung của bar chart hoặc line chart.
- scaleBand(): dùng cho dữ liệu phân loại, ví dụ tên sản phẩm A, B, C trên trục hoành.
- scaleOrdinal(): dùng để ánh xạ dữ liệu phân loại sang màu sắc hoặc nhãn.
Ví dụ 1:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div id="chart"></div>
</body>
</html>
<script>
const data = [10, 20, 30];
// scale tuyến tính: dữ liệu từ 0-30 sẽ đổi thành chiều rộng từ 0-300 pixel
const x = d3.scaleLinear()
.domain([0, 30])
.range([0, 300]);
d3.select("#chart")
.selectAll("div")
.data(data)
.join("div")
.style("height", "25px")
.style("margin", "5px")
.style("background", "steelblue")
.style("width", d => x(d) + "px")
.text(d => d);
</script>
Giải thích: scaleLinear() biến dữ liệu thành chiều rộng của các thanh. Chẳng hạn, giá trị 10 được đổi thành một chiều rộng nhỏ hơn, còn giá trị 30 được đổi thành chiều rộng lớn hơn. Nhờ scale, dữ liệu số có thể chuyển thành hình ảnh trực quan trên màn hình.

Ví dụ 2:
Trong biểu đồ cột, scaleBand() giúp xác định vị trí của từng cột, còn scaleLinear() giúp xác định độ cao của cột theo giá trị số. Đây là bước rất quan trọng, vì nếu không có scale thì dữ liệu không thể chuyển thành hình ảnh trực quan trên màn hình.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg id="chart" width="400" height="250"></svg>
</body>
</html>
<script>
const data = [
{ name: "A", value: 10 },
{ name: "B", value: 30 },
{ name: "C", value: 20 }
];
const width = 400;
const height = 250;
const margin = 30;
const svg = d3.select("#chart");
// ===== scaleBand: vị trí cột =====
const x = d3.scaleBand()
.domain(data.map(d => d.name))
.range([margin, width - margin])
.padding(0.3);
// ===== scaleLinear: chiều cao cột =====
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.range([height - margin, margin]);
// ===== vẽ cột =====
svg.selectAll("rect")
.data(data)
.join("rect")
.attr("x", d => x(d.name)) // vị trí ngang
.attr("y", d => y(d.value)) // vị trí trên
.attr("width", x.bandwidth()) // độ rộng cột
.attr("height", d => height - margin - y(d.value)) // chiều cao
.attr("fill", "steelblue");
// ===== nhãn =====
svg.selectAll("text")
.data(data)
.join("text")
.attr("x", d => x(d.name) + x.bandwidth()/2)
.attr("y", d => y(d.value) - 5)
.attr("text-anchor", "middle")
.text(d => d.value);
</script>
Giải thích :
- scaleBand() được dùng để xác định vị trí của từng cột theo tên (A, B, C). Nó chia trục ngang thành các khoảng đều nhau.
- scaleLinear() được dùng để chuyển giá trị số thành chiều cao cột. Giá trị càng lớn thì cột càng cao.
Nhờ hai loại scale này, dữ liệu không còn là những con số đơn thuần mà được chuyển thành vị trí và kích thước cụ thể trên màn hình, từ đó tạo thành biểu đồ trực quan.

Transition (animation)
D3.js hỗ trợ transition, tức là hiệu ứng chuyển động khi biểu đồ thay đổi. Đây là một điểm rất mạnh của D3. Thay vì thay đổi dữ liệu một cách đột ngột, biểu đồ có thể chuyển từ trạng thái cũ sang trạng thái mới một cách mượt mà.
Transition giúp người xem dễ theo dõi sự thay đổi của dữ liệu hơn. Ví dụ, khi người dùng chọn năm 2024 rồi chuyển sang năm 2025, các cột trong biểu đồ có thể tăng hoặc giảm dần thay vì biến mất rồi xuất hiện lại ngay lập tức. Điều này làm biểu đồ sinh động hơn và giúp trải nghiệm người dùng tốt hơn.
Trong D3, transition thường được dùng cùng với các thuộc tính như duration() để quy định thời gian chuyển động. Hiệu ứng animation thường xuất hiện trong các dashboard, biểu đồ cập nhật theo thời gian, hoặc các ứng dụng trực quan hóa dữ liệu có tính tương tác cao.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<button onclick="update()">Đổi dữ liệu</button>
<div id="chart"></div>
</body>
</html>
<script>
let data = [30, 60, 90];
function update() {
data = data.map(() => Math.floor(Math.random() * 100));
d3.select("#chart")
.selectAll("div")
.data(data)
.join("div")
.transition()
.duration(800)
.style("width", d => d * 3 + "px")
.style("height", "25px")
.style("margin", "5px")
.style("background", "steelblue");
}
update();
</script>
Trong ví dụ trên, mỗi giá trị dữ liệu được hiển thị bằng một thanh ngang. Khi nhấn nút “Đổi dữ liệu”, D3 tạo ra một bộ dữ liệu mới rồi dùng transition() và duration() để làm cho chiều rộng các thanh thay đổi từ từ. Nhờ vậy, người xem có thể quan sát sự thay đổi của dữ liệu một cách trực quan hơn.

Tooltip
Đây là phần thông tin nhỏ xuất hiện khi người dùng rê chuột vào một đối tượng trên biểu đồ. Chẳng hạn một cột, một điểm dữ liệu hay một phần của pie chart. Tooltip thường hiển thị giá trị chi tiết, nhãn dữ liệu hoặc thông tin bổ sung.
Đây là một tính năng rất thực tế vì nó giúp biểu đồ vừa gọn gàng vừa giàu thông tin. Thay vì hiển thị tất cả chi tiết làm rối mắt, D3 có thể chỉ hiển thị thông tin khi người dùng cần xem.
Ví dụ, với pie chart, khi rê chuột vào từng phần, tooltip có thể hiện tên nhóm dữ liệu và giá trị tương ứng. Với scatter plot, tooltip có thể hiện tọa độ (x, y) của từng điểm. Đây là một tính năng giúp biểu đồ trên web mạnh hơn so với hình ảnh tĩnh.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
#chart div {
width: 120px; height: 30px; margin: 8px;
background: steelblue; color: white;
line-height: 30px; text-align: center;
}
#tooltip {
position: absolute; display: none;
background: white; font-size: 14px;
border: 1px solid gray; border-radius: 4px;
padding: 6px 10px;
pointer-events: none;
}
</style>
</head>
<body>
<div id="chart"></div>
<div id="tooltip"></div>
</body>
</html>
<script>
const data = [10, 20, 30];
const tooltip = d3.select("#tooltip");
d3.select("#chart")
.selectAll("div")
.data(data)
.join("div")
.text(d => "Giá trị " + d)
.on("mouseover", function(event, d) {
tooltip
.style("display", "block")
.html("Dữ liệu: " + d);
})
.on("mousemove", function(event) {
tooltip
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY + 10) + "px");
})
.on("mouseout", function() {
tooltip.style("display", "none");
});
</script>
Trong ví dụ này, mỗi thanh dữ liệu được gắn sự kiện chuột. Khi người dùng rê chuột vào một thanh, tooltip sẽ xuất hiện và hiển thị giá trị tương ứng. Tooltip đi theo vị trí con trỏ. Đây là một kỹ thuật rất phổ biến trong các biểu đồ tương tác trên web.

SVG coordinate
D3.js thường sử dụng SVG để vẽ biểu đồ. Vì vậy, người học cần hiểu hệ tọa độ của SVG để làm việc hiệu quả hơn. Khác với hệ trục tọa độ trong toán học, trong SVG:
- gốc tọa độ (0, 0) nằm ở góc trên bên trái,
- trục X tăng dần từ trái sang phải,
- trục Y tăng dần từ trên xuống dưới.
Điều này khiến nhiều người dễ nhầm, đặc biệt khi vẽ biểu đồ cột hoặc line chart. Ví dụ, nếu muốn cột cao hơn thì phải giảm giá trị y của điểm bắt đầu và tăng chiều cao hình chữ nhật, chứ không thể nghĩ theo cách của hệ trục toán học thông thường.
Hiểu đúng hệ tọa độ SVG là điều rất quan trọng, vì mọi phần tử được vẽ trong D3 như hình chữ nhật, đường thẳng, hình tròn hay văn bản đều dựa trên hệ tọa độ này.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg id="svg" width="400" height="200" style="border:1px solid black"></svg>
</body>
</html>
<script>
const svg = d3.select("#svg");
// ===== điểm (0,0) =====
svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 5)
.attr("fill", "red");
// ===== điểm (100,50) =====
svg.append("circle")
.attr("cx", 100)
.attr("cy", 50)
.attr("r", 5)
.attr("fill", "blue");
// ===== điểm (200,100) =====
svg.append("circle")
.attr("cx", 200)
.attr("cy", 100)
.attr("r", 5)
.attr("fill", "green");
// ===== vẽ trục X =====
svg.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 300)
.attr("y2", 0)
.attr("stroke", "black");
// ===== vẽ trục Y =====
svg.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", 150)
.attr("stroke", "black");
// ===== nhãn =====
svg.append("text")
.attr("x", 5)
.attr("y", 15)
.text("(0,0)");
svg.append("text")
.attr("x", 100)
.attr("y", 65)
.text("(100,50)");
svg.append("text")
.attr("x", 200)
.attr("y", 115)
.text("(200,100)");
</script>
Event (tương tác)
D3.js hỗ trợ rất tốt các sự kiện tương tác như nhấp chuột, rê chuột, di chuột, kéo thả, hoặc thay đổi giá trị từ ô chọn. Đây chính là yếu tố giúp biểu đồ trên web khác biệt so với biểu đồ tĩnh.
Một số sự kiện phổ biến gồm:
- click: nhấp chuột,
- mouseover: đưa chuột vào phần tử,
- mouseout: đưa chuột ra khỏi phần tử,
- mousemove: di chuyển chuột,
- change: thay đổi giá trị trong select hoặc input.
Nhờ hệ thống sự kiện này, D3 có thể kết hợp biểu đồ với các thành phần giao diện như nút bấm, hộp chọn, thanh trượt hoặc form nhập liệu. Chẳng hạn, người dùng có thể bấm nút để đổi năm, chọn loại dữ liệu cần xem, hoặc rê chuột vào từng thành phần để xem thông tin chi tiết. Đây là một ưu điểm lớn của D3 khi làm các dashboard dữ liệu trên nền tảng web.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
#chart div {
width: 120px;
height: 30px;
margin: 8px;
background: steelblue;
color: white;
line-height: 30px;
text-align: center;
cursor: pointer;
}
</style>
</head>
<body>
<h3>Ví dụ Event trong D3</h3>
<div id="chart"></div>
</body>
</html>
<script>
const data = [10, 20, 30];
d3.select("#chart")
.selectAll("div")
.data(data)
.join("div")
.text(d => d)
// ===== rê chuột vào =====
.on("mouseover", function() {
d3.select(this)
.style("background", "orange");
})
// ===== rời chuột =====
.on("mouseout", function() {
d3.select(this)
.style("background", "steelblue");
})
// ===== click =====
.on("click", function(event, d) {
alert("Bạn vừa click vào giá trị: " + d);
});
</script>
Giải thích: Trong ví dụ trên:
- Khi rê chuột vào một thanh (mouseover), màu của thanh sẽ đổi sang màu cam.
- Khi đưa chuột ra (mouseout), màu sẽ trở lại như ban đầu.
- Khi nhấp chuột (click), một thông báo sẽ hiển thị giá trị của dữ liệu tương ứng.
Các sự kiện này giúp người dùng tương tác trực tiếp với dữ liệu. Từ đó làm cho biểu đồ trở nên sinh động và dễ khám phá hơn.
Kết luận
D3.js là công cụ mạnh mẽ giúp lập trình viên tạo biểu đồ và dashboard tương tác trên web. Thư viện cho phép kết hợp chặt chẽ HTML, CSS và SVG để xây dựng giao diện động.
D3.js giúp biểu đồ tự động cập nhật theo dữ liệu, hỗ trợ animation, tooltip và tương tác người dùng. Học D3.js giúp bạn tư duy tốt hơn về việc kết hợp dữ liệu với giao diện web hiện đại.


