d3.js画柱状图超详细教程d3.js画柱状图超详细教程
完整代码放在最后,有⽂本编辑器和浏览器就⾏。
先看效果图
1. 本地创建⼀个⽂件夹,名字随便
2. 如何创建⼀个⽤于画d3的空⽩html?
在⽂件夹中新建⽂本⽂件,将后缀改为.html
<!doctype html>
<html>
<head>
<title>D3.js基础教程</title>
<script src="/d3.v5.min.js"charset="utf-8"></script>
<!-- 注1 -->
</head>
<body>
<div >
<h1>D3.js 柱状图</h1>sort函数 js
<div id="d3-container"/><!-- 注3 -->
</div>
<script src="index.js"></script><!-- 注2 -->
</body>
</html>
注1:在线导⼊官⽅d3库,注意不同版本之间可能会有差异
注2:引⼊了同⽂件夹的index.js⽂件,我们等下会创建
注3:再次创建⼀个id为"d3-container"的div,将在index.js中在此部分内容中添加svg模块
将该⽂件在浏览器中打开,应当展⽰如下界⾯:
3. 如何在空⽩html中加⼊⼀个svg画图区域?
在⽂件中新建⽂本⽂件,重命名为index.js
const data =[
{name:'晓晓', age:13},
{name:'明明', age:12},
];
const width =700;
const height =400;
const margin ={top:40, bottom:40, left:40, right:40};
const svg = d3.select('#d3-container')
.append('svg')//注1
.attr('height', height - p - margin.bottom)
.attr('width', width - margin.left - margin.right)
.attr('viewBox',[0,0, width, height]);//注2
注1:可见我们在html中之前指定id的地⽅添加了svg模块
注2:viewBox定义了svg的可显⽰区域,这⾥把所有svg分区都⽤于显⽰。在svg中有⼀个类似的概念叫做viewPort,关于他们区别的⼀个⽐喻:“viewPort是屏幕,⽽viewBox截取了屏幕的⼀部分”
刷新浏览器,F12按下ctrl+shift+c可以看到创建了⼀个空⽩svg画布
4. 如何将数据插⼊到svg中(在index.js中添加代码)
const x = d3.scaleBand()//注1
.domain(d3.range(data.length))//注4
.range([margin.left, width - margin.right])//注5
.paddingInner(0.1);//注3
const y = d3.scaleLinear()//注2
.domain([0,20])//注4
.range([height - margin.bottom, p])//注5
注1和注2
scaleLinear()和scaleBand()是两种⽐例尺,作⽤是将我们data变量中的数据指定⼀种⽅式存放到svg⾥⾯去,实现输⼊具体数据,返回具体坐标/长度。
scaleBand()是离散的映射⽐例尺,本例是将data.length=2的数据映射到了[margin.left, width - margin.right]=[40,700-40]=[40,660]的区间,区间的中点在(660+40)/2=350的位置。
有耐⼼的童鞋可以⾃⼰输出x(0)试试,雀⾷返回了40,但x(1)却返回了366.3157894,也就是说默认第⼆条数据会在中点靠右⼤概16个坐标的位置处继续画。**猜猜为什么是16呢?没错就是注3的paddingInner!
scaleLinear()是连续的映射,与x中只存储了x(0)和x(1)两个数据不同,我们的y需要连续进⾏映射
注4和注5(注3哪去了?)
domain表⽰定义域,range表⽰值域,即按照⽐例将数据从定义域映射到值域,上⾯关于x(1)的例⼦已经说得⽐较清楚了。、
svg
.append("g")//注6
.attr("fill",'royalblue')//注7
.selectAll("rect")//注8
.data(data.sort((a, b)=> d3.descending(a.age, b.age)))//注9
.join("rect")//注10
.attr("x",(d, i)=>x(i))//注11
.attr("y", d =>y(d.age))//注12
.attr('height', d=>y(0)-y(d.age))//注13
.attr('width', x.bandwidth());//注14
注6和注7:
svg g`的含义是组合,这属于svg的知识(⽽并不仅是d3中的知识)。其⾃⾝具有width(宽度), fill(背景颜⾊), transform(变形: ⽐如旋转)等属性,还可以可以在其中添加line线条,rect矩形等属性,详情可以参照-
这⾥希望加⼊的组是柱状图的蓝⾊注条,所以注7设定了颜⾊
注8:
rect的含义是rectangle,翻译⼀段Jakob关于rect的描述:“基于rect元素你可以画出不同宽度width,长度hight,边缘stroke,背景⾊fill的矩形,设置他们为圆⾓或直⾓”
这⾥选择了⼩组中所有的矩形来设定data(可是我们都没有声明“rect”呀!这或许就是join的神奇之处)
注9.1:d3.sort()
d3.descending吸收两个数字,并返回他们“是否”是按照降序排列的,“是”则返回1,“否”则返回零。
d3.sort的运作格式为:sort( compare ),这⾥的compare为d3.descending表⽰将以降序的⽅式排序,将返回⼀串数组。注意;⾥⾯的data为含有我们数据的那个data字典,我们通过.sort的⽅式完成了排序,使⽤console.log(data.sort((a, b) => d3.descending(a.age,
b.age)))将数据在浏览器中打印出来吧
注9.2:d3.data()
d3.data()函数接受数组型数据,并逐个对元素做遍历操作。这⾥我们为每⼀个元素都join(‘rect’)
注10:d3.join() 在这⾥的作⽤类似enter
注11:这⾥的d和i是作为attribute使⽤,d表⽰当前"x"数据,i指定了指数;x是我们之前建⽴的坐标映射,x(0)表⽰第⼀个数据的最⼩的x坐标。并将这个x(i)赋值为当前data的"x"。
如果我们去掉i,会导致两张图重合,但通过浏览器选择元素按钮还是可以看出来;
另⼀种写法是(d,i) => i*40,相当于⼿⼯设置坐标间距了
类似还有nodes和this,碰到的时候再说
注12 13 14类似,略
注15执⾏de()进⾏绘图、
F5运⾏,柱状图就出现啦~
5. 最后插⼊坐标轴
在运⾏de前,执⾏画坐标轴的函数
function yAxis(g){
g.attr("transform",`translate(${margin.left}, 0)`)
.call(d3.axisLeft(y).ticks(null, data.format))
.attr("font-size",'20px')
}
function xAxis(g){
g.attr("transform",`translate(0,${height - margin.bottom})`) .call(d3.axisBottom(x).tickFormat(i => data[i].name))
.attr("font-size",'20px')
}
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);
⼤功告成~
检查你的代码
html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论