D3快速入门
D3安装
<script src="https://d3js.org/d3.v5.min.js"></script>
选择器
在 D3 中,用于选择元素的函数有两个,这两个函数返回的结果称为选择集。
d3.select():选择所有指定元素的第一个
d3.selectAll():选择指定全部元素
例如,选择集的常见用法如下。
var body = d3.select("body"); //选择文档中的body元素
var p1 = body.select("p"); //选择body中的第一个p元素
var p = body.selectAll("p"); //选择body中的所有p元素
var svg = body.select("svg"); //选择body中的svg元素
var rects = svg.selectAll("rect"); //选择svg中所有的rect元素
var id = body.select("#id"); //选择body中id元素
var class = body.select(".class");//选择body中class类元素
链式操作:
d3.select("#container").text("1000phone").attr("font-size","12px");
绑定数据 选择集和绑定数据通常是一起使用的,D3 中是通过以下两个函数来绑定数据的:
- datum():绑定一个数据到选择集上
- data():绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定
假设现在有三个段落元素如下:
<p></p>
<p></p>
<p></p>
对于datum(): 假设有一字符串 逆战2020,要将此字符串分别与三个段落元素绑定,代码如下:
var data = '逆战2020';
var container = d3.select("#app");
container.selectAll('p')
.datum(data)
.text(function (d, i) {
return "第 " + i + " 个元素绑定的数据是: " + d;
})
绑定数据后,使用此数据来修改三个段落元素的内容,其结果如下:
第 0 个元素绑定的数据是: 逆战2020
第 1 个元素绑定的数据是: 逆战2020
第 2 个元素绑定的数据是: 逆战2020
对于data():
有一个数组,接下来要分别将数组的各元素绑定到三个段落元素上。
var datalist = [10, 20, 30];
调用 data() 绑定数据,并替换三个段落元素的字符串为被绑定的字符串,代码如下:
var datalist = [10, 20, 30];
var container = d3.select("#app");
//更新数据
container.selectAll('p')
//绑定数据源
.data(datalist)
.text(function (data, index) {
return data;
})
结果自然是三个段落的文字分别变成了数组的三个字符串。
10
20
30
前面代码也用到了一个无名函数 function(d, i),其对应的情况如下:
d ------- data 数据
i ------- index 索引
当 i == 0 时, d 为 10。 当 i == 1 时, d 为 20。 当 i == 2 时, d 为 30。 此时,三个段落元素与数组 dataset 的三个字符串是一一对应的,在函数 function(d, i) 直接 return d 即可。
选择、插入、删除元素
1.选择元素
<p>10</p>
<p>20</p>
<p>30</p>
选择第一个元素
d3.select("body").select("p").style("color","red");
选择第所有元素
d3.select("body").selectAll("p").style("color","red");
选择第二个元素
<p id="second">20</p>
d3.select("#second").style("color","red");
选择后两个元素,给后两个元素添加 class,
<p class="myclass">Moon</p>
<p class="myclass">You</p>
由于需要选择多个元素,要用 selectAll。
d3.selectAll(".myclass").style("color","red")
插入元素 插入元素涉及的函数有两个:
append():在选择集末尾插入元素 insert():在选择集前面插入元素 假设有三个段落元素,与上文相同。
append()
d3.select("body").append("p").text("Star");
insert
d3.select("body").insert("p","#second").text("20");
删除元素
d3.select("#second").remove();
理解 update()、enter()、exit()
数据绑定的时候可能出现 DOM 元素与数据元素个数不匹配的问题,那么 enter 和 exit 就是用来处理这个问题的。enter 操作用来添加新的 DOM 元素,exit 操作用来移除多余的 DOM 元素
Update、Enter、Exit 是 D3 中三个非常重要的概念,它处理的是当选择集和数据的数量关系不确定的情况。
- update(), 当对应的元素正好满足时 ( 绑定数据数量 = 对应元素 ),实际上并不存在这样一个函数,只是为了要与之后的 enter 和 exit 一起说明才想象有这样一个函数。但对应元素正好满足时,直接操作即可,后面直接跟 text ,style 等操作即可。
- enter(), 当对应的元素不足时 ( 绑定数据数量 > 对应元素 ),当对应的元素不足时,通常要添加元素,使之与绑定数据的数量相等。后面通常先跟 append 操作。
- exit(), 当对应的元素过多时 ( 绑定数据数量 < 对应元素 ),当对应的元素过多时,通常要删除元素,使之与绑定数据的数量相等。后面通常要跟 remove 操作。
如果数组为 [3, 6, 9, 12, 15],将此数组绑定到三个 p 元素的选择集上。可以想象,会有两个数据没有元素与之对应,这时候 D3 会建立两个空的元素与数据对应,这一部分就称为 Enter。而有元素与数据对应的部分称为 Update。如果数组为 [3],则会有两个元素没有数据绑定,那么没有数据绑定的部分被称为 Exit。示意图如下所示。
而如下代码的意思是:此时 SVG 里没有 rect 元素,即元素数量为 0。有一数组 dataset,将数组与元素数量为 0 的选择集绑定后,选择其 Enter 部分(请仔细看上图),然后添加(append)元素,也就是添加足够的元素,使得每一个数据都有元素与之对应。
svg.selectAll("rect") //选择svg内所有的矩形
.data(dataset) //绑定数组
.enter() //指定选择集的enter部分
.append("rect") //添加足够数量的矩形元素
1. Update和Enter的使用
当对应的元素不足时 ( 绑定数据数量 > 对应元素 ),需要添加元素(append)。 现在 body 中有三个 p 元素,要绑定一个长度大于 3 的数组到 p 的选择集上,然后分别处理 update 和 enter 两部分。
var dataset = [ 3 , 6 , 9 , 12 , 15 ];
//选择body中的p元素
var p = d3.select("body").selectAll("p");
//获取update部分
var update = p.data(dataset);
//获取enter部分
var enter = update.enter();
//update部分的处理:更新属性值
update.text(function(d){
return "update " + d;
});
//enter部分的处理:添加元素后赋予属性值
enter.append("p")
.text(function(d){
return "enter " + d;
});
页面效果:
enter 3
enter 6
enter 9
enter 12
enter 15
需要注意的是:
update 部分的处理办法一般是:更新属性值 enter 部分的处理办法一般是:添加元素后,赋予属性值
2. Update和Exit的使用
当对应的元素过多时 ( 绑定数据数量 < 对应元素 ),需要删掉多余的元素。 现在 body 中有三个 p 元素,要绑定一个长度小于 3 的数组到 p 的选择集上,然后分别处理 update 和 exit 两部分。
var dataset = [ 3 ];
//选择body中的p元素
var p = d3.select("body").selectAll("p");
//获取update部分
var update = p.data(dataset);
//获取exit部分
var exit = update.exit();
//update部分的处理:更新属性值
update.text(function(d){
return "update " + d;
});
//exit部分的处理:修改p元素的属性
exit.text(function(d){
return "exit";
});
//exit部分的处理通常是删除元素
// exit.remove();
需要注意的是: exit 部分的处理办法一般是:删除元素(remove)
过渡
D3 支持动画效果,这种动画效果可以通过对样式属性的过渡实现。其补间插值支持多种方式,比如线性、弹性等。此外 D3 内置了多种插值方式,比如对数值类型、字符类型路径数据以及颜色等。
启动过渡效果,与以下四个方法相关:
//创建一个过渡对象。但是由于每个选择集中都有transition()方法,可用d3.select("rect").transition()的方式来创建过渡,因此一般不直接用d3.transition()。 d3.transition([selection],[name])
//设定延迟的时间。过渡会经过一定时间后才开始发生。单位是毫秒。 transition.delay([delay])
//设定过渡的持续时间(不包括延迟时间),单位是毫秒。如:duration(2000),是持续2000ms。 transition.duration([duration])
//设定过渡样式,例如线性过渡、在目标处弹跳几次等方式。 transition.ease(vlaue[,arguments])
接下来制作一个过渡效果:
var width = 600;
var height = 400;
var svg = d3.select("#body")
.append("svg")
.attr("width",width)
.attr("height",height)
svg.append("rect")
.attr("fill","yellow")
.attr("x",100)
.attr("y",100)
.attr("width",100)
.attr("height",30)
.transition()
.duration(750)
.delay(function(d, i) { return i * 10; })
.attr("width",300)
.attr("height",300)
除了 D3 提供的过渡之外,你也可以通过 CSS 动画来实现对元素的过渡效果。
做一个简单的图表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./d3.v5.min.js"></script>
<style>
#app {
margin: 0 auto;
width: 500px;
height: 400px;
background: #efefef;
position: relative;
}
.bar {
width: 30px;
/* height: 50px; */
background: green;
position: absolute;
bottom: 100px;
}
.bar span {
display: block;
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<!-- <div class="bar"></div> -->
</div>
<script>
var datalist = [10, 20, 30, 40, 50];
var container = d3.select("#app");
container.selectAll('div')
.data(datalist)
.enter()
.append('div')
.classed('bar', true)
.style('height', function (d, i) {
return d * 5 + 'px';
})
.style('left', function (d, i) {
return i * 35 + 'px';
})
.append('span')
.text(function (d) {
return d;
})
.style('color', function (d) {
if (d > 30) {
return 'red';
}
})
</script>
</body>
</html>
svg基础
https://developer.mozilla.org/zh-CN/docs/Web/SVG https://www.d3js.org.cn/svg/get_start/
常用标签
Rect Ellipse Line Circle polygon polyline
path Text defs g use Animate
<svg width="500" height="500" style="background: #efefef;">
<!-- <rect x="50" y="100" width="100" height="50" fill="red" style="" stroke="blue" stroke-width="5" /> -->
<!-- <ellipse cx="200" cy="200" rx="50" ry="100" style="fill:orange; stroke: orangered; stroke-width: 5px;" /> -->
<!-- <line x1="50" y1="50" x2="450" y2="450" stroke="red" stroke-width="3" /> -->
<!-- <circle cx="225" cy="225" r="100" style="fill:peru;" /> -->
<!-- <polygon points="50,20 150,60 120,200 100,200" style="fill:pink;" fill="none" stroke="red" stroke-width="5" /> -->
<!-- <!-- <polyline points="10,20 50,60 120,200 200,300" fill="blue" stroke="red" stroke-width="5"></polyline> -->
-->
<!-- <path d="M30,30 L200,200 L230,260" fill="none" stroke="green" stroke-width="5" />
-->
<!-- <defs>
<g id="group">
<rect x="50" y="100" width="100" height="50" style="fill:green;" stroke="blue" stroke-width="5">
<animate attributeName="opacity" from="1" to="0" dur="5s" repeatCount="indefinite" />
</rect>
<circle cx="225" cy="225" r="100" style="fill:peru;">
<animate attributeName="cx" from="225" to="100" dur="5s" repeatCount="indefinite" />
</circle>
</g>
</defs> -->
<!-- <use xlink:href="#group" x="30" y="30" />
<use xlink:href="#group" x="130" y="130" /> -->
<!-- <text x="200" y="200" style="fill: none; stroke: red; stroke-width: 1; font-size: 45px;">NZGP1916</text> -->
<clipPath id="myClipPath">
<rect width="200" height="100" x="200" y="200"></rect>
</clipPath>
<circle cx="260" clip-path="url(#myClipPath)" cy="260" r="100" style="" />
</svg>
将图表标签更换成svg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./d3.v5.min.js"></script>
<style>
#app {
margin: 0 auto;
width: 500px;
height: 400px;
background: #efefef;
position: relative;
}
.bar {
width: 30px;
/* height: 50px; */
fill: green;
position: absolute;
bottom: 100px;
}
.bar span {
display: block;
text-align: center;
}
</style>
</head>
<body>
<svg id="app" style="width: 500px; height:400;">
<!-- <div class="bar"></div> -->
</svg>
<script>
var datalist = [10, 20, 30, 40, 50];
var container = d3.select("#app");
container.selectAll('rect')
.data(datalist)
.enter()
.append('rect')
.classed('bar', true)
.style('height', function (d, i) {
return d * 5 + 'px';
})
.attr('x', function (d, i) {
return i * 35 + 'px';
})
.attr('y', function (d, i) {
return 400 - d * 5 - 20 + 'px';
})
.style('color', function (d) {
if (d > 30) {
return 'red';
}
})
container.selectAll('text')
.data(datalist)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.text(function (d) {
return d;
})
.attr('x', function (d, i) {
return i * 35 + 15 + 'px';
})
.attr('y', function (d, i) {
return 400 - d * 5 - 20 + 'px';
})
.style('color', function (d) {
if (d > 30) {
return 'red';
}
})
</script>
</body>
</html>