d3.js是一个用于创建数据可视化的JavaScript库,它提供了丰富的API和工具来操作文档对象模型(DOM),使得创建可交互的、动态的数据可视化变得更加容易。
选择元素:使用d3.select()函数可以选择一个元素,使用d3.selectAll()函数可以选择多个元素。选择函数可以接收CSS选择器、DOM元素或函数作为参数。
var svg = d3.select("#chart"); // 选择id为"chart"的元素
var circles = d3.selectAll("circle"); // 选择所有的circle元素
绑定数据:使用.data()
函数可以将数据绑定到选择的元素上。数据可以是数组、对象或函数的返回值。
var data = [1, 2, 3, 4, 5];
var circles = svg.selectAll("circle")
.data(data);
创建元素:使用.enter()
函数可以创建新的元素,这些元素对应于未绑定数据的选择集。可以使用.append()
、.insert()
等方法来创建元素。
var circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle");
设置元素属性:使用.attr()
函数可以设置元素的属性,可以传入属性名和对应的值,也可以传入一个函数来动态计算属性值。
circles.attr("cx", function(d, i) {
return i * 50; // 根据索引动态设置x坐标
})
.attr("cy", 50)
.attr("r", 20);
设置元素样式:使用.style()
函数可以设置元素的样式,可以传入属性名和对应的值,也可以传入一个函数来动态计算样式值。
circles.style("fill", "blue")
.style("opacity", 0.5);
缓动过渡:使用.transition()
可以为元素添加过渡效果,可以设置过渡时间、缓动函数等。
circles.transition()
.duration(1000)
.attr("cx", function(d, i) {
return i * 100;
});
事件处理:可以使用.on()
函数为元素绑定事件处理函数,可以处理鼠标事件(如click、mouseover等)和其他事件(如transitionend等)。
circles.on("click", function(d) {
console.log("Clicked:", d);
});
<div id="chart">div>
<div id="tooltip">div>
#tooltip
: 定义了一个绝对定位的工具提示框样式,包括居中对齐、背景颜色、文本颜色和字体样式,以及圆角边框。pointer-events: none;
禁用了鼠标事件,确保工具提示不会干扰用户操作。svg
: 设置了SVG元素的全局字体、显示为块级元素以及水平居中。.node rect
: 定义了节点(node)矩形的样式,包括移动光标时显示为移动样式、填充不透明度以及形状呈现方式。.node text
: 设置了节点文本的样式,包括禁用指针事件、设置不透明度以及字体样式。.link
: 设置了链接(link)的样式,包括不填充任何颜色、设置描边颜色以及描边不透明度。.link:hover
: 当鼠标悬停在链接上时,修改了描边的不透明度,以增强交互体验。body{
background: url(./assects/images/background.jpg) center;
}
#tooltip {
position: absolute;
text-align: center;
width: auto;
height: auto;
padding: 2px;
background: #13393E;
color: #F2CCA6;
font-size: 14px;
font-family: KaiTi, serif;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
svg {
font: 10px sans-serif;
display: block;
margin:0 auto;
}
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
opacity: .5;
font-weight: bold;
font-family: KaiTi, serif;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .06;
}
.link:hover {
stroke-opacity: .18;
}
引入js外部库:d3.js本地下载
<script src="./assects/js/d3/d3.v3.min.js"></script>
<!-- D3.js的作者之一Mike Bostock提供的Sankey图相关的Javascript库 -->
<script src="https://bost.ocks.org/mike/sankey/sankey.js"></script>
以下是自定义部分⭐️
var json = {
"nodes": [
{
"name": "洛阳"
},
{
"name": "陇西"
}
...
],
"links": [
{
"source": 0,
"target": 55,
"value": 99
},
{
"source": 1,
"target": 56,
"value": 47
}
...
]
};
// 定义边距、宽度和高度
var margin = {top: 3, right: 1, bottom: 3, left: 1}, // 定义边距的对象
width = window.innerWidth * 0.5 - margin.left - margin.right, // 计算宽度
height = window.innerHeight * 0.95 - margin.top - margin.bottom; // 计算高度
// 格式化和颜色比例尺
var formatNumber = d3.format(",.0f"), // 格式化数字的函数
format = function(d) { return formatNumber(d); }, // 定义格式化函数
color = d3.scale.category20(); // 创建颜色比例尺
// 创建一个SVG元素并将其附加到图表div中
var svg = d3.select("#chart").append("svg") // 选择图表元素,并添加SVG元素
.attr("width", width + margin.left + margin.right) // 设置SVG宽度
.attr("height", height + margin.top + margin.bottom) // 设置SVG高度
.append("g") // 添加一个分组元素
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // 设置图表的偏移量
// 初始化Sankey图布局
var sankey = d3.sankey() // 创建Sankey布局
.nodeWidth(30) // 设置节点宽度
.nodePadding(5) // 设置节点间距
.size([width, height]); // 设置布局大小
var path = sankey.link(); // 为链接定义路径生成器
// 在Sankey图中设置节点、链接和布局
sankey
.nodes(json.nodes) // 设置节点数据
.links(json.links) // 设置链接数据
.layout(32); // 执行布局计算
links
绑定// 创建链接并绑定数据
var link = svg.append("g").selectAll(".link") // 创建链接的选择集
.data(json.links) // 绑定数据
.enter().append("path") // 进入更新
.attr("class", "link") // 添加class
.attr("d", path) // 设置路径
.style("stroke-width", function(d) { return Math.max(1, d.dy); }) // 设置描边宽度
.sort(function(a, b) { return b.dy - a.dy; }); // 根据数据大小排序
nodes
设置// 创建节点并绑定数据
var node = svg.append("g").selectAll(".node") // 创建节点的选择集
.data(json.nodes) // 绑定数据
.enter().append("g") // 进入更新
.attr("class", "node") // 添加class
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) // 设置节点位置
.call(d3.behavior.drag() // 添加拖动行为
.origin(function(d) { return d; }) // 定义起始位置
.on("dragstart", function() { this.parentNode.appendChild(this); }) // 开始拖动时将节点置于顶层
.on("drag", dragmove)); // 拖动时的处理函数
// 节点颜色数组
var colorArray = ["#00577f", "#439083", "#aa5723", /* ... */ ]; // 节点颜色数组
// 为节点创建矩形
node.append("rect") // 添加矩形元素
.attr("height", function(d) { return d.dy; }) // 设置高度
.attr("width", sankey.nodeWidth()) // 设置宽度
.style("fill", function(d, i) { return colorArray[i % colorArray.length]; }) // 设置填充颜色
.style("stroke", function(d, i) { return d3.rgb(colorArray[i % colorArray.length]).darker(0); }) // 设置描边颜色
.append("title"); // 添加标题元素
// 为节点添加标签
node.append("text") // 添加文本元素
.attr("x", -6) // 设置x坐标
.attr("y", function(d) { return d.dy / 2; }) // 设置y坐标
.attr("dy", ".35em") // 设置dy属性
.attr("text-anchor", "end") // 设置文本锚点
.attr("transform", null) // 重置变换
.text(function(d) { return d.name; }) // 设置文本内容
.filter(function(d) { return d.x < width / 2; }) // 过滤条件
.attr("x", 6 + sankey.nodeWidth()) // 设置x坐标
.attr("text-anchor", "start"); // 设置文本锚点
// 当鼠标悬停在节点上时显示悬浮框
node.on("mouseover", function(d) {
d3.select("#tooltip")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.style("opacity", 0.9)
.html(d.name + ": " + format(d.value));
});
// 鼠标移出节点的时候隐藏自定义悬浮框
node.on("mouseout", function(d) {
d3.select("#tooltip").style("opacity", 0);
});
// 在鼠标悬浮在链接上的时候显示自定义悬浮框
link.on("mouseover", function(d) {
d3.select("#tooltip")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.style("opacity", 0.9)
.html(d.source.name + " → " + d.target.name + ": " + format(d.value));
});
// 鼠标移出链接的时候隐藏自定义悬浮框
link.on("mouseout", function(d) {
d3.select("#tooltip").style("opacity", 0);
});
// 通过拖动行为移动节点
function dragmove(d) {
d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}