日期:2014-05-17 浏览次数:20682 次
注:原创文章,转载注明原作者为dunhuangmi。
?
通常根据数据生成统计图,有柱状图,饼状图,折线图等等不同类型。柱状图可以通过js控制css的变化实现,比较简单。但是画圆必须用flash或html5来实现。
下面介绍一下用html5实现如下饼图的原理
?
我们都知道,用html5绘图需要使用CanvasRenderingContext2D对象提供的各种API,画圆需要用到arc()。
它的写法是arc(x, y, radius, startAngle, endAngle, counterclockwise),具体含义可查手册。
于是我们画一个π/6(30度)扇形(从0度开始,逆时针)就会是这样:
funciton draw(){ canvas = document.getElementById('tutorial'); ? if (canvas.getContext){ ? var ctx = canvas.getContext('2d'); ctx.fillStyle ="#3666B0"; ctx.strokeStyle = "#3666B0"; ctx.moveTo(300,200); ctx.arc(300,200,150,0,-Math.PI*/6,true); ctx.fill(); ctx.stroke(); } }
body部分这样写:
<body onload="draw();">
??? <canvas id="tutorial" width="700" height="400"><div class="nohtml5">你的浏览器不支持html5</div></canvas>
</body>
?
?需求是画饼图,因此要画一组扇形组成一个完整的圆。于是设置一组全局变量数组控制扇形的角度和颜色。
var color = ["#27255F","#2F368F","#3666B0","#2CA8E0","#77D1F6"]; /*5组扇形,不同颜色*/ var data = [5,30,15,30,20]; /*扇形的角度百分比,5组加起来正好是100*/ var startPoint = 0; /*其实点位置*/ var ctx; var o={x:300,y:200}/*坐标原点*/,rectbox={ox:0,oy:0,wid:700,hei:400}/*画布大小*/,radius=150/*圆半径*/;
?在draw()函数中用循环来控制连续画扇区
for (var i=0;i<data.length ; i++) { drawfan(i); }
?drawfun()代码
function drawfan(seq){ ctx.fillStyle =color[seq]; ctx.strokeStyle = color[seq]; ctx.moveTo(o.x,o.y); ctx.arc(o.x,o.y,radius,startPoint,startPoint-Math.PI*2*(data[seq]/100),true); ctx.fill(); ctx.stroke(); startPoint -= Math.PI*2*(data[seq]/100); }
?饼图效果还不错哒:
下面要实现当鼠标位于某扇区之上,该扇区浮动放大的效果,如下图效果:
1、扇区放大,放大radius即可实现
2、要实现浮动效果,一方面在扇区外加画阴影,另一方面,应将放大的扇形原点偏移出原先的原点。新原点的x,y坐标应根据扇区的中心点角度与半径偏移量计算而得。因此必须还要计算每个扇形的始末角度值。还要用sin,cos函数分别计算坐标。这里有一系列的算法。不记得中学数学的要去查查书了啊。注意网页的x轴y轴与数学上的坐标系方向不同,网页坐标原点在左上角,y轴的方向与数学坐标系的相反。
3、要判断鼠标此时是否在某扇区内,如果在,则放大浮动该扇区。
4、还要实现扇区渐进放大的效果,用setInterval()来实现。
5、鼠标位于扇区之上时增加一个浮动说明框(div+css实现,很简单,不赘述,只是跟随鼠标做位置变化即可)
?
增加全局变量:
var angle=new Array(5); /*扇形的始末角度*/ var hlnumber=3/*选中哪一块扇形*/,prenumber=-1/*已放大扇区序号*/,hlt,animating=false/*是否在动画中*/; var distance=8,/*选中扇区浮出距离*/expand=1.08,/*放大倍数*/shadow={blur:10,x:10,y:10};/*阴影的参数*/ var diffinfo={x:20,y:10}/*信息浮动框与鼠标的距离*/
计算扇区角度区间
function init(){ //计算每个扇区的角度区间 var sum=0; for (var i=0;i<data.length ;i++ ) { angle[i]=new Array(2); angle[i][0]=sum; sum+=data[i]/100; angle[i][1]=sum; } }
判断鼠标此时位于哪个扇区之上
function whichfan(x,y){ //计算某坐标点属于哪个扇区,圆外返回-1 var nx=x-o.x, ny=o.y-y; if (((nx*nx)+(ny*ny))>radius*radius){ return -1; } var ap=Math.atan2(ny,nx); if (ap<0) { ap+=Math.PI*2; } //alert(ap/Math.PI/2); for (var i=0;i<angle.length ;i++ ) { if (((ap/Math.PI/2)>=angle[i][0])&&((ap/Math.PI/2)<=angle[i][1])) { return i; } } return angle.length; }?
改写drawfan(),增加了两个参数:dist(放大扇区的偏移量),ifshadow(是否有阴影)
function drawfan(seq,dist,ifshadow){ ctx.fillStyle =color[seq]; ctx.strokeStyle = color[seq]; ctx.beginPath(); if (ifshadow){ var ang=(angle[seq][0]+angle[seq][1])/2; var newox,newoy; newox=o.x+dist* Math.cos(ang*2*Math.PI); newoy=o.y-dist* Math.sin(ang*2*Math.PI); ctx.shadowColor = '#cccccc'; ctx.shadowBlur = shadow.blur; //设置阴影模糊程度。此值越大,阴影越模糊 ctx.shadowOffsetX = shadow.x * Math.cos(ang*2*Math.PI); //阴影的x和y偏移量,单位是像素。 ctx.shadowOffsetY = -shadow.y * Math.sin(ang*2*Math.PI);