html5 ctx,HTML5 Canvas(基础知识)

本文介绍了HTML5 Canvas的基本用法,包括设置画布尺寸、获取绘图上下文、坐标变换、填充与描边、绘制2D图形如矩形、路径、文本以及图像。通过实例展示了如何使用Canvas绘制条形图、线图或饼图,为创建自定义图表库奠定了基础。涉及的关键技术包括路径绘制、阴影、渐变和图像处理。
摘要由CSDN通过智能技术生成

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

下面我们开始吧~

确认宽度和高度

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

Canvas is not supported.

取得绘图上下文

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

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);

1460000014745663

strokeRect(x, y, width, height)

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

context.strokeStyle = "#99cccc";

context.lineWidth = "50";

context.lineJoin = "bevel";

context.strokeRect(0, 0, 400, 200);

1460000014745664

属性名

含义

取值

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);

1460000014745665

绘制路径

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

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();

1460000014745666

弧线或圆形

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;

}

1460000014745667

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();

1460000014745668

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

1460000014745669

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

1460000014745670

曲线

二次贝塞尔曲线

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);

1460000014745671

变换

旋转

rotate(angle)

context.rotate(Math.PI/4)

context.fillText(text, 50, 50, maxWidth);

1460000014745672

缩放

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);

1460000014745673

移动坐标原点

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);

1460000014745674

每次执行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);

1460000014745675

渐变

线性渐变

使用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);

1460000014745676

径向渐变

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

图像重复

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值