资讯专栏INFORMATION COLUMN

HTML5 Canvas(基础知识)

2json / 2857人阅读

摘要:比如弧线或圆形从到绘制一条以为圆心,为半径的弧线,其中和用弧度表示,为时,顺时针画弧线,反之,逆时针画弧线。

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

确认宽度和高度

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


  
    
  
  
    Canvas is not supported.
  
取得绘图上下文

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

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

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

document.getElementById("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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/52304.html

相关文章

  • html5canvas

    摘要:是新加的标签,主要有和,的应用是动画和图像,的应用是游戏渲染。 HTML5 Canvas canvas是html5新加的标签,主要有2D和3D,2D的应用是动画和图像,3D的应用是游戏渲染。 1. 2D基础 1.1绘制线 canvas window.onload = function(){ ...

    苏丹 评论0 收藏0
  • html5canvas

    摘要:是新加的标签,主要有和,的应用是动画和图像,的应用是游戏渲染。 HTML5 Canvas canvas是html5新加的标签,主要有2D和3D,2D的应用是动画和图像,3D的应用是游戏渲染。 1. 2D基础 1.1绘制线 canvas window.onload = function(){ ...

    PingCAP 评论0 收藏0
  • HTML5 Canvas游戏开发实战 PDF扫描版

    摘要:游戏开发实战主要讲解使用来开发和设计各类常见游戏的思路和技巧,在介绍相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读者不仅知其然,而且知其所以然。HTML5 Canvas游戏开发实战主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧,在介绍HTML5 Canvas相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读者不仅知其然,而且知其所以然。在本书...

    cocopeak 评论0 收藏0
  • 前端知识点总结——H5

    摘要:前端知识点总结新特性新的语义标签增强型表单音频和视频绘图绘图地理定位拖动增强型表单新新的表单元素新特性数据列表本身不可见为提供输入建议列表新特性进度条左右晃动进度条具有指定进度值进度条新特性刻度尺用于标示一个值所值的范围不 前端知识点总结——H5 1.html5新特性 (1)新的语义标签 (2)增强型表单* (3)音频和视频 (4)Canvas绘图 (5)SVG绘图 (6)地...

    el09xccxy 评论0 收藏0
  • 前端知识点总结——H5

    摘要:前端知识点总结新特性新的语义标签增强型表单音频和视频绘图绘图地理定位拖动增强型表单新新的表单元素新特性数据列表本身不可见为提供输入建议列表新特性进度条左右晃动进度条具有指定进度值进度条新特性刻度尺用于标示一个值所值的范围不 前端知识点总结——H5 1.html5新特性 (1)新的语义标签 (2)增强型表单* (3)音频和视频 (4)Canvas绘图 (5)SVG绘图 (6)地...

    用户84 评论0 收藏0
  • SegmentFault 技术周刊 Vol.20 - 用 Canvas 画个星空

    摘要:在最后,推荐给大家几个相关的库,增加使用时的便捷。周刊筛选的每篇内容,是作者的独到见解,踩坑总结和经验分享。每周二更新,欢迎关注或者订阅。 showImg(https://sfault-image.b0.upaiyun.com/382/562/382562537-5874b30ad612b); SegmentFault 曾举办过一个社区官方的比赛「30 行 js 你能做出什么?」,产生...

    peixn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<