Canvas在线教程

Canvas在线教程

HTML5 Canvas 学习概览

HTML5 Canvas元素本身是一个HTML元素,用于在Canvas上工作的API是javascript API。我们将在后面的文章中逐一对其进行介绍。

声明一个Canvas元素

现在,让我们来看看如何在HTML页面中声明一个Canvas元素。

<canvas id="ex1" width="500" height="150" style="border: 1px solid #cccccc;">
    你的浏览器不支持HTML5 Canvas!
</canvas>

上面的代码声明了一个Canvas元素,它的宽度为500,高度为150,并且设置了1个像素的灰色描边。

如果浏览器支持HTML5 Canvas元素,那么在<canvas>中的文字会被忽略。如果浏览器不支持HTML5 Canvas元素,这些文字会被作为提示文字显示出来。

你可以将<canvas>元素放置在页面中任何你想显示它的地方,例如放置在一个<div>中。

在Canvas元素上绘制图形

在HTML5 Canvas上绘制图形是一种即时模式(immediate mode)。所谓的即时模式是指一旦在Canvas上绘制了图形之后,Canvas将不再知道这个图形的任何信息。被绘制的图形是可见的,但是你不能够操作这个图形。它就像一块正真的画布,在你绘制图形之后,留在上面的只是一些颜色(像素)。

这是Canvas和SVG同的地方,SVG图形是可以被单独操纵的,也可以被重新绘制。在HTML5 canvas中如果你想修改绘制的图形,你需要重新绘制所有的东西。

要想在HTML5 canvas中绘制各种图形,需要使用javascript。下面是绘制的步骤:

1、等待页面DOM元素加载完毕。
2、获取canvas元素的引用。
3、从canvas元素中获取一个2D上下文(context)。
4、从2D上下文中使用绘制函数绘制图形。
下面是一个简单的例子,它遵从了上面的4个步骤来在canvas中绘制一个矩形。

<script>
    // 1. 等待页面DOM元素加载完毕。
    window.onload = function() {
        drawExamples();
    }

    function drawExamples(){

        // 2. 获取canvas元素的引用。
        var canvas  = document.getElementById("ex1");

        // 3. 从canvas元素中获取一个2D上下文(context)。
        var context = canvas.getContext("2d");

        // 4. 从2D上下文中使用绘制函数绘制图形。
        context.fillStyle = "#ff0000";
        context.fillRect(10,10, 100,100);
    }
</script>                              

在上面的代码中,首先在window对象中添加了一个事件监听。这个事件监听函数在页面页面加载完成之后被执行。这个函数会调用一个已经定义好的函数drawExamples()。

接着,drawExamples()函数通过document.getElementById()方法获取canvaas元素的引用。然后,通过在canvas引用上执行getContext(“2d”)方法获取一个2D上下文。

最后,就可以在这个2D上下文中使用绘制函数来绘制图形了。

下面是上面代码的返回结果。

HTML5 Canvas:绘制矩形

不论你在HTML5 canvas上绘制什么图形,有两个属性是你必须设置的:

描边属性-stroke
填充属性-fill
填充属性和描边属性决定如何来绘制图形。stroke是图形的外轮廓边框。fill则是图形的填充颜色。

下面是一个简单的例子,在Canvas中绘制了一个蓝色边框和绿色填充的矩形(实际上这是两个矩形):

上面例子的实现代码如下:

// 1. 等待页面DOM元素加载完毕
window.onload = function() {
    drawExamples();
}
function drawExamples(){
    // 2. 获取canvas元素的引用
    var canvas  = document.getElementById("ex1");

    // 3. 从canvas元素中获取一个2D context
    var context = canvas.getContext("2d");

    // 4. 绘制图形
    context.fillStyle = "#009900";
    context.fillRect(10,10, 100,100);

    context.strokeStyle = "#0000ff";
    context.lineWidth   = 5;
    context.strokeRect(10,10, 100,100);
}                            

注意上面的填充样式和描边样式是分别设置的。分别是使用2D上下文的strokeStyle和fillStyle属性。

描边的宽度使用的是lineWidth属性,lineWidth设置为5表示矩形的外边框的线条宽度为5个单位。

绘制矩形

在HTML5 canvas中,可以绘制的最简单的图形莫过于绘制一个矩形。在上面的例子中我们就绘制了两个矩形。它们分别是通过2D上下文的fillRect()方法和strokeRect()方法来实现的。

绘制矩形的代码如下:

var canvas  = document.getElementById("ex1");
var context = canvas.getContext("2d");

context.fillStyle = "#ff0000";
context.fillRect(10,10, 100,100);

context.strokeStyle = "#0000ff";
context.strokeRect(30,20, 120,110);        

fillRect()

fillRect()方法用于绘制一个填充颜色的矩形。它由x和y属性决定矩形的左上角位置,width和height实现决定矩形的宽度和高度。

请记住,canvas的坐标系统由canvas的左上角(0,0)坐标开始,然后X轴向右为正值方向,Y轴向下为正值方向。它的Y轴和正常的几何坐标系统是相反的。

x、y、width和height4个变量作为参数传入fillRect()中,用以确定如何绘制这个矩形。下面是一个例子:

var x = 10;
var y = 10;
var width  = 100;
var height = 100;

context.fillRect(x, y, width, height);  

下面是上面的代码所绘制的矩形:

上面的矩形是黑色的,是因为我们没有设置2D上下文的fillStyle属性,它默认的颜色就是黑色的。

strokeRect()

strokeRect()方法用于绘制一个描边矩形,没有填充色。同样,它由x和y属性决定矩形的左上角位置,width和height实现决定矩形的宽度和高度。熄灭是一个例子:

var x = 10;
var y = 10;
var width  = 100;
var height = 100;

context.strokeRect(x, y, width,height); 

上面代码的返回结果如下:

同样,在我们没有设置2D上下文的strokeStyle属性的情况下,描边色是黑色的。

你可以使用2D上下文的lineWidth属性来设置描边的宽度。例如下面的例子:

var x = 10;
var y = 10;
var width  = 100;
var height = 100;

context.lineWidth = 4;
context.strokeRect(x, y, width, height);      

上面的代码的返回结果如下:

矩形的颜色

你可以使用2D上下文的fillStyle和strokeStyle来设置绘制矩形的颜色。例如下面的例子:

var canvas  = document.getElementById("ex1");
var context = canvas.getContext("2d");

context.fillStyle = "#f2784b";
context.fillRect(10,10, 100,100);

context.lineWidth   = 4;
context.strokeStyle = "#049372";
context.strokeRect(30,20, 120,110);  

上面的代码的返回结果如下:

clearRect()

2D上下文的clearRect()函数用于在Canvas中清除一个矩形区域。被清除的矩形区域变为透明。下面是一个例子:

var canvas  = document.getElementById("ex1");
var context = canvas.getContext("2d");

context.fillStyle = "#ff0000";
context.fillRect(10,10, 100,100);

context.strokeStyle = "#0000ff";
context.strokeRect(30,20, 120, 110);

context.clearRect(50, 30, 110, 35);    

上面代码的而返回结果如下:

注意观察上面的图形,红色和蓝色矩形分别被清除掉一部分。因为clearRect()会使矩形区域变得透明,而canvas元素位于其它元素的上面,所以透过透明区域可以看到这些canvas元素。

clearRect()和矩形一样也可以传入4个参数:clearRect(x, y, width, height)。这4个参数的意义和矩形的描述是相同的。

HTML5 Canvas:绘制路径

一条HTML5 canvas路径是通过绘制指令来连接一系列的点,由这一系列的点构成直线或曲线。路径可以用于在HTML5 canvas上绘制各种类型的图形:直线、圆形、多边形等等。路径的绘制是canvas的核心,必须很好的理解和掌握。

开始和关闭一条路径

要开始和关闭一条路径可以使用2D上下文的beginPath()和closePath()函数。例如下面的例子:

var canvas  = document.getElementById("ex1");
var context = canvas.getContext("2d");

context.beginPath();

//... 绘制路径

context.closePath();                                

moveTo()函数

当你在canvas中绘制一条路径的时候,你可以想象自己正在使用一支“虚拟笔”。这支虚拟笔总是位于某个位置,你可以使用2D上下文的moveTo(x, y)函数来移动这支虚拟笔。例如下面的代码:

context.moveTo(10,10);
这个例子将“虚拟笔”移动到(10,10)这个坐标点上。

lineTo()函数

lineTo函数用于从虚拟笔的当前位置绘制一条直线到lineTo()函数中指定的点。下面是一个例子:

context.beginPath();

context.moveTo(10,10);
context.lineTo(50,50);

context.closePath();                                

这个例子中首先移动虚拟笔到(10,10)坐标点位置,然后从这个点绘制一条直线到(50,50)坐标点。

lineTo()函数还会将虚拟笔移动到执行的结束点位置。上面的例子中是移动到(50,50)的位置。

stroke()函数 + fill()函数

在你没有通知2D上下文绘制路径之前,实际是不会在画布上绘制任何东西的。你可以通过stroke()或fill()函数来通知2D上下文。

stroke()函数用于路径操作指定的图形的外轮廓。

fill()函数用于填充有路径操作指定的图形。

下面的例子展示了stroke()或fill()函数的用法。

context.beginPath();
context.moveTo(10,10);
context.lineTo(60,50);
context.lineTo(110,50);
context.lineTo(10,10);
context.stroke();
context.closePath();

context.beginPath();
context.moveTo(100,10);
context.lineTo(150,50);
context.lineTo(200,50);
context.lineTo(100,10);
context.fill();
context.closePath();                                

上面代码的返回结果如下:

线条的宽度

你可以使用2D上下文的lineWidth属性来设置绘制线条的宽度。下面是一个例子:

context.lineWidth = 10;                                

上面的例子设置绘制线条的宽度为10像素。

下面的例子绘制3条直线,它们的宽度分别为1,5和10。

当你绘制的线条宽度大于1的时候,扩展的线条宽度将平均分配在线条中心线的两侧。距离来说,如果你从(10,10)这个点绘制一条直线到(100,10)这个点,线条的宽度为10,那么,实际上是从(10,5)这个点开始绘制,然后扩展到(10,15)这个点,在水平绘制到(100,5)和(100,15)这两个点,就像是绘制一个矩形。

线条的线条(Line Cap)

在使用路径来绘制线条的时候,你可以设置线条的线头样式。线头的样式通过2D上下文的lineCap属性来设置。它有三个可选值:

butt样式的线头是扁平且和线正交的样式。

round样式的线头是一个圆角的线头,圆的半径等于线条宽度的一半。

square样式的线头会在线的末端绘制一个矩形。矩形的大小为:线条的宽度 X 线条的宽/2。

下面是几个不同线头样式的线条的例子。所有的线条的宽度都是10。最总版的一组线条的lineCap的取值为butt,中间的一组线条的lineCap的取值为round,最右边的一组线条的lineCap的取值为square。

lineCap的取值butt和square非常相似。有时难以区别。这里制作了几个小例子,从这些例子中你可以看出它们之间的微小差别。下面又三组线条,每一组左边(或上边)的线条的lineCap属性取值为butt,右边(或下边)的线条的lineCap属性取值为square。

正如上面的结果所示,square线头的线条要比butt线头的线条要长。

线条的连接

2D上下文的lineJoin属性用于定义两条线条连接处的点如何绘制。两条线条连接处的点被称为“连接点”。lineJoin属性有下面的三种取值:

下面是这三种取值的示例代码:

context.lineJoin = "miter";
context.lineJoin = "bevel";
context.lineJoin = "round"; 

miter的连接点是一个三角形的连接点。

bevel的连接点是一个平头的连接点。

round的连接点是一个圆角的连接点。

下面分别是三种线条连接点的例子,从左到右的lineJoin属性分别是:miter,bevel和round。

绘制曲线

2D上下文的arc()函数可以用于绘制一条曲线。arc()函数有6个参数:

下面是一段示例代码:

context.lineWidth = 3;

var x = 50;
var y = 50;
var radius = 25;
var startAngle = (Math.PI / 180) * 45;
var endAngle   = (Math.PI / 180) * 180;
var anticlockwise = false;

context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, anticlockwise);
context.stroke();
context.closePath();                                

上面的代码绘制了一条弧线,它的中心点位于(50,50)坐标点,半径为25,从45度开始到180度结束。

下面是上面代码的返回结果:

上面的例子如果将anticlockwise设置为true,会得到下面的结果:

如果你要花一个完整的圆,可以简单的设置startAngle为0,endAngle设置为2 * Math.PI,它相当于(Math.PI / 180) * 360。

arcTo()函数

2D上下文中有一个arcTo()函数,它用于从当前的点绘制一条曲线到参数指定的点,曲线的半径也由参数指定。它的语法为:arcTo(x1, y1, x2, y2, radius)。注意:参数中x1, y1, x2, y2指的是这个点的控制点。arcTo()函数可以使用lineTo()和arc函数来模仿。

quadraticCurveTo()函数

quadraticCurveTo()函数用于绘制一条二次贝兹曲线。这条曲线由一个控制点来控制,它的语法为:quadraticCurveTo(cp1x, cp1y, x, y)。下面是一个示例代码:

context.lineWidth = 3;

var fromX = 50;
var fromY = 50;
var toX   = 100;
var toY   = 50;
var cpX   = 75;
var cpY   = 100;

context.beginPath();
context.moveTo(fromX, fromY);
context.quadraticCurveTo(cpX, cpY, toX, toY);
context.stroke();
context.closePath();                                

上面的代码绘制一条从(50,50)开始到(100,50)的二次贝兹曲线,这条曲线的控制点为(75,100)。得到的结果如下所示:

仔细看,在曲线下方有一个小点,那是这条曲线的控制点。(这个点是专门绘制出来让大家看的)

关于控制点,可以参考下面的图像:

bezierCurveTo()函数

bezierCurveTo()函数用于从一个点到另一个点绘制一条三次贝兹曲线。三次贝兹曲线有两个控制点,而二次贝兹曲线只有一个控制点。它的语法为:bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)。下面是一个例子:

context.lineWidth = 3;

var fromX = 50;
var fromY = 50;
var toX   = 300;
var toY   = 50;
var cp1X   = 100;
var cp1Y   = 100;
var cp2X   = 250;
var cp2Y   = 100;

context.beginPath();
context.moveTo(fromX, fromY);
context.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, toX, toY);
context.stroke();
context.closePath();  

这段代码从(50,50)绘制一条三次贝兹曲线到(300,50),两个控制点分别为:(100,100)和(250,100)。得到的结果如下:

曲线下方的两个小圆点是两个控制点,他们并不是曲线的一部分。

下面是一个不同的例子,它的开始点和结束点于上面的例子相同,但是控制点和上面的例子不相同。

context.lineWidth = 3;

var fromX = 50;
var fromY = 50;
var toX   = 300;
var toY   = 50;
var cp1X   = 100;
var cp1Y   = 10;
var cp2X   = 250;
var cp2Y   = 100;

context.beginPath();
context.moveTo(fromX, fromY);
context.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, toX, toY);
context.stroke();
context.closePath();  

上面的代码得到的结果如下:

文章的最后,我们引用MDN上的一个例子,它用Canvas路径绘制出“吃豆人”游戏的一个小场景:

实现的代码如下:

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    roundedRect(ctx,12,12,150,150,15);
    roundedRect(ctx,19,19,150,150,9);
    roundedRect(ctx,53,53,49,33,10);
    roundedRect(ctx,53,119,49,16,6);
    roundedRect(ctx,135,53,49,33,10);
    roundedRect(ctx,135,119,25,49,10);

    ctx.beginPath();
    ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false);
    ctx.lineTo(31,37);
    ctx.fill();

    for(var i=0;i<8;i++){
      ctx.fillRect(51+i*16,35,4,4);
    }

    for(i=0;i<6;i++){
      ctx.fillRect(115,51+i*16,4,4);
    }

    for(i=0;i<8;i++){
      ctx.fillRect(51+i*16,99,4,4);
    }

    ctx.beginPath();
    ctx.moveTo(83,116);
    ctx.lineTo(83,102);
    ctx.bezierCurveTo(83,94,89,88,97,88);
    ctx.bezierCurveTo(105,88,111,94,111,102);
    ctx.lineTo(111,116);
    ctx.lineTo(106.333,111.333);
    ctx.lineTo(101.666,116);
    ctx.lineTo(97,111.333);
    ctx.lineTo(92.333,116);
    ctx.lineTo(87.666,111.333);
    ctx.lineTo(83,116);
    ctx.fill();

    ctx.fillStyle = "white";
    ctx.beginPath();
    ctx.moveTo(91,96);
    ctx.bezierCurveTo(88,96,87,99,87,101);
    ctx.bezierCurveTo(87,103,88,106,91,106);
    ctx.bezierCurveTo(94,106,95,103,95,101);
    ctx.bezierCurveTo(95,99,94,96,91,96);
    ctx.moveTo(103,96);
    ctx.bezierCurveTo(100,96,99,99,99,101);
    ctx.bezierCurveTo(99,103,100,106,103,106);
    ctx.bezierCurveTo(106,106,107,103,107,101);
    ctx.bezierCurveTo(107,99,106,96,103,96);
    ctx.fill();

    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.arc(101,102,2,0,Math.PI*2,true);
    ctx.fill();

    ctx.beginPath();
    ctx.arc(89,102,2,0,Math.PI*2,true);
    ctx.fill();
  }
}

// A utility function to draw a rectangle with rounded corners.

function roundedRect(ctx,x,y,width,height,radius){
  ctx.beginPath();
  ctx.moveTo(x,y+radius);
  ctx.lineTo(x,y+height-radius);
  ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
  ctx.lineTo(x+width-radius,y+height);
  ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
  ctx.lineTo(x+width,y+radius);
  ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
  ctx.lineTo(x+radius,y);
  ctx.quadraticCurveTo(x,y,x,y+radius);
  ctx.stroke();
}                                

HTML5 Canvas:绘制渐变色

HTML5 Canvas渐变是一种用于填充或描边图形的颜色模式。渐变色是由不同的颜色进行过渡,而不是单一的颜色。先来看几个canvas渐变色的例子:

渐变按照类型来分可以分为两种类型:

线性渐变以线性的模式来改变颜色,也就是水平,垂直或对角方向。

径向渐变以圆形模式来改变颜色,颜色以圆形的中心向外辐射。

线性渐变

正如前面所说,线性渐变以线性的模式来改变颜色。我们可以通过2D上下文的createLinearGradient()方法来创建一个线性渐变。下面是一个例子:

var canvas  = document.getElementById("ex1");
var context = canvas.getContext("2d");

var x1 =   0;
var y1 =   0;
var x2 = 100;
var y2 =   0;
var linearGradient1 = context.createLinearGradient(x1,y1,x2,y2);        

createLinearGradient()函数有4个参数:x1,y1,x2和y2。这4个参数决定渐变的方向和距离。线性渐变会从第一个点(x1,y1)扩展到第二个点(x2,y2)。

水平的线性渐变仅仅是水平方向的参数值(x1和x2)不同,例如:

var x1 =   0;
var y1 =   0;
var x2 = 100;
var y2 =   0;
var linearGradient1 = context.createLinearGradient(x1,y1,x2,y2);                                

垂直的线性渐变仅仅是垂直方向的参数值(y1和y2)不同,例如:

var x1 =   0;
var y1 =   0;
var x2 =   0;
var y2 = 100;
var linearGradient1 = context.createLinearGradient(x1,y1,x2,y2);  

一个对角线的线性渐变水平和垂直方向上的参数都不相同,例如:

var x1 =   0;
var y1 =   0;
var x2 = 100;
var y2 = 100;
var linearGradient1 = context.createLinearGradient(x1,y1,x2,y2);         

颜色停止点(Color Stops)

在上面的例子中,并没有指明线性渐变使用什么颜色。为了指明使用什么渐变颜色,可以在渐变对象上使用addColorStop()方法来指定。例如:

var linearGradient1 = context.createLinearGradient(0,0,100,0);
linearGradient1.addColorStop(0, 'rgb(255, 0, 0)');
linearGradient1.addColorStop(1, 'rgb(  0, 0, 0)');

addColorStop()方法有两个参数。第一个参数是0-1之间的一个数值,这个数值指定该颜色进入渐变多长的距离,第二个参数是颜色值,例子中使用的是rgb()颜色值。

在上面的例子中为渐变添加了两种颜色。第一种颜色是红色,设置在渐变的开始处。第二种颜色是黑色,设置在渐变的结束处。

你可以添加通过addColorStop()函数来添加更多的颜色。例如下面的例子添加了三种颜色:

var linearGradient1 = context.createLinearGradient(0,0,100,0);
linearGradient1.addColorStop(0  , 'rgb(255, 0, 0)');
linearGradient1.addColorStop(0.5, 'rgb(  0, 0, 255);
linearGradient1.addColorStop(1  , 'rgb(  0, 0, 0)');  

上面的代码在渐变的中间添加了一个蓝色。整个渐变将平滑的从红色过渡到蓝色,在过渡到黑色。

使用渐变来填充和描边图形

你可以使用渐变来填充或描边图形。要填充或描边图形可以通过2D上下文的fillStyle或strokeStyle属性来完成。下面是一个示例代码:

var linearGradient1 = context.createLinearGradient(0,0,100,0);
linearGradient1.addColorStop(0  , 'rgb(255, 0, 0)');
linearGradient1.addColorStop(0.5, 'rgb(  0, 0, 255);
linearGradient1.addColorStop(1  , 'rgb(  0, 0, 0)');

context.fillStyle   = linearGradient1;

context.strokeStyle = linearGradient1;  

通过fillStyle或strokeStyle属性来指向渐变对象即可完成渐变的填充或描边。

现在我们可以为图形填充渐变色或描边渐变色。下面是一个例子,一个矩形的填充渐变色和一个矩形的描边渐变色。

var canvas  = document.getElementById("ex2");
var context = canvas.getContext("2d");

var linearGradient1 = context.createLinearGradient(0,0,100,0);
linearGradient1.addColorStop(0  , 'rgb(246, 36, 89)');
linearGradient1.addColorStop(0.5, 'rgb( 31, 58, 147)');
linearGradient1.addColorStop(1  , 'rgb( 34, 49,  63)');

context.fillStyle = linearGradient1;
context.fillRect(10,10,100, 100);

var linearGradient2 = context.createLinearGradient(125,0, 225,0);
linearGradient2.addColorStop(0  , 'rgb(255, 0,   0)');
linearGradient2.addColorStop(0.5, 'rgb(  0, 0, 255)');
linearGradient2.addColorStop(1  , 'rgb(  0, 0,   0)');

context.strokeStyle = linearGradient2;
context.strokeRect(125, 10, 100, 100);        

渐变的长度

我们在使用渐变的时候要非常明白的知道渐变的长度的概念。如果我们设置渐变从x=10扩展到x=110的距离,那么渐变只会作用在水平方向上从10到110的距离的范围内。超出这个范围的图形将任然受渐变色的影响,但是在这个范围之外的颜色只会是渐变的开始或结束颜色。

距离来说,加入有一个水平线性渐变,x1=150,x2=350。渐变从蓝色过渡到绿色。那么所有水平方向定位x值小于150的图形都会使用蓝色蓝填充。所有水平方向定位x值大于350的图形都会使用绿色来填充。只有那些在水平方向定位x值在150到350之间的图形会使用蓝绿渐变色来填充。

具体来看下面的代码,这里绘制了5个矩形,并用上面所说的渐变来填充它们,让我们蓝看看效果:

var linearGradient1 = context.createLinearGradient(150, 0, 350,0);
linearGradient1.addColorStop(0, 'rgb(0,   0, 255)');
linearGradient1.addColorStop(1, 'rgb(0, 255, 0)');

context.fillStyle = linearGradient1;

context.fillRect(10,10,130, 100);
context.fillRect(150,10, 200, 100);
context.fillRect(360,10, 130, 100);

context.fillRect(100,120, 150, 100);
context.fillRect(280,120, 150, 100);                 

从上面的结果可以看出,在渐变区域之外的图形仅会使用开始或结束颜色来填充。

渐变长度是非常重要的概念,需要大家仔细体会。只有掌握它才能在使用渐变是获得正确的结果。

径向渐变

径向渐变是一种圆形的颜色扩展模式,颜色从圆心位置开始向外辐射。下面是一个例子:

一个径向渐变于两个圆形来定义。每一个圆都有一个圆心和一条半径。下面是示例代码:

var x1 = 100;   // 第一个圆圆心的X坐标
var y1 = 100;   // 第一个圆圆心的Y坐标
var r1 = 30;    // 第一个圆的半径

var x2 = 100;   // 第二个圆圆心的X坐标
var y2 = 100;   // 第二个圆圆心的Y坐标
var r2 = 100;   // 第二个圆的半径

var radialGradient1 =
    context.createRadialGradient(x1, y1, r1, x2, y2, r2);

radialGradient1.addColorStop(0, 'rgb(0,   0, 255)');
radialGradient1.addColorStop(1, 'rgb(0, 255,   0)');

context.fillStyle = radialGradient1;
context.fillRect(10,10, 200, 200);                             

如上面的代码所示,这里有两个圆,圆心分别为x1,y1和x2,y2,它们的半径分别为r1和r2,这些值将作为参数传入到2D上下文的createRadialGradient()方法中。

这两个圆必须设置不同的半径,形成一个内圆和一个外圆。这样渐变色就从一个圆形辐射到另一个圆形。

颜色停止点会被添加到这两个圆形之间,例如上面的代码中,第一个颜色停止点中的参数0表示该颜色从第一个圆形开始,第二个颜色停止点中的参数1表示第二种颜色从第二个圆形开始。

下面是上面代码的返回结果:

如果两个圆形的圆心位置相同,那么径向渐变将是一个完整的圆形。如果两个圆的圆心位置不相同,那么径向渐变看起来就像是一个探照灯发出的光线。例如下面的样子:

var x1 = 100;
var y1 = 100;
var r1 = 30;
var x2 = 150;
var y2 = 125;
var r2 = 100;

var radialGradient1 = context.createRadialGradient(x1, y1, r1, x2, y2, r2);
radialGradient1.addColorStop(0, 'rgb(0,   0, 255)');
radialGradient1.addColorStop(1, 'rgb(0, 255,   0)');

context.fillStyle = radialGradient1;
context.fillRect(10,10, 200, 200);  

得到的结构如下所示:

HTML5 Canvas:绘制阴影和填充模式

绘制阴影

我们可以在HTML5 canvas上绘制出图形或文字的阴影效果。canvas的阴影效果非常简单,通过一些简单的设置,就可以自动在图片或文字下面生成相应的阴影。下面是一个简单的例子:

在canvas中,图形的阴影由2D上下文的4个属性来控制:

shadowOffsetX和shadowOffsetY属性阴影和图形之间的距离。正数值表示阴影绘制在图形的右边(X轴方向),或图形的下方(Y轴方向)。而负数值表示阴影绘制在图形的左边(X轴方向),或图形的上方(Y轴方向)。它们的默认值都是0。

shadowBlur属性用于设置阴影的模糊效果。数值越大,阴影越模糊。数值越小,用于越清晰。它的值是一个浮点数,0表示阴影不模糊。

shadowColor表示阴影的颜色。

上面例子的实现代码如下:

var canvas  = document.getElementById("ex1");
var context = canvas.getContext("2d");

context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.shadowBlur    = 4;
context.shadowColor   = "#666666";  //or use rgb(red, green, blue)

context.fillStyle = "#000000";
context.fillRect(10,10, 50, 50);

context.fillStyle = "#000066";
context.font = "30px Arial";
context.fillText("HTML5 Canvas Shadow", 10,120); 

填充模式

填充模式是指在canvas中使用某张图片作为一种模式来填充图形。我们可以通过createPattern()方法来创建一种填充模式。它的语法为:createPattern(image, type)。

参数image可以是一个HTML图片元素,另一个canvas或一个元素等。

参数type表示如何使用图片来创建特定的模式。它的取值可以是:

下面是一个使用填充模式的简单例子:

var ctx = document.getElementById('canvas').getContext('2d');

// create new image object to use as pattern
var img = new Image();
img.src = 'Canvas_createpattern.png';
img.onload = function(){

// create pattern
var ptrn = ctx.createPattern(img,'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0,0,150,150)    

我们在模式中使用的图片如下:

上面代码的返回结果如下:

HTML5 Canvas:绘制文字

我们可以在HTML5 canvas上绘制绘制文字,并且可以设置文字的字体,大小和颜色。

绘制文字的字体由2D上下文的font属性来控制。如果你需要使用颜色来填充文字或制作描边文字,可以使用2D上下文的fillStyle和strokeStyle属性来完成。

要在canvas上绘制文字,可以通过2D上下文的fillText()函数或strokeText()函数来完成。下面是一个简单的例子:

var canvas  = document.getElementById("ex1");
var context = canvas.getContext("2d");

context.font      = "normal 36px Verdana";
context.fillStyle = "#000000";
context.fillText("HTML5 Canvas Text", 50, 50);

context.font        = "normal 36px Arial";
context.strokeStyle = "#000000";
context.strokeText("HTML5 Canvas Text", 50, 90);                               

下面的图片是上面代码的返回结果:

字体和样式

当在HTML5 canvas上绘制文字的时候,我们可以设置文字的字体和样式。我们可以通过一组2D上下文的font属性来完成这些工作。这些属性和CSS中设置字体的属性是兼容的:

[font style][font weight][font size][font face]    

举例来说,我们可以这样设置字体:

context.font = "normal normal 20px Verdana";     

对于上面的这些属性,我们可以有下面的一些可取值:

需要注意的是,不是所有的浏览器都支持所有这些属性的,实际使用中你需要根据实际情况做一些测试。

绘制文字

当在HTML5 canvas中绘制文字的时候,你可以绘制填充文字,也可以绘制描边文字。它们分别通过2D上下文的fillText()和strokeText()函数来实现。这两个函数的定义如下:

fillText   (textString, x, y [,maxWidth]);
strokeText (textString, x, y [,maxWidth]);   

textString是要绘制的文字。

x和y表示文字在canvas上的位置。x参数是文字的X轴坐标,y是文字Y轴坐标,但是它如何在Y轴上定位还要取决于文本的基线。文本的基线会在后面介绍。

maxWidth表示文字在水平方向上的最大宽度。详细内容接着往下看。

下面是一个示例代码:

context.font      = "36px Verdana";
context.fillStyle = "#000000";
context.fillText("HTML5 Canvas Text", 50, 50);  

文本的最大宽度
可选参数maxWidth表示在canvas上绘制文字的时候,文字水平方向上最大的宽度不能大于参数指定的值。如果文本的宽度大于maxWidth指定的值,那么文字的宽度会被压缩。注意不是被剪裁掉。下面是一个例子,在canvas中绘制两串相同的文本,但是使用不同的maxWidth属性:

context.font      = "36px Verdana";
context.fillStyle = "#000000";
context.fillText("HTML5 Canvas Text", 50, 50);
context.fillText("HTML5 Canvas Text", 50, 100, 200); 

上面的代码的返回结果如下,注意第二串文字被压缩为总宽度200像素:

文字的颜色

文字的填充或描边颜色是通过2D上下文的fillStyle和strokeStyle属性来完成的。实现方式和图形的方式相同。可以参考HTML5 Canvas:绘制矩形中的介绍,这里不再重复。

测量文本的宽度

在2D上下文中有一个函数可以用于测量文本的宽度,返回以像素为单位的结果值。这个函数不能测量高度。这个函数是measureText()。下面是一段示例代码:

var textMetrics = context.measureText(“measure this”);

var width = textMetrics.width;
通过测量文本的宽度,我们可以知道当前的这些文字是否能够放在当前的canvas容器中,或者其它一些用途。

文本的基线

文本的基线用于决定如何解释fillText()和strokeText()函数中的y参数。通俗来讲,就是文字在垂直方向上如何定位。注意,在不同的浏览器中,这些解释可能会稍微有一些不同。

可以通过2D上下文的textBaseline属性来设置文本的基线。

文本基线的语法为:

ctx.textBaseline=
   "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom";            

下表中列出了文本基线的可取值及其描述。

取值 | 描述

top | 文本以文本中最高的字符为基线进行对齐

hanging | 文本的基线是悬停线(hanging baseline)。它和top取值基本相同,多数情况下你可能看不出有什么区别

middle | 文本的基线是文字的中心线

alphabetic | 文本的基线是正常的文字基线

ideographic | 文本的基线是水平方向的字形底部

bottom | 文本以文本中最低的字符为基线进行对齐

看了上面的描述大家会一头雾水。现在举例来说明。我们使用相同的y值(75)来绘制一串文本但是为每一个文字设置不同的基线值。在图片中我们绘制一条y=75的执行来表示所有文字的基线。

上面图片的实现代码如下:

context.stokeStyle = "#000000";
context.lineWidth  = 1;
context.beginPath();
context.moveTo(  0, 75);
context.lineTo(500, 75);
context.stroke();
context.closePath();

context.font      = "16px Verdana";
context.fillStyle = "#000000";

context.textBaseline = "top";
context.fillText("top", 0, 75);

context.textBaseline = "hanging";
context.fillText("hanging", 40, 75);

context.textBaseline = "middle";
context.fillText("middle", 120, 75);

context.textBaseline = "alphabetic";
context.fillText("alphabetic", 200, 75);

context.textBaseline = "ideographic";
context.fillText("ideographic", 300, 75);

context.textBaseline = "bottom";
context.fillText("bottom-glyph", 400, 75);

文本对齐

2D上下文的textAlignment属性用于定义文字在水平方向上如何对齐。换句话来说,就是textAlignment属性定义绘制文本时文本的x坐标属性。

textAlignment属性的语法为:

ctx.textAlign = "left" || "right" || "center" || "start"   || "end";       

下表中列出了textAlignment属性各个取值及其描述。

取值 | 描述

start | 文本从x左边开始绘制

left | 文本从x左边开始绘制,和start属性相同

center | x坐标位于文本的中心

end | x坐标位于文本的末尾

right | x坐标位于文本的末尾,和end属性相同

在下面的例子中显示了textAlignment属性的各种取值的定位。垂直直线的x坐标为x=250,所有的字的x属性值也是250,但是它们的textAlignment属性取值各不相同。

上面的图片的实现代码如下:

context.stokeStyle = "#000000";
context.lineWidth  = 1;
context.beginPath();
context.moveTo( 250, 0);
context.lineTo( 250, 250);
context.stroke();
context.closePath();

context.font      = "16px Verdana";
context.fillStyle = "#000000";

context.textAlign = "center";
context.fillText("center", 250, 20);

context.textAlign = "start";
context.fillText("start", 250, 40);

context.textAlign = "end";
context.fillText("end", 250, 60);

context.textAlign = "left";
context.fillText("left", 250, 80);

context.textAlign = "right";
context.fillText("right", 250, 100);

HTML5 Canvas:绘制图片

通过前面的学习,我们现在已经可以在HTML5 canvas中绘制图形和文字,并给它们设置一些样式。我们还可以在<canvas>中绘制图片。用于在<canvas>作为绘制源的图片可以是下面的几种元素类型:

我们可以通过2D上下文的三种方法来在<canvas>中绘制图片。

基本绘制图片方法:drawImage(image, dx, dy)
这个方法是在<canvas>中绘制一张图片。image参数是要绘制的图片,dx和dy参数是“destinationX”和“destinationY”的简写,这两个参数决定在canvas中什么位置绘制图片。

下面是一个例子。这个例子在<canvas>中(0,0)位置开始绘制指定的图片。

var ctx = document.getElementById('ex1').getContext('2d');
var img = new Image();
img.onload = function(){
    ctx.drawImage(img,0,0);
};
img.src = 'img/canvas-image-1.jpg';    

上面的代码的返回结果如下:

绘制并缩放图片:drawImage(image, dx, dy, dw, dh)

第二种在<canvas>中绘制图片的方法添加了两个参数:dw和dh,这两个参数分别是“destinationWidth”和“destinationHeight”的简写,它们决定在绘制图片时是否对图片进行缩放。

下面的例子中,我们将绘制的图片缩小1/3左右,然后将它重复排列形成一个网格。

var ctx = document.getElementById('ex2').getContext('2d');
var img = new Image();
img.onload = function(){
    for (var i=0;i<4;i++){
      for (var j=0;j<5;j++){
        ctx.drawImage(img,j*60,i*60,60,60);
      }
    }
};
img.src = 'img/canvas-image-2.jpg'; 

上面的代码的返回结果如下:

图片切片方法:drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dw, dh)

第三种在<canvas>中绘制图片的方法有8个参数。image是源图片,sx和sy是“sourceX”和“sourceY”的简写,这两个参数决定从什么位置开始在源图片上裁剪出一个矩形区域,这个区域的图片将会被绘制在Canvas中。sWidth和sHeight表示矩形区域的宽度和高度。剩下的4个参数和上面的绘制图片方法中的描述相同。看下面的图片,图片上标出了各个参数的位置。

来看下面的一个例子。这个例子中,我们将源图片剪裁出一部分,然后将它绘制在canvas的一个边框图片之上。

var canvas = document.getElementById('ex3');
var ctx = canvas.getContext('2d');
// 绘制图片切片
ctx.drawImage(document.getElementById('source'),
            98, 205, 104, 124, 21, 20, 87, 104);

// 绘制边框图片
ctx.drawImage(document.getElementById('frame'),0,0); 

上面的代码得到的结果如下:

创建和调用图片

在你能够在Canvas中绘制图片之前,你需要创建一个Image对象,然后将图片加载到内存中。下面是完成这个操作的js代码:

var image = new Image();
image.src = "img/sample.png";     

在你能够绘制图片之前,图片必须被完全加载。为了确保图片被完全加载,你可以为图片添加一个事件监听,这个事件监听中的方法会在图片被完全加载之后被调用。下面是一个示例代码:

image.addEventListener('load', drawImage1);     

或者:

var img = new Image();
img.onload = function(){
    ctx.drawImage(img,0,0);
};                               

HTML5 Canvas:合成模式

在我们前面所有HTML5 canvas的例子中,图形的绘制都是一个图形位于另一个图形之上的。我们可以通过设置globalCompositeOperation属性来修改这个默认的行为。换句话来说,我们可以设置绘制的图形与已经绘制在canvas上的图形的合成模式。

2D上下文有两个属性用于控制canvas的图形合成模式:

globalAlpha

globalAlpha属性决定你绘制图形的透明度。它的取值可以在0-1之间。0代表绘制的图形完全透明,1表示绘制的图形完全不透明。0.5则表示绘制的图形处于半透明状态。默认的取值为1。

设置globalAlpha属性的js代码如下:

context.globalAlpha = 0.5;             

globalCompositeOperation

globalCompositeOperation属性决定绘制的图形如何与canvas上已经存在的图形进行混合。

globalCompositeOperation的语法如下:

globalCompositeOperation = type       

globalCompositeOperation的值引用一个“源”和一个“目标”,并且指定源和目标如何进行合成。“源”就是你要绘制的图形,“目标”是已经绘制在canvas上的元素。下面列出了globalCompositeOperation属性的可选值和它们的描述。