最近笔者在学习HTML5的新元素<canvas>,会分享一些基础知识以及小例子,最终使用<canvas>实现一个绘制简单图表(条形图、线图或者饼图)的js库,会更新一到两篇文章~
下面我们开始吧~

确认宽度和高度

我们首先应该指定<canvas>标签即画布的宽度和高度属性,并在开始和闭合标签之间添加后备信息:

<html>
<head>
<meta charset="utf-8">
</head>
<body>
<canvas id="canvas" width="500" height="500">Canvas is not supported.</canvas>
</body>
</html>

取得绘图上下文

调用canvasgetContext()方法,这个方法接收一个参数,即上下文的名字:

var canvas = document.getElementById("canvas");
if(canvas.getContext) {
var context = canvas.getContext("2d")
}

上述例子中,我们在调用getContext()方法时,首先检测其是否存在,这是由于有的浏览器遇到HTML规范之外的标签时,也会创建一个DOM对象,比如我们在Chrome中尝试以下代码:

<ppp id="ppp"></ppp>
document.getElementById("ppp");
//<ppp id="ppp"></ppp>

因此即使当前浏览器不能兼容HTML规范中的canvas元素,同样会创建DOM对象,可其中却不存在getContext()
context上下文对象中包含了绘图需要的一系列属性和方法,大家在阅读本文时,记得区分属性和方法,改变属性会影响到后续的绘图效果,而调用方法往往是一次性的。

绘制简单的2D图形

坐标原点

2D上下文的坐标默认开始于左上角,原点坐标为(0, 0),使用translate(x, y)可以更改坐标原点。

填充

填充,就是用指定的样式,比如颜色、渐变或图像填充指定区域,对应的上下文属性为fillStyle,默认值为#000000, 比如:

context.fillStyle = "orange";
描边

描边就是在指定区域边缘画指定样式的线,比如:

context.strokeStyle = "grey";
绘制矩形

矩形是唯一一个可以在2D上下文中直接话的形状,其他的都需要绘制路径,可以使用3个方法直接绘制矩形。

fillRect(x, y, width, height)

可以绘制一个由fillStyle指定填充样式的矩形,比如:

context.translate(100, 100)
context.fillStyle = "#99cccc";
context.fillRect(-100, -50, 200, 100);
context.fillStyle="#3399cc";
context.fillRect(-60, -30, 120, 60);

strokeRect(x, y, width, height)

可以绘制一个由strokeStyle lineWidth lineCap lineJoin等属性指定描边样式的矩形,比如:

context.strokeStyle = "#99cccc";
context.lineWidth = "50";
context.lineJoin = "bevel";
context.strokeRect(0, 0, 400, 200);

属性名 含义 取值
lineCap 线条末端的形状 butt平头round圆头square方头
lineWidth 线条宽度 整数
lineJoin 线条相交的方式 round圆交bevel斜交mitter斜接
clearRect(x, y, width, height)

可以清楚画布上的指定区域,比如第一个例子中的两个矩形,我们将中间一小块清除:

context.translate(100, 100)
context.fillStyle = "#99cccc";
context.fillRect(-100, -50, 200, 100);
context.fillStyle="#3399cc";
context.clearRect(-60, -30, 120, 60);

绘制路径

使用路径我们可以绘制出比较复杂的图形,开始绘制前,首先执行:

context.beginPath();

结束绘制时,执行:

context.closePath();

以下我们列举了绘制路径的几个方法:

直线

lineTo(x, y),从当前游标至(x, y)画一条直线。

移动游标

moveTo(x, y) 将游标移动至(x, y),移动过程中不画线。比如:

context.beginPath();
context.moveTo(10, 10);
context.lineTo(50, 40);
context.moveTo(50, 50);
context.lineTo(100, 90);
context.stroke();
context.closePath();

弧线或圆形
arc(x, y, radius, startAngle, endAngle, counterclockwise)

从startAngle到endAngle绘制一条以(x, y)为圆心,radius为半径的弧线,其中startAngle和endAngle用弧度表示,couterclockwise为false时,顺时针画弧线, 反之,逆时针画弧线。

var canvas = document.getElementById("canvas");
if(canvas.getContext) {
var context = canvas.getContext("2d");
context.beginPath();
context.arc(400, 400, 50, arcUnit()*30, arcUnit()*180, false);
context.stroke();
}
function arcUnit() {
return Math.PI/180;
}

arcTo(startX, startY, endX, endY, radius)

arcTo()方法将利用当前坐标、起点(startX,startY)和终点(endX,endY)这三个点所形成的夹角,绘制一段与夹角的两边相切并且半径为radius的圆上的弧线。弧线的起点就是当前坐标所在边与圆的切点,弧线的终点就是终点(endX,endY)所在边与圆的切点,并且绘制的弧线是两个切点之间长度最短的那个圆弧。此外,如果当前端点不是(startX,startY),arcTo()方法还将添加一条当前端点到(startX,startY)的直线线段。
如果大家还记得高中数学的话,我们应该可以猜到,使用这个方法画弧线大致有三种情况:
** 只有一种半径可以使弧线两端正好在起点和终点
** 如果半径过大,画不出弧线
** 如果半径较小,必定会有一条当前端点到起点的直线
我们举三个例子:
首先定义一些通用的

var context = canvas.getContext("2d");
var currentPoint = {
x: 0,
y: 0
};
var startPoint = {
x: 50,
y: 50
};
var endPoint = {
x: 100,
y: 0
};

然后绘制参考线

context.moveTo(currentPoint.x, currentPoint.y);
context.lineTo(startPoint.x, startPoint.y);
context.lineTo(endPoint.x, endPoint.y);
context.strokeStyle = "red";
context.stroke();

画第一条弧线

context.moveTo(currentPoint.x, currentPoint.y);
context.arcTo(startPoint.x, startPoint.y, endPoint.x, endPoint.y, 80);
context.strokeStyle = "grey";
context.stroke();

context.arcTo(startPoint.x, startPoint.y, endPoint.x, endPoint.y, 120);

context.arcTo(startPoint.x, startPoint.y, endPoint.x, endPoint.y, 40);

曲线
二次贝塞尔曲线

quadraticCurveTo(cpX, cpY, x, y)
上述方法可以画一条从当前位置到(x, y), 以(cpX, cpY)为控制点的贝塞尔曲线

三次贝塞尔曲线

bezierCurveTo(cpX1, cpY1, cpX2, cpY2, x, y)
上述方法可以画一条从当前位置到(x, y), 以(cpX1, cpY1)和(cpX2, cpY2)为控制点的贝塞尔曲线。

二次贝塞尔与三次贝塞尔的绘制涉及到比较复杂的数学运算,笔者在此就忽略啦...
当然,大部分前端人士可能都跟笔者一样,只希望能画出一条优美的曲线,并不关心实现细节,那么一般认为什么样的曲线才算是优美的曲线呢:

  1. 对称的曲线
  2. 有一个适度的弧度

根据以上规则,我们写一个工具方法:

function drawCurvePath( ctx, start, end, curveness ) {
var cp = [
( start.x + end.x ) / 2 - ( start.y - end.y ) * curveness,
( start.y + end.y ) / 2 - ( end.x - start.x ) * curveness
];
ctx.moveTo( start.x, start.y );
ctx.quadraticCurveTo(
cp[ 0 ], cp[ 1 ],
end.x, end.y
);
ctx.stroke();
}

以上参考自用canvas绘制一个曲线动画——深入理解贝塞尔曲线,大家可以前往了解更深入的贝塞尔曲线画法。

矩形

使用rect(x, y, width, height)可以绘制一个左上角坐标为(x, y),宽width,高height的矩形路径。

context.rect(300, 300, 100, 200);
context.stroke();

绘制文本

在绘制本文之前,如果有必要,我们首先应该指定context的几个属性, 比如:

context.font = "bold 14px Arial"; // 格式同css中指定字体样式
context.textAlign = "center"; // start end center left right
context.textBaseline = "middle"; // top hanging middle alphabetic ideographic bottom

fillText(text, x, y, maxWidth)使用fillStyle属性显示文本,strokeText(text, x, y, maxWidth)使用strokeStyle属性为文本描边。
使用measureText(text)方法可以获得文本的宽度。如果我们并不清楚指定的宽度够不够显示当前字体设置下的一段文字,可以使用如下方法:

var fontSize = 50;
var maxWidth = 100;
context.font = "bold " + fontSize+"px Arial";
var text = "Hello World!";
while(context.measureText(text).width > maxWidth) {
fontSize--;
context.font = "bold " + fontSize+"px Arial";
}
context.fillText(text, 50, 50, maxWidth);

变换

旋转

rotate(angle)

context.rotate(Math.PI/4)
context.fillText(text, 50, 50, maxWidth);

缩放

scale(scaleX, scaleY)

context.scale(1.2, 1.2);
context.fillText(text, 50, 50, maxWidth);
context.scale(0.5, 0.5);
context.fillText(text, 50, 50, maxWidth);

移动坐标原点

translate(x, y)
假如我们要绘制一个对称图形,移动坐标原点将会大大简化对坐标的计算。

矩阵变换

使用transform(scaleX,skewX,skewY,scaleY,transX,transY)可以进行矩阵变换,其实以上讲的三个方法本质上都在调用矩阵变换,从参数名中可以看出,它们分别表示X轴方向的缩放,Y轴方向的缩放,X轴方向的斜切,Y轴方向的斜切,X轴方向的偏移量,Y轴方向的偏移量。默认值分别为1 0 0 1 0 0。
我们现在使用transform()重新定义一遍之前的三个方法:
rotate

function rotate (ctx, degree) {
var unit = Math.PI/180;
ctx.transform(Math.cos(degree*unit),Math.sin(degree*unit),-Math.sin(degree*unit),Math.cos(degree*unit),0,0)
}

scale

function scale (ctx, scale) {
ctx.transform(scale.x, 0, 0, scale.y, 0, 0);
}

translate

function translate (ctx, translate) {
ctx.transform(1, 0, 0, 1, translate.x, translate.y);
}

我们现在绘制一段文本,先平移(50, 50),然后缩放2倍,最后旋转30度。

context.fillText(text, 50, 50, maxWidth);
translate(context, {x: 50, y: 50});
scale(context, {x: 2, y: 2});
rotate(context, 30);
context.fillText(text, 50, 50, maxWidth);


每次执行transform()都是基于上一次的结果,并不是初始状态,很多时候我们想执行的是基于初始状态旋转、平移或缩放,而非上一次的状态,此时我们可以使用setTransfrom(scaleX,skewX,skewY,scaleY,transX,transY),此方法首先会重置变换矩阵,然后执行transform()
更加详细的内容可以参考html5 Canvas画图教程26:用transform来实现位移,缩放,旋转等

绘制图像

使用drawImage(image, x1, y1, width1, height1, x2, y2, width2, height2)可以将图像的指定部分按照指定的大小绘制到画布指定的位置上。

参数 含义
image 要绘制的图像,可以是HTMLImageElement,也可以是canvas
x1 源图像的x坐标
y1 源图像的y坐标
width1 源图像的宽度
height1 源图像的高度
x2 画布的x坐标
y2 画布的y坐标
width2 图像在画布上显示的宽度
height2 图像在画布上显示的高度

绘制阴影

如果要给形状或路径加上阴影,我们要在绘制前设置context对象的以下属性:

属性 含义
shadowColor 阴影颜色
shadowOffsetX x轴偏移量
shadowOffsetY y轴偏移量
shadowBlur 模糊的像素数
context.shadowColor = "grey";
context.shadowOffsetX = "20";
context.shadowBlur = "5";
context.fillText(text, 50, 50, maxWidth);

渐变

线性渐变

使用createLinearGradient(startX, startY, endX, endY)来创建线性渐变,这个方法确认了渐变的起始和方向,然后我们通过addColorStop(position, color)来添加渐变的颜色,position是0到1的数字。一下笔者画一个超级喜欢的条纹渐变:

var grad = context.createLinearGradient(50, 50, 200, 200)
grad.addColorStop(0, "grey");
grad.addColorStop(0.3, "grey");
grad.addColorStop(0.3, "red");
grad.addColorStop(0.5, "red");
grad.addColorStop(0.5, "orange");
grad.addColorStop(0.7, "orange");
context.fillStyle = grad;
context.fillRect(50, 50, 150, 150);

径向渐变

使用createRadialGradient(centerX1, centerY1, radius1, centerX2, centerY2, radius2)创建径向渐变。

图像重复

使用createPattern(image, repeatType)可以绘制重复的图像,用来填充或描边,第一个参数是要重复的HTMLImageElement或canvas或video,第二个参数表示如何重复该图像,可取repeat repeat-x repeat-y no-repeat

HTML5 Canvas(基础知识)的更多相关文章

  1. HTML5 Canvas基础知识

    HTML5画布 1.创建一个画布         <canvas id="myCanvas" width="200" height="100&q ...

  2. 《HTML5 CANVAS基础教程》读书笔记

    一.HTML5简介 1.HTML5新特性 1)结构元素:section,header,hgroup,footer,nav,article,aside, 2)内容元素:figure,figcaption ...

  3. canvas 基础知识整理(二)

    html部分: <canvas id="myCanvas" width="800" height="800" ></can ...

  4. canvas 基础知识整理(一)

    canvas这个 HTML 元素是为了客户端矢量图形而设计的.它自己没有行为,但却把一个绘图 API 展现给客户端 JavaScript 以使脚本能够把想绘制的东西都绘制到一块画布上. html的基本 ...

  5. canvas基础知识

    canvas基础知识 ## CanvasDOM对象 #### 获取绘图环境```canvas.getContext();``` #### 设置宽和高```canvas.width = 500;canv ...

  6. canvas API ,通俗的canvas基础知识(四)

    今天要讲的内容是canvas的转换功能,前面的内容没用看的同学可以出门右转,先看看前面的基础知识,废话不多说,开始进入正题吧! 何为转换功能?熟悉css3的同学都知道,css3里面有transform ...

  7. canvas 基础知识

    canvas 基础 低版本的ie不支持html5,需要引入excanvas.js来让ie支持canvas. 检测支持canvas <canvas id="canvas" wi ...

  8. canvas API ,通俗的canvas基础知识(一)

    在没学canvas的时候,觉得canvas是这么的神秘,这么的绚丽,这么的高深,用canvas做出来的效果是如此的炫酷,能做的事情如此的宽广,简直让我心生敬畏之心,时常感叹:我要是得此技能,必定要上天 ...

  9. HTML5 <canvas> 基础学习

    HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成. <canvas> 标签只是图形容器,您必须使用脚本来绘制图形 创建一个画布( ...

  10. HTML5 canvas准备知识

    利用canvas来进行画图工作.因此,我们有必要进行一些画图方面的术语说明. 一.画布 在日常生活中,如果我们要画画,可以找纸.板.画布等等工具.而在网页元素中,我们只需要定义一个标签即可. < ...

随机推荐

  1. 吴裕雄--天生自然python学习笔记:python 建立 Firebase 数据库连接

    Python 程序通过 python-firebase 包可以存取 Firebase 数据库. 使用 python-firebase 包 首先必须安装 python-firebase 包,安装方法如下 ...

  2. 吴裕雄--天生自然C语言开发:指针

    #include <stdio.h> int main () { int var1; ]; printf("var1 变量的地址: %p\n", &var1 ) ...

  3. PAT甲级——1061 Dating

    1061 Dating Sherlock Holmes received a note with some strange strings: Let's date! 3485djDkxh4hhGE 2 ...

  4. 5-7 学生cpp成绩统计

    完成“学生cpp成绩计算”之后,修改Person和Student类,各自增加两个无参构造函数. 仍以Person类为基础,建立一个派生类Teacher,增加以下成员数据: int ID;//教师工号 ...

  5. IDEA Maven项目中添加tomcat没有无artifact选项

    IntelliJ使用 ##使用IntelliJ IDEA配置web项目时,选择Edit Configration部署Tomcat的Deployment可能会出现以下情况: 导致新手部署过程中摸不着头脑 ...

  6. ReactJS - 组件的生命周期

    组件的生命周期分为三个状态 Mounting: 已插入真实DOM Updateing: 正在被重新渲染 Unmounting: 已移出真实DOM React 为每个状态都提供了两种处理函数,即函数在进 ...

  7. 构造函数中可以进行if判断

  8. [LC] 191. Number of 1 Bits

    Write a function that takes an unsigned integer and return the number of '1' bits it has (also known ...

  9. wios设置证书登陆

    设置wios为密钥登陆set service ssh 'allow-root' set service ssh 'disable-password-authentication' //禁用密码登陆 s ...

  10. 推荐几位jenkins发布war包和jar包大佬的博客

    jenkins部署tomcat的war包和jar包 https://blog.csdn.net/liuxiaoming1109/article/details/89311696