D3的全称是“Data-Driven Documents”,它是一个Javascript的函数库,用来做数据可视化的。不同于其他的图表组件,例如Highcharts等,它在图表的生成及与用户的数据交互方面提供了更大的灵活性。生成的图表基于SVG格式,以数据为驱动。其核心是“Data-Join”,即数据绑定。它解决了两个核心问题:
- 如何根据数据添加元素;
- 当数据发生更新的时候,如何修改元素;
D3是一个脚本库,只要在页面引入相应的.js文件即可使用。例如:
<script src="d3js/d3.min.js"></script>
选择元素
两个方法:
- d3.select()——返回匹配选择器的第一个元素;
d3.selectAll()——返回匹配选择器的所有元素;
方法的参数都是CSS选择器,例如:
var p = d3.select("body").selectAll("p");
选择集
d3.select()和d3.selectAll()返回一个选择集(selection)。
选择集有3个状态方法:
- sectiom.empty()——判断选择集是否为空。为空返回true;
- selection.node()——返回选择集的第一个非空元素。若选择集为空,则返回null;
- selection.size()——返回选择集中元素的个数;
<body>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<script>
var paragraphs = d3.selectAll("p");
console.log(paragraphs.empty()); //false
console.log(paragraphs.node()); //返回第一个p元素<p>paragraph 1</p>
console.log(paragraphs.size()); //3
</script>
</body>
选择集有6个属性方法:
- selection.attr(name[, value])——设置或获取属性值。name=属性名,value=属性值;
- selection.classed(name[, value])——设置样式名并决定是否开启。name=类名,value=是否开启,true表示启用样式,false表示不启用样式;
- selection.style(name[, value])——设置或获取具体的样式。name=样式名,value=样式值;
- selection.property(name[, value])——设置或获取特性值,例如text的value就属于特性而不是属性。name=属性名,value=属性值;
- selection.text([value])——获取或设置文本值;
- selection.html([value])——获取或设置HTML内容。
<body>
<p>This is a paragraph</p>
<input id="fname" type="text" name="fullname">
<svg></svg>
<!--HTML中的元素,标签里面包含标签-->
<p id="p1">This is <span>another</span> paragraph</p>
<script>
d3.select("p").attr("id", "para")
.classed("red", true)
.classed("bigsize", false)
.style("background-color", "silver");
d3.select("#fname").property("value", "张三");
var svg = d3.select("svg");
svg.append("circle")
.attr("cx", "50px")
.attr("cy", "50px")
.attr("r", "50px")
.attr("fill", "red");
console.log(d3.select("p").classed("red")); // true
console.log(d3.select("p").classed("bigsize")); // false
console.log(d3.select("p").style("background-color")); // silver
console.log(d3.select("#p1").text());
console.log(d3.select("#p1").html());
</script>
</body>
选择集有3个元素操作方法:
- selection.append(name)——在选择集的尾部追加一个元素,name=元素名;
- selection.insert(name[, before])——在指定的before元素前面插入一个元素;
- selection.remove()——删除选择集中的元素。注意这里是把选择集都删除了。
<body>
<!--body中的三个段落元素-->
<p>Car</p>
<p id="plane">Plane</p>
<p>Ship</p>
<script>
// 选择body元素
var body = d3.select("body");
// 在body中追加一个p元素,内容为Train
body.append("p").text("Train");
// 在Plane元素前面插入一个p元素,内容为Bike
body.insert("p", "#plane").text("Bike");
// 删除id为plane的p元素
d3.select("#plane").remove();
</script>
</body>
数据绑定
在有了选择集(selection)之后,其上是没有数据的。数据绑定就是让选择集拥有数据。有两个方法:
- selection.datum([value])——给选择集的每一个元素绑定相同的数据 value;
- selection.data([values[, key]])——给选择集的每一个元素分别绑定数组values的每一项。key是一个键函数,用于指定绑定数组时的对应规则。
对于数据绑定,无论是datum()还是data()函数,都是给选择集的元素附加了一个名为“data”的属性,该属性的值就是指定的value,可以是数值、字符串、布尔或者是对象。如果传递的值是undefined或null的话,则不会创建data属性。如同attr()一样,datum()可以不指定参数value,表示获取相应的data的值。如下所示:
<body>
<!--三个段落元素-->
<p>Fire</p>
<p>Water</p>
<p>Wind</p>
<script>
var p = d3.select("body").selectAll("p");
p.datum("Thunder").append("span")
.text(function(data, index){
return " " + data + " " + index;
});
console.log(p.datum());
</script>
</body>
在绑定了相应的数据以后,想使用这个数据,可以通过函数funcation(data, index)。其中data表示绑定的数据,index表示数据的索引。并且,我们在元素后面append了一个span之后,这个子元素也可以使用被绑定的数据。即“在被绑定数据的选择集中添加元素后,新元素会继承该数据”。此时通过控制台查看span元素,也可以发现一个名为data的属性,且属性值为Thunder。
datum()应用的较少,更多是使用data()来为选择集的元素绑定不同的数据。这里会有一个潜在的问题,即选择集中元素的长度和绑定的数组的长度不一致,实际上无非就是三种情况:
- selection.length = array.length
- selection.length < array.length
- selection.length > array.length
对此,带来3个选择集与之想对应:
- update——表示选择集中元素和数组相对应的部分,可以执行的操作就是修改attr属性的值;
- enter——表示选择集中元素小于数组的部分,可以执行的操作是给选择集append足够的元素。也就是说,这些元素即将“进入”(所以叫做enter)可视化;
- exit——表示选择集中元素大于数组的部分,可以执行的操作是删除选择集中多余的元素。也就是说,这些元素即将“退出”(所以叫做exit)可视化。
<body>
<p></p>
<script>
var dataset = [3,6,9];
var p = d3.select("body").selectAll("p");
// 绑定数据后,分别获取update部分和enter部分
var update = p.data(dataset);
var enter = update.enter();
// 对update的处理是直接修改内容
update.text(function(data){return data;});
// 对enter部分是追加元素后再修改内容
enter.append("p")
.text(function(data){return data;});
</script>
</body>
D3将数据的获取和呈现分为两个部分。一般而言,我们在向服务器请求数据的时候,一般并不会知道服务器将会返回给我们的确切的数据量。所以,通常的操作是,选择一个空选择集,并通过enter()操作来补足相应的元素。同样,当数据更新时,也会发生选择集的元素多于数据量,此时通过exit()操作删除多于的元素即可。