canvas 强大的功能让它成为了 html5 中非常重要的部分,至于它是什么,这里就不需要我多作介绍了。而可视化图表,则是 canvas 强大功能的表现之一。
现在已经有了很多成熟的图表插件都是用 canvas 实现的,Chart.js、ECharts 等可以制作出好看炫酷的图表,而且几乎覆盖了所有图表的实现。
有时候自己只想画个柱状图,自己写又觉得麻烦,用别人插件又感觉累赘,最后打开百度,拷段代码,粘贴上来修修改改。还不如自己撸一个呢。
原文作者:林鑫,作者博客:https://github.com/lin-xin/blog
动画效果图片显示不出来,可以到最下面找 demo 地址
可以这个图表由 xy 轴、数据条形和标题组成。
这样看来,似乎并没有多难。
- <canvas id="canvas" width="600" height="500">
- </canvas>
canvas 标签只是个容器,真正实现画图的还是 JavaScript。
坐标轴就是两条横线,也就是 canvas 里最基础的知识。
- varcanvas= document.getElementById('canvas');
- varctx= canvas.getContext('2d');
- varwidth= canvas.width;
- varheight= canvas.height;
- varpadding= 50; // 坐标轴到canvas边框的边距,留边距写文字
- ctx.beginPath();
- ctx.lineWidth = 1;
- // y轴线
- ctx.moveTo(padding+ 0.5,height-padding+ 0.5);
- ctx.lineTo(padding+ 0.5,padding+ 0.5);
- ctx.stroke();
- // x轴线
- ctx.moveTo(padding+ 0.5,height-padding+ 0.5);
- ctx.lineTo(width-padding+ 0.5,height-padding+ 0.5);
- ctx.stroke();
y 轴上多少坐标点由自己来定义,需要获取到数据的最大值来计算 y 轴上的坐标值。x 轴的点则由传入的数据长度决定,坐标值由传入数据的 xAxis 属性决定。
- varyNumber= 5; // y轴的段数
- varyLength= Math.floor((height-padding* 2) / yNumber); // y轴每段的真实长度
- varxLength= Math.floor((width-padding* 2) /data.length); // x轴每段的真实长度
- ctx.beginPath();
- ctx.textAlign = 'center';
- ctx.fillStyle = '#000000';
- ctx.strokeStyle = '#000000';
- // x轴刻度和值
- for(vari= 0;i< data.length;i++){
- varxAxis=data[i].xAxis;
- varxlen=xLength*(i+ 1);
- ctx.moveTo(padding+xlen,height-padding);
- ctx.lineTo(padding+xlen,height-padding+ 5);
- ctx.stroke(); // 画轴线上的刻度
- ctx.fillText(xAxis,padding+xlen-xLength /2,height-padding+ 15); // 填充文字
- }
- // y轴刻度和值
- for(vari= 0;i<yNumber;i++){
- vary=yFictitious*(i+ 1);
- varylen=yLength*(i+ 1);
- ctx.moveTo(padding,height-padding-ylen);
- ctx.lineTo(padding- 5,height-padding-ylen);
- ctx.stroke();
- ctx.fillText(y,padding- 10,height-padding-ylen+ 5);
- }
接下来要把数据通过柱状的高低显示出来,这里有个动画效果,柱状会从 0 升到对应的值。在 canvas 上实现动画我们可以使用 setInterval、setTimeout 和 requestAnimationFrame。
requestAnimationFrame 不需要自己设置定时时间,而是跟着浏览器的绘制走。这样就不会掉帧,自然就流畅。 requestAnimationFrame 原本只支持 IE10 以上,不过可以通过兼容的写法实现兼容到 IE6 都行。
- function looping(){looped= requestAnimationFrame(looping);
- if(current< 100){
- // current 用来计算当前柱状的高度占最终高度的百分之几,通过不断循环实现柱状上升的动画current=(current+ 3)> 100 ? 100: (current+ 3);
- drawAnimation();
- }else{
- window.cancelAnimationFrame(looped);looped= null;
- }
- }
- function drawAnimation(){
- for(vari= 0;i< data.length;i++){
- varx= Math.ceil(data[i].value *current /100 *yRatio);
- vary=height-padding-x;
- ctx.fillRect(padding+xLength*(i+ 0.25),y,xLength/2,x);
- // 保存每个柱状的信息data[i].left =padding+xLength /4 +xLength*i;data[i].top =y;data[i].right =padding+ 3 *xLength /4 +xLength*i;data[i].bottom =height-padding;
- }
- }
- looping();
到这里,一个最基本的柱状图就完成了。接下来,我们可以为他添加标题。
要放置标题,就会发现我们一大早定义的 padding 内边距确实有用,总不能把标题给覆盖到柱状图上吧。但是标题有的是在顶部,有的在底部,那么就不能写死了。定一个变量 position 来判断位置去画出来。这个简单。
- // 标题
- if(title){ // 也不一定有标题
- ctx.textAlign = 'center';
- ctx.fillStyle = '#000000'; // 颜色,也可以不用写死,个性化嘛
- ctx.font = '16px Microsoft YaHei'
- if(titlePosition=== 'bottom' &&padding>= 40){
- ctx.fillText(title,width/2,height-5)}else{
- ctx.fillText(title,width/2,padding/2)}
- }
我们看到,有些图表,把鼠标移上去,当前的柱状就变色了,移开之后又变回原来的颜色。这里就需要监听 mouseover 事件,当鼠标的位置位于柱状的面积内,触发事件。
那我怎么知道在柱状里啊,发现在 drawAnimation() 里会有每个柱状的坐标,那我干脆把坐标给保存到 data 里。那么鼠标在柱状里的条件应该是:
- canvas.addEventListener('mousemove',function(ev){
- varev=ev||window.event;
- for(vari=0;i<data.length;i++){
- for(vari=0;i<data.length;i++){
- if(ev.offsetX >data[i].left &&
- ev.offsetX <data[i].right &&
- ev.offsetY >data[i].top &&
- ev.offsetY <data[i].bottom){
- console.log('我在第'+i+'个柱状里。');
- }
- }
- })
为了更方便的使用,封装成构造函数。通过
- var chart = new sBarChart('canvas', data, {
- title: 'xxx公司年度盈利',
- // 标题
- titleColor: '#000000',
- // 标题颜色
- titlePosition: 'top',
- // 标题位置
- bgColor: '#ffffff',
- // 背景色
- fillColor: '#1E9FFF',
- // 柱状填充色
- axisColor: '#666666',
- // 坐标轴颜色
- contentColor: '#a5f0f6' // 内容横线颜色
- });
参数可配置,很简单就生成一个个性化的柱状图。代码地址:canvas-demo
来源: http://www.cnblogs.com/linxin/p/6892389.html