一直想写写D3,以为D3真心比较强大,基本上你能想出来的图表都能绘制出来,只不过使用起来比前几个要稍麻烦一点。git
正好最近读完了《数据可视化实战》,将关于D3的知识梳理了一遍,写这篇博客记录一下。github
D3 是一个缩写,它的全称叫Data-Driven Documents(数据驱动的文档)。D3是基于数据操做文档的JavaScript库。D3帮助你使用HTML,SVG和CSS生动的展示数据。D3不须要将你使用某个特定的框架,D3重点在于对主流浏览器的全兼容,同时结合了强大的虚拟化组件,以数据驱动的方式去操做DOM。数组
D3支持所谓的主流浏览器除了IE8及之前的版本。D3测试了火狐,Chrome、Safari、Opera和IE9。D3的大部分组件能够在旧的浏览器运行,D3核心库的最低运行要求:支持JavaScript和W3C DOM API.对于IE8,建议使用兼容性库Aight库.D3采用的是Selectors API的第一级标准,你要是考虑兼容性能够预加载Sizzle库。你得使用主流的浏览器以即可以支持SVG和CSS3的转场特效。浏览器
官网地址:http://d3js.org/app
下载官方包 d3.v3.zip 或者添加以下代码:框架
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
var dataset = [1,2,3,4,5]; d3.select("body").selectAll("p") .data(dataset) .enter() .append("p") .text("New paragraph!");
结果以下图dom
详细的解释svg
d3.select("body")
选择DOM 中的body 元素,把它交给连缀方法中的下一个方法。
.selectAll("p")
选择DOM 中的全部段落。由于尚未段落,因此返回空元素。能够认为这个空元素表明立刻就会建立的段落。
.data(dataset)
解析并数出数据值。dataset 数组中有5 个值,于是此后的全部方法都将执行五遍,每次针对一个值。
.enter()
要建立新的绑定数据的元素,必须使用enter()。这个方法会分析当前选择的DOM 元素和传给它的数据,若是数据值比对应的DOM 元素多,就建立一个新的占位元素。而后把这个新占位元素的引用交给链中的下一个方法。
.append("p")
取得由enter() 建立的空占位元素,并把一个p 元素追加到相应的DOM 中。而后它再把本身刚建立的元素交给链中的下一个方法。
.text("New paragraph!")
取得新建立的p 元素,插入文本值。函数
将最后一行修改成测试
.text(function(d) { return d; });
结果以下
咱们用数据填充了每一个段落,机关都在data() 方法里。在连缀方法中,只要调用data() 了,就能够随时建立一个接收d 为输入的匿名函数。与当前元素对应,方法data() 确保了每一个d 都会被赋予原始数据集中的一个值。随着D3 遍历每一个元素,“当前元素”的这个值也会跟着变化。好比,循环到第三次时,代码会建立第三个p 元素,而d 就会被赋予数据集中的第三个值(即dataset[2])。因而,第三个段落的文本就是“15”。
首先要建立一个SVG 元素,以便在其中保存全部图形,先找到文档的body 元素,而后在结束的</body> 标签前添加一个新的svg 元素,并设置长宽,代码以下
var svg = d3.select("body") .append("svg") .attr("width", 500) .attr("height", 50);
添加一些数据
var dataset = [ 5, 10, 15, 20, 25 ];
使用data() 迭代每一个数据点,为它们分别建立一个圆形
var circles = svg.selectAll("circle") .data(dataset) .enter() .append("circle");
最后设置图形的样式
circles.attr("cx", function(d, i) { return (i * 50) + 25; })//设置x的位置 .attr("cy", 50 / 2)//设置y的位置 .attr("r", function(d) { return d; })//设置圆的半径 .attr("fill", "yellow")//设置填充颜色 .attr("stroke", "orange")//设置圆的边缘线颜色 .attr("stroke-width", function(d) { return d / 2; });//设置圆的边缘线的宽度
结果以下图
“比例尺是一组把输入域映射为输出范围的函数。”
先建立比例尺,设定值域为100~500和实际范围10~350,代码以下
var scale = d3.scale.linear() .domain([100, 500]) .range([10, 350]);
能够测试一下scale
scale(100); // 返回10 scale(300); // 返回180 scale(500); // 返回350
添加数据集
var dataset = [ [5, 20], [480, 90], [250, 50], [100, 33], [330, 95], [410, 12], [475, 44], [25, 67], [85, 21], [220, 88] ];
能够根据d3的max()和min()方法建立一个动态映射轴值的比例尺函数,max() 函数只是简单地循环数组中的每一个值,而后找出其中最大的那个。min()则是找出其中最小的那个。
定义比例尺函数,其中w是svg宽,h是svg高。
var w = 500; var h = 100; var xScale = d3.scale.linear() .domain([0, d3.max(dataset, function(d) { return d[0]; })]) .range([0, w]); var yScale = d3.scale.linear() .domain([0, d3.max(dataset, function(d) { return d[1]; })]) .range([0, h]);
使用比例尺函数处理数据,并到svg中显示
svg.selectAll("circle") .data(dataset) .enter() .append("circle") .attr("cx", function(d) { return d[0]; }) .attr("cy", function(d) { return d[1]; }) .attr("r", function(d) { return Math.sqrt(h - d[1]); });
效果以下
d3.scale.linear() 还有几个很是方便的方法。
nice()
告诉比例尺取得为range() 设置的任何值域,把两端的值扩展到最接近的整数。根据D3 的维基:“好比,值域[0.20147987687960267, 0.996679553296417]的优化值域为[0.2, 1]。”这个方法对正常人都有用,由于人不是计算机,看到0.20147987687960267 这样的数你必定会头大。
rangeRound()
用rangeRound() 代替range() 后,则比例尺输出的全部值都会舍入到最接近的整数值。对输出值取整有利于图形对应精确的像素值,避免边缘出现模糊不清的锯齿。
clamp()
默认状况下,线性比例尺能够返回指定范围以外的值。例如,假如给定的值位于输入值域以外,那么比例尺也会返回一个位于输出范围以外的值。不过,在比例尺上调用clamp(true) 后,就能够强制全部输出值都位于指定的范围内。这意味着超出范围的值,会被取整到范围的最低值或最高值(总之是最接近的那个值)。
除了线性(linear)比例尺,D3 还内置了另外几个比例尺方法。
sqrt
平方根比例尺。
pow
幂比例尺,适合值以指数级变化的数据集。
log
对数比例尺。
quantize
输出范围为独立的值的线性比例尺,适合想把数据分类的情形。
quantile
与quantize 相似,但输入值域是独立的值,适合已经对数据分类的情形。
ordinal
使用非定量值(如类名)做为输出的序数比例尺,很是适合比较苹果和桔子。
d3.scale.category10()、d3.scale.category20()、d3.scale.category20b() 和d3.scale.category20c()
可以输出10 到20 种类别颜色的预设序数比例尺,很是方便。
d3.time.scale()
针对日期和时间值的一个比例尺方法,能够对日期刻度做特殊处理。
接着上面的例子进行,建立数轴
var xAxis = d3.svg.axis()//建立通用的数轴函数 .scale(xScale)//基于xScale比例尺工做 .orient("bottom");//设置标签相对数轴显示在什么地方。默认位置是底部。
在SVG 中生成数轴,放在脚本底部,以便在SVG 中的其余元素都生成以后再生成数轴,这样数轴就能够出如今“上面”了。
svg.append("g") .attr("class", "axis") // 指定"axis" 类 .call(xAxis);
效果以下
略难看,并且x轴的位置也不对。
修整一下数轴,在<head> 中的<style> 标签里写两条CSS 样式规则。
.axis path, .axis line { fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: sans-serif; font-size: 11px; }
用到SVG 变换(transform)了。添加一行代码,把整个数轴分组平移到图表下方,详细以下
svg.append("g") .attr("class", "axis") .attr("transform", "translate(0," + (h - 20) + ")") .call(xAxis);
效果以下
而后添加Y轴,作一些调整,最后JS文件以下
var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var dataset = [ [ 5, 20 ], [ 480, 90 ], [ 250, 50 ], [ 100, 33 ], [ 330, 95 ], [ 410, 12 ], [ 475, 44 ], [ 25, 67 ], [ 85, 21 ], [ 220, 88 ] ]; var x = d3.scale.linear() .domain([0, d3.max(dataset, function(d) { return d[0]; })]) .range([0, width]); var y = d3.scale.linear() .domain([0, d3.max(dataset, function(d) { return d[1]; })]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg.selectAll("circle") .data(dataset) .enter() .append("circle") .attr("cx", function(d) { return x(d[0]); }) .attr("cy", function(d) { return y(d[1]); }) .attr("r", function(d) { return 10; }); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("X轴"); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Y轴");
最终效果以下
D3的基础今天就到这里~~
有时间的话,推荐读一下《数据可视化实战》~~