参考:
【D3.js】基础教程-CSDN博客
https://blog.csdn.net/weixin_39085822/article/details/119755130
D3 by Observable | The JavaScript library for bespoke data visualization
目录
动态方法
- transition()
是指从状态A变到状态B,d3会自动计算。比如从颜色A过渡到颜色B,d3会自动插值。 - duration()
指定过渡的时间,单位为毫秒 - ease()
指定过渡的方式,比如.ease(d3.easeLinear)
是普通的线性变换,.ease(d3.easeBounce)
是弹跳着变换。变换方式有很多,看:https://d3js.org/d3-ease#easeLinear - delay()
指定延迟时间,表示经过一定时间后才开始转换。单位是毫秒。如果要对整体做延迟就放在最后并给一个固定值;如果需要对所有图形进行不同的延迟,可以用匿名函数(function(d, i)
)
javascript
var body = d3.select("body"); //选择文档中的body元素
var svg = body.select("svg"); //选择body中的svg元素
var circle1 = svg.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 45)
.style("fill", "green");
//在1秒(1000毫秒)内将圆心坐标由100变为300
circle1.transition()
.duration(1000)
.ease(d3.easeLinear)
.attr("cx", 300) // 改属性
.style("fill", "red");
柱状图上文字跳动实例
效果:
javascript
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
//画布大小
var width = 400;
var height = 400;
//在 body 里添加一个 SVG 画布
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
//画布周边的空白
var padding = {left:30, right:30, top:20, bottom:20};
// 定义数据
var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
//x轴的比例尺(创建一个序列化比例尺)
var xScale = d3.scaleBand()
.domain(d3.range(dataset.length))
.rangeRound([0, width - padding.left - padding.right]);
var xAxis = d3.axisBottom(xScale); //定义x轴
// y轴的比例尺
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([height - padding.top - padding.bottom, 0]);
var yAxis = d3.axisLeft(yScale); //定义y轴
//矩形之间的空白
var rectPadding = 4;
//添加矩形元素
var rects = svg.selectAll(".MyRect")
.data(dataset)
.enter()
.append("rect")
.attr("class", "MyRect")
.attr(
"transform",
"translate(" + padding.left + "," + padding.top + ")"
)
.attr("x", function(d, i) {
return xScale(i) + rectPadding / 2;
})
.attr("y", function(d) {
return yScale(d);
})
.attr("width", xScale.step() - rectPadding)
.attr("height", function(d) {
return height - padding.top - padding.bottom - yScale(d);
})
.attr("fill","blue");
//添加文字元素
var texts = svg.selectAll(".MyText")
.data(dataset)
.enter()
.append("text")
.attr("class", "MyText")
.attr(
"transform",
"translate(" + padding.left + "," + padding.top + ")"
)
.attr("x", function(d, i) {
return xScale(i) + rectPadding / 2;
})
.attr("dx", function() {
return (xScale.step() - rectPadding) / 2;
})
.attr("dy", function(d) {
return 20;
})
.attr("fill","white")
.text(function(d) {
return d;
})
// 先从底端出现
.attr("y", function(d) {
//return yScale(d);
var min = yScale.domain()[0];
return yScale(min);
})
// 开始动
.transition()
.delay(function(d,i){
return i * 200;
})
.duration(2000)
.ease(d3.easeBounce)
// 最后跳到顶端
.attr("y",function(d){
return yScale(d);
});
//添加x轴
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);
//添加y轴
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.call(yAxis);
</script>
交互式操作
有d3-brush(刷选,允许用户选择一个区域)、d3-zoom(缩放,允许用户用鼠标滚轮或手势缩放图表)、d3-drag(允许用户拖动元素,如节点、滑块等),还有一些鼠标和键盘事件可以用.on()
,第一个参数是监听的事件,第二个参数是一个函数,用来处理事件。
javascript
var circle = svg.append("circle");
circle.on("click", function(){
//在这里添加交互内容
});
鼠标常用的事件有:click、mouseover、mouseout、mousemove、mousedown、mouseup、dblclick(双击)。
键盘常用的事件有:keydown(按住不放触发、不区分大小写;keypress区分大小写)、keyup(释放键时触发,不区分字母大小写)
下面的实例创建一个柱状图,并实现以下交互功能:
- 悬停高亮:当鼠标悬停在柱子上时,柱子颜色改变。
- 点击切换:点击柱子时,柱子高度变化。
- 工具提示:悬停时显示工具提示,显示柱子的值。
- 缩放:允许用户通过鼠标滚轮缩放整个图表。

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>D3.js 交互示例</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
.bar:hover {
fill: orange; /* 悬停时柱子的颜色 */
}
.tooltip {
position: absolute;
background: white;
padding: 5px;
border: 1px solid #ccc;
border-radius: 5px;
pointer-events: none; /* 防止工具提示干扰鼠标事件 */
}
</style>
</head>
<body>
<div id="chart"></div>
<div class="tooltip" style="opacity: 0;"></div>
<script>
// 数据
const data = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
// 定义画布尺寸和边距
const width = 600;
const height = 400;
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
// 创建 SVG 画布
const svg = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", (event) => {
svg.attr("transform", event.transform); // 缩放整个 SVG
}))
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
// 定义比例尺
const xScale = d3.scaleBand()
.domain(data.map((d, i) => i))
.range([0, width - margin.left - margin.right])
.padding(0.1);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([height - margin.top - margin.bottom, 0]);
// 创建柱子
svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", (d, i) => xScale(i))
.attr("y", d => yScale(d))
.attr("width", xScale.bandwidth())
.attr("height", d => height - margin.top - margin.bottom - yScale(d))
.attr("fill", "steelblue")
.on("mouseover", function (event, d) {
d3.select(this).attr("fill", "orange"); // 悬停时改变颜色
tooltip.style("opacity", 1)
.html(`值: ${d}`)
.style("left", `${event.pageX + 5}px`)
.style("top", `${event.pageY - 20}px`);
})
.on("mouseout", function () {
d3.select(this).attr("fill", "steelblue"); // 恢复颜色
tooltip.style("opacity", 0);
})
.on("click", function (event, d) {
const newHeight = d === 0 ? 100 : d / 2; // 点击时改变柱子高度
d3.select(this)
.transition()
.duration(500)
.attr("y", yScale(newHeight))
.attr("height", height - margin.top - margin.bottom - yScale(newHeight));
});
// 创建 X 轴
svg.append("g")
.attr("transform", `translate(0, ${height - margin.top - margin.bottom})`)
.call(d3.axisBottom(xScale));
// 创建 Y 轴
svg.append("g")
.call(d3.axisLeft(yScale));
// 工具提示
const tooltip = d3.select(".tooltip");
</script>
</body>
</html>