canvas图表(3) - 饼图
原文地址:canvas图表(3) - 饼图
这几天把canvas图表都优化了下,动画效果更加出色了,可以说很逼近echart了。刚刚写完的饼图,非常好的实现了既定的功能,交互的动画效果也是很棒的。
效果请看:饼图https://edwardzhong.github.io/sites/demo/dist/chartpie.html
功能点包括:
3. 数据动画的实现;
4. 鼠标事件的处理。
饼图的邳州巅峰蜘蛛池资讯网数据方面要简单很多,因为不用多个分组的数据。把所有的数据相加得出总数,然后每个数据分别求出百分比,有了百分比再相乘360度的弧度得出每个数据在圆盘中对应的要显示的角度。
pie(con)[ ] });
代码结构因为为了同时实现新增动画和更新动画,这次的代码结构经过了重构和优化,跟之前的有比较大的区别。
(container)(opt)()(pos(index)()()()()
组织数据这次把组织数据的功能单独拎了出来,这样方便重用和修改。然后随州巅峰蜘蛛池资讯网还要给动画对象增加是否创建的属性create和上次最后更新的度数last,为什么呢?因为我们要同时实现创建和更新图形的动画效果。
item, total(..(ii++){ item(hsli/.hsl.......i)total(ii++){ item(.i......)/)(.........)/
绘制饼图的绘制功能很简单,因为不用坐标系,只需要绘制标题和标签列表。
............).ii++){ item.....(ctx.....:......restore(); }
执行绘制饼图动画动画区分了创建和更新,这样用户很容易就能看出数据的比例关系变化,也就更加的直观。创建就是从0弧度到指定的弧度,只有数值的增加;而更新动画就要区分增加和减少的情况,因为当用户点击某个标签的时候,会隐藏显示某个分类的数据,于是需要重新计算每个分类的比例,那么相应的分类百分比就会增加或减少。我们根据当前最新要达到的比例ang和已经执行完的当前比例last的进行对比,相应执行增加和减少比例,动画原理就是这样。
canvas绘制圆形context.arc(x,y,r,sAngle,eAngle,counterclockwise);只要我们指定开始角度和结束角度就会画出披萨饼一样的效果,所有的披萨饼加起来就是一个圆。
animate(){ var that=this, ctx=that.ctx, canvas=that.canvas, item,startAng,ang, isStop=true; (function run(){ isStop=true; ctx.save(); ctx.translate(that.W/2,that.H/2); ctx.fillStyle="#fff"; ctx.beginPath(); ctx.arc(0,0,that.H/3+30,0,Math.PI*2,false); ctx.fill(); for(var i=0,l=that.animateArr.length;i<l;i++){ item=that.animateArr[i]; if(item.hide)continue; startAng=-Math.PI/2; that.animateArr.forEach((obj,j)=>{ if(j<i&&!obj.hide){startAng+=obj.cur;} }); ctx.fillStyle=item.color; if(item.create){//创建动画 if(item.cur>=item.ang){ item.cur=item.last=item.ang; } else { item.cur+=0.05; 广元巅峰蜘蛛池资讯网 isStop=false; } } else {//更新动画 if(item.last>item.ang){ ang=item.cur-0.05; if(ang<item.ang){ 六盘水巅峰蜘蛛池资讯网 item.cur=item.last=item.ang; } } else { ang=item.cur+0.05; if(ang>item.ang){ item.cur=item.last=item.ang; } } if(item.cur!=item.ang){ item.cur=ang; isStop=false; } } ctx.beginPath(); ctx.moveTo(0,0); ctx.arc(0,0,that.H/3,startAng,startAng+item.cur,false); ctx.closePath(); ctx.fill(); } ctx.restore(); if(isStop) { that.clearGrid(); return; } requestAnimationFrame(run); }()); } 交互处理执行完动画后,我这里再执行了一遍清除绘制,这个也是鼠标触摸标签和饼图时的对应动画方法,会绘制每个分类的名称描述,更方便用户查看。
clearGrid(index){ var that=this, ctx=that.ctx, canvas=that.canvas, item,startAng=-Math.PI/2, len=that.animateArr.filter(item=>!item.hide).length, j=0,angle=0, r=that.H/3; ctx.clearRect(0,0,that.W,that.H); that.draw(); ctx.save(); ctx.translate(咸阳巅峰蜘蛛池资讯网that.W/2,that.H/2); for(var i=0,l=that.animateArr.length;i<l;i++){ item=that.animateArr[i]; if(item.hide)continue; ctx.strokeStyle=item.color; ctx.fillStyle=item.color; angle=j>=len-1?Math.PI*2-Math.PI/2:startAng+item.ang; ctx.beginPath(); ctx.moveTo(0,0); if(index===i){ ctx.save(); // ctx.shadowColor="hsla(0,0%,50%,1)"; ctx.shadowColor=item.color; ctx.shadowBlur=5; ctx.arc(0,0,r+20,startAng,angle,false); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.restore(); } else { ctx.arc(0,0,r,startAng,angle,false); ctx.closePath(); ctx.fill(); } //画分类描述 var tr=r+40,tw=0, tAng=startAng+item.ang/2, x=tr*Math.cos(tAng), y=tr*Math.sin(tAng); ctx.lineWidth=2; ctx.lineCap="round"; ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(x,y); if(tAng>=-Math.PI/2&&tAng<=Math.PI/2){ ctx.lineTo(x+30,y); ctx.fillText(item.name,x+40,y+10); } else { tw=ctx.measureText(item.name).width;//计算字符长度 ctx.lineTo(x-30,y); ctx.fillText(item.name,x-40-tw,y+10); } ctx.stroke(); startAng+=item.ang; j++; } ctx.restore(); } 事件处理mousemove的时候,触摸标签和触摸饼图都是基本相同的效果,选中的分类扩大半径,同时增加阴影,以达到凸出来的动画效果,具体实现请看上面的clearGrid方法。判断是否点中都是使用isPointInPath这个api,之前已经介绍过,不再细讲。
mousedown某个击标签就会显示隐藏对应分类,每次触发就会看到饼图的比例变化的动画效果,这个和之前的柱状图和折线图的功能一致。
canvasctx(.(e)box=canvas.getBoundingClientRect(), pos ....(itemi<len;i++){ item(ctx....(.))(.clearGrid(i); } isLegend..(isLegend) startAng(li<l;i++){ item(.....); ctx.closePath(); startAng(.)).....])..)(e)boxpos ....(itemi<len;i++){ item(ctx....(.))..); }
最后所有图表代码请看chart.js
当前文章:
发布时间:2017-12-02 00:44:17
澳门金沙开户 澳门金沙开户 澳门金沙开户