d3.js學習筆記--Mike Bostock: VIZBI: D3 Workshop

Preface

    d3是基於HTML和SVG的數據可視化JS庫. 它將數據(data)和元素(DOM)相互綁定在一塊兒, 而且在數據實時改變狀況下DOM元素也會實時改變.javascript

因此, D3是Data-Driven Documents, 即數據驅動元素, 而D3的命名則來源於W3C Document Object Model.html

html模板文件爲:html5

<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>

<script src="d3.js"></script>
<script>

</script>

咱們須要在當前html模板文件下啓動一個簡單的服務器, 這樣才能讀取數據文件:java

leicj@lishunan:~$ python -m SimpleHTTPServer 8888 &
[1] 16960
leicj@lishunan:~$ Serving HTTP on 0.0.0.0 port 8888 ...
127.0.0.1 - - [23/Oct/2016 13:02:13] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [23/Oct/2016 13:02:13] code 404, message File not found
127.0.0.1 - - [23/Oct/2016 13:02:13] "GET /favicon.ico HTTP/1.1" 404 -
127.0.0.1 - - [23/Oct/2016 13:02:37] "GET /test/ HTTP/1.1" 200 -
127.0.0.1 - - [23/Oct/2016 13:02:37] "GET /test/d3.js HTTP/1.1" 200 -

 

Selections

d3的選擇器和jQuery很像, 如下是常常要用到的選擇器:python

#foo // <any id="foo">
foo // <foo>
.foo // <any class="foo">
[foo=bar] // <any foo="bar">
foo bar // <foo><bar></foo>
foo.bar // <foo class="bar">
foo#bar // <foo id="bar">

d3使用selectAll來篩選, 因此:git

d3.selectAll("pre,code")

等價於jQuery中:github

$("pre,code")

選擇器自己返回的是一個數組. 數組

一個實際的例子:服務器

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  svg {
    margin-top: 20px;
    margin-left: 20px;
  }
</style>

<svg height="960" width="960">
  <circle></circle>
</svg>
<script src="d3.js"></script>
<script>
  var circle = d3.selectAll("circle");
  circle.attr('cx', 50);
  circle.attr('cy', 52);
  circle.attr('r', 24);
  circle.style("fill", "red");

</script>

繪製一個circle:app

而d3支持鏈式編寫:

d3.selectAll("circle")
      .attr('cx', 50)
      .attr('cy', 52)
      .attr('r', 24)
      .style("fill", "red");

selection.append用於建立一個新的元素, 選擇其元素, 並在其元素後append數據.

d3.select("body").append("h1")
      .text("Hello!");

或者建立多個小圓圈:

<svg height="960" width="960">
</svg>
<script src="d3.js"></script>
<script>
  var data = [5, 10, 15, 20, 25, 20, 15, 10, 5];
  var g = d3.select('svg').append('g'),
      circle = g.selectAll('circle').data(data);
  circle.enter()
      .append("circle")
      .attr('cx', function(d, i) { return (i + 1) * 32; })
      .attr('cy', function(d, i) { return d * 20; })
      .attr('r', function(d, i) { return 10; })
      .attr('fill', 'red');

</script>

 

Data

咱們考慮下以下的圖形如何繪製:

這裏由五部分組成: 五個rect圖形, x軸的索引值, y軸的索引值, x軸, y軸. 開些編寫前, 先普及一些基本的svg函數:

1. rect: 用來繪製矩形, 基本屬性以下:

x: 矩形左上角的x位置

y: 矩形左下角的y位置

width: 矩形的寬度

height: 矩形的高度

rx: 圓角的x方位的半徑

ry: 圓角的y方位的半徑

2. translate: 使元素進行移動

首先, 咱們繪製五個rect:

var rect_arr = [
    {"height": 40, "width": 100},
    {"height": 40, "width": 200},
    {"height": 40, "width": 300},
    {"height": 40, "width": 400},
    {"height": 40, "width": 500}
    ];

  var g = d3.select("svg").append("g").attr("transform", "translate(40,60)"),
      rect = g.selectAll("rect").data(rect_arr);
  rect.enter()
      .append("rect")
      .attr("class", "bar")
      .attr("height", function(d, i) { return d.height; })
      .attr("width", function(d, i) { return d.width; })
      .attr("y", function(d, i) { return 80 + i * 70; })
      .attr("fill", "steelblue");

效果圖以下:

其次, 咱們繪製x軸:

var x_arr = [0, 100, 200, 300, 400, 500, 600],
      gx = d3.select("svg").append("g").attr("class", "x axis").attr("transform", "translate(40, 460)"),
      xaxis = gx.selectAll("g").data(x_arr);
  xaxis.enter()
      .append("g")
      .attr("transform", function(d, i) { return "translate(" + d + ",0)"})
      .attr("style", "opacity:1")
      .append("text")
      .attr("y", 14)
      .attr("x", 0)
      .attr("dy", ".71em")
      .attr("text-anchor", "middle")
      .text(function(d, i) { return i; });

和x軸的線:

var xaxis_path = d3.select("svg g.x").append("path")
      .attr("stroke", "#000")
      .attr("d", "M0 6H600");

y軸:

var y_arr = [
    {"y": 20, "text": "A"},
    {"y": 90, "text": "B"},
    {"y": 160, "text": "C"},
    {"y": 230, "text": "D"},
    {"y": 300, "text": "E"}
  ],
      gy = d3.select("svg").append("g").attr("class", "y axis").attr("transform", "translate(40, 100)"),
      yaxis = gy.selectAll("g").data(y_arr);
  yaxis.enter()
      .append("g")
      .attr("transform", function(d, i) { return "translate(0," + (40 + d.y) + ")"})
      .attr("style", "opacity:1")
      .append("text")
      .attr("x", "-8")
      .attr("y", 0)
      .attr("dy", ".32em")
      .attr("text-anchor", "end")
      .text(function(d, i) { return d.text; });

和y軸的線:

var yaxis_path = d3.select("svg g.y").append("path")
      .attr("stroke", "#000")
      .attr("d", "M0 0V370");

 

咱們來看如下做者給出的一個實例, 涉及到d3.js中的不少函數. 若是是初學d3.js, 須要查看文檔才能看懂如下代碼.

效果圖:

具體代碼:

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style>
  circle.dot {
    fill: steelblue;
  }
  .axis text {
    font: 10px sans-serif;
  }
  .axis path, .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }
</style>

<body>
<!--<script src="d3.js"></script>-->
<script src="http://d3js.org/d3.v2.min.js" charset="utf-8"></script>
<script>
  var data = [
    {x: 10.0, y: 9.14},
    {x: 8.0, y: 8.14},
    {x: 13.0, y: 8.74},
    {x: 9.0, y: 8.77},
    {x: 11.0, y: 9.26},
    {x: 14.0, y: 8.10},
    {x: 6.0, y: 6.13},
    {x: 4.0, y: 3.10},
    {x: 12.0, y: 9.13},
    {x: 7.0, y: 7.26},
    {x: 5.0, y: 4.74}
  ];
  var margin = {top: 40, right: 40, bottom: 40, left: 40},
      width = 960,
      height = 500;
  var x = pad(d3.scale.linear()
      .domain(d3.extent(data, function(d) { return d.x; }))
      .range([0, width - margin.left - margin.right]), 40);
  var y = pad(d3.scale.linear()
      .domain(d3.extent(data, function(d) { return d.y; }))
      .range([height - margin.top - margin.bottom, 0]), 40);
  var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom")
      .tickPadding(8);
  var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left")
      .tickPadding(8);
  var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height)
      .attr("class", "dot chart")
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  svg.selectAll(".dot")
      .data(data)
      .enter().append("circle")
      .attr("class", "dot")
      .attr("cx", function(d) { return x(d.x); })
      .attr("cy", function(d) { return y(d.y); })
      .attr("r", 12);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + y.range()[0] + ")")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

  function pad(scale, k) {
    var range = scale.range();
    if (range[0] > range[1]) k *= -1;
    return scale.domain([range[0] - k, range[1] + k].map(scale.invert)).nice();
  }
</script>
</body>
</html>

經過查詢API文檔, 解釋一些基本的函數:

domain和range相伴相生, domain用來設置比例尺, 而range用來設置實際的長度. 例如在一個SVG內部(寬度爲960), 咱們繪製X軸, 則range的範圍能夠是[0,900], 而domain表明實際的數據(例如5個點, x軸分別爲0, 1, 2, 3, 4), 則domain的範圍就是[0,4]. 因此第一個點繪製在0處, 中間2繪製在450處, 最後一個點4繪製在900處.

d3.extent: 用來找出數組中的最大值和最小值.

axis().scale: 用來設置比例尺

備註: 此代碼沒法理解, 須要學習到後面, 多聯繫, 才能夠本身完整寫出來.

 

以上兩個例子有難度. 如今來看看具體如何操做數據:

svg.selectAll("circle")
      .data(data)
      .enter()
      .append("circle")
      .attr("cx", x)
      .attr("cy", y)
      .attr("r", 2.5);

這裏咱們可能有疑惑, 爲何circle還爲存在狀況下, 咱們卻selectAll("circle")呢?

這裏是語法糖, 主要代碼塊應該這樣看: selectAll("circle").data(data); 它的做用是將data和DOM元素關聯起來, 使用enter()表明進入要遞歸的每一個元素, 而後append()生成此元素. 因此代碼實際上應該分開成:

var circle = svg.selectAll("circle")
      .data(data);
  
  circle.enter()
      .append("circle")
      .attr("cx", x)
      .attr("cy", y)
      .attr("r", 2.5);

 

Scales&Axes

Data-->Attributes: 屬性(attribute/style)是用來控制元素的位置和展示.

Domain-->Range: 用來控制data-space和visual-space.

var x = d3.scale.linear()
      .domain([12, 24])
      .range([0, 720]);
  console.log(x(16)); // 240 = (16 - 12) * ((720 - 0) / (24 - 12)) + 0

咱們可使用d3.max/d3.min獲取數組的最大最小值, 也可使用d3.extent獲取數組的最小最大值.

而extent甚至還能夠接收一個對象和函數:

var objects = [
    {"num": 1},
    {"num": 3},
    {"num": 2},
    {"num": 4}
  ];
  function value(d) { return d.num; }
  // [1,4]
  console.log(d3.extent(objects, value));

對於顏色, 咱們也能夠編寫:

var x = d3.scale.linear()
      .domain([12, 24])
      .range(["steelblue", "brown"]);
//  #ʚ586
  console.log(x(16));

甚至對像素, 咱們也能夠編寫:

var x = d3.scale.linear()
      .domain([12, 24])
      .range(["0px", "720px"]);
// 240px 
  console.log(x(16));

咱們可使用interpolate來更改所要顯示的格式:

var x = d3.scale.linear()
      .domain([12, 24])
      .range(["steelblue", "brown"])
      .interpolate(d3.interpolateHsl);
// #5f3cb0 
  console.log(x(16));

實際上, 對於domain/range, 不單單隻支持兩個參數, 容許傳遞多個參數:

var x = d3.scale.linear()
      .domain([-10, 0, 100])
      .range(["red", "white", "green"]);
  console.log(x(-5)); // #ff8080
  console.log(x(50)); // #80c080

對於ordinal來講, 其domain和range是顯式一一對應的:

var x = d3.scale.ordinal()
      .domain(["A", "B", "C", "D"])
      .range([0, 10, 20, 30, 40]);
  console.log(x("B"));  // 10
  console.log(x("f"));  // 40

而ordinal常常用於categorical colors:

var x = d3.scale.category20()
      .domain(["A", "B", "C", "D"])
  console.log(x("B"));  // #aec7e8

d3.js提供的顏色:

而對於ordinal來講, 其range會依據domain進行等間距劃分:

var x = d3.scale.ordinal()
      .domain(["A", "B", "C", "D"])
      .rangePoints([0, 720]);
  console.log(x("B"));  // 240

咱們能夠經過給定的scale, 建立一個axis:

var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left");

而後將y軸綁定到指定的繪圖區間:

svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

而經過以上代碼生成的html, 實際上大概以下:

由line進行線條的繪製, 而text顯示座標值. 因此咱們一般須要爲line或path進行style的設置:

.axis path, .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }

 

咱們通常使用transforms進行元素的移動:

 

後記:

1. HTML學習資料:

https://www.w3.org/TR/html5/

https://developers.whatwg.org/

http://diveintohtml5.info/

https://developer.mozilla.org/zh-CN/

2. SVG學習資料

https://www.w3.org/TR/SVG/

https://developer.mozilla.org/en-US/docs/Web/SVG

https://github.com/d3/d3/wiki/SVG-Shapes

3. CSS學習資料

https://www.w3.org/TR/CSS2/

https://www.w3.org/TR/selectors/

4. JavaScript學習資料

https://developer.mozilla.org/en-US/docs/Web/JavaScript

http://javascript.crockford.com/

5. D3學習資料

https://github.com/d3/d3/wiki/API-Reference

https://github.com/d3/d3/wiki

https://groups.google.com/forum/#!forum/d3-js

http://stackoverflow.com/questions/tagged/d3.js

6. 本學習資料來自:

https://bost.ocks.org/mike/d3/workshop/#0

相關文章
相關標籤/搜索