无意间翻到了之前某次考核做的一个环形统计图,今天又捣鼓了一下把它封装成了一个类,可以根据不同的数据切换内容,下面分享一下我的实现思路。
0.效果预览
基本功能
- 环形统计图,按每一项数据自动分配比例。
- 只需简单地更换数据便可以生成新的环形统计图(统计图大小也可以更改)。
- 点击每一项可以关闭该项,隐藏右侧数据,然后再重新生成。
1.该示例的完整JS代码pieChart.js
window.onload = function(){
var data1 = [
{"id":"item0","text":"这是第一行","num":10,"color":"#1e90ff","isdraw":1},
{"id":"item1","text":"这是第二行","num":20,"color":"#36cbcb","isdraw":1},
{"id":"item2","text":"这是第三行","num":30,"color":"#2fc25b","isdraw":1},
{"id":"item3","text":"这是第四行","num":40,"color":"#ffd700","isdraw":1},
{"id":"item4","text":"这是第五行","num":50,"color":"#ff3030","isdraw":1},
{"id":"item5","text":"这是第六行","num":60,"color":"#8a2be2","isdraw":1},
];
var apie = new pieChart('这里是标题',data1,150,40);
apie.add_data();
apie.draw();
}
function pieChart(title, data, radius, width){
this.title = title;
this.data = data;
this.width = width;
this.radius = radius;
this.add_data = function(){
var width = 2*radius;
var chart = document.createElement('div');
chart.style.width = width+'px';
var top = document.createElement('div');
top.setAttribute('style','text-align:center;font-weight:bold;width:'+width+'px');
top.innerText = title;
var circle = document.createElement('canvas');
circle.setAttribute('id','circle');
circle.setAttribute('width',width+"px");
circle.setAttribute('height',width+"px");
var list = document.createElement('div');
list.setAttribute('id','list');
var ul = document.createElement('ul');
ul.setAttribute('style','font-family:Simsun;margin:0;padding:0;list-style:none;');
for(var i=0; i"+data[i].num+"";
li.onclick = this.draw;
ul.appendChild(li);
}
list.appendChild(ul);
chart.appendChild(top);
chart.appendChild(circle);
chart.appendChild(list);
document.body.appendChild(chart);
}
this.draw = function(){
var len = data.length;
var id = this.id;
for(var i=0; i
在一个空白html
文件中导入该js文件即可使用(基本的html
,body
标签要有),不需导入其他的css
文件。新建一个pieChart
对象,调用add_data()
和draw()
方法即可。
下面是实现思路的分享。
2.实现思路
使用JS绘制图形,那自然离不开canvas
标签,这里我们最终绘制的是一个圆环,我的大体思路是:
- 根据数据计算所占比例,再根据所占比例使用较大半径绘制每部分的扇形。
- 所有部分绘制完毕,再使用一个较小的半径绘制一个白底的完整的圆。
- 填充文本。
也就是说,实际上我先是绘制的一个扇形统计图,然后用一个白底的较小的圆将其覆盖,这样看上去就是一个环形统计图了。
下面结合代码详细讲解;
在window.onload
外我封装了一个pieChart
类,他有四个变量和两个方法:
四个变量
title:统计图的标题。
data:统计图的数据,每一条数据含下面五个内容:
①id:该项数据在html中的id值。
②text:该项数据在统计图下方显示的文本。
③num:该项数据的值(数量)。
④color:该项数据在统计图中对应的颜色。
⑤isdraw:是否绘制该项数据,只能填为1或0,默认填1,表示要绘制(在点击重绘时会用到该值)。
radius:外层圆的半径,单位为px。
width:圆环宽度,单位为px,可理解为外层圆与内层圆半径的差值。
两个方法
add_data()方法:负责添加统计图下方的每行内容。
draw()方法:绘制圆环的方法,同时也会绑定到每一行数据中。
3.方法详解
add_data()
this.add_data = function(){
var width = 2*radius;//区域宽度即为直径的长度,画布区域(canvas)的宽高等于直径,下方每一个li的宽度也等于直径。
/***div 'chart',为整个页面的父div。***/
var chart = document.createElement('div');
chart.style.width = width+'px';
/***div 'top',统计图标题区域***/
var top = document.createElement('div');
top.setAttribute('style','text-align:center;font-weight:bold;width:'+width+'px');
top.innerText = title;
/***canvas 'circle',圆环区域***/
var circle = document.createElement('canvas');
circle.setAttribute('id','circle');
circle.setAttribute('width',width+"px");
circle.setAttribute('height',width+"px");
/***div 'list',数据行区域***/
var list = document.createElement('div');
list.setAttribute('id','list');
var ul = document.createElement('ul');
ul.setAttribute('style','font-family:Simsun;margin:0;padding:0;list-style:none;');
/*每次循环添加data中的一条数据*/
for(var i=0; i"+data[i].num+"";
li.onclick = this.draw;//为每一行添加onclick事件
ul.appendChild(li);
}
list.appendChild(ul);
chart.appendChild(top);
chart.appendChild(circle);
chart.appendChild(list);
document.body.appendChild(chart);
}
实际上最终的页面结构为一个父div
,包含三个部分:标题区域div 'top'
,图形区域canvas 'circle'
,数据区域div 'list'
;数据区域div 'list'
包含一个无序列表ul
,根据创建对象的数据条数创建一个个li
,向其写入数据并绑定onclick
事件draw()
;每个li
又含三个span
标签,分别代表:数据前缀(指定该行和统计图中哪个颜色对应),数据文本,文本对应的数量。
页面结构如下:
draw()
代码片段一:
var id = this.id;
for(var i=0; i
实际上draw()
是为数据区域中的每一个li
量身定做的,每一次对li
标签的点击都会重绘图形,这时this
指向的是被点击的li
标签,如果它正在统计图中显示将会去除它,前缀变为灰色,数据值隐藏,isdraw
标记为0,接下来的重绘将跳过对此项的绘制。
虽说draw()
方法是为li
服务的,但第一次生成统计图时也不用担心报错,这时的this
标签并不会指向任何一个li
标签,id
赋值为undefined
,虽然也会进入for循环,但始终不会进入if语句,对绘制不会产生任何影响。
代码片段二:
canvas.height = canvas.height;
每次重绘都会先清空画布,这里有个小技巧,重新设置画布的宽度或高度都会使画布清空。
代码片段三:
/*绘制部分*/
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var PI = Math.PI;
var start = PI*1.5;//绘制开始位置
var gap = 0.01;//两项数据间取的间隙,每个间隙占比1%
var pros;//除去空隙后内容所占比例
var sum = 0;//总和
var zero = 0;//isdraw值为0数据个数(重绘过程不显示的数据个数)
/*计算总和(sum)*/
for(var i=0; i
务必理解到pros
这个变量的意义,在之前的预览图里大家可以看到,每两个数据间是有空隙的,每次扇形比例的计算都是在去掉这些空白区域的前提下进行的,pros
为【全部内容】在圆环上的比例,即除去空隙部分后剩余部分所占比例。
当数据显示项大于1时,间隙数等于数据数,只剩一项数据显示时,间隙数为0,该项内容占比100%。
若你对canvas
的用法不够熟悉,建议先作一定了解,过程中多百度也是很好的选择。
对代码有疑问,欢迎评论;若你有其他的实现一个圆环的方式,欢迎评论;若你发现我文章中的错误,欢迎评论!感激不尽~