HTML5 Canvas(基础知识)
最近笔者在学习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>
取得绘图上下文
调用canvas的getContext()方法,这个方法接收一个参数,即上下文的名字:
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)为控制点的贝塞尔曲线。
二次贝塞尔与三次贝塞尔的绘制涉及到比较复杂的数学运算,笔者在此就忽略啦...
当然,大部分前端人士可能都跟笔者一样,只希望能画出一条优美的曲线,并不关心实现细节,那么一般认为什么样的曲线才算是优美的曲线呢:
- 对称的曲线
- 有一个适度的弧度
根据以上规则,我们写一个工具方法:
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(基础知识)的更多相关文章
- HTML5 Canvas基础知识
HTML5画布 1.创建一个画布 <canvas id="myCanvas" width="200" height="100&q ...
- 《HTML5 CANVAS基础教程》读书笔记
一.HTML5简介 1.HTML5新特性 1)结构元素:section,header,hgroup,footer,nav,article,aside, 2)内容元素:figure,figcaption ...
- canvas 基础知识整理(二)
html部分: <canvas id="myCanvas" width="800" height="800" ></can ...
- canvas 基础知识整理(一)
canvas这个 HTML 元素是为了客户端矢量图形而设计的.它自己没有行为,但却把一个绘图 API 展现给客户端 JavaScript 以使脚本能够把想绘制的东西都绘制到一块画布上. html的基本 ...
- canvas基础知识
canvas基础知识 ## CanvasDOM对象 #### 获取绘图环境```canvas.getContext();``` #### 设置宽和高```canvas.width = 500;canv ...
- canvas API ,通俗的canvas基础知识(四)
今天要讲的内容是canvas的转换功能,前面的内容没用看的同学可以出门右转,先看看前面的基础知识,废话不多说,开始进入正题吧! 何为转换功能?熟悉css3的同学都知道,css3里面有transform ...
- canvas 基础知识
canvas 基础 低版本的ie不支持html5,需要引入excanvas.js来让ie支持canvas. 检测支持canvas <canvas id="canvas" wi ...
- canvas API ,通俗的canvas基础知识(一)
在没学canvas的时候,觉得canvas是这么的神秘,这么的绚丽,这么的高深,用canvas做出来的效果是如此的炫酷,能做的事情如此的宽广,简直让我心生敬畏之心,时常感叹:我要是得此技能,必定要上天 ...
- HTML5 <canvas> 基础学习
HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成. <canvas> 标签只是图形容器,您必须使用脚本来绘制图形 创建一个画布( ...
- HTML5 canvas准备知识
利用canvas来进行画图工作.因此,我们有必要进行一些画图方面的术语说明. 一.画布 在日常生活中,如果我们要画画,可以找纸.板.画布等等工具.而在网页元素中,我们只需要定义一个标签即可. < ...
随机推荐
- day29-struct模块解决黏包问题
#struct模块可以把一个数据类型,例如数字int,转化成固定长度(4个字节)的bytes.int转为4个bytes. #在大量传输数据之前先告诉接收端即将接收数据的大小,方可解决黏包问题: #利用 ...
- 电脑莫名重启,VS代码丢失的解决办法
今天写了一天的代码,然后电脑放在公司了,出去看电影(公司组织红色文化培训..)回来发现电脑重启,再打开电脑,VS的代码都不见了.好慌.... 别慌处理办法来了: 打开everything(没有的可以下 ...
- TreeviewEditor.rar
本工具可以打开.保存指定格式的XML文件. 树形控件的节点可以编辑.删除.增加.使用本工具看方便地创建书或论文的目录大纲,我用这个工具已经写了好几本书了. 动态图1: 动态图2:编辑效果,支持节点拖曳 ...
- Fastjson主要接口和类库说明
2.主要的使用入口 Fastjson API入口类是com.alibaba.fastjson.JSON,常用的序列化操作都可以在JSON类上的静态方法直接完成. public static final ...
- 专利|Pct||
专利:有些专利写的尽量模糊,为了不让别人检出,让别人能轻易侵犯专利权 优先权:在本国申请后,在他国也是同一个专利人申请,并也是同一个申请日. 发明20年:实用新型外观设计:20年 Pct:专利合作条约 ...
- [蓝桥杯2015初赛]方程整数解 unordered_map
unordered_map: 如果直接写报错加上tr1: #include<tr1/unordered_map>//注意写法 using namespace std; using name ...
- 使用jQuery在屏幕上居中一个DIV
文章目录 我如何去使用jQuery在屏幕的中心设置<div>? 我喜欢给jQuery添加函数,所以这个函数将有助于: jQuery.fn.center = function () { th ...
- 统计学方法(t-检验)
数据出来要做几件事:首先判断数据是否符合正态分布,如果符合的话,就要进行t-检验,那么进行t-检验的作用在哪呢? t-检验主要用于样本含量较小(例如n<30),总体标准差σ未知的正态分布 htt ...
- pycharm中无法调用pip的安装包
https://blog.csdn.net/sinat_23619409/article/details/79962518 较详细:https://blog.csdn.net/weixin_41287 ...
- Adam项目展示微软研究院人工智能领域新突破
编者按:在美国时间7月14日举行的2014年微软教育峰会上,Adam项目面对牵上台的3只小狗,一一准确地报出了它们的品种.Adam项目代表了微软研究院在机器学习和人工智能领域的前沿进展.它可不仅仅认得 ...