前言
小編在之前已經跟大家分享過關於怎樣用柱狀圖和折線圖這兩種基本圖表。這兩種圖表都是有坐標軸的,現在來說一種沒有坐標軸的圖表——餅圖。
餅狀圖實現
還是和之前一樣,我們先把簡單的畫圖框架搭起來,添加SVG畫布。但是這裡需要注意的是,為了方便後面畫餅圖上的弧形,我們把組合這些元素的g元素移動到畫布的中心:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>餅圖</title> <style> .container { margin: 30px auto; width: 600px; height: 300px; border: 1px solid #000; } </style> </head> <body> <div class="container"> <svg width="100%" height="100%"></svg> </div> <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> window.onload = function() { var width = 600, height = 300; // 創建一個分組用來組合要畫的圖表元素 var main = d3.select('.container svg').append('g') .classed('main', true) // 注意這裡和前面幾種圖表的差別 .attr('transform', "translate(" + width/2 + ',' + height/2 + ')'); }; </script> </body> </html>
模擬數據並轉化
為了畫餅圖,我們模擬了一些這樣的數據。
// 模擬數據 var dataset = [ {name: '購物', value: 983}, {name: '日常飲食', value: 300}, {name: '醫藥', value: 1400}, {name: '交通', value: 402}, {name: '雜費', value: 134} ];
在柱狀圖等有坐標軸的圖表中,我們通過創建合適的比例尺來將模擬好的數據轉化成適合畫圖的數據,那在餅圖裡,又用什麼來轉化呢?看這裡~
// 轉換原始數據為能用於繪圖的數據 var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.value; }); // pie是一個函數 var pieData = pie(dataset);
layout叫做布局,在D3.js中它提供了一些轉化成特定圖表數據的函數,如其中就包括餅圖。它提供一個基礎的轉化函數,在此基礎上我們根據自己的需要再對該函數進行進一步的設置,就得到了如上述代碼中pie變量保存的函數一樣的轉化工具,通過把原始的數據dataset傳入pie中就能得到繪圖數據pieData。
具體的變化我們可以看下圖。
左邊是轉化前的原始的數據結構,右邊是轉化後的適合繪圖的數據結構。可以看到,在保留原本的數據的基礎上,轉化後的數據新增了該項在整個餅圖中的起始角度(startAngle和endAngle),以及弧形之間的間隙角度(padAngle)。
計算弧形路徑
在餅圖中,我們用SVG中的path元素來表示每一塊弧形,而從pieData到path元素的d屬性還是有一定的距離,所以我還需要再通過一步操作來用pieData計算出d屬性可用的值。
// 創建計算弧形路徑的函數 var radius = 100; var arc = d3.svg.arc() .innerRadius(0) .outerRadius(radius);
添加弧形
上面的代碼用svg.arc()
創建了一個計算弧形路徑的函數,通過這個函數就可以計算出path的d屬性的值,就像下面這樣。
// 添加弧形 main.selectAll('g') .data(pieData) .enter() .append('path') .attr('fill', function(d, i) { return getColor(i); }) .attr('d', function(d){ return arc(d); });
好了,餅圖就這樣畫好了。
下面給大家分享個實例代碼,實現餅圖中加上下圖這樣的文字標簽。
效果圖
實例代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>餅圖</title> <style> .container { margin: 30px auto; width: 600px; height: 300px; border: 1px solid #000; } polyline { fill: none; stroke: #000000; stroke-width: 2px; stroke-dasharray: 5px; } </style> </head> <body> <div class="container"> <svg width="100%" height="100%"></svg> </div> <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> window.onload = function() { var width = 600, height = 300; // 創建一個分組用來組合要畫的圖表元素 var main = d3.select('.container svg').append('g') .classed('main', true) .attr('transform', "translate(" + width/2 + ',' + height/2 + ')'); // 模擬數據 var dataset = [ {name: '購物', value: 983}, {name: '日常飲食', value: 300}, {name: '醫藥', value: 1400}, {name: '交通', value: 402}, {name: '雜費', value: 134} ]; // 轉換原始數據為能用於繪圖的數據 var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.value; }); // pie是一個函數 var pieData = pie(dataset); // 創建計算弧形路徑的函數 var radius = 100; var arc = d3.svg.arc() .innerRadius(0) .outerRadius(radius); var outerArc = d3.svg.arc() .innerRadius(1.2 * radius) .outerRadius(1.2 * radius); var oArc = d3.svg.arc() .innerRadius(1.1 * radius) .outerRadius(1.1 * radius); var slices = main.append('g').attr('class', 'slices'); var lines = main.append('g').attr('class', 'lines'); var labels = main.append('g').attr('class', 'labels'); // 添加弧形元素(g中的path) var arcs = slices.selectAll('g') .data(pieData) .enter() .append('path') .attr('fill', function(d, i) { return getColor(i); }) .attr('d', function(d){ return arc(d); }); // 添加文字標簽 var texts = labels.selectAll('text') .data(pieData) .enter() .append('text') .attr('dy', '0.35em') .attr('fill', function(d, i) { return getColor(i); }) .text(function(d, i) { return d.data.name; }) .style('text-anchor', function(d, i) { return midAngel(d)<Math.PI ? 'start' : 'end'; }) .attr('transform', function(d, i) { // 找出外弧形的中心點 var pos = outerArc.centroid(d); // 改變文字標識的x坐標 pos[0] = radius * (midAngel(d)<Math.PI ? 1.5 : -1.5); return 'translate(' + pos + ')'; }) .style('opacity', 1); var polylines = lines.selectAll('polyline') .data(pieData) .enter() .append('polyline') .attr('points', function(d) { return [arc.centroid(d), arc.centroid(d), arc.centroid(d)]; }) .attr('points', function(d) { var pos = outerArc.centroid(d); pos[0] = radius * (midAngel(d)<Math.PI ? 1.5 : -1.5); return [oArc.centroid(d), outerArc.centroid(d), pos]; }) .style('opacity', 0.5); }; function midAngel(d) { return d.startAngle + (d.endAngle - d.startAngle)/2; } function getColor(idx) { var palette = [ '#2ec7c9', '#b6a2de', '#5ab1ef', '#ffb980', '#d87a80', '#8d98b3', '#e5cf0d', '#97b552', '#95706d', '#dc69aa', '#07a2a4', '#9a7fd1', '#588dd5', '#f5994e', '#c05050', '#59678c', '#c9ab00', '#7eb00a', '#6f5553', '#c14089' ] return palette[idx % palette.length]; } </script> </body> </html>
總結
以上就是利用D3.js實現餅圖的全部內容,希望這篇文章對大家的學習和工作能有所幫助。如果有疑問大家可以留言交流,小編還會陸續更新關於D3.js的文章,請大家繼續關注。