本章建议学习时间4小时

学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记)

学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步骤,本次讲解柱状图。

源文件下载地址:https://github.com/sutianbinde/charts

柱状图


柱状图是前端最基本的图表之一,我们的案例展示效果如下

功能:横轴年份,纵轴产量,图表会根据年份的多少自动分配柱的宽度,高度会有由低到高的运动效果,当鼠标移入时,当前柱会颜色加深。点击图表会有刷新重载动画效果。

实现步骤


--新建Html文件,写入canvas标签,并且定义绘制图表的方法

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<canvas id="barChart" height="400" width="600" style="margin:50px"> 你的浏览器不支持HTML5 canvas </canvas> <script type="text/javascript">
//封装绘制图表的方法
function goBarChart(dataArr){ } //调用方法,并传入需要显示的数据
goBarChart(
[[2007, 750], [2008, 425], [2009, 960], [2010, 700], [2011, 800], [2012, 975], [2013, 375], [2014, 775]]
)
</script>
</body>
</html>

--在 goBarChart方法中定义需要使用的变量 并获取 canvas上下文

            // 声明所需变量
var canvas,ctx;
// 图表属性
var cWidth, cHeight, cMargin, cSpace;
var originX, originY;
// 柱状图属性
var bMargin, tobalBars, bWidth, maxValue;
var totalYNomber;
var gradient; // 运动相关变量
var ctr, numctr, speed;
//鼠标移动
var mousePosition = {}; // 获得canvas上下文
canvas = document.getElementById("barChart");
if(canvas && canvas.getContext){
ctx = canvas.getContext("2d");
}

--初始化图表  (接着上一步的代码写在 goBarChart方法中 )

            initChart(); // 图表初始化

            // 图表初始化
function initChart(){
// 图表信息
cMargin = 30;
cSpace = 60;
cHeight = canvas.height - cMargin*2 - cSpace;
cWidth = canvas.width - cMargin*2 - cSpace;
originX = cMargin + cSpace;
originY = cMargin + cHeight; // 柱状图信息
bMargin = 15;
tobalBars = dataArr.length;
bWidth = parseInt( cWidth/tobalBars - bMargin );
maxValue = 0;
for(var i=0; i<dataArr.length; i++){
var barVal = parseInt( dataArr[i][1] );
if( barVal > maxValue ){
maxValue = barVal;
}
}
maxValue += 50;
totalYNomber = 10;
// 运动相关
ctr = 1;
numctr = 100;
speed = 10; //柱状图渐变色
gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(0, 'green');
gradient.addColorStop(1, 'rgba(67,203,36,1)'); }

--绘制图表的轴和标记 (接着上一步的代码写在 goBarChart方法中 )

            drawLineLabelMarkers(); // 绘制图表轴、标签和标记

            // 绘制图表轴、标签和标记
function drawLineLabelMarkers(){
ctx.translate(0.5,0.5); // 当只绘制1像素的线的时候,坐标点需要偏移,这样才能画出1像素实线
ctx.font = "12px Arial";
ctx.lineWidth = 1;
ctx.fillStyle = "#000";
ctx.strokeStyle = "#000";
// y轴
drawLine(originX, originY, originX, cMargin);
// x轴
drawLine(originX, originY, originX+cWidth, originY); // 绘制标记
drawMarkers();
ctx.translate(-0.5,-0.5); // 还原位置
} // 画线的方法
function drawLine(x, y, X, Y){
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(X, Y);
ctx.stroke();
ctx.closePath();
} // 绘制标记
function drawMarkers(){
ctx.strokeStyle = "#E0E0E0";
// 绘制 y
var oneVal = parseInt(maxValue/totalYNomber);
ctx.textAlign = "right";
for(var i=0; i<=totalYNomber; i++){
var markerVal = i*oneVal;
var xMarker = originX-5;
var yMarker = parseInt( cHeight*(1-markerVal/maxValue) ) + cMargin;
//console.log(xMarker, yMarker+3,markerVal/maxValue,originY);
ctx.fillText(markerVal, xMarker, yMarker+3, cSpace); // 文字
if(i>0){
drawLine(originX, yMarker, originX+cWidth, yMarker);
}
}
// 绘制 x
ctx.textAlign = "center";
for(var i=0; i<tobalBars; i++){
var markerVal = dataArr[i][0];
var xMarker = parseInt( originX+cWidth*(i/tobalBars)+bMargin+bWidth/2 );
var yMarker = originY+15;
ctx.fillText(markerVal, xMarker, yMarker, cSpace); // 文字
}
// 绘制标题 y
ctx.save();
ctx.rotate(-Math.PI/2);
ctx.fillText("产 量", -canvas.height/2, cSpace-10);
ctx.restore();
// 绘制标题 x
ctx.fillText("年份", originX+cWidth/2, originY+cSpace/2+10);
};

-- 绘制柱状图(接着上一步的代码写在 goBarChart方法中 )

            drawBarAnimate(); // 绘制柱状图的动画
//绘制柱形图
function drawBarAnimate(mouseMove){
for(var i=0; i<tobalBars; i++){
var oneVal = parseInt(maxValue/totalYNomber);
var barVal = dataArr[i][1];
var barH = parseInt( cHeight*barVal/maxValue * ctr/numctr );
var y = originY - barH;
var x = originX + (bWidth+bMargin)*i + bMargin;
drawRect( x, y, bWidth, barH, mouseMove ); //高度减一避免盖住x轴
ctx.fillText(parseInt(barVal*ctr/numctr), x+15, y-8); // 文字
}
if(ctr<numctr){
ctr++;
setTimeout(function(){
ctx.clearRect(0,0,canvas.width, canvas.height);
drawLineLabelMarkers();
drawBarAnimate();
}, speed);
}
}
//绘制方块
function drawRect( x, y, X, Y, mouseMove ){ ctx.beginPath();
ctx.rect( x, y, X, Y );
if(mouseMove && ctx.isPointInPath(mousePosition.x, mousePosition.y)){ //如果是鼠标移动的到柱状图上,重新绘制图表
ctx.fillStyle = "green";
}else{
ctx.fillStyle = gradient;
ctx.strokeStyle = gradient;
}
ctx.fill();
ctx.closePath(); }

--检测鼠标移动并显示当前项(接着上一步的代码写在 goBarChart方法中 )

注:这里鼠标移动的检测在有文字缩放显示的高清屏幕上会有偏差不准确的情况,而且在高清屏幕中canvas中的文字会略显模糊,以后的章节中会说明如何处理这个问题,大家可以先不管这个问题。(github上的 柱状图-高清.html也已经解决了这个问题,你可以点击上面的下载链接去查看源码)

 //检测鼠标移动
var mouseTimer = null;
canvas.addEventListener("mousemove",function(e){
e = e || window.event;
if( e.offsetX || e.offsetX==0 ){
mousePosition.x = e.offsetX;
mousePosition.y = e.offsetY;
}else if( e.layerX || e.layerX==0 ){
mousePosition.x = e.layerX;
mousePosition.y = e.layerY;
} clearTimeout(mouseTimer);
mouseTimer = setTimeout(function(){
ctx.clearRect(0,0,canvas.width, canvas.height);
drawLineLabelMarkers();
drawBarAnimate(true);
},10);
});

  

--当点击canvas的时候重新刷新图表(接着上一步的代码写在 goBarChart方法中 )

            //点击刷新图表
canvas.onclick = function(){
initChart(); // 图表初始化
drawLineLabelMarkers(); // 绘制图表轴、标签和标记
drawBarAnimate(); // 绘制折线图的动画
};

这样我们整个代码就编写完成了,为了代码更便于阅读,我们可以将所有方法放到后面,把调用方法的代码放到前面,经过调整的全部代码如下

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<canvas id="barChart" height="400" width="600" style="margin:50px"> 你的浏览器不支持HTML5 canvas </canvas> <script type="text/javascript">
function goBarChart(dataArr){
// 声明所需变量
var canvas,ctx;
// 图表属性
var cWidth, cHeight, cMargin, cSpace;
var originX, originY;
// 柱状图属性
var bMargin, tobalBars, bWidth, maxValue;
var totalYNomber;
var gradient; // 运动相关变量
var ctr, numctr, speed;
//鼠标移动
var mousePosition = {}; // 获得canvas上下文
canvas = document.getElementById("barChart");
if(canvas && canvas.getContext){
ctx = canvas.getContext("2d");
}
initChart(); // 图表初始化
drawLineLabelMarkers(); // 绘制图表轴、标签和标记
drawBarAnimate(); // 绘制柱状图的动画
//检测鼠标移动
var mouseTimer = null;
canvas.addEventListener("mousemove",function(e){
e = e || window.event;
if( e.layerX || e.layerX==0 ){
mousePosition.x = e.layerX;
mousePosition.y = e.layerY;
}else if( e.offsetX || e.offsetX==0 ){
mousePosition.x = e.offsetX;
mousePosition.y = e.offsetY;
} clearTimeout(mouseTimer);
mouseTimer = setTimeout(function(){
ctx.clearRect(0,0,canvas.width, canvas.height);
drawLineLabelMarkers();
drawBarAnimate(true);
},10);
}); //点击刷新图表
canvas.onclick = function(){
initChart(); // 图表初始化
drawLineLabelMarkers(); // 绘制图表轴、标签和标记
drawBarAnimate(); // 绘制折线图的动画
}; // 图表初始化
function initChart(){
// 图表信息
cMargin = 30;
cSpace = 60;
cHeight = canvas.height - cMargin*2 - cSpace;
cWidth = canvas.width - cMargin*2 - cSpace;
originX = cMargin + cSpace;
originY = cMargin + cHeight; // 柱状图信息
bMargin = 15;
tobalBars = dataArr.length;
bWidth = parseInt( cWidth/tobalBars - bMargin );
maxValue = 0;
for(var i=0; i<dataArr.length; i++){
var barVal = parseInt( dataArr[i][1] );
if( barVal > maxValue ){
maxValue = barVal;
}
}
maxValue += 50;
totalYNomber = 10;
// 运动相关
ctr = 1;
numctr = 100;
speed = 10; //柱状图渐变色
gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(0, 'green');
gradient.addColorStop(1, 'rgba(67,203,36,1)'); } // 绘制图表轴、标签和标记
function drawLineLabelMarkers(){
ctx.translate(0.5,0.5); // 当只绘制1像素的线的时候,坐标点需要偏移,这样才能画出1像素实线
ctx.font = "12px Arial";
ctx.lineWidth = 1;
ctx.fillStyle = "#000";
ctx.strokeStyle = "#000";
// y轴
drawLine(originX, originY, originX, cMargin);
// x轴
drawLine(originX, originY, originX+cWidth, originY); // 绘制标记
drawMarkers();
ctx.translate(-0.5,-0.5); // 还原位置
} // 画线的方法
function drawLine(x, y, X, Y){
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(X, Y);
ctx.stroke();
ctx.closePath();
} // 绘制标记
function drawMarkers(){
ctx.strokeStyle = "#E0E0E0";
// 绘制 y
var oneVal = parseInt(maxValue/totalYNomber);
ctx.textAlign = "right";
for(var i=0; i<=totalYNomber; i++){
var markerVal = i*oneVal;
var xMarker = originX-5;
var yMarker = parseInt( cHeight*(1-markerVal/maxValue) ) + cMargin;
//console.log(xMarker, yMarker+3,markerVal/maxValue,originY);
ctx.fillText(markerVal, xMarker, yMarker+3, cSpace); // 文字
if(i>0){
drawLine(originX, yMarker, originX+cWidth, yMarker);
}
}
// 绘制 x
ctx.textAlign = "center";
for(var i=0; i<tobalBars; i++){
var markerVal = dataArr[i][0];
var xMarker = parseInt( originX+cWidth*(i/tobalBars)+bMargin+bWidth/2 );
var yMarker = originY+15;
ctx.fillText(markerVal, xMarker, yMarker, cSpace); // 文字
}
// 绘制标题 y
ctx.save();
ctx.rotate(-Math.PI/2);
ctx.fillText("产 量", -canvas.height/2, cSpace-10);
ctx.restore();
// 绘制标题 x
ctx.fillText("年份", originX+cWidth/2, originY+cSpace/2+10);
}; //绘制柱形图
function drawBarAnimate(mouseMove){
for(var i=0; i<tobalBars; i++){
var oneVal = parseInt(maxValue/totalYNomber);
var barVal = dataArr[i][1];
var barH = parseInt( cHeight*barVal/maxValue * ctr/numctr );
var y = originY - barH;
var x = originX + (bWidth+bMargin)*i + bMargin;
drawRect( x, y, bWidth, barH, mouseMove ); //高度减一避免盖住x轴
ctx.fillText(parseInt(barVal*ctr/numctr), x+15, y-8); // 文字
}
if(ctr<numctr){
ctr++;
setTimeout(function(){
ctx.clearRect(0,0,canvas.width, canvas.height);
drawLineLabelMarkers();
drawBarAnimate();
}, speed);
}
} //绘制方块
function drawRect( x, y, X, Y, mouseMove ){ ctx.beginPath();
ctx.rect( x, y, X, Y );
if(mouseMove && ctx.isPointInPath(mousePosition.x, mousePosition.y)){ //如果是鼠标移动的到柱状图上,重新绘制图表
ctx.fillStyle = "green";
}else{
ctx.fillStyle = gradient;
ctx.strokeStyle = gradient;
}
ctx.fill();
ctx.closePath(); } } goBarChart(
[[2007, 750], [2008, 425], [2009, 960], [2010, 700], [2011, 800], [2012, 975], [2013, 375], [2014, 775]]
) </script>
</body>
</html>

好了,今天就讲到这里,希望大家把代码都自己敲一遍。

关注公众号,博客更新即可收到推送

canvas图表详解系列(1):柱状图的更多相关文章

  1. canvas图表详解系列(2):折线图

    本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...

  2. canvas图表详解系列(4):动态散点图

    本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...

  3. canvas图表详解系列(5):雷达(面积)图

    雷达(面积)图 本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种 ...

  4. canvas图表详解系列(3):动态饼状图(原生Js仿echarts饼状图)

    本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...

  5. 【转】Android Canvas绘图详解(图文)

    转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...

  6. Python绘制六种可视化图表详解,三维图最炫酷!你觉得呢?

    Python绘制六种可视化图表详解,三维图最炫酷!你觉得呢? 可视化图表,有相当多种,但常见的也就下面几种,其他比较复杂一点,大都也是基于如下几种进行组合,变换出来的.对于初学者来说,很容易被这官网上 ...

  7. JDBC详解系列(二)之加载驱动

    ---[来自我的CSDN博客](http://blog.csdn.net/weixin_37139197/article/details/78838091)---   在JDBC详解系列(一)之流程中 ...

  8. JDBC详解系列(三)之建立连接(DriverManager.getConnection)

      在JDBC详解系列(一)之流程中,我将数据库的连接分解成了六个步骤. JDBC流程: 第一步:加载Driver类,注册数据库驱动: 第二步:通过DriverManager,使用url,用户名和密码 ...

  9. Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

    Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...

随机推荐

  1. poj 1011--Sticks(搜索)

    题目链接 Description George took sticks of the same length and cut them randomly until all parts became ...

  2. 规则集Set与线性表List性能分析

    前言 本章节将通过实验,测试规则集与线性表的性能.那么如何进行实验呢?针对不同的集合都进行指定数量元素的添加和删除操作,计算耗费时间进行分析. 那么,前两个章节呢,我们分别讲述了什么时候使用Set以及 ...

  3. Bash 脚本进阶,经典用法及其案例

    前言:在linux中,Bash脚本是很基础的知识,大家可能一听脚本感觉很高大上,像小编当初刚开始学一样,感觉会写脚本的都是大神.虽然复杂的脚本是很烧脑,但是,当我们熟练的掌握了其中的用法与技巧,再多加 ...

  4. 发布一个Python小程序:ManHourCalendar

    程序诞生的那些事儿 先聊聊背景资料档案.. 大约两年前,我只身前往岛国赚点外快.在那边的派遣制度工作中,存在一个大约叫每月的标准工作时间的概念,按照自家公司跟派遣目标公司(业界称为现场)的合同,规定了 ...

  5. return 的使用

    (一):while中使用return //编译不通过,编译器不知道isTrue()方法是否会返回true,这样不能test()方法一定有返回值. public String test(){ while ...

  6. list后台转化为JSON的方法ajax

    导入alibaba的fastJson包 后台: protected void doGet(HttpServletRequest request, HttpServletResponse respons ...

  7. 201521123105 第8周Java学习总结

    1.本周学习总结 1.1思维导图 2. 书面作业 本次作业题集集合 1.List中指定元素的删除(题目4-1) 1.1 实验总结 1.删除元素的时候从最后一个元素开始,避免删除元素后位置发生变化而导致 ...

  8. 201521123110 《JAVA程序设计》第3周学习总结

    1.本章学习总结 ` ` 2.书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...

  9. 201521123067《Java程序设计》第1周学习总结

    1.本周学习总结 在本周的java学习中,我知道了java的发展历程,JDK和JRE以及JVM的区别与联系,并学习了如何安装Eclipse和搭建java的环境,编写出了第一个java程序,明白了jav ...

  10. 201521123096《Java程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...