有了canvas,我们可以轻松制作简单的图标,无需任何插件。但是,也有朋友觉得很难。作者深思熟虑后,只能说说他们的绘画技巧了。。。所以在开始绘画之前,先画个草图吧~在讲解之前,先贡献源码:https://github.com/Sue1024/Ca...MakeItReusablefor为了创建一个可以重复使用和灵活重复使用的饼图,作者决定创建饼图的最终方法接收两个参数,分别是要显示的数据,以及绘图参数optionsDataData来自服务器。在实际应用场景中,我们从后台拿到的往往是几年的输出等数据,例如(这里为了简化代码,我们在后台返回的数据中也放上了颜色):vardata=[{data:10,color:"red",label:"2016"},{data:15,color:"grey",label:"2017"},{data:15,color:"black",label:"2018"}];处理数据在绘制饼图的时候,我们需要按照比例来“分饼”,在某些地方(比如tooltip)显示实际的数据,所以我们需要一个数据处理函数如下:functioncalculateData(data){if(datainstanceofArray){varsum=data.reduce(function(a,b){returna+b.data;},0);varmap=data.map(函数(a){返回{标签:a.label,数据:a.data,颜色:a.color,部分:a.data/sum}});返回地图;}}Options另外,虽然我们可以根据不同的数据绘制不同的图表,但恐怕只能满足个人需求。毕竟每个人的喜好都不一样。我们需要创建一个图表,可以显示不同的数据,可以有不同的布局和排版。为了实现上述目标,我们需要如下参数列表:varoptions={legend:{font:{size:18,family:'Arial',weight:'bold'}},title:{text:'PieChart',字体:{size:18,family:'Arial',weight:'bold'}},tooltip:{template:'
Year:{{label}}
Production:{{data}}
',font:{size:18,family:'Arial',weight:'bold'}}}Canvas我们的实用函数不应该提前知道用户想要使用的画布绘制图表。用户可能希望在页面中的多个画布上绘制图表,因此实用函数应该能够接受一个参数来确定绘制图表的画布。许多开源库使用id作为识别画布的标识符。我觉得还是receiveelement比较好,因为不是所有的用户都愿意给canvas加上ID属性。有时,用户希望批量绘制某个类属性的所有画布,并根据其数据集属性动态生成数据总结一下,最后我们的工具函数应该是这样的:)方法。varcanvas=document.getElementById("canvas");if(canvas.getContext){varctx=canvas.getContext("2d");}GenerateOptions然后,我们需要将自定义参数和默认参数组合在一起,形成一个全新且完整的参数列表,原则是没有自定义就使用默认值。函数mergeJSON(source1,source2){varmergedJSON=JSON.parse(JSON.stringify(source2));for(varattrnameinsource1){if(mergedJSON.hasOwnProperty(attrname)){if(source1[attrname]!=null&&source1[attrname].constructor==Object){mergedJSON[attrname]=mergeJSON(source1[attrname],mergedJSON[属性名]);}}else{mergedJSON[attrname]=source1[attrname];}}returnmergedJSON;}functiongenerateOptions(givenOptions,defaultOptions){returnmergeJSON(defaultOptions,givenOptions);}DrawTitle在画布顶部中间绘制标题,与页面顶部留出20像素的空隙,并根据参数绘制具有特定内容和样式的标题。varwidth=canvas.width,height=canvas.height,op=generateOptions(options,defaultOptions),title_text=op.title.text,title_position={};ctx.font=op.title.font.weight+""+op.title.font.size+"px"+op.title.font.family;title_position.x=(width-title_width)/2;title_position.y=20+op.title.font.size;title_width=ctx.measureText(title_text).width,title_height=op.title.font.size;ctx.fillText(title_text,title_position.x,title_position.y);Radius&Center作者决定让饼图离标题有30个像素的间隙,离左边框底部和底部有20个像素的间隙,所以它的半径和中心分别是:varradius=(height-title_height-title_position.y-20)/2;varcenter={x:radius+20,y:radius+30+title_position.y};Legend图例的高度设置为图例字体大小的1.2倍,宽度设置为图例字体大小的2.5倍,与饼图相距40像素,第一个图例的顶部距离页面顶部80像素,文字距离图例5像素,垂直居中,所以图例的大致信息总结如下:varlegend_width=op.legend.font.size*2.5,legend_height=op.legend.font.size*1.2,legend_posX=center.x*2+20,legend_posY=80,legend_textX=legend_posX+legend_width+5,legend_textY=legend_posY+op.legend.font.size*0.9;绘制饼图&LegendsBorder首先给图表添加边框ctx.strokeStyle='grey';ctx.lineWidth=3;ctx.strokeRect(0,0,canvas.width,canvas.height);Pie&Legends遍历数据绘制vardata_c=calculateData(数据);var开始角度=0,结束角度=0;for(vari=0,len=data.length;i