本篇大纲:选择最合适的图表、圆饼图、本次范例的画面与互动效果、pie( ) 与 arc( )、绘制圆饼图
终於要正式进到一天一张图的篇章了!在开始绘制图表之前,很重要的一点是:如何为资料选择最合适的图表呈现。
图表分成很多种,有圆饼图、长条图、折线图、散点图等等,为什麽不乾脆用一种图表呈现资料就好吗?这是因为每一种图表适合呈现的资料不一样。当我们拿到一组资料後,就要依照我们的目的,找到最适合的图表来将这组资料呈现给别人看。
下面这张图将各种图表适合用来表达的事情整理出来
( 图片来源 )
我这边用文字简单整理常用的几种图表,以及它们适合呈现的资料
适合用在 | 比较资料 | 整体占比 | 了解分布 | 分析趋势 |
---|---|---|---|---|
图表 | 长条图、折线图 | 圆饼图、长条堆积图、面积图 | 散点图、气泡图 | 折线图 |
想更了解该怎麽选择图表的人,可以另外看看这几篇不错的文章
了解完该选择哪种图表之後,开始来画第一张图吧!圆饼图适合用来表达 每笔资料於整体的占比
,生活中最常见的地方就是记帐App啦~常用App来记帐的人一定都看过这种图
透过这种圆饼图或甜甜圈图,我们就能弄清楚自己的钱都花到哪里、哪边的支出占最多,今天就来练习画一张圆饼帐本图吧!
这次我们要做的范例画面与互动效果有:
实际范例如下
绘制圆饼图之前,我们要先知道 d3.arc( )
与 d3.pie( )
这两个方法跟它们细节设定。关於 d3.arc( ) 的用法在 Day9 讲过了,今天再来讲讲 d3.pie 的用法吧!
d3.arc( ) 跟 a3.pie( ) 通常都是都配一起使用。当我们用arc( )建立好圆弧之後,就能将资料带进 pie( )的方法中去建立圆饼图。pie( ) 包含以下几种API:
很多设定跟 arc( ) 的设定类似,像是两者都有 startAngle、endAngle、padding等API,它们的功能也是一样的,我们就直接进入下方的范例做一次吧!
绘制圆饼图之前,我们先把要进行的步骤稍微拆解一下:
接着就按照这些顺序来撰写程序码吧!首先,先建立资料
// css
.chartContainer {
margin: auto;
width: 80%;
min-width: 200px;
/* height: 600px; */
margin: auto;
}
//html
<h4 class="text-center mt-5">金金的帐本</h4>
<div class="chartContainer"></div>
<div>
<button type="button" class="btn btn-primary January">1月</button>
<button type="button" class="btn btn-primary Feburary">2月</button>
</div>
// JS
// Data
let data = [{item:'交通', data:30},{item:'房租', data:45},
{item:'其他', data:9},{item:'吃饭', data:67},{item:'娱乐', data:22}];
// 切换一二月资料
d3.select('.Feburary').on('click', function(){
data = [{item:'交通', data:50},{item:'房租', data:65},
{item:'其他', data:39},{item:'吃饭', data:17},{item:'娱乐', data:72}];
drawPie()
})
d3.select('.January').on('click', function(){
data = [{item:'交通', data:30},{item:'房租', data:45},
{item:'其他', data:9},{item:'吃饭', data:67},{item:'娱乐', data:22}];
drawPie()
})
const drawPie = () => {
// RWD 清除原本的图型
d3.select('svg').remove()
// svg图形区大小、边界
const svgWidth = parseInt(d3.select(".chartContainer").style("width")),
svgHeight = svgWidth*0.8,
margin = 40;
// 先设定 svg 大小
const svg = d3.select(".chartContainer")
.append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
// 图表与线条、标签
svg.append("g")
.attr("class", "slices")
.attr('transform', `translate(${svgWidth / 2}, ${svgHeight / 2})`);
svg.append("g")
.attr("class", "labels");
svg.append("g")
.attr("class", "lines");
// 接下来的程序码都放这边哦.....
// 接下来的程序码都放这边哦.....
// 接下来的程序码都放这边哦.....
}
drawPie()
// 设定颜色
const color = d3.scaleOrdinal()
.range(["#4BEFCF","#0bbc17","#F96262", '#ffbe32', '#e271fc']);
// radius 用来设定半径,圆饼图的圆弧大小是区域的一半
const radius = Math.min(svgWidth, svgHeight) / 2 - margin;
// 设定每个资料在圆饼图上:
const piechart = d3.pie()
.value(d => d.data)
.sort(function(a,b){
console.log(a,b) // 固定圆饼图的项目排序
return d3.ascending(a.key, b.key)
});
// innerRadius 跟 outerRadius 决定圆饼内圈外圈的大小 radius
const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius)
.padAngle(.02),
outerArc = d3.arc()
.outerRadius(radius * 0.9)
.innerRadius(radius * 0.9),
data_ready = piechart(data)
// 计算每块资料的占比%
// 先用 d3.sum 加总全部资料,再将资料一一除上总数
const total = d3.sum(data, d => d.data)
data.forEach(d => {
d.percentage = Math.round((d.data/total)*100)
})
// 建立pie
const cutePie = svg.select('.slices')
.selectAll('g')
.data(data_ready)
.enter()
.append('g')
.attr('class', 'arc')
cutePie.append('path')
.attr('d', arc)
.attr('fill', color)
.attr("stroke", "#fff")
.style("stroke-width", "2px")
.style("opacity", 1);
// 加上每个区块的标示
// 控制文字的位置
const arcText = d3.arc()
.innerRadius(radius)
.outerRadius(radius - 10)
const itemText = cutePie.append('text')
.attr('transform', d => `translate(${arcText.centroid(d)})`)
.text(d => d.data.item + d.data.percentage + '%')
.style('text-anchor', 'middle')
.style('font-size', 16)
.style('fill', 'black')
// 滑鼠互动 mouseover、mouseleave
d3.selectAll('.arc path')
.style('cursor', 'pointer')
.on('mouseover', function(){
d3.select(this)
.transition()
.duration(500)
.style("filter", "drop-shadow(2px 4px 6px black)")
.style('transform', 'scale(1.1)')
})
.on('mouseleave', function(){
d3.select(this)
.transition()
.duration(500)
.style("filter", "drop-shadow(0 0 0 black)")
.style('transform', 'scale(1)')
})
这样就完成啦!最後的最後,别忘了要用 window resize 把完成的圆饼图调整为 RWD 圆饼图唷
// RWD
d3.select(window).on("resize", drawPie);
想看完整的程序码请往这走 Github ,想看完成的实际画面请往这走 Github Page,需要的人请自行取用~
Net Core 为一跨平台的应用开发,其此框架上可以加上许多自制服务,称之为容器也不为过。 如果...
String type和Container type的运算子 连接运算子 重复运算子 成员运算子 关...
前言 非同步程序设计基本上就是没有等待或非阻塞程序的设计模型,在Flutter中,非同步是用Futu...
已经先有测试资料了 来试试看删除文件的方法 doc_info/views.py 一样使用修饰器来验证...
我的梦想就是带这一台笔电走遍全世界,「成为一个工程师似乎可以完成这个梦想」,於是在去年底毅然决然的投...