D3.js實(shí)現(xiàn)餅狀圖的方法詳解
前言
小編在之前已經(jīng)跟大家分享過(guò)關(guān)于怎樣用柱狀圖和折線圖這兩種基本圖表。這兩種圖表都是有坐標(biāo)軸的,現(xiàn)在來(lái)說(shuō)一種沒(méi)有坐標(biāo)軸的圖表——餅圖。
餅狀圖實(shí)現(xiàn)
還是和之前一樣,我們先把簡(jiǎn)單的畫(huà)圖框架搭起來(lái),添加SVG畫(huà)布。但是這里需要注意的是,為了方便后面畫(huà)餅圖上的弧形,我們把組合這些元素的g元素移動(dòng)到畫(huà)布的中心:
<!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; // 創(chuàng)建一個(gè)分組用來(lái)組合要畫(huà)的圖表元素 var main = d3.select('.container svg').append('g') .classed('main', true) // 注意這里和前面幾種圖表的差別 .attr('transform', "translate(" + width/2 + ',' + height/2 + ')'); }; </script> </body> </html>
模擬數(shù)據(jù)并轉(zhuǎn)化
為了畫(huà)餅圖,我們模擬了一些這樣的數(shù)據(jù)。
// 模擬數(shù)據(jù) var dataset = [ {name: '購(gòu)物', value: 983}, {name: '日常飲食', value: 300}, {name: '醫(yī)藥', value: 1400}, {name: '交通', value: 402}, {name: '雜費(fèi)', value: 134} ];
在柱狀圖等有坐標(biāo)軸的圖表中,我們通過(guò)創(chuàng)建合適的比例尺來(lái)將模擬好的數(shù)據(jù)轉(zhuǎn)化成適合畫(huà)圖的數(shù)據(jù),那在餅圖里,又用什么來(lái)轉(zhuǎn)化呢?看這里~
// 轉(zhuǎn)換原始數(shù)據(jù)為能用于繪圖的數(shù)據(jù) var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.value; }); // pie是一個(gè)函數(shù) var pieData = pie(dataset);
layout叫做布局,在D3.js中它提供了一些轉(zhuǎn)化成特定圖表數(shù)據(jù)的函數(shù),如其中就包括餅圖。它提供一個(gè)基礎(chǔ)的轉(zhuǎn)化函數(shù),在此基礎(chǔ)上我們根據(jù)自己的需要再對(duì)該函數(shù)進(jìn)行進(jìn)一步的設(shè)置,就得到了如上述代碼中pie變量保存的函數(shù)一樣的轉(zhuǎn)化工具,通過(guò)把原始的數(shù)據(jù)dataset傳入pie中就能得到繪圖數(shù)據(jù)pieData。
具體的變化我們可以看下圖。
左邊是轉(zhuǎn)化前的原始的數(shù)據(jù)結(jié)構(gòu),右邊是轉(zhuǎn)化后的適合繪圖的數(shù)據(jù)結(jié)構(gòu)??梢钥吹?,在保留原本的數(shù)據(jù)的基礎(chǔ)上,轉(zhuǎn)化后的數(shù)據(jù)新增了該項(xiàng)在整個(gè)餅圖中的起始角度(startAngle和endAngle),以及弧形之間的間隙角度(padAngle)。
計(jì)算弧形路徑
在餅圖中,我們用SVG中的path元素來(lái)表示每一塊弧形,而從pieData到path元素的d屬性還是有一定的距離,所以我還需要再通過(guò)一步操作來(lái)用pieData計(jì)算出d屬性可用的值。
// 創(chuàng)建計(jì)算弧形路徑的函數(shù) var radius = 100; var arc = d3.svg.arc() .innerRadius(0) .outerRadius(radius);
添加弧形
上面的代碼用svg.arc()
創(chuàng)建了一個(gè)計(jì)算弧形路徑的函數(shù),通過(guò)這個(gè)函數(shù)就可以計(jì)算出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); });
好了,餅圖就這樣畫(huà)好了。
下面給大家分享個(gè)實(shí)例代碼,實(shí)現(xiàn)餅圖中加上下圖這樣的文字標(biāo)簽。
效果圖
實(shí)例代碼
<!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; // 創(chuàng)建一個(gè)分組用來(lái)組合要畫(huà)的圖表元素 var main = d3.select('.container svg').append('g') .classed('main', true) .attr('transform', "translate(" + width/2 + ',' + height/2 + ')'); // 模擬數(shù)據(jù) var dataset = [ {name: '購(gòu)物', value: 983}, {name: '日常飲食', value: 300}, {name: '醫(yī)藥', value: 1400}, {name: '交通', value: 402}, {name: '雜費(fèi)', value: 134} ]; // 轉(zhuǎn)換原始數(shù)據(jù)為能用于繪圖的數(shù)據(jù) var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.value; }); // pie是一個(gè)函數(shù) var pieData = pie(dataset); // 創(chuàng)建計(jì)算弧形路徑的函數(shù) 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); }); // 添加文字標(biāo)簽 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) { // 找出外弧形的中心點(diǎn) var pos = outerArc.centroid(d); // 改變文字標(biāo)識(shí)的x坐標(biāo) 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>
總結(jié)
以上就是利用D3.js實(shí)現(xiàn)餅圖的全部?jī)?nèi)容,希望這篇文章對(duì)大家的學(xué)習(xí)和工作能有所幫助。如果有疑問(wèn)大家可以留言交流,小編還會(huì)陸續(xù)更新關(guān)于D3.js的文章,請(qǐng)大家繼續(xù)關(guān)注腳本之家。
相關(guān)文章
JavaScript鏈?zhǔn)秸{(diào)用原理與實(shí)現(xiàn)方法詳解
這篇文章主要介紹了JavaScript鏈?zhǔn)秸{(diào)用,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript鏈?zhǔn)秸{(diào)用基本原理、實(shí)現(xiàn)方法與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2020-05-05JavaScript中判斷函數(shù)是new還是()調(diào)用的區(qū)別說(shuō)明
具名函數(shù)的各種調(diào)用方式 在之前篇幅中已經(jīng)介紹過(guò)了。這篇看看如何判斷一個(gè)函數(shù)是被new調(diào)用的,還是被其它方式調(diào)用的。2011-04-04Javascript基于對(duì)象三大特性(封裝性、繼承性、多態(tài)性)
這篇文章主要介紹了Javascript基于對(duì)象三大特性,包括封裝性、繼承性、多態(tài)性,感興趣的小伙伴們可以參考一下2016-01-01JavaScript去除空格的三種方法(正則/傳參函數(shù)/trim)
個(gè)人認(rèn)為去除空格最好的方法.采用的是正則表達(dá)式,這是最核心的原理,同時(shí)呢,還是有其他方法可以辦到的,接下來(lái)將介紹一下三種方法(trim)空格,感興趣的朋友可以了解下,或許對(duì)你有幫助呢2013-02-02讓網(wǎng)站自動(dòng)生成章節(jié)目錄索引的多個(gè)js代碼
這篇文章主要介紹了讓博客園博客自動(dòng)生成章節(jié)目錄索引的多個(gè)js代碼,需要的朋友可以參考下2018-01-01JavaScript中在光標(biāo)處插入添加文本標(biāo)簽節(jié)點(diǎn)的詳細(xì)方法
本文主要介紹了JavaScript中在光標(biāo)處插入添加文本標(biāo)簽節(jié)點(diǎn)的詳細(xì)方法。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03如何在JavaScript中等分?jǐn)?shù)組的實(shí)現(xiàn)
這篇文章主要介紹了如何在JavaScript中等分?jǐn)?shù)組的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12