标题: D3.js学习笔记1

时间: 2014-01-19 16:33:05

正文:

D3.js : 最流行的可视化 HTML5 概念前端 js 库之一。它允许绑定任意数据到DOM,创建惊人的SVG 图形。个人理解 SVG(Scalable Vector Graphics) 技术相对 Canvas 技术最大的特点是支持 DOM 结构,尽管复杂图形渲染不是长处,但是是真正的脱胎 HTML 的代表。D3.js 依赖 jquery 库,使用风格等也是一系的。

学习资料: Learning D3.js(1)学习制作一个柱形图/直方图

首先学习一个简单的横向柱状图的用法。 对柱状图的实现做下分解: 首先是需要有柱状图数据,这里定义一个 js 数组;然后是 D3.js 定义柱状图 DOM 结构;再用 css 对柱状图进行渲染。

        转载请注明出处 http://blog.hickwu.com/posts/319 by Hick

数据:

var data = [4, 8, 15, 16, 23, 42];

D3.js 的 DOM 结构定义:

var chart = d3.select("body").append("div").attr("class", "chart");
chart.selectAll("div")
    .data(data)
    .enter().append("div")
    .style("width", function(d) { return d * 10 + "px"; })
    .text(function(d) { return d; });

上边 DOM 的定义,第一行是选择 html 的 body 以后,追加一个 div 标签,并把样式 class 设置为 chart 。接着使用selectAll方法会选择chart内部所有的div元素。但注意,这个集合是空的,因为内部并没有div元素。下面的data方法,可以给这个集合绑定一组数据,绑定后比较有意思了,返回的是一系列的“空房间”:占位节点。数组中的每个元素占据一个节点。这样你就可以给这些节点追加元素了。空房间创建好后,我们使用enter()来“进入”这个房间,之后每个房间追加一个div,然后用style给房间“装修”一下。那么text()方法可以设置每个柱形图的文字。这个方法对于数字,会使用javascript自己的字符串转换,类似于toString. style 和 text 的匿名函数中都传递了 d 作为参数,实际上就是 data 的元素作为参数。

定义样式渲染:

.chart div {
  font: 10px sans-serif;
  background-color: steelblue;
  text-align: right;
  padding: 3px;
  margin: 1px;
  color: white;
}

最后渲染完成的 html 代码类似:

<div class="chart">
  <div style="width: 40px;">4</div>
  <div style="width: 80px;">8</div>
  <div style="width: 150px;">15</div>
  <div style="width: 160px;">16</div>
  <div style="width: 230px;">23</div>
  <div style="width: 420px;">42</div>
</div>

我们来改进下,上面的 style 方法使用具体数据的值运算得到一个像素宽度,这样当数据有比较大的偏差的时候,容易导致图形混乱。我们经常是需要设定图形的整个大小,然后数据在其范围内等比缩放, 我们可以使用一个非常好用的类:D3’s linear scale (直线标尺)定义宽度:

var x = d3.scale.linear()
    .domain([0, d3.max(data)])
    .range(["0px", "600px"]);

style 方法这样调用即可: .style("width", x) 。 上边是创建 D3.js 的直线标尺,domain 设置数据中的最大值, range 则是设置实际显示的最大像素。

说起来有点坑人, 实际上上边一直在用 html 的方式去构建图形,但是 svg 的思路是类似,下面是 svg 的方式. 首先,我们使用svg标签来代替div标签,表示一个图表容器.

var chart = d3.select("body").append("svg")
    .attr("class", "chart")
    .attr("width", 420)
    .attr("height", 20 * data.length);

不同的是这里还指定了宽度和高度,数字单位为 px 。类似的我们创建直线标尺:

var x = d3.scale.linear()
    .domain([0, d3.max(data)])
    .range([0, 420]);

svg图形的定位相对于左上角,称为原点。因此,默认情况下,柱形图也会从那个点开始绘制。为了解决这个问题,我们设置明确的y坐标和高度:

chart.selectAll("rect")
    .data(data)
  .enter().append("rect")
    .attr("y", function(d, i) { return i * 20; })
    .attr("width", x)
    .attr("height", 20);

注意attr方法中,i表示这个元素在数组中的序列。特别注意跟数据课本上学到的相比, x 轴是一样的,y 轴则是倒转过来的。

svg 的 css有些不同。fill属性决定了svg图形的颜色,stroke属性设置图形的边框。

.chart rect {
  stroke: white;
  fill: steelblue;
}

上边每条柱状图形的宽度是固定了 20px 。 如果 data 中的数据比较多就会拉得 Y 轴很长。 实际上我们可以用类似 x 轴的处理方式,动态的根据数据个数和总长度来计算 y 轴值:

var y = d3.scale.ordinal()
    .domain(data)
    .rangeBands([0, 120]);

其中 120 表示总的 y 轴高度。上面的定义以后, y.rangeBand() 返回是总长度/数组的元素个数, 所以可以这样定义了:

chart.selectAll("rect")
    .data(data)
    .enter().append("rect")
    .attr("y", y)
    .attr("width", x)
    .attr("height", y.rangeBand());

可以有一些属性来渲染图表的标签:

chart.selectAll("text")
    .data(data)
    .enter().append("text")
    .attr("x", x)
    .attr("y", function(d) { return y(d) + y.rangeBand() / 2; })
    .attr("dx", -3)       // padding-right 右边距
    .attr("dy", ".35em")  // vertical-align: middle 标签垂直居中
    .attr("text-anchor", "end") // text-align: right 文字水平居右
    .text(String);

用text创建标签,注意标签的位置:框y值+框高度的一半,也就是中心位置。dx,dy之类属性都在svg标准里规定了 http://www.w3.org/TR/SVG/text.html

demo见http://www.d3js.cn/demo/bar3.html

接下来给图表增加新的功能-纵向的标度。我们使用svg的标签,g与line来完成。这里的g类似于html标签的div,是一个容器元素。设置transform属性可以影响元素子元素的定位。这里我们利用translate,实质是设置边距,可以给上面的文字留下空白。当然你也可以利用这个属性使用丰富多彩的图形效果,比如缩放,旋转,裁剪等。详细参考 transform

var chart = d3.select("body").append("svg")
    .attr("class", "chart")
    .attr("width", 440)
    .attr("height", 140)
  .append("g")
    .attr("transform", "translate(10,15)");

注意了,这时候chart返回的是g容器,而不是svg。d3提供了ticks方法来方便我们制作这种周期性的刻度。

chart.selectAll("line")
        .data(x.ticks(10))

加上参考线, 指定x1,x2,y1,y2 分别是起点与终点的横纵坐标:

chart.selectAll("line")
        .data(x.ticks(10))
        .enter().append("line")
        .attr("x1", x)
        .attr("x2", x)
        .attr("y1", 0)
        .attr("y2", 120)
        .style("stroke", "#ccc");

加上标注线上面的文字:

chart.selectAll("a")
        .data(x.ticks(10))
        .enter().append("text")
        .attr("class", "rule")
        .attr("x", x)
        .attr("y", 0)
        .attr("dy", -3)
        .attr("text-anchor", "middle")
        .text(String);

最终效果:http://www.d3js.cn/demo/bar4.html

上面的教程信息量比较大,涉及了d3.js几个核心的概念:数据绑定,属性,文字,svg等等。

附最终代码:

  <meta charset="utf-8">
  <style type="text/css">
      .chart rect {
          stroke: white;
          fill: steelblue;
      }

  </style>
  <script src="jquery-1.10.2.min.js"></script>
  <script src="d3.v3.min.js"></script>

  <body>

  </body>
  <script type="text/javascript">
  $(function(){
      // 数据
      var data = [4, 8, 15, 16, 23, 42];
      // 图表对象
      var chart = d3.select("body").append("svg")
              .attr("class", "chart")
              .attr("width", 840)
              .attr("height", 140)
              .append("g")
              .attr("transform", "translate(10,15)");
      var x = d3.scale.linear()
              .domain([0, d3.max(data)])
              .range([0, 820]);
      var y = d3.scale.ordinal()
              .domain(data)
              .rangeBands([0, 120]);
      chart.selectAll("rect")
              .data(data)
              .enter().append("rect")
              .attr("y", y)
              .attr("width", x)
              .attr("height", y.rangeBand());
      chart.selectAll("text")
              .data(data)
              .enter().append("text")
              .attr("x", x)
              .attr("y", function(d) { return y(d) + y.rangeBand() / 2; })
              .attr("dx", -3) // padding-right
              .attr("dy", ".35em") // vertical-align: middle
              .attr("text-anchor", "end") // text-align: right
              .text(String);
      chart.selectAll("line")
              .data(x.ticks(10))
              .enter().append("line")
              .attr("x1", x)
              .attr("x2", x)
              .attr("y1", 0)
              .attr("y2", 120)
              .style("stroke", "#ccc");
      chart.selectAll("a")
              .data(x.ticks(10))
              .enter().append("text")
              .attr("class", "rule")
              .attr("x", x)
              .attr("y", 0)
              .attr("dy", -3)
              .attr("text-anchor", "middle")
              .text(String);

  });
  </script>
  </html>

查看更多文章
分享到:


分享到: