最近再做一个应用,然后需要做一些表格,其中有柱状图和饼状图,柱状图感觉还可以用div模拟,然是饼状图就不知道了,想了半天,css我是实现不了了。
我想起来,现在前端可视化有好多的库,我刚好可以趁这个机会学习一下,然后上网一搜,频率出现的比较多的就是d3了,想来,数据可视化的东西库应该是一类东西,学习其中一个比较经典的,其他的以后就算要用,应该思想是差不多的,就和当初学jquery一样,jquery的思想和写法,在其他的库中隐约可以看到。
d3开始并不知道如何下手,看了他的api文档,妈呀,这么多,就算知道怎么用,还是不知道该怎么组合使用这些api,我查了半天,就知道了一些概念。
d3是基于svg的,他是jquery加上svg创造的,并且有许多的工具函数,所以需要有一定的svg基础,然后看一下svg,发现想要入门一个东西,w3school是一个好网站,里面的教程简单易懂,作为入门来讲是极好的。
稍微看看了一下,svg不难svg基础;他有几种嵌入方式,然后再里面可以定义一些标签,还有可以定义好多属性,进行表现不同的界面。
然后我就想先做一个简单的柱状图练练手:
先来复习一下常用的svg:svg里面可以预定义一些形状元素,rect,circle等。然后内部可以像html元素定义一些属性,比如定义class属性,还有自定义的属性,常见的属性有: width, height, style中的fill stroke 等。
有没有发现定义形状或者牵扯到画图的东西就有stroke这些东西,和canvas中的一模一样,以后有时间一定要把canvas好好搞搞。
好下面就正式写柱状图的代码了:
我们先来理一下思路,画一个柱状图需要经历哪些步骤,首先我们要有一片画布,所以我们就有了下面这段代码:
<div class="container">
</div>
var svg = d3.select('.container').append('svg').attr('width', '100%').attr('height', '100%');
var main = svg.append('g').attr('transform', 'translate('+ padding.left + ',' + padding.top + ')');
好,画布我们有了,先是画一个svg,然后我们在里面定义了我们要画的地方就是g了,然后把g添加进svg,然后再设置g的偏移量,好这样就ok了,画布有了。
接下来就是我们的坐标轴了,坐标轴画起来需要花点时间的,开始我是一直不理解他的思想,然后看了一天之后终于明白了,他就是数学,你安装数据的思路去思考就可以,首先你要画坐标轴,其实就是两条线,你得先知道他的定义域吧,也就是你要显示的数据,这里分x轴和y轴,为了不乱,我们一个一个讲。
x轴:他因为是要显示一些离散的坐标,所以我们要用d3的序数刻度尺,这时候就要去查api文档了,文档,然后我就按照上面的来了,然后主要用的就是设定一个定义域和值域,所以我们使用的是 ordinal.domain([values]),这个方法用来做x值和域的映射,然后再使用 ordinal.rangeRoundPoints(interval[, padding]),来指定我们的输出范围,他就是自己对应上去,好,这样我们x轴的代码有点样子出来了,
var xScale = d3.scale.ordinal().domain(data.x).rangeRoundBands([0, width - padding.left - padding.right], 0, 0);
然后把x轴的比例尺已经给构造出来了,那么我们现在需要的是把坐标轴画出来,这下就又不看api,画轴有没有,查看这里的api,
创建轴要和定量,时间,比例尺一块使用,先把他的比例尺给应用上去,
var xAxis = d3.svg.axis().scale(xScale).orient('bottom');
然后把坐标轴画上去,
main.append('g').attr('class', 'axis').attr('transform', 'translate(0 ,' + (height - padding.top - padding.bottom) + ')').call(xAxis);
好这就把x轴画出来了,y轴也是一样的道理,不过y轴是线性比例尺,因为他的数值是连续的,柱状图嘛,还是和上面的步骤一样,先画一个比例尺,这时候就用线性的,
var yScale = d3.scale.linear().domain([0, d3.max(data.y)]).range([height - padding.top - padding.bottom, 0]);
文档中写range里面的参数要倒置写,希望大家注意。
然后就去画y轴,
var yAxis = d3.svg.axis().scale(yScale).orient('left');
main.append('g').attr('class', 'axis').call(yAxis);
这个就把这个轴给画出来了,然后我们下来就是画柱状图了,柱状图分析一下就是一个一个的矩形,我们可以使用svg的rect来画。
我们先使用selectAll把元素选中,然后给他添加数据,用enter占位符,等到他把数据和元素匹配好了,然后我们再用append到文档的位置上去,然后就可以给他设置属性了,class和其他的一些信息等,还要给柱子设置宽度和高度,宽度是固定的,高度因为数据已经再开始已经注入,所以我们只需要在第二个参数中传入一个函数,然后我们所需要的高度,最后再设置他的填充颜色属性,这样就ok了,这段话可能会有点绕,结合代码看会好一点,
main.selectAll('.bar').data(data.y).enter().append('rect').attr('class', 'bar').attr('x', function(d, i){
return xScale(data.x[i]) + rectMargin;
}).attr('y', function(d, i){
return yScale(d)
}).attr('width', xScale.rangeBand() - 2*rectMargin).attr('height', function(d, i){
return height - padding.top - padding.bottom - yScale(d);
}).attr('fill', function(d, i){
return getColor(i);
})
我们再给他下面定一个getColor()就好了,
function getColor(idx) {
var palette = ['#2ec7c9', '#b6a2de', '#5ab1ef', '#ffb980', '#d87a80', '#8d98b3', '#e5cf0d', '#97b552', '#95706d', '#dc69aa','#07a2a4', '#9a7fd1', '#588dd5', '#f5994e', '#c05050','#59678c', '#c9ab00', '#7eb00a', '#6f5553', '#c14089'];
return palette[idx % palette.length];
}
好了,已经画出来了,最后我们在把他具体的数据给写到柱子里面去,直接看这个api,
还是和刚刚添加柱子一样,你把文本给选中,然后给他注入数据,然后可以设置属性,然后就好了,再把text值给放进去,因为刚刚已经把数据注入了,所以现在只需要直接一个函数传入在返回要的值就可以了。
main.selectAll('.text').data(data.y).enter().append('text').attr('class', 'text').attr('x', function(d, i){
return xScale(data.x[i])
}).attr('y', function(d, i){
return yScale(d)
}).attr('dx', (xScale.rangeBand() - 14)/2).attr('dy', '20').text(function(d){
return d;
});
好,初次使用d3做数据可视化终于完成了,这次d3给我最大感受就是数学和如何把数据呈现出来要经历怎么样一个步骤,才能把数据用图标的形式展示出来,我需要这种思想,希望大神可以给我推荐几本书。