D3.js 中的所有功能在 JavaScript 中都能实现,它仅仅是一个函数库而已。D3 所做的事就是减轻你的工作量,以及使你的代码十分简单易懂。
使用 d3.select() 或 d3.selectAll() 选择元素后返回的对象,就是选择集
关于 select 和 selectAll 的参数,其实是符合 CSS 选择器的条件的,即用“井号(#)”表示 id,用“点(.)”表示 class。
如何选择元素
在 D3 中,用于选择元素的函数有两个:
D3 能将数据绑定到 DOM 上,也就是绑定到文档上
例如网页中有段落元素 p 和一个整数 5,于是可以将整数 5 与 p 绑定到一起。绑定之后,当需要依靠这个数据才操作元素的时候,会很方便。
D3 中是通过以下两个函数来绑定数据的:
var str = "China";
var body = d3.select("body");
var p = body.selectAll("p");
p.datum(str);
p.text(function(d, i){
return "第 "+ i + " 个元素绑定的数据是 " + d;
});
在上面的代码中,用到了一个无名函数 function(d, i)。当选择集需要使用被绑定的数据时,常需要这么使用。其包含两个参数,其中:
例如,上述例子中:第 0 个元素 apple 绑定的数据是 China
var p = body.select("#myid");
p.remove();
如此即可删除指定 id 的段落元素。
组成要素:矩形、文字标签、坐标轴组成
HTML 5 提供两种强有力的“画布”:SVG 和 Canvas。
(1)SVG 有如下特点:
(2)Canvas 有如下特点:
- 绘制的是位图,图像放大后会失真。
- 不支持事件处理器。
- 能够以 .png 或 .jpg 格式保存图像
- 适合游戏应用
D3 虽然没有明文规定一定要在 SVG 中绘图,但是 D3 提供了众多的 SVG 图形的生成器,它们都是只支持 SVG 的。因此,建议使用
SVG 画布。
var width = 300; //画布的宽度
var height = 300; //画布的高度
var svg = d3.select("body") //选择文档中的body元素
.append("svg") //添加一个svg元素
.attr("width", width) //设定宽度
.attr("height", height); //设定高度
在 SVG 中,矩形的元素标签是 rect,
x 轴的正方向是水平向右,y 轴的正方向是垂直向下的。
矩形的属性,常用的有四个:
- x:矩形左上角的 x 坐标
- y:矩形左上角的 y 坐标
- width:矩形的宽度
- height:矩形的高度
有数据,而没有足够图形元素的时候,使用此方法可以添加足够的元素。
svg.selectAll("rect") //选择svg内所有的矩形
.data(dataset) //绑定数组
.enter() //指定选择集的enter部分
.append("rect") //添加足够数量的矩形元素
//demo
//创建画布
var width = 300; //画布的宽度
var height = 300; //画布的高度
var svg = d3.select("body") //选择文档中的body元素
.append("svg") //添加一个svg元素
.attr("width", width) //设定宽度
.attr("height", height).style("background","red");
var rectHeight = 25; //每个矩形所占的像素高度(包括空白)
var dataset = [ 250 , 210 , 170 , 130 , 90 ]; //数据(表示矩形的宽度)
svg.selectAll("rect") //选择svg内所有的矩形
.data(dataset) //绑定数组
.enter() //指定选择集的enter部分
.append("rect") //添加足够数量的矩形元素
.attr("x",20)
.attr("y",function(d,i){
return i * rectHeight;
})
.attr("width",function(d){
return d;
})
.attr("height",rectHeight-2)
.attr("fill","steelblue");//是给矩形元素设置颜色。一般来说,最好写成外置 CSS 的形式,方便归类和修改
绘图时,直接使用 250 给矩形的宽度赋值,即矩形的宽度就是 250 个像素。此方式非常具有局限性,如果数值过大或过小,例如:
var dataset_1 = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
var dataset_2 = [ 2500, 2100, 1700, 1300, 900 ];
2.5 个像素来代表矩形的宽度,那样根本看不见;也不可能用 2500 个像素来代表矩形的宽度,因为画布没有那么长。
比例尺,很像数学中的函数。例如,对于一个一元二次函数,有 x 和 y 两个未知数,当 x 的值确定时,y 的值也就确定了。在数学中,x 的范围被称为定义域,y 的范围被称为值域。
D3 中的比例尺,也有定义域和值域,分别被称为 domain 和 range。开发者需要指定 domain 和 range 的范围,如此即可得到一个计算关系。
能将一个连续的区间,映射到另一区间
//将 dataset 中最小的值,映射成 0;将最大的值,映射成 300。
var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];
var min = d3.min(dataset);//求数组最小值
var max = d3.max(dataset);//求数组最大值
var linear = d3.scale.linear()
.domain([min, max])
.range([0, 300]);
linear(0.9); //返回 0
linear(2.3); //返回 175
linear(3.3); //返回 300
其中,d3.scale.linear() 返回一个线性比例尺。domain() 和 range() 分别设定比例尺的定义域和值域
比例尺的定义域 domain 为:[0.9, 3.3]
比例尺的值域 range 为:[0, 300]
d3.scale.linear() 的返回值,是可以当做函数来使用的。因此,才有这样的用法:linear(0.9)。
有时候定义域和值域不一定是连续,例如,有两个数组:
var index = [0, 1, 2, 3, 4];
var color = ["red", "blue", "green", "yellow", "black"];
我们希望 0 对应颜色 red,1 对应 blue,依次类推, 但是,这些值都是离散的,线性比例尺不适合,需要用到序数比例尺
var index = [0, 1, 2, 3, 4];
var color = ["red", "blue", "green", "yellow", "black"];
var ordinal = d3.scale.ordinal()
.domain(index)
.range(color);
由一些列线段和刻度组成,坐标轴在 SVG 中需要用其他的元素组合构成,D3提供了坐标轴的组件
在 SVG 画布的预定义元素里,有六种基本图形:
x:矩形左上角的x坐标
y:矩形左上角的y坐标
width:矩形的宽度
height:矩形的高度
<rect x="20" y="20" width="200" height="100" style="fill:steelblue;stroke:blue;stroke-width:4;opactity:0.5"/>
cx:圆心的x坐标
cy:圆心的y坐标
r:圆的半径
<circle cx="150" cy="150" r="80" style="fill:yellow;stroke:black;stroke-width:2"/>
cx:椭圆圆心的x坐标
cy:椭圆圆心的y坐标
rx:椭圆的x轴半径
ry:椭圆的y轴半径
<ellipse cx="250" cy="150" rx="200" ry="100" style="fill:green;stroke:blue;stroke-width:1"/>
x1:起点的x坐标
y1:起点的y坐标
x2:终点的x坐标
y2:重点的y坐标
<line x1="20" y1="10" x2="200" y2="230" style="stroke:red;stroke-width:3"/>
points:折线各个点坐标
"100,30, 20,80 60,160 140,160 180,90" style="fill:white;stroke:black;stroke-width:1" transform="translate(200,0)" />
points:多边形各个点的坐标
<polygon points="100,30, 20,80 60,160 140,160 180,90" style="fill:LawnGreen;stroke:black;stroke-width:1" />
M:起点坐标
L:画直线到指定坐标
H:画水平直线到指定坐标,省略了y轴坐标
V:画垂直直线到指定坐标,省略了x轴坐标
C:三次贝赛尔曲线经两个指定控制点和到达终点坐标
S:与前一条贝塞尔曲线相连,第一个控制点为前一条曲线第二个控制点的对称点,只需要第二个控制点和终点
<svg width="500" height="300" version="1.1">
<path d="M30,50 L200,200" style="stroke:black;stroke-width:1"/>
<path d="M30,50 H200" style="stroke:red;stroke-width:1"/>
<path d="M30,50 V200" style="stroke:blue;stroke-width:1"/>
svg>
基础图形在演变而来的图形
- 圆角矩形
- x:矩形左上角的x坐标
- y:矩形左上角的y坐标
- width:矩形的宽度
- height:矩形的高度
- rx:对于圆角矩形,圆角对应的椭圆在x方向上的半径
- ry:对于圆角矩形,圆角对应的椭圆在y方向上的半径
<rect x="20" y="20" rx="30" ry="50" width="200" height="100" style="fill:red;stroke:black;stroke-width:3;opacity: 0.5;">
C:三次贝赛尔曲线经两个指定控制点和到达终点坐标
S:与前一条贝塞尔曲线相连,第一个控制点为前一条曲线第二个控制点的对称点,只需要第二个控制点和终点
<svg width="500" height="300" version="1.1">
<path d="M30,100 C100,20 190,20 270,100 S400,180 450,100" style="fill:white;stroke:red;stroke-width:2"/>
svg>
A( rx , ry , x-axis-ratation , large-arc-flag , sweep-flag , x , y)
rx:椭圆x方向的半轴大小
ry:椭圆y方向的半轴大小
x-axis-ratation:椭圆的x轴与水平轴顺时针方向夹角
large-arc-flag:两个值(1:大角度弧线 0:小角度弧线)
sweep-flag:两个值(1:顺时针至终点 0:逆时针至终点)
x:终点x坐标
y:终点y坐标
<svg width="500" height="300" version="1.1">
<path d="M100,200 A50,30 0 1,0 150,-150 " style="fill:red;stroke:blue;stroke-width:1"/>
svg>
D3 提供了一个组件:d3.svg.axis(), 坐标轴和比例尺经常一起使用 (1)定义坐标轴
//数据
var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
//定义比例尺
var linear = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([0, 250]);
var axis = d3.svg.axis()
.scale(linear) //指定比例尺
.orient("bottom") //指定刻度的方向
.ticks(7); //指定刻度的数量
(2)在 SVG 中添加坐标轴
定义了坐标轴之后,只需要在 SVG 中添加一个分组元素 ,再将坐标轴的其他元素添加到这个 里即可。代码如下:
svg.append("g")
.call(axis);
call() 函数,其参数是前面定义的坐标轴 axis。在 D3 中,call() 的参数是一个函数。调用之后,将当前的选择集作为参数传递给此函数。
未完成
1、一个完整的柱形图(矩形、文字、坐标轴 )
2、图标添加动画