示例代码托管于:http://www.github.com/dashnowords/blogs博客园地址:《大史住在大前端》原博文目录华为云社区地址:【你想要的前端打怪升级指南】【TOC】1.任务描述使用原生canvasAPI绘制直方图。(柱状图截图来自百度Echarts官方示例库【见示例链接】)2、需要特别提醒的是,柱状图可能是最容易实现的图表类型。矩形部分可以直接使用fillRect()绘制。为了填充坐标轴标签文本绘制在小分界线的中间,需要用measureText()测量文本的宽度,然后做相应的偏移,否则文本的左边框如果直接绘制,将与直线对齐。其他部分是一些基础API的使用。希望大家通过练习熟悉这些API的用法。3.示例代码提示:代码中,个别图表参数直接写在函数中(所谓的“魔鬼数字”)。这种做法是不提倡的,因为它违反了“开放原则和封闭原则”的发展基本原则之一。如果你使用过Echarts图表库,你会发现图表中几乎所有的元素都可以通过参数进行自定义。这里只需要关注canvasAPI的实现方法即可。/***获取画布绘图上下文*@type{[type]}*/constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');//绘图配置letoptions={chartZone:[50,50,1000,700],//标记绘图区域yAxisLabel:['0','100','200','300','400'],//标记Y轴坐标yMax:400,//Y轴最大值xAxisLabel:['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],//X轴坐标数据:[10,50,200,330,390,320,220],//直方图数据barStyle:{width:70,//直方图宽度颜色:'#1abc9c'//直方图颜色}}/*使用Echarts时会调用实例方法echartsInstance.setOptions(options)开始绘图*/drawBarChart(options);/***绘制直方图*/functiondrawBarChart(options){drawAxis(options);//绘制坐标轴drawYLabels(options);//绘制y轴坐标drawXLabels(options);//绘制x轴坐标//drawData(options);//绘制直方图drawDataGradient(options);//绘制梯度直方图}/***绘制坐标轴*/functiondrawAxis(options){letchartZone=选项。图表区;context.strokeWidth=4;context.strokeStyle='#353535';context.moveTo(chartZone[0],图表区[1]);context.lineTo(chartZone[0],chartZone[3]);//y轴总高度从50到700context.lineTo(chartZone[2],chartZone[3]);//x轴总长度从50到1000context.stroke();}/***绘制y轴坐标*/functiondrawYLabels(options){letlabels=options.yAxisLabel;让yLength=(options.chartZone[3]-options.chartZone[1])*0.98;让gap=yLength/(labels.length-1);labels.forEach(function(label,index){//绘制坐标文本letoffset=context.measureText(label).width+20;context.strokeStyle='#eaeaea';context.font='16px';context.fillText(label,options.chartZone[0]-offset,options.chartZone[3]-index*gap);//画一个小区间context.beginPath();context.strokeStyle='#353535';context.moveTo(options.chartZone[0]-10,options.chartZone[3]-index*gap);context.lineTo(options.chartZone[0],options.chartZone[3]-index*gap);context.stroke();//绘制辅助线context.beginPath();context.strokeStyle='#eaeaea';context.strokeWidth=2;context.moveTo(options.chartZone[0],options.chartZone[3]-index*gap);context.lineTo(options.chartZone[2],options.chartZone[3]-index*gap);context.stroke();});}/***绘制x轴坐标*/functiondrawXLabels(options){letlabels=options.xAxisLabel;让xLength=(options.chartZone[2]-options.chartZone[0])*0.96;让gap=xLength/labels.length;labels.forEach(function(label,index){//绘制坐标文字letoffset=context.measureText(label).width;context.strokeStyle='#eaeaea';context.font='18px';context.fillText(label,options.chartZone[0]+(index+1)*gap-offset,options.chartZone[3]+20);//绘制小间隔context.beginPath();context.strokeStyle='#353535';context.moveTo(options.chartZone[0]+(index+1)*gap-offset/2,options.chartZone[3]);context.lineTo(options.chartZone[0]+(index+1)*gap-offset/2,options.chartZone[3]+5);context.stroke();//存储偏移量options.offsetXLabel=offset/2;});}/***绘制数据*/functiondrawData(options){letdata=options.data;让xLength=(options.chartZone[2]-options.chartZone[0])*0.96;让yLength=(options.chartZone[3]-options.chartZone[1])*0.98;让gap=xLength/options.xAxisLabel.length;//绘制图表data.forEach(function(item,index){context.fillStyle=options.barStyle.color||'#1abc9c';//02BAD4letx0=options.chartZone[0]+(index+1)*间隙-options.barStyle.width/2-options.offsetXLabel;让height=item/options.yMax*(options.chartZone[3]-options.chartZone[1])*0.98;让y0=options.chartZone[3]-height;letwidth=options.barStyle.width;context.fillRect(x0,y0,width,height);});}/***绘制线条性变形柱状图*/functiondrawDataGradient(options){let数据=选项.数据;让xLength=(options.chartZone[2]-options.chartZone[0])*0.96;让yLength=(options.chartZone[3]-options.chartZone[1])*0.98;让gap=xLength/options.xAxisLabel.length;//创建渐变色letfillStyleGradient=context.createLinearGradient(50,50,50,700);fillStyleGradient.addColorStop(0,options.barStyle.color);fillStyleGradient.addColorStop(1,'rgba(1,176,241,0.6)');//绘制矩形data.forEach(function(item,index){context.fillStyle=fillStyleGradient;letx0=options.chartZone[0]+(index+1)*gap-options.barStyle.width/2-options.offsetXLabel;让height=item/options.yMax*(options.chartZone[3]-options.chartZone[1])*0.98;让y0=options.chartZone[3]-height;让width=options.barStyle.width;context.fillRect(x0,y0,width,height);});}在浏览器中查看效果:4.思考题如果想在坐标轴的末端加一个箭头,应该怎么办?/*x轴箭头示例*///在1.options中添加箭头颜色和大小设置letoptions={//...axisArrow:{size:2,color:'#DA5961'}}//箭头绘制函数/***x轴绘制箭头*/functiondrawArrow(options){letfactor=options.axisArrow.size;//获取箭头大小因子context.save();//保存当前设置的绘图上下文context.translate(options.chartZone[2],options.chartZone[3]);//移动坐标系原点到x轴结束context.beginPath();//开始绘制箭头context.moveTo(0,0);//移动到新的原点context.lineTo(2*factor,-3*factor);context.lineTo(10*factor,0);context.lineTo(2*factor,3*factor);context.lineTo(0,0);context.globalAlpha=0.7;//设置填充颜色透明度context.fillStyle=options.axisArrow.color;//获取箭头颜色上下文.fill();//填充箭头路径context.restore();//恢复绘制上下文样式设置}箭头效果:y轴上的箭头可以自己完成
