--- slideOptions: mouseWheel: true width: 100% height: 90% margin: 0.1 minScale: 1.0 maxScale: 2.0 loop: true --- # D3.js基礎圖形繪製 黃安聖(andy) andy@kyosei.ai ###### tags: `D3.js` ---- 請先開啟程式碼同步網站 https://instacode-live.herokuapp.com/channel/andy ---- ## D3.js Data-Driven Documents https://d3js.org/ ---- ## 引用D3.js 可從CDN.js網站中搜尋d3 https://cdnjs.com/ ---- 將D3.js Library的連結放入HTML的script標籤已啟用 ```htmlmixed= <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.min.js"></script> ``` ---- ## 繪製一個簡單的SVG圖形 SVG(Scalable Vector Graphics) ---- ### 定義SVG邊界 ```javascript= // 將圖形儲存以利後續使用 const svg = d3 // 選擇一個畫面上元素作為容器 .select('#chart') // 設定要新增的標籤名稱 .append('svg') // 設定svg的width屬性 .attr('width', 600) // 設定svg的height屬性 .attr('height', 400) ``` ---- ### 在svg上繪製一個矩形 ```javascript= svg // 在指定元素(svg)上放置一個矩形 .append('rect') // 設定寬度 .attr('width', 50) // 設定高度 .attr('height', 100) // 設定所在座標 .attr('x', 0) .attr('y', 0) // 設定顏色 .attr('fill', 'royalblue'); ``` ---- ### 在svg上繪製一個圓形 ```javascript= svg // 在指定元素(svg)上放置一個圓形 .append('circle') // 設定半徑 .attr('r', 50) // 設定圓心位置 .attr('cx', 200) .attr('cy', 200) .attr('fill', 'tomato'); ``` ---- 除此之外你也可以透過d3直接控制HTML標籤 ```javascript= d3 .select('#box1') // 改變元素內部的html內容 .html('我是box1') ``` ---- 甚至是標籤的CSS屬性 ```javascript= d3 .select('#box1') .html('我是box1') .style('background-color', 'tomato') .style('width', '200px') .style('height', '100px') ``` ---- ### 陣列資料繪製 ---- 陣列資料可能產生的問題: ==資料數量與元素(DOM)不相等== ---- 當畫面上有多個元素 ```htmlmixed= <div id="barContainer"> <div class="bar"></div> <div class="bar"></div> <div class="bar"></div> </div> ``` ---- 選取元素的容器 ```javascript= const barContainer = d3.select('#barContainer') ``` ---- 準備資料 ```javascript= const data = [10, 20, 30] ``` ---- 繪製圖型 ```javascript= barContainer .selectAll('.bar') .data(data) .style('width', function (d) { return `${d}%`; }) ``` ---- 圖形可被成功繪製 ![](https://i.imgur.com/HIxiDDW.png) ---- 但若是資料的數量有變動將會發生什麼事? ```javascript= const data = [10, 20, 30, 40, 50] ``` ---- 圖形將會缺少追加的資料,原因在於在HTML內==缺少了對應的元素== ![](https://i.imgur.com/HIxiDDW.png) ---- #### 解決方式 選擇容器 ```javascript= const barContainer = d3.select('#barContainer') ``` ---- 準備資料 ```javascript= const data = [10, 20, 30, 40, 50] ``` ---- 選擇容器內的目標.bar並配對資料 ```javascript= const bars = barContainer // 選擇容器內的.bar .selectAll('.bar') .data(data) ``` ---- 繪製每個長條圖的資料 ```javascript= bars // 當資料與DOM初次配對完成後 .enter() // 放入div .append('div') // 賦予class="bar" // 讓上述選擇條件可選擇 .attr('class', 'bar') // 設定CSS寬度 .style('width', function (d) { return `${d}%`; }) ``` ---- ### 課堂練習 將陣列資料轉換為圖表 ```javascript= const data = [12, 2, 5, 6, 7, 18]; ``` ---- 選擇SVG容器並填入SVG ```javascript= // 將圖形儲存以利後續使用 const svg = d3 // 選擇一個畫面上元素作為容器 .select('#chart') // 設定要新增的標籤名稱 .append('svg') // 設定svg的width屬性 .attr('width', 600) // 設定svg的height屬性 .attr('height', 400) ``` ---- 帶入資料 ```javascript= const circles = svg // 選擇circles裡面的circle .selectAll("circle") // 在每個circle內帶入data裡的每筆資料 .data(data); ``` ---- 透過資料數據顯示圖形 ```javascript= circles // 初次將資料帶入元素內 .enter() .append('circle') .attr('r', function (d, i) { // 值可帶入一個function,並且自動帶有兩筆輸入 // d: 資料 , i:索引(排序) return d; }) .attr('cx', 10) .attr('cy', 50) .attr('fill', 'tomato'); ``` ---- ### 課堂練習 1. 將圖面中的圓形由左至右排列 2. 設定填色條件,資料大於10填入#f85a40,反之則填入#ffc845 ---- ### 設定mouseenter事件 ```javascript= .on('mouseenter', function(d, i) { // 游標進入事件 }); ``` ---- ### 取得事件參數 透過==d3.event==取得事件參數 ```javascript= .on('mouseenter', function(d, i) { console.log(d3.event); }); ``` ---- 也可整合其他滑鼠事件 |事件名稱|敘述| |-|-| |mouseenter|游標進入元素| |mouseleave|游標離開元素| |mousemove|游標在元素移動| ---- ### 課堂練習 1. 設計一個標籤用以顯示該圖型背後的數值 2. 於滑鼠游標碰觸圖型時顯示標籤 ---- ### 載入JSON檔案 ```javascript= d3.json('檔案名稱.json') .then(function(data){ // 載入成功 }) .catch(function(err){ // 載入失敗 }) ``` ---- ### 以政府公開資料為例 細懸浮微粒資料(PM2.5) https://data.gov.tw/dataset/34827 ---- ### 課堂練習 1. 繪製新北市各區PM25指數 2. 滑鼠游標碰觸後可顯示資料標籤