【带着canvas去流浪】(1)绘制柱状图

示例代码托管在:http://www.github.com/dashnowords/blogs
博客园地址:《大史住在大前端》原创博文目录
华为云社区地址:【你要的前端打怪升级指南】
一. 任务说明
使用原生canvasAPI绘制柱状图。(柱状图截图来自于百度Echarts官方示例库【查看示例链接】)

二. 重点提示
柱状图或许是最容易实现的图表类型了,矩形的部分直接使用fillRect()来绘制即可,为了将坐标轴标签文字绘制在小分割线中间,需要用measureText()来测量文本的宽度,然后进行相应的偏移,否则直接绘制的话文字的左边界会和直线相对齐。其他部分都是一些基本API的使用,希望各位小伙伴通过做练习来熟悉这些API的用法。
三. 示例代码
提示:代码中将个别图表参数直接写在了函数里(也就是所谓的“魔鬼数字”),这种做法是不提倡的,因为它违反了开发的基本原则之一“开放封闭原则”。如果你使用过Echarts图表库就会发现,图表中几乎所有要素都可以通过参数来定制,此处只需要关注canvasAPI的实现方法即可。
/**
* 获取canvas绘图上下文
* @type {[type]}
*/
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
//绘图配置
let options = {
chartZone:[50,50,1000,700],//标识绘图区域
yAxisLabel:['0','100','200','300','400'],//标示Y轴坐标
yMax:400,//Y轴最大值
xAxisLabel:['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],//X轴坐标
data:[10,50,200,330,390,320,220],//柱状图数据
barStyle:{
width:70,//柱状图宽度
color:'#1abc9c'//柱状图颜色
}
}
/*Echarts使用时,会调用实例方法echartsInstance.setOptions(options)来启动绘图*/
drawBarChart(options);
/**
* 绘制柱状图
*/
function drawBarChart(options) {
drawAxis(options); //绘制坐标轴
drawYLabels(options); //绘制y轴坐标
drawXLabels(options); //绘制x轴坐标
//drawData(options);//绘制柱状图
drawDataGradient(options);//绘制渐变色柱状图
}
/**
* 绘制坐标轴
*/
function drawAxis(options) {
let chartZone = options.chartZone;
context.strokeWidth = 4;
context.strokeStyle = '#353535';
context.moveTo(chartZone[0],chartZone[1]);
context.lineTo(chartZone[0],chartZone[3]); //y轴总高从50到700
context.lineTo(chartZone[2],chartZone[3]); //x轴总长从50到1000
context.stroke();
}
/**
* 绘制y轴坐标
*/
function drawYLabels(options) {
let labels = options.yAxisLabel;
let yLength = (options.chartZone[3] - options.chartZone[1])*0.98;
let gap = yLength / (labels.length - 1);
labels.forEach(function (label, index) {
//绘制坐标文字
let offset = 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轴坐标
*/
function drawXLabels(options) {
let labels = options.xAxisLabel;
let xLength = (options.chartZone[2] - options.chartZone[0])*0.96;
let gap = xLength / labels.length;
labels.forEach(function (label, index) {
//绘制坐标文字
let offset = 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;
});
}
/**
* 绘制数据
*/
function drawData(options) {
let data = options.data;
let xLength = (options.chartZone[2] - options.chartZone[0])*0.96;
let yLength = (options.chartZone[3] - options.chartZone[1])*0.98;
let gap = xLength / options.xAxisLabel.length;
//绘制矩形
data.forEach(function (item, index) {
context.fillStyle = options.barStyle.color || '#1abc9c'; //02BAD4
let x0 = options.chartZone[0] + (index + 1) * gap - options.barStyle.width / 2 - options.offsetXLabel;
let height = item / options.yMax * (options.chartZone[3] - options.chartZone[1])*0.98;
let y0 = options.chartZone[3] - height;
let width = options.barStyle.width;
context.fillRect(x0,y0,width,height);
});
}
/**
* 绘制线性渐变色柱状图
*/
function drawDataGradient(options) {
let data = options.data;
let xLength = (options.chartZone[2] - options.chartZone[0])*0.96;
let yLength = (options.chartZone[3] - options.chartZone[1])*0.98;
let gap = xLength / options.xAxisLabel.length;
//创建渐变色
let fillStyleGradient = 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;
let x0 = options.chartZone[0] + (index + 1) * gap - options.barStyle.width / 2 - options.offsetXLabel;
let height = item / options.yMax * (options.chartZone[3] - options.chartZone[1])*0.98;
let y0 = options.chartZone[3] - height;
let width = options.barStyle.width;
context.fillRect(x0,y0,width,height);
});
}
浏览器中可查看效果:

四. 思考题
如果希望在坐标轴末端加一个箭头,需要怎么做呢?
/*x轴箭头示例*/
//1.options中增加箭头颜色和大小的设置
let options = {
//...
axisArrow:{
size:2,
color:'#DA5961'
}
}
//箭头绘制函数
/**
* x轴绘制箭头
*/
function drawArrow(options) {
let factor = 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;//获取箭头颜色
context.fill();//填充箭头路径
context.restore();//恢复绘图上下文样式设置
}
箭头效果:

y轴的箭头请自行完成即可。
【带着canvas去流浪】(1)绘制柱状图的更多相关文章
- 【带着canvas去流浪】(2)绘制折线图
目录 一. 任务说明 二. 重点提示 三. 示例代码 3.1 一般折线图 3.2 用贝塞尔曲线绘制平滑折线图 四. 大数据量场景 示例代码托管在:https://github.com/dashnowo ...
- 带着canvas去流浪系列之二 绘制折线图
[摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之一:绘制柱状图
[摘要] 学习使用canvasAPI来实现数据可视化. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制柱 ...
- 【带着canvas去流浪(5)】绘制K线图
目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...
- 带着canvas去流浪系列之五 绘制K线图
[摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 【带着canvas去流浪(7)】绘制水球图
目录 一. 任务说明 二. 重点提示 三. 示例代码 四. 文字淹水效果的实现 五. 关于canvas抗锯齿 六. 小结 示例代码托管在:http://www.github.com/dashnowor ...
- 【带着canvas去流浪(6)】绘制雷达图
目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...
- 【带着canvas去流浪(4)】绘制散点图
目录 一. 任务说明 二. 重点提示 三. 示例代码 四.散点hover交互效果的实现 4.1 基本算法 4.2 参考代码 4.3 Demo中的小问题 示例代码托管在:http://www.githu ...
- 【带着canvas去流浪】 (3)绘制饼图
目录 一. 任务说明 二. 重点提示 三. 示例代码 四. hover高亮的实现思路 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:< ...
随机推荐
- Solr的中英文分词实现
对于Solr应该不需要过多介绍了,强大的功能也是都体验过了,但是solr一个较大的问题就是分词问题,特别是中英文的混合分词,处理起来非常棘手. 虽然solr自带了支持中文分词的cjk,但是其效果实在不 ...
- EffictiveC++笔记 第1章
Chapter 一: 条款 1 :视 C++为一个语言联邦 (P41 ) c++其实可以视为有四个部分: C Object-Oriented C++ Template C++ STL 条款 2:尽量以 ...
- dubbo+zookeeper的使用
我们讨论过Nginx+tomcat组成的集群,这已经是非常灵活的集群技术,但是当我们的系统遇到更大的瓶颈,全部应用的单点服务器已经不能满足我们的需求,这时,我们要考虑另外一种,我们熟悉的内容,就是分布 ...
- ASP.Net Core MVC 发生二次请求
Bug回忆录 昨天搭建新框架的时候,遇到一个很奇怪的“Bug”,每次请求都会触发两次Aciton,举例子吧,Demo: _Layout.cshtml <!DOCTYPE html> < ...
- 你需要知道的这几种 asp.net core 修改默认端口的方式
一般情况下,aspnetcore发布后的默认端口是5000,这个大家都知道,而且默认骨架代码中没有看到任何让你输入的ip地址和端口号,但作为程序员的我们,不希望 被框架所管制,那如何实现默认端口的修改 ...
- Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget
前言 上一篇我们对 Flutter UI 有了一个基本的了解. 这一篇我们通过自定义 Widget 来了解下如何写一个 Widget? 然而 Widget 有两个,StatelessWidget 和 ...
- 关于ef+codefirst+mysql/dapper(dbFirse)(入门)
ef+mssql详细是许多.net程序员的标配.作为一个程序员当然不能只会mssql这一个数据库,今天简单聊聊ef+mysql.推荐新人阅读. 1]首先创建一个mvc项目,如图: 创建完毕之后再nug ...
- Iconfont 在HTML中的使用
一.准备阶段: a.进入阿里巴巴矢量图标库www.iconfont.cn挑选所需的图标,加入购物车 b.点击网页中的购物车下载代码 二.3种方法实现 Iconfont 的HTML显示 Unicode ...
- A项目轶事之加入项目2个月
A项目轶事之加入项目2个月 4月18号是我入A项目整整2个月的日子. 加入项目第一天,就发现A项目是一个大规模的SAP ERP项目. SAP各大模块,Salesforce, MES等各个系统相关的顾问 ...
- Android音视频之AudioRecord录音(一)
在音视频开发中,录音当然是必不可少的.首先我们要学会单独的录音功能,当然这里说的录音是指用AudioRecord来录音,读取录音原始数据,读到的就是所谓的PCM数据.对于录音来说,最重要的几个参数要搞 ...