iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 17
0

前言

恭喜你進展到第 17 天,來到旅程的中央。相信你已經在 js 荒漠中,學會不少技能,並且找到一些綠洲。現在開始我們要往後半段前進,首先會花個幾天在"使用 js 繪製圖表"這座小鎮停留,快跟我一起出發吧!

SVG 圖檔

話說電腦繪圖有兩種模式:向量和點陣圖。用 adobe illustrator 畫出來的是向量圖, photoshop 畫出來的是點陣圖。向量圖的特色是,即使畫完以後突然回心轉意想要放大縮小,圖也不會模糊,非常適合猶豫不絕的天秤座。

svg 也是畫向量圖的一種格式,可用在 2D 圖中。( 3D 可使用 canvas ) svg 本身可以直接用 html 標籤的方式,在網頁上放入一個畫布,再在標籤底下畫圖。你可以把以下的程式碼貼到 html 中,看看會跑出什麼?

<svg width="75" height="75">
  <circle cx="35" cy="35" r="30" stroke="black" stroke-width="5" fill="red">
</svg>

現在讓我們仔細解釋一下上面。

我先設定我要一張 75x75 大小的 svg 畫布,接著在畫布上放一個圓,圓心在 x 軸 35 、 y 軸 35 的位置,半徑長30。圓的邊要是黑色的,圓的肉是紅色的,邊寬 5 。當然,如果你的畫布太小、圓太大,或圓心的位置比較偏,那可能會出現 1/4 圓等等其他的圖案。

相信應該不難理解,那就可以繼續推進下一步: D3.js 了。

D3.js

D3.js 可以讓我們在 js 中動態放入 svg 檔(記得登場無數次的 innerHTML 嗎?),也可以選取 html 標籤並更改它們的樣式。要使用這麼方便的工具,要記得在你的 html 裡載入 <script src="https://d3js.org/d3.v5.min.js"></script> ,並放在 </body> 上方,比較容易讀取到。

使用 codepen 練習的朋友們,請點右上方 settings > JS 並貼上上面的網址,按下 Save&Close 唷!

接下來我會介紹幾個用法,但因為 D3.js 能玩的實在太多,建議大家可以抽空閱讀 D3.js 的 API ,裡面有各式各樣的語法和使用方法。

selectAll : 一次選取所有標籤

要一次選取所有 html 標籤,去更改 css 樣式嗎?你可以用 d3.js 做到!寫法如下:
d3.selectAll("要選的標籤").style("項目","改成什麼");

範例:

d3.selectAll("p").style("color","blue"); //把所有p段落選起來,調整css style中的顏色,變成藍色

select : 選第一個標籤

如果只是要改第一個標籤,寫法為:
d3.select("要選的標籤").style("項目","改成什麼");

範例:

d3.select("p").style("color","blue") //只選第一個p段落,調整css style中的顏色,把它變成藍色

其中選取的標籤也可以是自訂的 class 名稱,但要記得加上點。例如:.select(".header")

selectAll 和 select 當然也能夠合併使用。如果覺得太過於抽象,可以把這個想成用繪圖軟體時會去選圖層下面的物件,而圖層下有時還會再有圖層,選取時就會需要先單獨點某個圖層,再去全選下面的物件。以實際範例來說,我可以先選擇 body 標籤裡的 svg ,然後全選裡頭所有 rect 。

d3.select("body").select("svg").selectAll("rect") 

接著終於要進入重頭戲了!前面介紹完如何幫標籤改屬性之後,現在要說怎麼為標籤加入 svg 畫布。

.append 搭配 .attr 可新增 svg 畫布並加上屬性

語法很簡單:
d3.select(".要加在哪個標籤裡")
.append('要新增的東西')
.attr('要加的屬性','詳細資料');

在 .append 裡的東西可以是 svg 畫布、圓,或是其他圖形。請看下面的範例:

// 繪製SVG
d3.select('.chart-d3')
    .append('svg')
    .attr('width',"75")
    .attr('height',"75");
    
// 畫圓
d3.select('.chart-d3 svg')
  .append('circle')
  .attr('cx','35')
  .attr('cy','35')
  .attr('r','30')
  .attr('stroke','black')
  .attr('fill','red')
  .attr('stroke-width','5');

.transition 可做漸變動畫

寫法為:
d3.select('')
.transition().duration(動畫時間為幾毫秒).delay(延遲幾毫秒產生).attr('要加的屬性','詳細資料')

在上面的圖片已經創建後,在下方寫下下面的程式碼,則動畫會延遲兩秒後,讓肉在五秒內慢慢變成粉紅色。

d3.select('.chart-d3 svg circle').transition().attr('fill','black');

.data 可導入資料

好像越來越有模有樣哩!在今天的最後,我們要來試畫看看長條圖。

假設有四個候選人,分別得到 30 、 50 、 100 、 120 票,我們可能會先把這些資料儲存在陣列中,等到需要的時候才把它提領出來,放到畫面上。像這種需要導入資料的狀況,就可以使用 .data 。以條列式 ul li 為例,首先在 html 放要安插資料的標籤。

  • html:
<ul class = "list"></ul>

.data 使用起來跟上述大同小異,語法為 .data(要導入的陣列).enter() 。請看下列程式碼:

  • js:
const vote = ['30','50','100','120']
d3.select('.list') //選html裡的list
    .selectAll('li') //選所有底下的li標籤
    .data(vote) //導入vote資料
    .enter()
    .append('li') //動態加入li標籤
    .text(function(d){ //d是上面30、50等資料
        return d; //把30、50等資料依序帶進相對位置
    })

這段程式碼的重點是,即使 html 的 ul 中沒有 li ,當寫 .selectAll('li') 時,系統還是會先幫你新增相對的欄位出來,放入資料,之後在下面用 .append 動態加入 li 標籤即可。欸...怎麼有種先上車後補票的港覺

進入重點,要畫長條圖可以這樣寫:

  • html:
<div class = "chart"></div>
  • css:
.chart div {
  display: inline-block;
  background: blue;
  width: 50px;
  margin-right: 5px;
  vertical-align: bottom;
  color: #fff;
  text-align: center;
}
  • js:
var vote = [
    {
        "name":"tom",
        "num":"50"
    },
    {
        "name":"mary",
        "num":"80"
    },
];
d3.select('.chart') //選html裡的chart
    .selectAll('div') //選所有底下的div標籤
    .data(vote) //導入vote資料
    .enter()
    .append('div') //動態加入div標籤
    .html(function(d){ //d是上面name、num裡的資料
        return d.name+'<br>'+d.num; //長條圖上會各自出現名字及票數
    })
    .style("height",function(d){
        return d.num+'px'; //長條圖高度用d的num的數據加上px畫出來
    })

不知道今天的內容對你而言吸收的是否流暢?明天我們會繼續進行 C3.js ,如果還是似懂非懂也歡迎你觀看下面的學習與參考資料,找到適合自己的教學文章或影片喔!

學習與參考資料

JS 學徒特訓班教學影片
六角學院 D3.js、C3.js 資料視覺化教學:https://www.youtube.com/watch?v=0PQ8VOsyjzw
D3.js API: https://github.com/d3/d3/blob/master/API.md
SVG 基本圖形 - 圓形 circle: https://abgne.tw/svg/svg-getting-started/svg-shape-circle.html
SVG D3.js - 淺談 D3.js 的資料處理: https://www.oxxostudio.tw/articles/201411/svg-d3-01-data.html

特別感謝回答我疑惑的:
Tim Hsu
SeanLiu
William Kang


上一篇
16 來寫 BMI 計算機 (下)
下一篇
18 C3.js 繪製圖表
系列文
花三十天找到 JavaScript 沙漠中的綠洲35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言