【D3.js 入門系列一】從零開始繪製一個柱形圖

混沌傳奇發表於2019-03-04

宣告:本教程針對D3.js v3版本進行講解。

D3 是什麼

D3 的全稱是(Data-Driven Documents),顧名思義可以知道是一個被資料驅動的文件。聽名字有點抽象,說簡單一點,其實就是一個 JavaScript 的函式庫,使用它主要是用來做資料視覺化的。

D3 提供了各種簡單易用的函式,大大簡化了 JavaScript 運算元據的難度。由於它本質上是 JavaScript ,所以用 JavaScript 也是可以實現所有功能的,但它能大大減小你的工作量,尤其是在資料視覺化方面,D3 已經將生成視覺化的複雜步驟精簡到了幾個簡單的函式,你只需要輸入幾個簡單的資料,就能夠轉換為各種絢麗的圖形。有過 JavaScript 基礎的朋友一定很容易理解它。

為什麼使用D3.js

我們知道現在有很多開源的圖表庫Echarts、HighCharts、G2.js等等。那麼D3跟這些圖表庫相比有什麼優勢和劣勢?

  1. D3 基於svg,因此對影像進行放大不會失真。(D3.js v4版本已經支援canvas了,本系列教程只講v3版本)

  2. D3 相對來說較底層,對初學者來說不太方便,但是一旦掌握了,就比其他工具更加得心應手。下圖展示了 D3 與其它視覺化工具的區別:

    【D3.js 入門系列一】從零開始繪製一個柱形圖

    可以看到,D3 的步驟相對來說較多。壞處是對初學者不方便、也不好理解。好處是能夠製作出更加精密的圖形。因此,我們可以據此定義什麼時候選擇 D3 比較好:

    選擇 D3:如果希望開發腦海中任意想象到的圖表。

    選擇 Highcharts、Echarts 等:如果希望開發幾種固定種類的、十分大眾化的圖表。

    看起來,D3 似乎是為藝術家或發燒友準備的。有那麼點意思,但請初學者也不要放棄。

SVG 是什麼

SVG,指可縮放向量圖形(Scalable Vector Graphics),是用於描述二維向量圖形的一種圖形格式,是由全球資訊網聯盟制定的開放標準。SVG 使用 XML 格式來定義圖形,除了 IE8 之前的版本外,絕大部分瀏覽器都支援 SVG,可將 SVG 文字直接嵌入 HTML 中顯示。

SVG 有如下特點:

  1. SVG 繪製的是向量圖,因此對影像進行放大不會失真。
  2. 基於 XML,可以為每個元素新增 JavaScript 事件處理器。
  3. 每個圖形均視為物件,更改物件的屬性,圖形也會改變。
  4. 不適合遊戲應用。

學習 D3 需要什麼預備知識

想要通過 D3 來開啟資料視覺化之旅的朋友,需要什麼預備知識呢?

  1. HTML:超文字標記語言,用於設定網頁的內容
  2. CSS:層疊樣式表,用於設定網頁的樣式
  3. JavaScript:一種直譯式指令碼語言,用於設定網頁的行為
  4. DOM:文件物件模型,用於修改文件的內容和結構
  5. SVG:可縮放向量圖形,用於繪製視覺化的圖形

有人會問:多久能學會D3.js?

我可以告訴各位:只要跟著我這個D3入門系列教程學習、練習下來,你就學會了用D3.js編寫常用的圖表。學得快的人,兩三天就掌握了,學的慢的人,可能需要一週時間吧。

下面開始學習D3.js具體技術細節。。。


【Lesson1】選擇元素和繫結資料

1. 如何選擇元素

在 D3 中,用於選擇元素的函式有兩個:

  • d3.select():是選擇所有指定元素的第一個
  • d3.selectAll():是選擇指定元素的全部

這兩個函式返回的結果稱為選擇集

這裡涉及一個概念:選擇集
使用 d3.select() 或 d3.selectAll() 選擇元素後返回的物件,就是選擇集

例如,選擇集的常見用法如下:

var body = d3.select("body"); //選擇文件中的body元素
var p1 = body.select("p");      //選擇body中的第一個p元素
var p = body.selectAll("p");    //選擇body中的所有p元素
var svg = body.select("svg");   //選擇body中的svg元素
var rects = svg.selectAll("rect");  //選擇svg中所有的svg元素
複製程式碼

選擇集和繫結資料通常是一起使用的。

2. 如何繫結資料

D3 有一個很獨特的功能:能將資料繫結到 DOM 上,也就是繫結到文件上。這麼說可能不好理解,例如網頁中有段落元素 和一個整數 5,於是可以將整數 5 與 繫結到一起。繫結之後,當需要依靠這個資料才操作元素的時候,會很方便。

D3 中是通過以下兩個函式來繫結資料的:

  • datum():繫結一個資料到選擇集上
  • data():繫結一個陣列到選擇集上,陣列的各項值分別與選擇集的各元素繫結

相對而言,data() 比較常用。

假設現在有三個段落元素如下:

<p>Apple</p>
<p>Pear</p>
<p>Banana</p>
複製程式碼

接下來分別使用 datum() 和 data(),將資料繫結到上面三個段落元素上。

2.1 datum()

假設有一字串 China,要將此字串分別與三個段落元素繫結,程式碼如下:

var str = "China";

var body = d3.select("body");
var p = body.selectAll("p");

p.datum(str);

p.text(function(d, i){
    return "第 "+ i + " 個元素繫結的資料是 " + d;
});
複製程式碼

繫結資料後,使用此資料來修改三個段落元素的內容,其結果如下:

第 0 個元素繫結的資料是 China
 
第 1 個元素繫結的資料是 China
 
第 2 個元素繫結的資料是 China
複製程式碼

在上面的程式碼中,用到了一個無名函式 function(d, i)。 當選擇集需要使用被繫結的資料時,常需要這麼使用。其包含兩個引數,其中:

  • d 代表資料,也就是與某元素繫結的資料。
  • i 代表索引,代表資料的索引號,從 0 開始。

例如,上述例子中:第 0 個元素 apple 繫結的資料是 China。

2.2 data()

有一個陣列,接下來要分別將陣列的各元素繫結到三個段落元素上。

var dataset = ["I like dogs","I like cats","I like snakes"];
複製程式碼

繫結之後,其對應關係的要求為:

  • Apple 與 I like dogs 繫結
  • Pear 與 I like cats 繫結
  • Banana 與 I like snakes 繫結

呼叫 data() 繫結資料,並替換三個段落元素的字串為被繫結的字串,程式碼如下:

var body = d3.select("body");
var p = body.selectAll("p");
 
p.data(dataset)
  .text(function(d, i){
      return d;
  });
複製程式碼

這段程式碼也用到了一個匿名函式 function(d, i),其對應的情況如下:

  • 當 i == 0 時, d 為 I like dogs。
  • 當 i == 1 時, d 為 I like cats。
  • 當 i == 2 時, d 為 I like snakes。

此時,三個段落元素與陣列 dataset 的三個字串是一一對應的,因此,在函式 function(d, i) 直接 return d 即可。

結果自然是三個段落的文字分別變成了陣列的三個字串。

I like dogs

I like cats

I like snakes
複製程式碼
有人會發現,D3 能夠連續不斷地呼叫函式,形如:
d3.select().selectAll().text()
這稱為鏈式語法,和 JQuery 的語法很像,常用 JQuery 的朋友一定會感到很親切。

【Lesson2】選擇、插入、刪除元素

1. 選擇元素

前面已經講解了 select 和 selectAll,以及選擇集的概念。本節具體講解這兩個函式的用法。

假設在 body 中有三個段落元素:

<p>Apple</p>
<p>Pear</p>
<p>Banana</p>
複製程式碼

現在,要分別完成以下四種選擇元素的任務。

1.1 選擇第一個 p 元素

使用 select ,引數傳入 p 即可,如此返回的是第一個 p 元素。

var p1 = body.select("p");
p1.style("color","red");
複製程式碼

結果如下,被選擇的元素標記為紅色。

【D3.js 入門系列一】從零開始繪製一個柱形圖

1.2 選擇三個 p 元素

使用 selectAll 選擇 body 中所有的 p 元素。

var p = body.selectAll("p");
p.style("color","red");
複製程式碼

結果如下:

【D3.js 入門系列一】從零開始繪製一個柱形圖

1.3 選擇第二個 p 元素

有不少方法,一種比較簡單的是給第二個元素新增一個 id 號。

<p id="myid">Pear</p>
複製程式碼

然後,使用 select 選擇元素,注意引數中 id 名稱前要加 # 號。

var p2 = body.select("#myid");
p2.style("color","red");
複製程式碼

結果如下:

【D3.js 入門系列一】從零開始繪製一個柱形圖

1.4 選擇後兩個 p 元素

給後兩個元素新增 class,

<p class="myclass">Pear</p>
<p class="myclass">Banana</p>
複製程式碼

由於需要選擇多個元素,要用 selectAll。注意引數,class 名稱前要加一個點。

var p = body.selectAll(".myclass");
p.style("color","red");
複製程式碼

結果如下:

【D3.js 入門系列一】從零開始繪製一個柱形圖

關於 select 和 selectAll 的引數,其實是符合 CSS 選擇器的條件的,即用“井號(#)”表示 id,用“點(.)”表示 class。

此外,對於已經繫結了資料的選擇集,還有一種選擇元素的方法,那就是靈活運用 function(d, i)。我們已經知道引數 i 是代表索引號的,於是便可以用條件判定語句來指定執行的元素。

2. 插入元素

插入元素涉及的函式有兩個:

  • append():在選擇集末尾插入元素
  • insert():在選擇集前面插入元素

假設有三個段落元素,與上文相同。

2.1 append()

body.append("p")
    .text("append p element");
複製程式碼

在 body 的末尾新增一個 p 元素,結果為:

Apple
Pear
Banana
append p element
複製程式碼

2.2 insert()

在 body 中 id 為 myid 的元素前新增一個段落元素。

body.insert("p","#myid")
  .text("insert p element");
複製程式碼

已經指定了 Pear 段落的 id 為 myid,因此結果如下。

Apple
insert p element
Pear
Banana
複製程式碼

3. 刪除元素

刪除一個元素時,對於選擇的元素,使用 remove 即可,例如:

var p = body.select("#myid");
p.remove();
複製程式碼

如此即可刪除指定 id 的段落元素。


【Lesson3】做一個簡單的圖表

柱形圖是一種最簡單的視覺化圖表,主要有矩形、文字標籤、座標軸組成。本節為簡單起見,只繪製矩形的部分,用以講解如何使用 D3 在 SVG 畫布中繪圖。

【D3.js 入門系列一】從零開始繪製一個柱形圖

1. 新增畫布

D3 雖然沒有明文規定一定要在 SVG 中繪圖,但是 D3 提供了眾多的 SVG 圖形的生成器,它們都是隻支援 SVG 的。因此,建議使用 SVG 畫布。
使用 D3 在 body 元素中新增 svg 的程式碼如下:

var width = 300;  //畫布的寬度
var height = 300;   //畫布的高度
 
var svg = d3.select("body")     //選擇文件中的body元素
    .append("svg")          //新增一個svg元素
    .attr("width", width)       //設定寬度
    .attr("height", height);    //設定高度
複製程式碼

有了畫布,接下來就可以在畫布上作圖了。

2. 繪製矩形

本文繪製一個橫向的柱形圖。只繪製矩形,不繪製文字和座標軸。

在 SVG 中,矩形的元素標籤是 rect。例如:

<svg>
    <rect></rect>
    <rect></rect>
</svg>
複製程式碼

上面的 rect 裡沒有矩形的屬性。矩形的屬性,常用的有四個:

  • x:矩形左上角的 x 座標
  • y:矩形左上角的 y 座標
  • width:矩形的寬度
  • height:矩形的高度

要注意,在 SVG 中,x 軸的正方向是水平向右,y 軸的正方向是垂直向下的。

現在給出一組資料,要對此進行視覺化。資料如下:

var dataset = [ 250 , 210 , 170 , 130 , 90 ];  //資料(表示矩形的寬度)
複製程式碼

為簡單起見,我們直接用數值的大小來表示矩形的畫素寬度(後面會說到這不是一種好方法)。然後,新增以下程式碼。

var rectHeight = 25;   //每個矩形所佔的畫素高度(包括空白)
 
svg.selectAll("rect")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("x",20)
    .attr("y",function(d,i){
         return i * rectHeight;
    })
    .attr("width",function(d){
         return d;
    })
    .attr("height",rectHeight-2)
    .attr("fill","steelblue");
複製程式碼

這段程式碼新增了與 dataset 陣列的長度相同數量的矩形,所使用的語句是:

svg.selectAll("rect")   //選擇svg內所有的矩形
    .data(dataset)  //繫結陣列
    .enter()        //指定選擇集的enter部分
    .append("rect") //新增足夠數量的矩形元素
複製程式碼

這段程式碼以後會常常出現在 D3 的程式碼中,請務必牢記。目前不深入討論它的作用機制是怎樣的,只需要讀者牢記,當:

有資料,而沒有足夠圖形元素的時候,使用此方法可以新增足夠的元素。

新增了元素之後,就需要分別給各元素的屬性賦值。在這裡用到了 function(d, i),前面已經講過,d 代表與當前元素繫結的資料,i 代表索引號。給屬性賦值的時候,是需要用到被繫結的資料,以及索引號的。

最後一行的:

.attr("fill","steelblue");
複製程式碼

是給矩形元素設定顏色。一般來說,最好寫成外接 CSS 的形式,方便歸類和修改。這裡為了便於初學者理解,將樣式直接寫到元素裡。

結果圖如本文開頭的圖片所示。

程式碼示例地址:github.com/legend-li/D…


【Lesson4】比例尺、座標軸的使用

比例尺

比例尺是 D3 中很重要的一個概念,上一章裡曾經提到過直接用數值的大小來代表畫素不是一種好方法,本章正是要解決此問題。

1. 為什麼需要比例尺

上一章製作了一個柱形圖,當時有一個陣列:

var dataset = [ 250 , 210 , 170 , 130 , 90 ];
複製程式碼

繪圖時,直接使用 250 給矩形的寬度賦值,即矩形的寬度就是 250 個畫素。

此方式非常具有侷限性,如果數值過大或過小,例如:

var dataset_1 = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
var dataset_2 = [ 2500, 2100, 1700, 1300, 900 ];
複製程式碼

對以上兩個陣列,絕不可能用 2.5 個畫素來代表矩形的寬度,那樣根本看不見;也不可能用 2500 個畫素來代表矩形的寬度,因為畫布沒有那麼長。

於是,我們需要一種計算關係,能夠:將某一區域的值對映到另一區域,其大小關係不變。

這就是比例尺(Scale)。

2. 有哪些比例尺

比例尺,很像數學中的函式。例如,對於一個一元二次函式,有 x 和 y 兩個未知數,當 x 的值確定時,y 的值也就確定了。

在數學中,x 的範圍被稱為定義域,y 的範圍被稱為值域

D3 中的比例尺,也有定義域和值域,分別被稱為 domain 和 range。開發者需要指定 domain 和 range 的範圍,如此即可得到一個計算關係。

D3 提供了多種比例尺,下面介紹最常用的兩種。

2.1. 線性比例尺

線性比例尺,能將一個連續的區間,對映到另一區間。要解決柱形圖寬度的問題,就需要線性比例尺。

假設有以下陣列:

var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];
複製程式碼

現有要求如下:

將 dataset 中最小的值,對映成 0;將最大的值,對映成 300。

程式碼如下:

var min = d3.min(dataset);
var max = d3.max(dataset);
 
var linear = d3.scale.linear()
        .domain([min, max])
        .range([0, 300]);
 
linear(0.9);    //返回 0
linear(2.3);    //返回 175
linear(3.3);    //返回 300
複製程式碼

其中,d3.scale.linear() 返回一個線性比例尺。domain() 和 range() 分別設定比例尺的定義域和值域。在這裡還用到了兩個函式,它們經常與比例尺一起出現:

  • d3.max()
  • d3.min()

這兩個函式能夠求陣列的最大值和最小值,是 D3 提供的。按照以上程式碼,

比例尺的定義域 domain 為:[0.9, 3.3]

比例尺的值域 range 為:[0, 300]

因此,當輸入 0.9 時,返回 0;當輸入 3.3 時,返回 300。當輸入 2.3 時呢?返回 175,這是按照線性函式的規則計算的。

有一點請大家記住:

d3.scale.linear() 的返回值,是可以當做函式來使用的。因此,才有這樣的用法:linear(0.9)。

2.2. 序數比例尺

有時候,定義域和值域不一定是連續的。例如,有兩個陣列:

var index = [0, 1, 2, 3, 4];
var color = ["red", "blue", "green", "yellow", "black"];
複製程式碼

我們希望 0 對應顏色 red,1 對應 blue,依次類推。

但是,這些值都是離散的,線性比例尺不適合,需要用到序數比例尺。

var ordinal = d3.scale.ordinal()
        .domain(index)
        .range(color);
 
ordinal(0); //返回 red
ordinal(2); //返回 green
ordinal(4); //返回 black
複製程式碼

用法與線性比例尺是類似的。

3. 給柱形圖新增比例尺

在上一節的基礎上,修改一下陣列,再定義一個線性比例尺。

var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
 
var linear = d3.scale.linear()
        .domain([0, d3.max(dataset)])
        .range([0, 250]);
複製程式碼

其後,按照上一章的方法新增矩形,在給矩形設定寬度的時候,應用比例尺。

var rectHeight = 25;   //每個矩形所佔的畫素高度(包括空白)
 
svg.selectAll("rect")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("x",20)
    .attr("y",function(d,i){
         return i * rectHeight;
    })
    .attr("width",function(d){
         return linear(d);   //在這裡用比例尺
    })
    .attr("height",rectHeight-2)
    .attr("fill","steelblue");
複製程式碼

如此一來,所有的數值,都按照同一個線性比例尺的關係來計算寬度,因此數值之間的大小關係不變。

座標軸

座標軸,是視覺化圖表中經常出現的一種圖形,由一些列線段和刻度組成。座標軸在 SVG 中是沒有現成的圖形元素的,需要用其他的元素組合構成。D3 提供了座標軸的元件,如此在 SVG 畫布中繪製座標軸變得像新增一個普通元素一樣簡單。

【D3.js 入門系列一】從零開始繪製一個柱形圖

1. 座標軸由什麼構成

在 SVG 畫布的預定義元素裡,有六種基本圖形:

  • 矩形
  • 圓形
  • 橢圓
  • 線段
  • 折線
  • 多邊形

另外,還有一種比較特殊,也是功能最強的元素:

  • 路徑

畫布中的所有圖形,都是由以上七種元素組成。

顯然,這裡面沒有座標軸 這種元素。如果有的話,我們可以採用類似以下的方式定義:

<axis x1="" x2="" ...></axis>
複製程式碼

很可惜,沒有這種元素。但是,這種設計是合理的:不可能為每一種圖形都配備一個單獨的元素,那樣 SVG 就會過於龐大。

因此,我們需要用其他元素來組合成座標軸,最終使其變為類似以下的形式:

<g>
<!-- 第一個刻度 -->
<g>
<line></line>   <!-- 第一個刻度的直線 -->
<text></text>   <!-- 第一個刻度的文字 -->
</g>
<!-- 第二個刻度 -->
<g>
<line></line>   <!-- 第二個刻度的直線 -->
<text></text>   <!-- 第二個刻度的文字 -->
</g> 
...
<!-- 座標軸的軸線 -->
<path></path>
</g>
複製程式碼

分組元素 ,是 SVG 畫布中的元素,意思是 group。此元素是將其他元素進行組合的容器,在這裡是用於將座標軸的其他元素分組存放。

如果需要手動新增這些元素就太麻煩了,為此,D3 提供了一個元件:d3.svg.axis()。它為我們完成了以上工作。

2. 定義座標軸

上面提到了比例尺的概念,要生成座標軸,需要用到比例尺,它們二者經常是一起使用的。下面,在上一章的資料和比例尺的基礎上,新增一個座標軸的元件。

//資料
var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
//定義比例尺
var linear = d3.scale.linear()
      .domain([0, d3.max(dataset)])
      .range([0, 250]);
 
var axis = d3.svg.axis()
     .scale(linear)      //指定比例尺
     .orient("bottom")   //指定刻度的方向
     .ticks(7);          //指定刻度的數量
複製程式碼

第 1 – 2 行:定義陣列。

第 4 – 7 行:定義比例尺,其中使用了陣列 dataset。

第 9 – 12 行:定義座標軸,其中使用了線性比例尺 linear。其中:

  • d3.svg.axis():D3 中座標軸的元件,能夠在 SVG 中生成組成座標軸的元素。
  • scale():指定比例尺。
  • orient():指定刻度的朝向,bottom 表示在座標軸的下方顯示。
  • ticks():指定刻度的數量。

3. 在 SVG 中新增座標軸

定義了座標軸之後,只需要在 SVG 中新增一個分組元素 ,再將座標軸的其他元素新增到這個 裡即可。程式碼如下:

svg.append("g")
   .call(axis);
複製程式碼

上面有一個 call() 函式,其引數是前面定義的座標軸 axis。

在 D3 中,call() 的引數是一個函式。呼叫之後,將當前的選擇集作為引數傳遞給此函式。也就是說,以下兩段程式碼是相等的。

function foo(selection) {
  selection
      .attr("name1", "value1")
      .attr("name2", "value2");
}
foo(d3.selectAll("div"))
複製程式碼

d3.selectAll("div").call(foo);
複製程式碼

因此,

svg.append("g").call(axis);
複製程式碼

axis(svg.append(g));
複製程式碼

是相等的。

4. 設定座標軸的樣式和位置

預設的座標軸樣式不太美觀,下面提供一個常見的樣式:

	
<style>
.axis path,
.axis line{
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
}
 
.axis text {
    font-family: sans-serif;
    font-size: 11px;
}
</style>
複製程式碼

分別定義了類 axis 下的 path、line、text 元素的樣式。接下來,只需要將座標軸的類設定為 axis 即可。

座標軸的位置,可以通過 transform 屬性來設定。

通常在新增元素的時候就一併設定,寫成如下形式:

svg.append("g")
  .attr("class","axis")
  .attr("transform","translate(20,130)")
  .call(axis);
複製程式碼

程式碼示例地址:github.com/legend-li/D…


【Lesson5】完整的柱形圖

一個完整的柱形圖包含三部分:矩形、文字、座標軸。本章將對前幾章的內容進行綜合的運用,製作一個實用的柱形圖,內容包括:選擇集、資料繫結、比例尺、座標軸等內容。

【D3.js 入門系列一】從零開始繪製一個柱形圖

1. 新增 SVG 畫布

//畫布大小
var width = 400;
var height = 400;
 
//在 body 裡新增一個 SVG 畫布   
var svg = d3.select("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height);
 
//畫布周邊的空白
 var padding = {left:30, right:30, top:20, bottom:20};
複製程式碼

上面定義了一個 padding,是為了給 SVG 的周邊留一個空白,最好不要將圖形繪製到邊界上。

2. 定義資料和比例尺

//定義一個陣列
var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
        
//x軸的比例尺
var xScale = d3.scale.ordinal()
    .domain(d3.range(dataset.length))
    .rangeRoundBands([0, width - padding.left - padding.right]);
 
//y軸的比例尺
var yScale = d3.scale.linear()
    .domain([0,d3.max(dataset)])
    .range([height - padding.top - padding.bottom, 0]);
複製程式碼

x 軸使用序數比例尺,y 軸使用線性比例尺。要注意兩個比例尺值域的範圍。

d3.range()用法講解:

 d3.range([start,]stop[,step]); //返回等差數列
 var a = d3.range( 10);
 console.log(a)  //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 var b = d3.range( 2,10 );
 console.log(b);//[2, 3, 4, 5, 6, 7, 8, 9]
 var c = d3.range( 2,10 ,2);
 console.log(c);//[2, 4, 6, 8]
複製程式碼

ordinal.rangeRoundBands()用法講解:
github.com/d3/d3/wiki/…

3. 定義座標軸

//定義x軸
var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom");
        
//定義y軸
var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient("left");
複製程式碼

x 軸刻度的方向向下,y 軸的向左。

4. 新增矩形和文字元素

//矩形之間的空白
var rectPadding = 4;
 
//新增矩形元素
var rects = svg.selectAll(".MyRect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("class","MyRect")
        .attr("transform","translate(" + padding.left + "," + padding.top + ")")
        .attr("x", function(d,i){
            return xScale(i) + rectPadding/2;
        } )
        .attr("y",function(d){
            return yScale(d);
        })
        .attr("width", xScale.rangeBand() - rectPadding )
        .attr("height", function(d){
            return height - padding.top - padding.bottom - yScale(d);
        });
 
//新增文字元素
var texts = svg.selectAll(".MyText")
        .data(dataset)
        .enter()
        .append("text")
        .attr("class","MyText")
        .attr("transform","translate(" + padding.left + "," + padding.top + ")")
        .attr("x", function(d,i){
            return xScale(i) + rectPadding/2;
        } )
        .attr("y",function(d){
            return yScale(d);
        })
        .attr("dx",function(){
            return (xScale.rangeBand() - rectPadding)/2;
        })
        .attr("dy",function(d){
            return 20;
        })
        .text(function(d){
            return d;
        });
複製程式碼

矩形元素和文字元素的 x 和 y 座標要特別注意,要結合比例尺給予適當的值。

5. 新增座標軸的元素

//新增x軸
svg.append("g")
  .attr("class","axis")
  .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
  .call(xAxis); 
        
//新增y軸
svg.append("g")
  .attr("class","axis")
  .attr("transform","translate(" + padding.left + "," + padding.top + ")")
  .call(yAxis);
複製程式碼

座標軸的位置要結合空白 padding 的值來設定。

程式碼示例地址:github.com/legend-li/D…

下一章:《【D3.js 入門系列二】理解 Update && Enter && Exit、製作互動式動態圖表

參考資料:www.ourd3js.com/
D3.js(v3)中文api:github.com/d3/d3/wiki/…

相關文章