D3.js入门
D3(Data-Driven Document):数据驱动文档
D3是一个JavaScript的数据库,是用来做数据可视化的。其中文档指的是DOM,即文档对象模型(Document Object Model)。D3允许用户绑定任意数据到DOM,然后根据数据来操作文档,创建可交互式图表。
D3的优势:
- 数据能够与DOM绑定在一起 ,使数据和图形成为一个整体。
- 数据转换和绘制是独立的 。
- 代码简洁 。
- 大量布局 。
- 基于SVG,缩放不会损失精度。
学习D3.js之前需要学习的:
- HTML/HTML5基础
- CSS/CSS3基础 。
- JavaScript基础 。
- DOM基础 。
- SVG基础。
学习D3.js的网站:
D3的官网,含有API和大量示例:http://d3js.org/
D3创始人制作的,有很多说明文档:https://www.dashingd3js.com/
使用d3是需要引用:
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
第一节:数据集与数据
选择集:select()、selectAll()
选择集:d3.select、d3.selectAll返回的对象称为选择集(selection),添加、删除、设定网页中的元素,都得使用选择集。
- select() :返回匹配选择器的第一个元素。
- selectAll(): 返回匹配选择器的所有元素。
以下是关于它们的例子:
选择元素:
//使用CSS选择器
d3.select("body");//直接选择元素
d3.select("#part1");//选择id为part1的元素
d3.select(".part2");//选择class为part2的元素(多个中的第一个)
d3.selectAll(".part2");//选择class为part2的所有元素
d3.selectAll("ul li");//选择ul中所有的li元素
//使用DOM API(不建议使用,建议直接使用上面那种)
var x=document.getElementById("part1");//getElementByClassName(用selectAll())、getElementByTagName...
d3.select(x);//选择id为part1的元素
//选择元素需要进行选择==>“连缀语法”。
d3.select("body")
.selectAll("p");//选择body下的所有p元素
- 查看选择集状态:
selection.empty():如果选择集为空,则返回true;如果不为空,返回false。
selection.node():返回第一个非空元素,如果选择集为空,返回null。
selection.size():返回选择集中的元素个数 - 设置和获得属性:
①设置和获得属性: .append()生成标签、.attr()生成属性。
<1>设置标签:selection.append(“标签名”);
<2>设置属性:selection.attr(“name”,“value”);//name属性名称、value属性值
获得属性:selection.attr(“name”);
var svg=d3.select("body") //选择元素body
.append("svg") //生成svg标签
.attr("width",width) //生成width属性
.attr("height",height);
②设值和获取class(CSS类):
<1>设置class:selection.classed(“name”,“value”);//name类名、value布尔值,表示类是否开启。
<2>获得class:selection.classed(“name”);
注:.attr()也可以设置类,但设置多个类不方便:d3.select(“p”).attr(“class”,“part1 part2”);//类名间用空格隔开
d3.select("p")
.classed("part1",true)//开启part1类,会在元素标签添加class="part1"。
.classed("part2",false);//不开启part2类
③设置或获取选择集的样式style:
<1>设置style:selection.style(“name”,“value”);//name样式名,value样式值
<2>获得style:selection.style(“name”);
d3.select("p")
.style("color","red");
.style("font-size","30px");
④(有些属性不能通过.attr()添加:比如文本输入中的value)设置或获取选择集的属性:
<1>设置属性:selection.property(“name”,“value”);//name属性名,value属性值
<2>获得属性:selection.property(“name”);
//html代码
<input id="part1" type="text" name="part1" />//设置value属性
//script代码
d3.select("#part1")
.property("value","输入");
⑤设置或获得文本内容:
<1>设置文本内容:selection.text(“value”);
相当于DOM中的innerHTML替换标签文本,不包括文本中的标签内容
<2>获得文本内容:selection.text();
//html代码
<p>This<span>is</span>a paragraph</p>
//script代码
d3.select("body") //选择元素body
.selectAll("p") //选择所有元素p
.text();
//输出:This is a paragraph
⑥设置或获得选择集的内部HTML内容:
<1>设置HTML内容:selection.html(“value”);
相当于DOM中的innerHTML替换标签文本,包括文本中的标签内容
<2>获得HTML内容:selection.html();
//html代码
<p>This<span>is</span>a paragraph</p>
//script代码
d3.select("body") //选择元素body
.selectAll("p") //选择所有元素p
.html();
// 输出:This<span>is</span>a paragraph
- 选择集的添加、插入、删除操作:
①添加selection.append(“name”);//在末尾添加标签名为name
②插入selection.insert(“name”,“before”);//插入标签name,在before标签之前
③删除selection.remove();//删除某标签内容
//HTML代码
<p>Car</p>
<p id="plane">Plane</p>
<p>Ship</p>
//script代码
var body=d3.select("body");//选择body元素
body.append("p")
.text("Train");//在body中所有元素的末尾添加一个p元素,内容为Train
body.insert("p","#plane")
.text("Bike");//在body中id为plane的元素前添加p元素,内容为Bike
var plane=d3.select("#plane");
plane.remove();//删除id为plane的元素
数据绑定:datum()、data()
数据绑定:使用选择元素里“含有”数据。
绑定的顺序:默认,data()是按索引号顺序绑定。可以不按顺序进行,使用key键函数(只有在原选择集已经绑定有数据的情况下,使用键函数才有效果)。
- selection.datum(“value”):选择集中的每个元素绑定相同的数据value。
//.datum()用法:
var p=d3.select("body")
.selectAll("p");
p.datum("Animal")//绑定字符串Animal到选择集上
.append("span")//在每个p元素后创建一个span元素,在被绑定数据的选择集中添加元素后,新元素会继承改数据。
.text(function (d,i) {//定义一个无名函数,d代表被绑定的字符串,i代表索引号(可以改变字母但意思不变)
return d+" "+i;
});
console.log(p);//查看选择集p,含有属性__data__。子元素span继承该属性。
- selection.data(“values”,key):选择集每一个元素分别绑定values的每一项,key是一个键函数,用于指定绑定数组时的对应规则。
//.data()用法:
var dataset=[3,6,9,12,15];//定义数组
var p=d3.select("body").selectAll("p");
var update=p.data(dataset);//绑定数据到选择集
console.log(update);//输出绑定的结果
console.log(update.enter());
console.log(update.exit());
//update:数组长度=元素数量(绑定的数据的元素,即将被更新)
//enter:数组长度>元素数量(部分还不存在的元素,即将进入可视化)
//exit:数组长度<元素数量(多余的元素,即将退出可视化)
//绑定顺序
var persons=[{id:3,name:"张三"},
{id:6,name:"李四"},
{id:9,name:"王五"}];
var p=d3.select("body")
.selectAll("p");
//绑定数据,并修改p元素的内容
p.data(persons)
.text(function(d){
return d.id+":"+d.name;
})
// 输出:3:张三
// 6:李四
// 9:王五
//更新persons里面的数据
persons=[{id:6,name:"张三"},
{id:9,name:"李四"},
{id:3,name:"王五"}];
//根据键函数规则绑定数据,并修改数据
p.data(persons,function(d){return d.id;})//使用id作为键
.text(function(d){
return d.id+":"+d.name;
})
//输出顺序不按索引顺序绑定,而是按照键值依次对应
// 输出:3:王五
// 6:张三
// 9:李四
①enter(存在多余数据)的处理方法:append()添加元素后修改内容
//例子:p不为空集
var dataset=[3,6,9,12,15];//定义数组,设p元素少于5个
var p=d3.select("body")
.selectAll("p");
//绑定数据后获得update和enter部分
var update=p.data(dataset);//绑定数据到选择集
var enter=update.enter();
//update部分的处理方法是直接修改内容
update.text(function (d) { return d;});
//enter部分的处理方法是添加元素后在修改内容
enter.append("p")
.text(function(d){ return d;});
//例子:p为空集
var dataset=[10,20,30,40,50];//定义数组
var body=d3.select("body");
body.selectAll("p") //没有p元素,则选中一个空集
.data(dataset)
.enter()
.append("p")
.text(function(d){ return d;});
②exit(存在多余元素)的处理方法:remove()删除元素
var dataset=[10,20,30];
var p=d3.select("body")
.selectAll("p");
//绑定数据后,分别获取update和exit部分
var update=p.data(dataset);
var exit=update.exit();
//update部分的处理方法是修改内容
update.text( function(d){ return d});
//exit部分的处理方法是删除
exit.remove();
注:无论是什么情况都可以使用此处理模板:
//处理模板:
var dataset=[10,20,30];
var p=d3.select("body")
.selectAll("p");
//绑定数据后返回update、enter和exit部分
var update=p.data(dataset);
var enter=update.enter();
var exit=update.exit();
//update部分的处理方法是直接修改内容
update.text( function(d){ return d});
//enter部分的处理方法是添加元素后在修改内容
enter.append("p")
.text(function(d){ return d;});
//exit部分的处理方法是删除
exit.remove();
③过滤器(filter):根据被绑定数据对某选择集的元素进行过滤。
selection.filter(function(d,i){
if(d>20)
return true;
else
return false;
});
④选择集顺序sort():可以根据被绑定数据重新排列选择集中的元素。
注:sort()的参数是一个无名函数,该函数也称为比较器
selection.sort(function(a,b){return b-a;});//递减顺序
selection.sort(function(a,b){return a-b;});//递增顺序
⑤each():允许对选择集的各元素分别处理。
var persons=[{id:1001,name:"zhangsan"},
{id:1002,name:"lisi"}];
var p=d3.select("body")
.selectAll("p");
p.data(persons)
.each(function(d,i){ //被绑定数据里没有age属性,通过each()函数为每一项添加了age属性
d.age=20;
})
.text(function(d,i){
return d.id+" "+d.name+" "+d.age;
});
⑥call():允许将选择集自身作为参数,传递给某一个函数
d3.selectAll("div").call(myfun);//将选择集div传递给myfun函数
数组Array:
数组:通常是由相同数据类型的项组成集合,拥有数组名,可以凭借数组名和下标来访问数据项。
①排序:对选择集使用sort()时,如果不指定比较函数,默认是d3.ascending。
有函数时,function(a,b),a位于b之前,则返回值小于0;a位于b之后,则返回值大于0;a与b相等,则返回值为0。
没有函数时,d3.ascending(a,b),递增函数。a<b,返回-1;a>b,返回1;a=b,返回0。d3.descending(a,b),递减函数。a>b,返回-1;a<b,返回1;a=b,返回0。
var numbers=[54,23,77,11,34];
numbers.sort(d3.ascending);
console.log(numbers); // [11,23,34,54,77]
②求值:求取数组的最大值、最小值、中间值、平均值等。
accessor为可选函数,即可以在求值时调用函数。
<1>d3.min(array[])、d3.min(array[],accessor):返回数组最大值
<2>d3.max(array[])、d3.max(array[],accessor):返回数组最小值
<3>d3.extend(array[])、d3.extend(array[],accessor):返回数组最小值和最大值
//例子:min、max、extend
//数组定义
var numbers=[30,20,10,50,40];
//求最小值和最大值
var min=d3.min(numbers);
var max=d3.max(numbers);
var extent=d3.extent(numbers);
//输出结果
console.log(min);//10
console.log(max);//50
console.log(extent);//[10,50]
//使用accessor,在求值前先处理数据
//numbers数组的每一项都会调用此函数。
var minAcc=d3.min(numbers,function(d){return d*3;});
//numbers的每一项*3==>[90,60,30,150,120]==>再取最小值
var maxAcc=d3.max(numbers,function(d){return d-5;});
var extendAcc=d3.extent(numbers,function(d){return d%7;});
//输出结果
console.log(minAcc);//30
console.log(maxAcc);//45
console.log(extendAcc);//[1,6]
<4>d3.sum(array[])、d3.sum(array[],accessor):返回数组总和,如果数组为空,则返回0
<5>d3.mean(array[])、d3.mean(array[],accessor):返回数组的平均值,如果数组为0,则返回0
//例子:sum、mean
//数组定义,undefined和NaN不会影响
var numbers=[69,11,undefined,53,27,82,65,34,NaN];
//求总和、平均值
var sum=d3.sum(numbers,function(d){return d/3;});
var mean=d3.mean(numbers);
//输出结果
console.log(sum);//113.66666666666667
console.log(mean); //48.714285714285715
<6>d3.median(array[])、d3.median(array[],accessor):求数组的中间值,如果数组为空,则返回undefined
//例子:median直接忽略无效值
var numbers1=[3,1,7,undefined,9,NaN];
d3.median(numbers1);//返回5,偶数,返回中间两位相加除以2
var numbers2=[3,1,7,undefined,9,10,NaN];
d3.median(numbers2);//返回7,奇数,返回最中间的值
<7>d3.quantile(numbers,p):求取p分位点的值,p的范围[0,1]。(数组需先递增排序)
//例子:quantile
var numbers=[3,1,10];
numbers.sort(d3.ascending);
d3.quantile(numbers,0);//返回1
d3.quantile(numbers,0.25);//返回2
d3.quantile(numbers,0.5);//返回3
d3.quantile(numbers,0.75);//返回6.5
d3.quantile(numbers,1.0);//返回10
//简化:d3.quantile(numbers.sort(d3.ascending),0.5);
<8>d3.variance(array[])、d3.variance(array[],accessor):求方差
<9>d3.deviation(array[])、d3.deviation(array[],accessor):求标准差
<10>d3.bisectLeft():获取数组项左边位置
d3.bisect()、d3.bisectRight():获取数组项右边的位置
与JavaScript中的splice()函数一起使用:splice(3,1,“China”,“Japan”);//删除索引为3的一个元素,再插入两个元素
//例子:bisect、bisectLeft
var numbers=[10,13,16,19,22,25];
//iLeft的值为2
var iLeft=d3.bisectLeft(numbers.sort(d3.accending),16);//16的左边位置
//在iLeft位置处,删除0个项后,插入77
numbers.splice(iLeft,0,77);
console.log(numbers);//输出[10,13,77,16,19,22,25]
<11>d3.shuffle(array[]):将数组重新排列
//例子:shuffle
var numbers=[10,13,16,19,22,25]
d3.shuffle(numbers);
console.log(numbers);//结果随机
<12>d3.merge(array[]):合并两个数组
//例子:merge
d3.merge([[1],[2,3]]);//合并两个数组
<13>d3.pairs(array[]):返回邻接的数组对。以i项和i-1项为对返回。
//例子:pairs
var colors=["red","blue","yellow"];
var pairs=d3.pairs(colors);
console.log(paris);//结果为[["red","blue"],["blue","yellow"]]
<14>d3.range([start],[stop],[step]):返回等差数列。stop为正,则最后的值小于stop;stop为负,则最后的值大于stop。start和step如果省略,则默认分别为0和1。
//例子:range
var c=d3.range(2,10,2);//从2开始到10结束,不包括10,等差值为2。
console.log(c);//输出[2,4,6,8]
<15>d3.permute(array,indexes):根据指定的索引号数组返回排列后的数组。
//例子:permute
var animals=["cat","dog","bird"];
var newAnimals=d3.permute(animals,[2,1,0]);//根据索引号[2,1,0]重新排序animals
console.log(newAnimals);//输出:["bird","dog","cat"]
<16>d3.zip(arrays…):用多个数组来制作数组的数组。
//例子:zip
var zip=d3.zip([1000,1001,1002],["zhangsan","lisi","wangwu"],[true,false,true]);//制作新的数组
console.log(zip); //输出:[[1000,"zhangsan",true],[1001,"lisi",false],[1002,"wangwu",true]]
<17>d3.transpose(matrix):求转置矩阵。
//例子:transpose
var a=[[1,2,3],[4,5,6]];
var t=d3.transpose(a);//转置矩阵
console.log(t);//输出:[[1,4],[2,5],[3,6]]
映射Map:
映射Map:一种数据结构,由一系列键(key)和值(value)组成。每个key对应一个value,根据key可以获取和设定value,也可以根据key来查询value。
<1>d3.map([object],[key]):构建映射。object源数组,key用于指定映射的key
<2>map.has(key):如果指定的key存在,则返回true;反之,则返回false。
<3>map.get(key):如果指定的key存在,则返回key的value;否则,返回undefined。
<4>map.set(key,value):对指定的key设定value,如果该key已经存在,则新的value会覆盖旧的;如果不存在,则添加一个新的value。
<5>map.remove(key):如果指定key存在,则将此key和value删除,并返回true;如果不存在,返回false。
<6>map.keys():以数组形式返回该map的所有key。
<7>map.values():以数组形式返回该map的所有value。
<8>map.entries():以数组形式返回该map的所有key和value。
<9>map.forEach(function):分别对该映射中的每一项调用function函数,function函数传入两个参数:key、value。分别代表每一项的key和value。
<10>map.empty():如果该映射为空,返回true;否则,返回false。
<11>map.size():返回该映射的大小
var dataset=[{id:1000,color:"red"},
{id:1001,color:"green"},
{id:1002,color:"blue"}]
//以数组dataset构成映射,并以其中各项的id作为键
var map=d3.map(dataset,function(d){return d.id;});
map.has(1001);//返回true
map.has(1003);//返回false
map.get(1001);//返回{id:1001,color:"green"}
map.get(1003);//返回undefined
//将1001键的值设置为{ id:1001,color:"yellow"}
map.set(1001,{id:1001,color:"yellow"});
//将1003键的值设置为{id:1003,color:"white"}
map.set(1003,{id:1003,color:"white"})
map.remove(1001);//删除键为1001的键和值
map.keys();//返回["1000","1002","1003"]
map.values();//返回所有的值
map.entries();//返回所有的键和值
//该循环会进行三次,键依次为1000、1002、1003
map.forEach(function(key,value){
console.log(key);
console.log(value);
});
map.empty();//返回false
map.size();//返回3
集合Set:
集合Set:表示具有特定性质的事物的总体。集合里的项叫做元素。
<1>d3.set([array]):使用数组构建集合,如果数组里有重复的元素,则只添加其中一项。
<2>set.has(value):如果集合中有指定元素,则返回true;如果没有,返回false。
<3>set.add(value):如果该集合中没有指定元素,则将其添加到集合中,并返回该元素;如果有,则不添加。
<4>set.remove(value):如果该集合中有指定元素,则将其删除并返回true;否则,返回false。
<5>set.values:以数组形式返回该集合中所有元素。
<6>set.forEach(function):对每个元素都调用function函数,函数里传入一个参数,即该元素的值。
<7>set.empty():如果该集合为空,则返回true;否则,返回false。
<8>set.size():返回该集合的大小。
//源数组
var dataset=[{"tiger","dragon","snake","horse","sheep"}];
//构建一个集合,将其保存在变量set中
var set=d3.set(dataset);
set.has("tiger");//返回true
set.add("monkey");//添加monkey,并返回monkey
set.remove("snake");//删除snake
set.values();//返回["tiger","dragon","horse","sheep","monkey"]
set.forEach(function(value){console.log(value);});//集合中的每一个元素都调用function函数,该函数的内容为输出各元素。
set.empty();//返回false
set.size();//返回5//源数组
var dataset=[{"tiger","dragon","snake","horse","sheep"}];
//构建一个集合,将其保存在变量set中
var set=d3.set(dataset);
set.has("tiger");//返回true
set.add("monkey");//添加monkey,并返回monkey
set.remove("snake");//删除snake
set.values();//返回["tiger","dragon","horse","sheep","monkey"]
set.forEach(function(value){console.log(value);});//集合中的每一个元素都调用function函数,该函数的内容为输出各元素。
set.empty();//返回false
set.size();//返回5
嵌套结构Nest:
嵌套结构(Nest):能够使用键(key)对数组中的大量对象进行分类,多个键一层套一层,使得分类越来越具体,索引越来越方便。
<1>d3.nest():该函数没有任何参数,表示接下来将会构建一个新的嵌套结构。其他函数和它一起使用。
<2>nest.key(function):指定嵌套结构的键
<3>nest.entries(array):指定数组array将被用于构建嵌套结构的键。
//例子:key、entries
var persons=[{id:100,name:"zhangsan",year:1989,hometown:"beijing"},
{id:101,name:"lisi",year:1987,hometown:"beijing"},
{id:102,name:"wangwu",year:1988,hometown:"shanghai"},
{id:103,name:"zhaoliu",year:1987,hometown:"guangzhou"},
{id:104,name:"sunqi",year:1989,hometown:"shanghai"}];
var nest=d3.nest()
//将year作为第一个键
.key(function(d){return d.year;})
//将hometown作为第二个键
.key(function(d){return d.homeown;})
//指定将应用嵌套结构的数组为persons
.entries(persons);
console.log(nest);
<4>nest.sortKeys(comparator):按照键对嵌套结构进行排序,接在nest.key()后使用。
// 例子:sortkeys
d3.nest()
.key(function(d){return d.year;})
.sortKeys(d3.descending)//按照键year进行排序
.key()//其他键的定义
<5>nest.sortValues(comparator):按照值对嵌套结构进行排序。
// 例子:sorValues
var persons=[{sex:"男",age:48,name:"zhangsan"},
{sex:"男",age:42,name:"lisi"},
{sex:"男",age:45,name:"wangwu"},
{sex:"女",age:33,name:"zhaoliu"},
{sex:"女",age:31,name:"sunqi"}];
var nest=d3.nest()
.key(function(d){return d.sex;})
.sortValues(function(a,b){
return d3.ascending(a.age,b.age);
})
.entries(persons);
// 输出:[{key:"男",values:[
// {sex:"男",age:42,name:"lisi"},
// {sex:"男",age:45,name:"wangwu"},
// {sex:"男",age:48,name:"zhangsan"}
// ]},
// {key:"女",values:[
// {sex:"女",age:31,name:"sunqi"},
// {sex:"女",age:33,name:"zhaoliu"}
// ]}]
<6>nest.rollup(function):对每一组叶子节点调用指定的函数function,该函数含有一个参数values,是当前叶子节点的数组。
// 例子:rollup
var nest=d3.nest()
.key(function(d){return d.sex;})
.rollup(function(values){return values.length;})
.entries(persons);
// 输出:[{key:"男",value:3},
// {key:"女",value:2}]
<7>nest.map([array],“mapType”):以映射的形式输出数组。
//例子:map
var map=d3.nest()
.key(function(d){return d.sex;})
.map(persons,d3.map);
// 输出:{
// "女":[
// {sex:"女",age:33,name:"zhaoliu"},
// {sex:"女",age:31,name:"sunqi"}
// ],
// "男":[
// {sex:"男",age:48,name:"zhangsan"},
// {sex:"男",age:42,name:"lisi"},
// {sex:"男",age:45,name:"wangwu"}
// ]
// }
注:使用映射的方式输出时,其结果最外层是一个花括号,而不是中括号。即它是一个对象,而不是一个数组。内部的形式也有很多不同之处,请注意区别。
练习:制作一个Bar Chart
//html代码
<button type="button" onclick="mysort()">排序</button>
<button type="button" onclick="myadd()">增加数据</button>
//script代码
//柱状图制作:矩形、坐标轴和文字
//dataset定义柱状图中矩形长短
var dataset=[50,43,120,87,99,167,142];
var width=400;//SVG绘制区域的宽度
var height=400;//SVG绘制区域的高度
var svg=d3.select("body")//选择<body>
.append("svg")//在<body>中添加<svg>
.attr("width",width)//设定<svg>的宽度属性
.attr("height",height);//设定<svg>的高度属性
var padding={top:20,right:20,bottom:20,left:20};//定义上下左右边框
var rectStep=35;//矩形所占的宽度(包括空白),单位像素
var rectWidth=30;//矩形所占的宽度(不包括空白),单位像素
var rect=svg.selectAll("rect")
.data(dataset)//绑定数据
.enter()//获得enter部分
.append("rect")//添加rect元素,使其与绑定数组的长度一致
.attr("fill","black")//设置颜色为steelblue
.attr("x",function(d,i){//设置矩形的x坐标
return padding.left+i*rectStep;
})
.attr("y",function(d){//设置矩形的y坐标
return height-padding.bottom-d;
})
.attr("width",rectWidth)//设置矩形的宽度
.attr("height",function(d){//设置矩形的高度
return d;
});
var text=svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("fill","white")
.attr("font-size","14px")
.attr("text-anchor","middle")
.attr("x",function(d,i){
return padding.left+i*rectStep;
})
.attr("y",function(d){
return height-padding.bottom-d;
})
.attr("dx",rectWidth/2)
.attr("dy","1em")
.text(function(d){
return d;
});
//更新数据
function draw(){
//获取矩形的update部分
var updateRect=svg.selectAll("rect")
.data(dataset);
//获取矩形的enter部分
var enterRect=updateRect.enter();
//获取矩形的exit部分
var exitRect=updateRect.exit();
//矩形的update部分的处理方法:直接修改内容
updateRect.attr("fill","black")
.attr("x", function(d,i){
return padding.left+i*rectStep;
})
.attr("y",function(d){
return height-padding.bottom-d;
})
.attr("width",rectWidth)
.attr("height",function(d){
return d;
});
//矩形的enter部分的处理方法:添加元素后修改内容
enterRect.append("rect")
.attr("fill","black")
.attr("x", function(d,i){
return padding.left+i*rectStep;
})
.attr("y",function(d){
return height-padding.bottom-d;
})
.attr("width",rectWidth)
.attr("height",function(d){
return d;
});
//矩形的exit部分的处理方法:删除
exitRect.remove();
var updateText=svg.selectAll("text")
.data(dataset);
var enterText=updateText.enter();
var exitText=updateText.exit();
updateText.attr("fill","white")
.attr("font-size","14px")
.attr("text-anchor","middle")
.attr("x",function(d,i){
return padding.left+i*rectStep;
})
.attr("y",function(d){
return height-padding.bottom-d;
})
.attr("dx",rectWidth/2)
.attr("dy","1em")
.text(function(d){
return d;
});
enterText.append("text")
.attr("fill","white")
.attr("font-size","14px")
.attr("text-anchor","middle")
.attr("x",function(d,i){
return padding.left+i*rectStep;
})
.attr("y",function(d){
return height-padding.bottom-d;
})
.attr("dx",rectWidth/2)
.attr("dy","1em")
.text(function(d){
return d;
});
exitText.remove();
}
function mysort(){
dataset.sort(d3.ascending);//排序
draw();
}
function myadd(){
dataset.push(Math.floor(Math.random()*100));//添加一个项
draw();
}
转载于图书:《精通D3.js:交互式数据可视化高级编程》吕之华 著