canvas八日一练,基本语法

时间:2019-08-16 14:19来源:2020欧洲杯冠军竞猜官方网站
点评 :HTML 5 规范引进了很多新特性,其中最令人期待的之一就是 canvas元素。   HTML5添加的最受欢迎的功能就是canvas元素。这个元素负责在页面中设定一个区域,然后就可以通过Jav

点评:HTML 5 规范引进了很多新特性,其中最令人期待的之一就是 canvas 元素。

  HTML5 添加的最受欢迎的功能就是<canvas>元素。这个元素负责在页面中设定一个区域,然后就可以通过 JavaScript 动态地在这个区域中绘制图形。

canvas一周一练,canvas

从上个星期开始,耳朵就一直在生病,里面长了个疙瘩,肿的一碰就疼,不能吃饭不能嗨 (┳_┳)……在此提醒各位小伙伴,最近天气炎热,一定要注意防暑上火,病来如山倒呀~  

接下来我正在喝着5块一颗的药学习canvas……

canvas(画布)是html5新增的标签元素,用来定义图形,比如图表和其他图像。<canvas>标签只是图形容器,必须使用脚本(通常为javascript)来绘制图形。

canvas与svg的区别  

canvas是HTML5提供的新元素<canvas>,而svg存在的历史要比canvas久远,已经有十几年了。svg并不是html5专有的标签,最初svg是用xml技术(超文本扩展语言,可以自定义标签或属性)描述二维图形的语言。

首先,从它们的功能上来讲,canvas可以看做是一个画布。其绘制出来的图形为标量图,因此,可以在canvas中引入jpg或png这类格式的图片,在实际开发中,大型的网络游戏都是用canvas画布做出来的,并且canvas的技术现在已经相当的成熟。
另外,我们喜欢用canvas来做一些统计用的图表,如柱状图曲线图或饼状图等。而svg,所绘制的图形为矢量图,所以其用法上受到了限制。因为只能绘制矢量图,所以svg中不能引入普通的图片,因为矢量图的不会失真的效果,在项目中我们会用来做一些动态的小图标。
但是由于其本质为矢量图,可以被无限放大而不会失真,这很适合被用来做地图,而百度地图就是用svg技术做出来的。

另外从技术发面来讲canvas里面绘制的图形不能被引擎抓取,如我们要让canvas里面的一个图片跟随鼠标事件:canvas.onmouseover=function(){}。而svg里面的图形可以被引擎抓取,支持事件的绑定。
另外canvas中我们绘制图形通常是通过JavaScript来实现,svg更多的是通过标签来来实现,如在svg中绘制正矩形形就要用<rect>,这里我们不能用属性style="width:XXX;height:XXX;"来定义。
我再来介绍一个svg的js库:TWO.JS。其中包含two.js和three.js前者用于绘制二维图形,后者用于绘制三维图形。TWO.JS可以支持三种格式,svg(默认)、canvas、和WEBGL。当然也可以在普通div中引入。

要从同一图形的一个<canvas>标记中移除元素,需要擦掉重新绘制;而svg很容易编辑,只要从其描述中移除元素即可。

以上是之前在别人博客中看到的,所以先引用过来,待之后熟练掌握canvas,svg再写自己的心得体会。

具体请参考 http://blog.csdn.net/helloword_chen/article/details/49788309
1、基本语法

<canvas id="canvasMain" width="800" height="600" >
    您的浏览器不支持canvas
</canvas>

当没有设置宽度和高度的时候,canvas会初始化宽度为300px和高度为150px;当浏览器不支持canvas标签的时候,会显示其中的文字。

在canvas坐标体系中,以左上角为坐标原点,向右为x轴正方向,向下为y轴正方向,如下图:

图片 1

进行绘制需要获取canvas的上下文环境context,之后调用API进行图像绘制

var canvas = document.getElementById("canvasMain"),
    ctx = canvas.getContext("2d");

 替换内容是在不支持<canvas>标签的浏览器中展示的。也可以通过检测getContext()方法的存在来判断是否支持(有些浏览器会为html规范之外的元素创建默认的html元素对象)

var canvas = document.getElementById("canvasMain");
if(canvas.getContext("2d")) {
    var ctx = canvas.getContext("2d");
    // drawing code here
} else {
    // canvas-unsupported code here
}

导出在<canvas>元素上绘制的图像,接收一个参数,即图像的MIME类型格式。若绘制到画布上的图像来自不同域,该方法会报错

var canvas = document.getElementById("canvasMain");
if(canvas.getContext) {
    //取得图像的数据URI
    var imgURI = canvas.toDataURL('image/png');
    //显示图像
    var image =  document.createElement('img');
    image.src = imgURI;
    document.body.appendChild(image);        
}

2、2D上下文

  • 填充和描边

  填充:用指定的样式(颜色、渐变、图像)填充图形;描边:在图形的边缘画线   两个属性分别是fillStyle  strokeStyle,属性的值可以是字符串、渐变对象或模式对象

  • 绘制矩形

        图片 2  

  绘制矩形方法:fillRect()  strokeRect()   clearRect()  参数依次为:矩形x坐标、y坐标、宽度、高度

var drawing = document.getElementById('drawing');
if(drawing.getContext) {
    var context = drawing.getContext('2d');
    context.strokeStyle = 'rgba(0, 0, 255, 0.5)';//描边属性
    context.fillStyle = 'pink';//填充属性

    context.lineWidth = 3; //描边线条宽度
    context.lineCap = 'square';//线条末端形状(butt平头、round圆头、square方头)
    context.lineJoin = 'round';//线条相交的方式(round圆交、bevel斜交、miter斜接)

    context.fillRect(10, 10, 50, 50);//填充矩形
    context.fillStyle = 'green';
    context.fillRect(30, 30, 50, 50);
    context.strokeRect(100, 10, 50, 50);//描边矩形
    context.clearRect(40, 40, 15, 15);//清除画布上的矩形区域             
}
  • 绘制路径

   图片 3

   closePath()绘制一条连接到路径起点的线条

   fill()填充路径    stroke()描边路径   clip()在路径上创建一个剪切区域

   isPointInPath(x,y)判断画布上的某一点是否位于路径上

var drawing = document.getElementById('drawing');
if(drawing.getContext) {
            /*绘制路径*/
            var context = drawing.getContext('2d');
            context.strokeStyle = 'pink';
            context.beginPath();//开始绘制新路径
            //绘制外圆
            context.arc(100, 100, 99, 0, 2*Math.PI, false);//参数依次为圆心坐标x、y、半径、起始角度(用弧度表示)、结束角度、起始角度是否按逆时针方向计算(flase为顺时针)
            context.moveTo(194, 100);//将绘图游标移动到(x,y),不画线
            //绘制内圆
            context.arc(100, 100, 94, 0, 2*Math.PI, false);
            //绘制分针
            context.moveTo(100, 100);
            context.lineTo(100, 25);//从上一点开始绘制一条直线,到(x,y)为止
            //绘制时针
            context.moveTo(100, 100);
            context.lineTo(35, 100);
            //绘制文本
            context.font = 'bold 14px Arial';//表示文本样式、大小、字体
            context.textAlign = 'center';//文本对齐方式(start、end、left、right、center),建议用start、end代替left、right
            context.textBaseline = 'middle';//文本的基线(top、hanging、middle、alphabetical、ideopgraphic、bottom)
            context.fillText('12', 100, 20);
            //描边路径
            context.stroke();
            //额外练习
            context.moveTo(230, 10);
            //arcTo(x1,y1,x2,y2,radius):从上一点开始绘制一条弧线,到(x2,y2)为止,并以给定的半径穿过(x1,y1)
            context.arcTo(280, 60, 330, 10, 50);
            //bezierCurveTo(c1x,c1y,c2x,c2y,x,y):从上一点开始绘制一条曲线,到(x,y)为止,并以(c1x,c1y)(c2x,c2y)为控制点
            context.bezierCurveTo(210, 70, 290, 90, 300, 100);
            context.moveTo(320, 10);
            //quadraticCurveTo(cx,cy,x,y):从上一点开始绘制一条二次曲线,到(x,y)为止,并以(cx,cy)为控制点
            context.quadraticCurveTo(420, 100, 400, 10);
            //rect(x,y,width,height):从点(x,y)开始绘制矩形,此方法绘制的是矩形路径而不是独立的形状
            context.rect(450, 10, 50, 50);
            context.stroke();
}
  • 绘制文本

  fillText()绘制文本    strokeText()为文本描边    参数:文本字符串、x坐标、y坐标、可选的最大像素宽度

  • 变换

  图片 4

var drawing = document.getElementById('drawing');
if(drawing.getContext) {
            //变换
            var context = drawing.getContext('2d');
            context.strokeStyle = 'rgba(0, 0, 255, 0.5)';
            context.beginPath();
            context.arc(100, 100, 99, 0, 2*Math.PI, false);
            context.moveTo(194, 100);
            context.arc(100, 100, 94, 0, 2*Math.PI, false);
            //变换原点
            context.translate(100, 100);//将坐标原点移动到该点
            //旋转表针
            context.rotate(1);//围绕原点旋转图像angle弧度
            //绘制分针
            context.moveTo(0, 0);
            context.lineTo(0, -80);
            //绘制时针
            context.moveTo(0, 0);
            context.lineTo(-65, 0);
            context.stroke();

            context.rotate(-1);
            context.fillStyle = 'rgba(0, 0, 255, 0.5)';
            context.save();//保存上下文状态,只保存绘图上下文的设置和变换,不会保存绘图上下文的内容
            context.fillStyle = 'pink';
            context.translate(-100, -100);
            context.save();
            context.fillStyle = 'green';
            context.fillRect(220, 10, 50, 50);

            context.restore();//返回之前保存的设置
            context.fillRect(280, 10, 50, 50);

            context.restore();
            context.fillRect(340, 10, 50, 50);
}
  • 绘制图像

  图片 5 

  drawImage()还可传入<canvas>元素作为第一个参数,表示把另一个画布内容绘制到当前画布上。

  可能遇到的问题:drawImage()图片不显示在画布上,原因可能是你取图片的时候,此时图片还没有加载出来

window.onload = function(){
        var drawing = document.getElementById('drawing');
        if(drawing.getContext) {
            //图像
            var context = drawing.getContext('2d');
            var image = document.images[0];
            //参数依次表示为:图像元素、源图像x坐标、y坐标、目标的宽度、高度
            context.drawImage(image, 0, 0, 150, 250);
            //参数依次表示为:图像元素、源图像x坐标、y坐标、源图像宽度、高度、目标图像x坐标、y坐标、目标图像宽度、高度
            context.drawImage(image, 100, 300, 500, 600, 0, 0, 70, 80);
        }
};
  • 阴影、渐变、模式

  图片 6

   模式与渐变一样,都是从画布原点(0,0)开始的,将填充样式设置为模式对象,只表示在某个特定区域内显示重复的图像,而不是从某个位置开始绘制重复的图像。

   createPattern()第一个参数也可以是<video>元素,或者是另一个<canvas>元素

window.onload = function(){
        var drawing = document.getElementById('drawing');
        if(drawing.getContext) {
            //阴影
            var context = drawing.getContext('2d');
            context.shadowColor = 'rgba(0, 0, 0, 0.5)';//阴影颜色,默认黑色
            context.shadowOffsetX = 5;//x轴方向的阴影偏移量,默认0
            context.shadowOffsetY = 5;//y轴方向的阴影偏移量,默认0
            context.shadowBlur = 4;//模糊的像素数,默认0

            context.fillStyle = 'rgba(0, 0, 255, 0.5)';
            context.fillRect(10, 10, 50, 50);
            context.fillStyle = 'pink';
            context.fillRect(30, 30, 50, 50);

            //渐变
            var gradient = context.createLinearGradient(100, 10, 130, 130);//创建线性渐变,返回CanvasGradient对象的实例。参数:起点x坐标、y坐标、终点x坐标、y坐标
            gradient.addColorStop(0, 'white');//指定色标,参数:色标位置(0到1之间的数字,0表示开始的颜色,1为结束的颜色)、css颜色值
            gradient.addColorStop(1, 'black');

            context.fillStyle = gradient;
            context.fillRect(100, 10, 50, 50);

            var createLinearGradient = function(context, x, y, width, height) {
                return context.createLinearGradient(x, y, x width, y height);
            };

            var gradientNew = createLinearGradient(context, 180, 10, 50, 50);
            gradientNew.addColorStop(0, 'red');
            gradientNew.addColorStop(1, 'green');
            context.fillStyle = gradientNew;
            context.fillRect(180, 10, 50, 50);

            var gradientRound = context.createRadialGradient(275, 35, 10, 275, 35, 30);//径向渐变,参数:起点圆的圆心、半径,终点圆的圆心、半径
            gradientRound.addColorStop(0, 'pink');
            gradientRound.addColorStop(1, 'blue');
            context.fillStyle = gradientRound;
            context.fillRect(250, 10, 50, 50);

            //模式,即重复的图像,可以用来填充或描边图形
            var image = document.images[0],
                pattern = context.createPattern(image, 'repeat-x');//创建新模式,参数:图像元素、是否重复(repeat、repeat-x、repeat-y、no-repeat)
            context.fillStyle = pattern;
            context.fillRect(350, 10, 350, 350);
        }
}    
  • 使用图像数据

  getImageData()可取得原始图像数据,参数:要取得数据的画面区域的x坐标、y坐标、宽度、高度。返回的对象是ImageData的实例,该对象有3个属性:width、height和data。其中data为数组,保存着图像中

每一个像素的数据,每一个像素用4个元素来表示,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据保存在数组的第0到第3个元素中。

  注意:只有在画布“干净”的情况下(即图像并非来自其他域),才可以取得图像数据。

  • 合成

  globalAlpha:介于0和1之间的值(包括0和1),用于指定透明度,默认为0。

  globalComositionOperation:表示后绘制的图形怎样与先绘制的图形结合。

  图片 7

   图片 8

3、WebGL

  WebGL是针对canvas的3D上下文,并不是由W3C制定的标准。

 

本文持续更新中~

 

 

从上个星期开始,耳朵就一直在生病,里面长了个疙瘩,肿的一碰就疼,不能吃饭不能嗨(┳_┳)在此提醒各位小伙伴...

简述

5 规范引进了很多新特性,其中最令人期待的之一就是 元素。HTML 5 提供了通过 JavaScript 绘制图形的方法,此方法使用简单但功能强大。每一个 元素都有一个"上下文( context )" (想象成绘图板上的一页),在其中可以绘制任意图形。浏览器支持多个 canvas 上下文,并通过不同的 提供图形绘制功能。 5 规范引进了很多新特性,其中最令人期待的之一就是 元素。 5 提供了通过 JavaScript 绘制图形的方法,此方法使用简单但功能强大。每一个 元素都有一个"上下文( context )" (想象成绘图板上的一页),在其中可以绘制任意图形。浏览器支持多个 canvas 上下文,并通过不同的 提供图形绘制功能。

大部分的浏览器都支持 2D canvas 上下文——包括 Opera, Firefox, Konqueror 和 Safari。而且某些版本的 Opera 还支持 3D canvas ,Firefox 也可以通过插件形式支持 3D canvas :

  • 下载支持 3D canvas, HTML video 和 File I/O 的 Opera
  • 关于 Opera 3D canvas 上下文的文章
  • 关于 Firefox 3D canvas
    上下文的文章

本文介绍 2D canvas
基础以及如何使用基本 canvas 函数,如线条、形状、图像和文字等。为了理解此文章,你最好了解 JavaScript 基础知识。

可以点击此处批量下载本文实例代码

  <canvas>元素最早是由苹果公司推出的,当时主要用在其 Dashboard 微件中。

canvas 基础

创建 canvas 的方法很简单,只需要在 HTML 页面中添加 <canvas> 元素:

<canvas id="myCanvas" width="300" height="150">
Fallback content, in case the browser does not support Canvas.
</canvas>

为了能在 JavaScript 中引用元素,最好给元素设置 ID ;也需要给 canvas 设定高度和宽度。

创建好了画布后,让我们来准备画笔。要在画布中绘制图形需要使用 JavaScript 。首先通过getElementById 函数找到 canvas
元素,然后初始化上下文。之后可以使用上下文 API 绘制各种图形。下面的脚本在 canvas 中绘制一个矩形 (点击此处查看效果):

// Get a reference to the element.
var elem = document.getElementById('myCanvas');

// Always check for properties 和 methods, to make sure your code doesn't break 
// in other browsers.
if (elem && elem.getContext) {
  // Get the 2d context.
  // Remember: you can only initialize one context per element.
  var context = elem.getContext('2d');
  if (context) {
    // You are done! Now you can draw your first rectangle.
    // You only need to provide the (x,y) coordinates, followed by the width and 
    // height dimensions.
    context.fillRect(0, 0, 150, 100);
  }
}

可以把上面代码放置在文档 head 部分中,或者放在外部文件中。

  很快,HTML5 加入了这个元素,主流浏览器也迅速开始支持它。IE9 、Firefox 1.5 、Safari 2 、Opera 9 、Chrome、iOS 版 Safari 以及 Android 版 WebKit 都在某种程度上支持<canvas>。

2D context API

介绍了如何创建 canvas 后,让我们来看看 2D canvas API,看看能用这些函数做些什么。

  与浏览器环境中的其他组件类似,<canvas>由几组 API 构成,但并非所有浏览器都支持所有这些 API。除了具备基本绘图能力的 2D 上下文,<canvas>还建议了一个名为 WebGL 的 3D 上下文。

基本线条

上面的例子中展示了绘制矩形是多么简单。

通过 fillStyle 和 strokeStyle 属性可以轻松的设置矩形的填充和线条。颜色值使用方法和 十六进制数、()、() 和 ()( 若浏览器支持,如 Opera10 和 Firefox 3)。十六进制数、()、() 和 ()( 若浏览器支持,如 Opera10 和 Firefox 3)。

通过 fillRect 可以绘制带填充的矩形。使用 strokeRect 可以绘制只有边框没有填充的矩形。如果想清除部分 canvas 可以使用 clearRect。上述三个方法的参数相同:x, y, width, height。前两个参数设定 (x,y) 坐标,后两个参数设置矩形的高度和宽度。

可以使用 lineWidth 属性改变线条粗细。让我们看看使用了fillRect,
strokeRect clearRect 和其他的例子:

context.fillStyle   = '#00f'; // blue
context.strokeStyle = '#f00'; // red
context.lineWidth   = 4;

// Draw some rectangles.
context.fillRect  (0,   0, 150, 50);
context.strokeRect(0,  60, 150, 50);
context.clearRect (30, 25,  90, 60);
context.strokeRect(30, 25,  90, 60);

此例子效果图见图1.

图片 9

图 1: fillRect, strokeRect 和
clearRect效果图

  目前,支持该元素的浏览器都支持 2D 上下文及文本 API,但对 WebGL 的支持还不够好。由于 WebGL 还是实验性的,因此要得到所有浏览器支持还需要很长一段时间。Firefox 4 和 Chrome 支持 WebGL 规范的早期版本,但一些老版本的操作系统,比如 Windows XP,由于缺少必要的绘图驱动程序,即便安装了这两款浏览器也无济于事。

路径

通过 canvas 路径(path)可以绘制任意形状。可以先绘制轮廓,然后绘制边框和填充。创建自定义形状很简单,使用beginPath()开始绘制,然后使用直线、曲线和其他图形绘制你的图形。绘制完毕后调用 fillstroke 即可添加填充或者设置边框。调用closePath() 结束自定义图形绘制。

下面是一个绘制三角形的例子:

// Set the style properties.
context.fillStyle   = '#00f';
context.strokeStyle = '#f00';
context.lineWidth   = 4;

context.beginPath();
// Start from the top-left point.
context.moveTo(10, 10); // give the (x,y) coordinates
context.lineTo(100, 10);
context.lineTo(10, 100);
context.lineTo(10, 10);

// Done! Now fill the shape, 和 draw the stroke.
// Note: your shape will not be visible until you call any of the two methods.
context.fill();
context.stroke();
context.closePath();

其效果图见图2.

图片 10

图 2: 三角形

另一个较负责的例子中使用了直线、曲线和圆弧。

1、基本用法

  要使用 <canvas> 元素,必须先设置 width 和 height 属性,指定可以绘图的区域大小。出现在开始和结束标签中的内容是后备信息,如果浏览器不支持 <canvas> 元素,就会显示这些信息。下面就是 <canvas> 元素的例子。

<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

  与其它元素一样,<canvas> 元素对应的 DOM 元素对象也有 width 和 height 属性,可以随意修改。而且,也能通过 CSS 为该元素添加样式,如果不添加任何样式或者不绘制任何图形,在页面中是看不到该元素的。
  要在这块画布(canvas)上绘图,需要取得绘图上下文。而取得绘图上下文对象的引用,需要调用 getContext() 方法并传入上下文的名字。传入"2d",就可以取得 2D 上下文对象。

var drawing = document.getElementById('drawing');

// 确定浏览器支持<canvas>元素
if (drawing.getContext) {
    var context = drawing.getContext("2d");
    // 更多代码
}

  在使用 <canvas> 元素之前,首先要检测 getContext() 方法是否存在,这一步非常重要。有些浏览器会为 HTML 规范之外的元素创建默认的 HTML 元素对象(假设你想在 Firefox3 中使用 <canvas> 元素,虽然浏览器会为该标签创建一个 DOM 对象,但这个对象中并没有 getContext() 方法。)。在这种情况下,即使 drawing 变量中保存着一个有效的元素引用,也检测不到 getContext() 方法。
  使用 toDataURL() 方法,可以导出在<canvas>元素上绘制的图像。这个方法接受一个参数,即图像的 MIME 类型格式,而且适合用于创建图像的任何上下文。比如,要取得画布中的一幅 PNG 格式的图像,可以使用以下代码。

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext()) {
    // 取得图像的数据 URI
    var imgURI = drawing.toDataURL("image/png");

    // 显示图像
    var image = document.creatElement("img");
    image.src = imgURI;
    document.body.appendChild(image);
}

  默认情况下,浏览器会将图像编码为 PNG 格式(除非另行指定)。Firefox 和 Opera 也支持基于 "image/jpeg" 参数的 JPEG 编码格式。由于这个方法是后来才追加的,所以支持<canvas>的浏览器也是在较新的版本中才加入了对它的支持,比如 IE9、Firefox3.5 和 Opera10。

如果绘制到画布上的图像源自不同的域,toDataURL() 方法会抛出错误。

插入图像

drawImage 方法允许在 canvas 中插入其他图像
(imgcanvas 元素) 。在 Opera 中可以再 canvas 中绘制 SVG 图形。此方法比较复杂,可以有3个、5个或9个参数:

  • 3个参数:最基本的 drawImage 使用方法。一个参数指定图像位置,另两个参数设置图像在 canvas中的位置。
  • 5个参数:中级的 drawImage 使用方法,包括上面所述3个参数,加两个参数指明插入图像宽度和高度 (如果你想改变图像大小)。
  • 9个参数:最复杂 drawImage 杂使用方法,包含上述5个参数外,另外4个参数设置源图像中的位置和高度宽度。这些参数允许你在显示图像前动态裁剪源图像。

下面是上述三个使用方法的例子:

// Three arguments: the element, destination (x,y) coordinates.
context.drawImage(img_elem, dx, dy);

// Five arguments: the element, destination (x,y) coordinates, and destination 
// width and height (if you want to resize the source image).
context.drawImage(img_elem, dx, dy, dw, dh);

// Nine arguments: the element, source (x,y) coordinates, source width and 
// height (for cropping), destination (x,y) coordinates, and destination width 
// and height (resize).
context.drawImage(img_elem, sx, sy, sw, sh, dx, dy, dw, dh);

其效果见图3.

图片 11

图 3: drawImage 效果图。

2、2D 上下文

  使用 2D 绘图上下文提供的方法,可以绘制简单的 2D 图形,比如矩形、弧线和路径。
  2D 上下文的坐标开始于<canvas>元素的左上角,原点坐标是(0,0)。所有坐标值都基于这个原点计算,x 值越大表示越靠右,y 值越大表示越靠下。默认情况下,width 和 height 表示水平和垂直两个方向上可用的像素数目。

像素级操作

2D Context API 提供了三个方法用于像素级操作:createImageData, getImageData, 和
putImageData

ImageData对象保存了图像像素值。每个对象有三个属性: width, height 和
data。data 属性类型为CanvasPixelArray,用于储存width*height*4个像素值。每一个像素有RGB值和透明度alpha值(其值为 0 至
255,包括alpha在内!)。像素的顺序从左至右,从上到下,按行存储。

为了更好的理解其原理,让我们来看一个例子——绘制红色矩形

// Create an ImageData object.
var imgd = context.createImageData(50,50);
var pix = imgd.data;

// Loop over each pixel 和 set a transparent red.
for (var i = 0; n = pix.length, i < n; i  = 4) {
  pix[i  ] = 255; // red channel
  pix[i 3] = 127; // alpha channel
}

// Draw the ImageData object at the given (x,y) coordinates.
context.putImageData(imgd, 0,0);

注意: 不是所有浏览器都实现了createImageData。在支持的浏览器中,需要通过getImageData 方法获取ImageData 对象。请参考示例代码。

通过 ImageData 可以完成很多功能。如可以实现图像滤镜,或可以实现数学可视化 (如分形和其他特效)。下面特效实现了简单的颜色反转滤镜:

// Get the CanvasPixelArray from the given coordinates and dimensions.
var imgd = context.getImageData(x, y, width, height);
var pix = imgd.data;

// Loop over each pixel and invert the color.
for (var i = 0, n = pix.length; i < n; i  = 4) {
  pix[i  ] = 255 - pix[i  ]; // red
  pix[i 1] = 255 - pix[i 1]; // green
  pix[i 2] = 255 - pix[i 2]; // blue
  // i 3 is alpha (the fourth element)
}

// Draw the ImageData at the given (x,y) coordinates.
context.putImageData(imgd, x, y);

图 4 显示了使用此滤镜后的 Opera
图像 (图 3是原图)。

图片 12

图 4: 颜色反转滤镜

2.1、 填充和描边

  2D 上下文的两种基本绘图操作是填充和描边。

  填充,就是用指定的样式(颜色、渐变或图像)填充图形;

  描边,就是只在图形的边缘画线。

  大多数 2D 上下文操作都会细分为填充和描边两个操作,而操作的结果取决于两个属性:fillStyle 和 strokeStyle。这两个属性的值可以是字符串、渐变对象或模式对象,而且它们的默认值是"#000000"。
  如果为它们指定表示颜色的字符串值,可以使用 CSS 中指定颜色值的任何格式,包括颜色名、十六进制码、rgb、rgba、hsl 或 hsla。示例:

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){
    var context = drawing.getContext("2d");
    context.strokeStyle = "red";
    context.fillStyle = "#0000ff";
}

  以上代码将 strokeStyle 设置为 red(CSS 中的颜色名),将 fillStyle 设置为#0000ff(蓝色)。
  然后,所有涉及描边和填充的操作都将使用这两个样式,直至重新设置这两个值。如前所述,这两个属性的值也可以是渐变对象或模式对象。本章后面会讨论这两种对象。

文字

虽然最近的 WebKit 版本和 Firefox 3.1 nightly build 才开始支持 Text API ,为了保证文章完整性我决定仍在这里介绍文字 API 。

context 对象可以设置以下 text 属性:

  • font:文字字体,同属性 属性
  • textAlign:文字水平对齐方式。可取属性值: start, end, left,
    right, center。默认值:
    start.
  • textBaseline:文字竖直对齐方式。可取属性值:top, hanging, middle,
    alphabetic, ideographic, bottom。默认值:alphabetic.

有两个方法可以绘制文字: fillTextstrokeText。第一个绘制带 fillStyle 填充的文字,后者绘制只有 strokeStyle 边框的文字。两者的参数相同:要绘制的文字和文字的位置(x,y) 坐标。还有一个可选选项——最大宽度。如果需要的话,浏览器会缩减文字以让它适应指定宽度。

文字对齐属性影响文字与设置的
(x,y) 坐标的相对位置。

下面是一个在 canvas 中绘制"hello world" 文字的例子

context.fillStyle    = '#00f';
context.font         = 'italic 30px sans-serif';
context.textBaseline = 'top';
context.fillText  ('Hello world!', 0, 0);
context.font         = 'bold 30px sans-serif';
context.strokeText('Hello world!', 0, 50);

图 5 是其效果图。

图片 13

图 5: 文字效果

2.2、 绘制矩形

  矩形是唯一一种可以直接在 2D 上下文中绘制的形状。与矩形有关的方法包括 fillRect()、strokeRect() 和 clearRect()。
  这三个方法都能接收 4 个参数:矩形的 x 坐标、矩形的 y 坐标、矩形宽度和矩形高度。这些参数的单位都是像素。

  首先,fillRect() 方法在画布上绘制的矩形会填充指定的颜色。填充的颜色通过 fillStyle 属性指定,比如:

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){
    var context = drawing.getContext("2d");

    // 绘制红色矩形
    context.fillStyle = "#ff0000";
    context.fillRect(10, 10, 50, 50);

    // 绘制半透明的蓝色矩形
    context.fillStyle = "rgba(0, 0, 255, .5)";
    context.fillRect(30, 30, 50, 50);
}

  以上代码首先将 fillStyle 设置为红色,然后从(10, 10)处开始绘制矩形,矩形的宽和高均为 50 像素。然后,通过 rgba() 格式再将 fillStyle 设置为半透明的蓝色,在第一个矩形上面绘制第二个矩形。结果就是可以透过蓝色的矩形看到红色的矩形。

  strokeRect() 方法在画布上绘制的矩形会使用指定的颜色描边。描边颜色通过 strokeStyle 属性指定。示例:

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){
    var context = drawing.getContext("2d");

    // 绘制红色描边矩形
    context.strokeStyle= "#ff0000";
    context.strokeRect(10, 10, 50, 50);

    // 绘制半透明的蓝色描边矩形
    context.strokeStyle= "rgba(0, 0, 255, .5)";
    context.strokeRect(30, 30, 50, 50);
}

  以上代码绘制了两个重叠的矩形。不过,这两个矩形都只有框线,内部并没有填充颜色。

  描边线条的宽度由 lineWidth 属性控制,该属性的值可以是任意整数。
  另外,通过 lineCap 属性可以控制线条末端的形状是平头、圆头还是方头("butt"、"round" 或 "square")。
  通过 lineJoin 属性可以控制线条相交的方式是圆交、斜
交还是斜接("round"、"bevel" 或 "miter")。

  最后,clearRect() 方法用于清除画布上的矩形区域。本质上,这个方法可以把绘制上下文中的某一矩形区域变透明。通过绘制形状然后再清除指定区域,就可以生成有意思的效果,例如把某个形状切掉一块。示例:

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){
    var context = drawing.getContext("2d");

    // 绘制红色矩形
    context.fillStyle = "#ff0000";
    context.fillRect(10, 10, 50, 50);

    // 绘制半透明的蓝色矩形
    context.fillStyle = "rgba(0, 0, 255, .5)";
    context.fillRect(30, 30, 50, 50);

   // 在两个矩形重叠的地方清除一个小矩形
    context.clearRect(40, 40, 10, 10); 
}

阴影

目前只有 Konqueror 和 Firefox 3.1 nightly build 支持 Shadows API 。API 的属性为:

  • shadowColor:阴影颜色。其值和 CSS 颜色值一致。
  • shadowBlur:设置阴影模糊程度。此值越大,阴影越模糊。其效果和 Photoshop 的高斯模糊滤镜相同。
  • shadowOffsetXshadowOffsetY:阴影的 x 和 y 偏移量,单位是像素。

下面是 canvas 阴影的例子:

context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur    = 4;
context.shadowColor   = 'rgba(255, 0, 0, 0.5)';
context.fillStyle     = '#00f';
context.fillRect(20, 20, 150, 100);

其效果见图 6。

图片 14

图 6: canvas 阴影效果——蓝色矩形,红色阴影

2.3、绘制路径

  2D 绘制上下文支持很多在画布上绘制路径的方法。通过路径可以创造出复杂的形状和线条。

  要绘制路径,首先必须调用 beginPath() 方法,表示要开始绘制新路径。然后,再通过调用下列方法来实际地绘制路径。

  • arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x, y)为圆心绘制一条弧线,弧线半径为 radius,起始和结束角度(用弧度表示)分别为 startAngle 和 endAngle。最后一个参数表示 startAngle 和 endAngle 是否按逆时针方向计算,值为 false 表示按顺时针方向计算。
  • arcTo(x1, y1, x2, y2, radius):从上一点开始绘制一条弧线,到(x2, y2)为止,并且以给定的半径 radius 穿过(x1, y1)。
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y):从上一点开始绘制一条曲线,到(x, y) 为止,并且以 (c1x, c1y) 和 (c2x, c2y) 为控制点。
  • lineTo(x, y):从上一点开始绘制一条直线,到(x, y)为止。
  • moveTo(x, y):将绘图游标移动到(x, y),不画线。
  • quadraticCurveTo(cx, cy, x, y):从上一点开始绘制一条二次曲线,到(x, y)为止,并且以(cx, cy)作为控制点。
  • rect(x, y, width, height):从点(x, y)开始绘制一个矩形,宽度和高度分别由 width 和 height 指定。这个方法绘制的是矩形路径,而不是 strokeRect() 和 fillRect() 所绘制的独立的形状。

  创建了路径后,接下来有几种可能的选择。如果想绘制一条连接到路径起点的线条,可以调用 closePath()。

  如果路径已经完成,你想用 fillStyle 填充它,可以调用 fill() 方法。

  另外,还可以调用 stroke() 方法对路径描边,描边使用的是 strokeStyle。

  最后还可以调用 clip(),这个方法可以在路径上创建一个剪切区域。

  下面看一个例子,即绘制一个不带数字的时钟表盘。

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){

    var context = drawing.getContext("2d");

    // 开始路径
    context.beginPath();

    // 绘制外圆
    context.arc(100, 100, 99, 0, 2 * Math.PI, false);

    // 绘制内圆
    context.moveTo(194, 100);
    context.arc(100, 100, 94, 0, 2 * Math.PI, false);

    // 绘制分针
    context.moveTo(100, 100);
    context.lineTo(100, 15);

    // 绘制时针
    context.moveTo(100, 100);
    context.lineTo(35, 100);

    // 描边路径
    context.stroke();
}

  上述例子使用 arc() 方法绘制了两个圆形:一个外圆和一个内圆,构成了表盘的边框。外圆的半径是 99 像素,圆心位于点(100,100),也是画布的中心点。为了绘制一个完整的圆形,我们从 0 弧度开始,绘制 2π 弧度(通过 Math.PI 来计算)。
  在绘制内圆之前,必须把路径移动到内圆上的某一点,以避免绘制出多余的线条。
  第二次调用 arc() 使用了小一点的半径,以便创造边框的效果。
  然后,组合使用 moveTo() 和 lineTo() 方法来绘制时针和分针。
  最后一步是调用 stroke() 方法,这样才能把图形绘制到画布上,如下图所示:

图片 15

  在 2D 绘图上下文中,路径是一种主要的绘图方式,因为路径能为要绘制的图形提供更多控制。
  由于路径的使用很频繁,所以就有了一个名为 isPointInPath() 的方法。这个方法接收 x 和 y 坐标作为参数,用于在路径被关闭之前确定画布上的某一点是否位于路径上,例如:

if (context.isPointInPath(100, 100)){
    alert("Point (100, 100) is in the path.");
}

  2D 上下文中的路径 API 已经非常稳定,可以利用它们结合不同的填充和描边样式,绘制出非常复杂的图形来。

颜色渐变

除了 CSS 颜色,fillStylestrokeStyle 属性可以设置为 CanvasGradient 对象。——通过 CanvasGradient可以为线条和填充使用颜色渐变。

欲创建 CanvasGradient 对象,可以使用两个方法:createLinearGradientcreateRadialGradient。前者创建线性颜色渐变,后者创建圆形颜色渐变。

创建颜色渐变对象后,可以使用对象的 addColorStop 方法添加颜色中间值。

下面的代码演示了颜色渐变使用方法:

// You need to provide the source 和 destination (x,y) coordinates 
// for the gradient (from where it starts 和 where it ends).
var gradient1 = context.createLinearGradient(sx, sy, dx, dy);

// Now you can add colors in your gradient.
// The first argument tells the position for the color in your gradient. The 
// accepted value range is from 0 (gradient start) to 1 (gradient end).
// The second argument tells the color you want, using the CSS color format.
gradient1.addColorStop(0,   '#f00'); // red
gradient1.addColorStop(0.5, '#ff0'); // yellow
gradient1.addColorStop(1,   '#00f'); // blue

// For the radial gradient you also need to provide source
// 和 destination circle radius.
// The (x,y) coordinates define the circle center points (start 和 
// destination).
var gradient2 = context.createRadialGradient(sx, sy, sr, dx, dy, dr);

// Adding colors to a radial gradient is the same as adding colors to linear 
// gradients.

我也准备了一个更复杂的例子,使用了线性颜色渐变、阴影和文字。其效果见图 7。

图片 16

图 7: 使用线性颜色渐变的例子

2.4、 绘制文本

  文本与图形总是如影随形。为此,2D 绘图上下文也提供了绘制文本的方法。

  绘制文本主要有两个方法:fillText() 和 strokeText()。这两个方法都可以接收 4 个参数:要绘制的文本字符串、x 坐标、y 坐标和可选的最大像素宽度。而且,这两个方法都以下列 3 个属性为基础。

  • font:表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定,例如"10px Arial"。
  • textAlign:表示文本对齐方式。可能的值有 "start"、"end"、"left"、"right" 和 "center"。建议使用"start"和"end",不要使用"left"和"right",因为前两者的意思更稳妥,能同时适合从左到右和从右到左显示(阅读)的语言。
  • textBaseline:表示文本的基线。可能的值有 "top"、"hanging"、"middle"、 "alphabetic"、"ideographic" 和 "bottom"。

  这几个属性都有默认值,因此没有必要每次使用它们都重新设置一遍值。

  fillText() 方法使用 fillStyle 属性绘制文本,而 strokeText() 方法使用 strokeStyle 属性为文本描边。
  相对来说,还是使用 fillText() 的时候更多,因为该方法模仿了在网页中正常显示文本。例如,下面的代码在前一节创建的表盘上方绘制了数字 12:

context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20); 

  因为这里把 textAlign 设置为"center",把 textBaseline 设置为"middle",所以坐标(100, 20) 表示的是文本水平和垂直中点的坐标。
  如果将 textAlign 设置为"start",则 x 坐标表示的是文本左端的位置(从左到右阅读的语言);设置为"end",则 x 坐标表示的是文本右端的位置(从左到右阅读的
语言)。例如:

// 正常
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);

// 起点对齐
context.textAlign = "start";
context.fillText("12", 100, 40);

// 终点对齐
context.textAlign = "end";
context.fillText("12", 100, 60);

  这一回绘制了三个字符串"12",每个字符串的 x 坐标值相同,但 textAlign 值不同。另外,后两个字符串的 y 坐标依次增大,以避免相互重叠。结果如下图所示:

图片 17

  表盘中的分针恰好位于正中间,因此文本的水平对齐方式如何变化也能够一目了然。

  类似地,修改 textBaseline 属性的值可以调整文本的垂直对齐方式:值为"top",y 坐标表示文本顶端;值为 "bottom",y 坐标表示文本底端;值为 "hanging"、"alphabetic" 和 "ideographic",则 y 坐标分别指向字体的特定基线坐标。

  由于绘制文本比较复杂,特别是需要把文本控制在某一区域中的时候,2D 上下文提供了辅助确定文本大小的方法 measureText()。
  这个方法接收一个参数,即要绘制的文本;返回一个 TextMetrics 对象。返回的对象目前只有一个 width 属性,但将来还会增加更多度量属性。

  measureText() 方法利用 font、textAlign 和 textBaseline 的当前值计算指定文本的大小。
  比如,假设你想在一个 140 像素宽的矩形区域中绘制文本 Hello world!,下面的代码从 100 像素的字体大小开始递减,最终会找到合适的字体大小。

var fontSize = 100;
context.font = fontSize   "px Arial";
while(context.measureText("Hello world!").width > 140){
    fontSize--;
    context.font = fontSize   "px Arial";
}
context.fillText("Hello world!", 10, 10);
context.fillText("Font size is "   fontSize   "px", 10, 50); 

  前面提到过,fillText 和 strokeText() 方法都可以接收第四个参数,也就是文本的最大像素宽度。不过,这个可选的参数尚未得到所有浏览器支持(最早支持它的是 Firefox 4)。
  提供这个参数后,调用 fillText() 或 strokeText() 时如果传入的字符串大于最大宽度,则绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度。
  绘制文本还是相对比较复杂的操作,因此支持<canvas>元素的浏览器也并未完全实现所有与绘制文本相关的 API。

canvas 演示

如果你想知道使用 Canvas可以做些什么,可以参看以下的工程:

  • Opera Widget:
    • SimAquarium
    • Artist's
      Sketchbook
    • Spirograph
  • 在线工程和演示
    • Newton polynomial
    • Canvascape - "3D Walker"
    • Paint.Web - painting
      demo, open-source
    • Star-field
      flight
    • Interactive blob

2.5、变换

  通过上下文的变换,可以把处理后的图像绘制到画布上。2D 绘制上下文支持各种基本的绘制变换。
  创建绘制上下文时,会以默认值初始化变换矩阵,在默认的变换矩阵下,所有处理都按描述直接绘制。
  为绘制上下文应用变换,会导致使用不同的变换矩阵应用处理,从而产生不同的结果。
  可以通过如下方法来修改变换矩阵。

  • rotate(angle):围绕原点旋转图像 angle 弧度。
  • scale(scaleX, scaleY):缩放图像,在 x 方向乘以 scaleX,在 y 方向乘以 scaleY。scaleX 和 scaleY 的默认值都是 1.0。
  • translate(x, y):将坐标原点移动到(x,y)。执行这个变换之后,坐标(0,0)会变成之前由(x, y)表示的点。
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改变换矩阵,方式是乘以如下矩阵。
    m1_1  m1_2  dx
    m2_1  m2_2  dy
    0    0    1
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用 transform()。

  变换有可能很简单,但也可能很复杂,这都要视情况而定。比如,就拿前面例子中绘制表针来说,如果把原点变换到表盘的中心,然后再绘制表针就容易多了。请看下面的例子。

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){ 

    var context = drawing.getContext("2d");

    // 开始路径
    context.beginPath();

    // 绘制外圆
    context.arc(100, 100, 99, 0, 2 * Math.PI, false);

    // 绘制内圆
    context.moveTo(194, 100);
    context.arc(100, 100, 94, 0, 2 * Math.PI, false);

    // 变换原点
    context.translate(100, 100);

    // 绘制分针
    context.moveTo(0,0);
    context.lineTo(0, -85);

    // 绘制时针
    context.moveTo(0, 0);
    context.lineTo(-65, 0);

    // 描边路径
    context.stroke();
}

  把原点变换到时钟表盘的中心点(100, 100)后,在同一方向上绘制线条就变成了简单的数学问题了。所有数学计算都基于(0, 0),而不是(100, 100)。
  还可以更进一步,像下面这样使用 rotate() 方法旋转时钟的表针。

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){ 

    var context = drawing.getContext("2d");

    // 开始路径
    context.beginPath();

    // 绘制外圆
    context.arc(100, 100, 99, 0, 2 * Math.PI, false);

    // 绘制内圆
    context.moveTo(194, 100);
    context.arc(100, 100, 94, 0, 2 * Math.PI, false);

    // 变换原点
    context.translate(100, 100);

     // 旋转表针
     context.rotate(1);

    // 绘制分针
    context.moveTo(0,0);
    context.lineTo(0, -85);

    // 绘制时针
    context.moveTo(0, 0);
    context.lineTo(-65, 0);

    // 描边路径
    context.stroke();
}

  因为原点已经变换到了时钟表盘的中心点,所以旋转也是以该点为圆心的。结果就像是表针真地被固定在表盘中心一样,然后向右旋转了一定角度。

  无论是刚才执行的变换,还是 fillStyle、strokeStyle 等属性,都会在当前上下文中一直有效,除非再对上下文进行什么修改。
  虽然没有什么办法把上下文中的一切都重置回默认值,但有两个方法可以跟踪上下文的状态变化。如果你知道将来还要返回某组属性与变换的组合,可以调用 save() 方法。
  调用这个方法后,当时的所有设置都会进入一个栈结构,得以妥善保管。然后可以对上下文进行其他修改。等想要回到之前保存的设置时,可以调用 restore() 方法,在保存设置的栈结构中向前返回一级,
恢复之前的状态。
  连续调用 save() 可以把更多设置保存到栈结构中,之后再连续调用 restore() 则可以一级一级返回。下面来看一个例子。

context.fillStyle = "#ff0000";
context.save();

context.fillStyle = "#00ff00";
context.translate(100, 100);
context.save();

context.fillStyle = "#0000ff";
context.fillRect(0, 0, 100, 200); // 从点(100,100)开始绘制蓝色矩形

context.restore();
context.fillRect(10, 10, 100, 200); // 从点(110,110)开始绘制绿色矩形

context.restore(); 
context.fillRect(0, 0, 100, 200); // 从点(0,0)开始绘制红色矩形

  首先,将 fillStyle 设置为红色,并调用 save() 保存上下文状态。
  接下来,把 fillStyle 修改为绿色,把坐标原点变换到(100, 100),再调用 save() 保存上下文状态。
  然后,把 fillStyle 修改为蓝色并绘制蓝色的矩形。因为此时的坐标原点已经变了,所以矩形的左上角坐标实际上是(100, 100)。
  然后调用 restore(),之后 fillStyle 变回了绿色,因而第二个矩形就是绿色。之所以第二个矩形的起点坐标是(110, 110),是因为坐标位置的变换仍然起作用。
  再调用一次 restore(),变换就被取消了,而 fillStyle 也返回了红色。所以最后一个矩形是红色的,而且绘制的起点是(0,0)。
  需要注意的是,save() 方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。

小节

Canvas 是 HTML 5最让人期待的特性之一,目前已获得大部分 Web 浏览器支持。Canvas 可以帮助创建游戏、增强图形用户界面。2D context
API 提供大量图形绘制功能——我希望通过本文你了解了 canvas 使用,并且你有兴趣了解更多!

2.6、 绘制图像

   绘图上下文内置了对图像的支持。如果你想把一幅图像绘制到画布上,可以使用 drawImage() 方法。根据期望的最终结果不同,调用这个方法时,可以使用三种不同的参数组合。最简单的调用方式是传入一个 HTML <img> 元素,以及绘制该图像的起点的 x 和 y 坐标。例如:

var image = document.images[0];
context.drawImage(image, 10, 10);

  这两行代码取得了文档中的第一幅图像,然后将它绘制到上下文中,起点为(10, 10)。绘制到画布上的图像大小与原始大小一样。
  如果你想改变绘制后图像的大小,可以再多传入两个参数,分别表示目标宽度和目标高度。通过这种方式来缩放图像并不影响上下文的变换矩阵。例如:

context.drawImage(image, 50, 10, 20, 30);

  执行代码后,绘制出来的图像大小会变成 20×30 像素。

  除了上述两种方式,还可以选择把图像中的某个区域绘制到上下文中。

  drawImage() 方法的这种调用方式总共需要传入 9 个参数:要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度。这样调用 drawImage() 方法可以获得最多的控制。例如:

context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60); 

  这行代码只会把原始图像的一部分绘制到画布上。原始图像的这一部分的起点为(0, 10),宽和高都是 50 像素。最终绘制到上下文中的图像的起点是(0, 100),而大小变成了 40×60 像素。
  这种调用方式可以创造出很有意思的效果,如下图所示:

图片 18

  除了给 drawImage() 方法传入 HTML <img> 元素外,还可以传入另一个<canvas>元素作为其第一个参数。这样,就可以把另一个画布内容绘制到当前画布上。
  结合使用 drawImage() 和其他方法,可以对图像进行各种基本操作。而操作的结果可以通过 toDataURL() 方法获得。(请读者注意,虽然本章至今一直在讨论 2D 绘图上下文,但 toDataURL()是 Canvas 对象的方法,不是上下文对象的方法。)
  不过,有一个例外,即图像不能来自其他域。如果图像来自其他域,调用 toDataURL() 会抛出一个错误。打个比方,假如位于www.example.com 上的页面绘制的图像来自于 www.wrox.com,那当前上下文就会被认为“不干净”,因而会抛出错误。

2.7、阴影

  2D 上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。

  • shadowColor:用 CSS 颜色格式表示的阴影颜色,默认为黑色。
  • shadowOffsetX:形状或路径 x 轴方向的阴影偏移量,默认为 0。
  • shadowOffsetY:形状或路径 y 轴方向的阴影偏移量,默认为 0。
  • shadowBlur:模糊的像素数,默认 0,即不模糊。

  这些属性都可以通过 context 对象来修改。只要在绘制前为它们设置适当的值,就能自动产生阴影。例如:

var context = drawing.getContext("2d");

// 设置阴影
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = "rgba(0, 0, 0, 0.5)";

// 绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);

// 绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)"; 
context.fillRect(30, 30, 50, 50); 

  两个矩形的阴影样式相同,如下图所示:

图片 19

  不同浏览器对阴影的支持有一些差异。IE9、Firefox 4 和 Opera 11 的行为最为规范,其他浏览器多多少少会有一些奇怪的现象,甚至根本不支持阴影。
  Chrome(直至第 10 版)不能正确地为描边的形状应用实心阴影。Chrome 和 Safari(直至第 5 版)在为带透明像素的图像应用阴影时也会有问题:不透明部分的下方本来是该有阴影的,但此时则一概不见了。Safari 也不能给渐变图形应用阴影,其他浏览器都可以。

2.8、渐变

  渐变由 CanvasGradient 实例表示,很容易通过 2D 上下文来创建和修改。要创建一个新的线性渐变,可以调用 createLinearGradient() 方法。这个方法接收 4 个参数:起点的 x 坐标、起点的 y 坐标、终点的 x 坐标、终点的 y 坐标。
  调用这个方法后,它就会创建一个指定大小的渐变,并返回 CanvasGradient 对象的实例。
  创建了渐变对象后,下一步就是使用 addColorStop() 方法来指定色标。这个方法接收两个参数:色标位置和 CSS 颜色值。色标位置是一个 0(开始的颜色)到 1(结束的颜色)之间的数字。例如:

var gradient = context.createLinearGradient(30, 30, 70, 70);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");

  此时,gradient 对象表示的是一个从画布上点(30, 30)到点(70, 70)的渐变。起点的色标是白色,终点的色标是黑色。然后就可以把 fillStyle 或 strokeStyle 设置为这个对象,从而使用渐变来绘制形状或描边:

// 绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);

// 绘制渐变矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);

  为了让渐变覆盖整个矩形,而不是仅应用到矩形的一部分,矩形和渐变对象的坐标必须匹配才行。以上代码会得到如下图所示的结果:

图片 20

  如果没有把矩形绘制到恰当的位置,那可能就只会显示部分渐变效果。例如:

context.fillStyle = gradient; 
context.fillRect(50, 50, 50, 50);

  这两行代码执行后得到的矩形只有左上角稍微有一点白色。这主要是因为矩形的起点位于渐变的中间位置,而此时渐变差不多已经结束了。由于渐变不重复,所以矩形的大部分区域都是黑色。如下图所示:

图片 21

  确保渐变与形状对齐非常重要,有时候可以考虑使用函数来确保坐标合适。例如:

function createRectLinearGradient(context, x, y, width, height){
    return context.createLinearGradient(x, y, x   width, y   height);
}

  这个函数基于起点的 x 和 y 坐标以及宽度和高度值来创建渐变对象,从而让我们可以在 fillRect() 中使用相同的值。

var gradient = createRectLinearGradient(context, 30, 30, 50, 50);

gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");

//绘制渐变矩形
context.fi llStyle = gradient;
context.fillRect(30, 30, 50, 50);

  使用画布的时候,确保坐标匹配很重要,也需要一些技巧。类似 createRectLinearGradient() 这样的辅助方法可以让控制坐标更容易一些。

  要创建径向渐变(或放射渐变),可以使用 createRadialGradient() 方法。这个方法接收 6 个参数,对应着两个圆的圆心和半径。前三个参数指定的是起点圆的原心(x 和 y)及半径,后三个参数指定的是终点圆的原心(x 和 y)及半径。
  可以把径向渐变想象成一个长圆桶,而这 6 个参数定义的正是这个桶的两个圆形开口的位置。如果把一个圆形开口定义得比另一个小一些,那这个圆桶就变成了圆锥体,而通过移动每个圆形开口的位置,就可达到像旋转这个圆锥体一样的效果。
  如果想从某个形状的中心点开始创建一个向外扩散的径向渐变效果,就要将两个圆定义为同心圆。
  比如,就拿前面创建的矩形来说,径向渐变的两个圆的圆心都应该在(55, 55),因为矩形的区域是从(30, 30)到(80,80)。请看代码:

var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);

gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");

//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);

//绘制渐变矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50); 

  运行代码,会得到如下图所示的结果。

图片 22

  因为创建比较麻烦,所以径向渐变并不那么容易控制。不过,一般来说,让起点圆和终点圆保持为同心圆的情况比较多,这时候只要考虑给两个圆设置不同的半径就好了。

2.9、模式

  模式其实就是重复的图像,可以用来填充或描边图形。要创建一个新模式,可以调用 createPattern() 方法并传入两个参数:一个 HTML <img> 元素和一个表示如何重复图像的字符串。
  其中,第二个参数的值与 CSS 的background-repeat 属性值相同,包括"repeat"、"repeat-x"、"repeat-y" 和 "no-repeat"。示例:

var image = document.images[0],
    pattern = context.createPattern(image, "repeat");

// 绘制矩形
context.fillStyle = pattern;
context.fillRect(10, 10, 150, 150); 

  需要注意的是,模式与渐变一样,都是从画布的原点(0, 0)开始的。
  将填充样式(fillStyle)设置为模式对象,只表示在某个特定的区域内显示重复的图像,而不是要从某个位置开始绘制重复的图像。
  createPattern() 方法的第一个参数也可以是一个<video>元素,或者另一个<canvas>元素。

2.10、使用图像数据

  2D 上下文的一个明显的长处就是,可以通过 getImageData() 取得原始图像数据。
  这个方法接收 4 个参数:要取得其数据的画面区域的 x 和 y 坐标以及该区域的像素宽度和高度。
  示例,要取得左上角坐标为(10, 5)、大小为 50x50 像素的区域的图像数据,可以使用以下代码:

var imageData = context.getImageData(10, 5, 50, 50);

  上述返回的对象是 ImageData 的实例。
  每个 ImageData 对象都有三个属性:width、height 和 data。
  其中 data 属性是一个数组,保存着图像中每一个像素的数据。在 data 数组中,每一个像素用 4 个元素来保存,分别表示红、绿、蓝和透明度。因此,第一个像素的数据就保存在数组的第 0 到第 3 个元素中,示例:

var data = imageData,
    red = data[0],
    green = data[1],
    blue = data[2],
    alpha = data[3];

  数组中的每个元素的值都介于 0 到 255 之间(包括 0 和 255)。能够直接访问到原始图像数据,就能够以各种方式来操作这些数据。
  例如,通过修改图像数据,可以像下面这样创建一个简单的灰阶过滤器。

var drawing = document.getElementById("drawing");

// 确定浏览器支持<canvas>元素
if (drawing.getContext){
    var context = drawing.getContext("2d"),
        image = document.images[0],
        imageData, data,
        i, len, average,
        red, green, blue, alpha;

    // 绘制原始图像
    context.drawImage(image, 0, 0);

    // 取得图像数据
    imageData = context.getImageData(0, 0, image.width, image.height);
    data = imageData.data;

    for (i=0, len=data.length; i < len; i =4){
        red = data[i];
        green = data[i 1];
        blue = data[i 2];
        alpha = data[i 3];

        // 求得 rgb 平均值
        average = Math.floor((red   green   blue) / 3);

        // 设置颜色值,透明度不变
        data[i] = average;
        data[i 1] = average;
        data[i 2] = average;
    }

    // 回写图像数据并显示结果
    imageData.data = data;
    context.putImageData(imageData, 0, 0);
} 

  上述例子首先在画面上绘制了一幅图像,然后取得了原始图像数据。其中的 for 循环遍历了图像数据中的每一个像素。这里要注意的是,每次循环控制变量 i 都递增 4。
  在取得每个像素的红、绿、蓝颜色值后,计算出它们的平均值。再把这个平均值设置为每个颜色的值,结果就是去掉了每个像素的颜色,只保留了亮度接近的灰度值(即彩色变黑白)。
  在把 data 数组回写到 imageData 对象后,调用putImageData() 方法把图像数据绘制到画布上。最终得到了图像的黑白版。
  当然,通过操作原始像素值不仅能实现灰阶过滤,还能实现其他功能。

  只有在画布“干净”的情况下(即图像并非来自其他域),才可以取得图像数据。如果画布“不干净”,那么访问图像数据时会导致 JavaScript 错误。

2.11、合成

  还有两个会应用到 2D 上下文中所有绘制操作的属性:globalAlpha 和 globalCompositionOperation。
  其中,globalAlpha 是一个介于 0 和 1 之间的值(包括 0 和 1),用于指定所有绘制的透明度。默认值为 0。如果所有后续操作都要基于相同的透明度,就可以先把 globalAlpha 设置为适当值,然后绘制,最后再把它设置回默认值 0。示例:

// 绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);

// 修改全局透明度
context.globalAlpha = 0.5;

// 绘制蓝色矩形
context.fillStyle = "rgba(0, 0, 255, 1)";
context.fillRect(30, 30, 50, 50);

// 重置全局透明度
context.globalAlpha = 0; 

  在上述例子中,我们把蓝色矩形绘制到了红色矩形上面。因为在绘制蓝色矩形前,globalAlpha 已经被设置为 0.5,所以蓝色矩形会呈现半透明效果,透过它可以看到下面的红色矩形。

  第二个属性 globalCompositionOperation 表示后绘制的图形怎样与先绘制的图形结合。这个属性的值是字符串,可能的值如下。

  • source-over(默认值):后绘制的图形位于先绘制的图形上方。
  • source-in:后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明。
  • source-out:后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明。
  • source-atop:后绘制的图形与先绘制的图形重叠的部分可见,先绘制图形不受影响。
  • destination-over:后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见。
  • destination-in:后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明。
  • destination-out:后绘制的图形擦除与先绘制的图形重叠的部分。
  • destination-atop:后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明。
  • lighter:后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮。
  • copy:后绘制的图形完全替代与之重叠的先绘制图形。
  • xor:后绘制的图形与先绘制的图形重叠的部分执行“异或”操作。

  这个合成操作实际上用语言或者黑白图像是很难说清楚的。要了解每个操作的具体效果,请参见 https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html。推荐使用 IE9 或 Firefox 4 访问前面的网页,因为这两款浏览器对 Canvas 的实现最完善。下面来看一个例子。

// 绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);

// 设置合成操作
context.globalCompositeOperation = "destination-over";

// 绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)";
context.fillRect(30, 30, 50, 50);

  如果不修改 globalCompositionOperation,那么蓝色矩形应该位于红色矩形之上。但把 globalCompositionOperation 设置为"destination-over"之后,红色矩形跑到了蓝色矩形上面。
  在使用 globalCompositionOperation 的情况下,一定要多测试一些浏览器。因为不同浏览器对这个属性的实现仍然存在较大的差别。Safari 和 Chrome 在这方面还有问题,至于有什么问题,大家可以比较在打开上述页面的情况下,IE9 和 Firefox 4 与它们有什么差异。

小结

  HTML5 的<canvas>元素提供了一组 JavaScript API,让我们可以动态地创建图形和图像。图形是在一个特定的上下文中创建的,而上下文对象目前有两种。第一种是 2D 上下文,可以执行原始的绘图操作,比如:

  • 设置填充、描边颜色和模式
  • 绘制矩形
  • 绘制路径
  • 绘制文本
  • 创建渐变和模式

  第二种是 3D 上下文,即 WebGL 上下文。WebGL 是从 OpenGL ES 2.0 移植到浏览器中的,而 OpenGLES 2.0 是游戏开发人员在创建计算机图形图像时经常使用的一种语言。WebGL 支持比 2D 上下文更丰富和更强大的图形图像处理能力,比如:

  • 用 GLSL(OpenGL Shading Language,OpenGL 着色语言)编写的顶点和片段着色器
  • 支持类型化数组,即能够将数组中的数据限定为某种特定的数值类型
  • 创建和操作纹理

  目前,主流浏览器的较新版本大都已经支持<canvas>标签。同样地,这些版本的浏览器基本上也都支持 2D 上下文。但对于 WebGL 而言,目前还只有 Firefox 4 和 Chrome 支持它。

编辑:2020欧洲杯冠军竞猜官方网站 本文来源:canvas八日一练,基本语法

关键词: 欧洲杯竞猜