使用Canvas绘图

笔记-JavaScript 专栏收录该内容
12 篇文章 0 订阅

<canvas>元素负责在页面中设定一个区域,然后就可以通过 JavaScript 动态地在这个区域中绘制图形。

IE9+、 Firefox 1.5+、 Safari 2+、 Opera 9+、 Chrome、 iOS 版 Safari 以及 Android 版 WebKit
都在某种程度上支持<canvas>

<canvas>由几组 API 构成,除了具备基本绘图能力的 2D 上下文, <canvas>还建议了一个名为 WebGL 的 3D 上下文。目前,支持该元素的浏览器都支持 2D 上下文及文本 API,但对 WebGL 的支持还不够好。

基本语法

要使用<canvas>元素,必须先设置其 width 和 height 属性,指定可以绘图的区域大小。出现在开始和结束标签中的内容是后备信息,如果浏览器不支持<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 元素对象(假设你想在 Firefox 3 中使用<canvas>元素。虽然浏览器会为该标签创建一个 DOM 对象,而且也可以引用它,但这个对象中并没有 getContext()方法。)。在这种情况下,即使 drawing 变量中保存着一个有效的元素引用,也检测不到 getContext()方法。

使用 toDataURL()方法,可以导出在<canvas>元素上绘制的图像。这个方法接受一个参数,即图像的 MIME 类型格式,而且适合用于创建图像的任何上下文。

var drawing = document.getElementById("drawing");
//确定浏览器支持<canvas>元素
if (drawing.getContext){
//取得图像的数据 URI
var imgURI = drawing.toDataURL("image/png");
//显示图像
var image = document.createElement("img");
image.src = imgURI;
document.body.appendChild(image);
}

默认情况下,浏览器会将图像编码为 PNG 格式(除非另行指定 。 Firefox 和 Opera 也支持基于”image/jpeg”参数的 JPEG 编码格式。

2D上下文

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

填充和描边

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";
}

绘制矩形

矩形是唯一一种可以直接在 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,0.5)";
context.fillRect(30, 30, 50, 50);
}

1

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,0.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,0.5)";
context.fillRect(30, 30, 50, 50);
//在两个矩形重叠的地方清除一个小矩形
context.clearRect(40, 40, 10, 10);
}

这里写图片描述

绘制路径

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(),这个方法可以在路径上创建一个剪切区域。

isPointInPath()的方法。这个方法接收 x 和 y 坐标作为参数,用于在路径被关闭之前确定画布上的某一点是否位于路径上

绘制文本

文本与图形总是如影随形。为此, 2D 绘图上下文也提供了绘制文本的方法。绘制文本主要有两个方法:fillText()strokeText()。这两个方法都可以接收 4 个参数:要绘制的文本字符串、 x 坐标、 y 坐标和可选的最大像素宽度。而且,这两个方法都以下列 3 个属性为基础。

  • font:表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定

  • textAlign:表示文本对齐方式。可能的值有”start”、”end”、”left”、”right”和”center”。建议使用”start”和”end”,不要使用”left”和”right”,因为前两者的意思更稳妥,能同时适合从左到右和从右到左显示(阅读)的语言。

  • textBaseline:表示文本的基线。可能的值有”top”、”hanging”、”middle”、”alphabetic”、
    “ideographic”和”bottom”。

这几个属性都有默认值,因此没有必要每次使用它们都重新设置一遍值。 fillText()方法使用fillStyle 属性绘制文本,而 strokeText()方法使用 strokeStyle 属性为文本描边。

fillText()strokeText()方法都可以接收第四个参数,也就是文本的最大像素宽度。不过,这个可选的参数尚未得到所有浏览器支持( 最 早 支 持 它 的 是 Firefox 4 )。 提 供 这 个 参 数 后 , 调 用 fillText()strokeText()时如果传入的字符串大于最大宽度,则绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度 。

绘制文本还是相对比较复杂的操作,因此支持<canvas>元素的浏览器也并未完全实现所有与绘制文本相关的 API。

变换

通过上下文的变换,可以把处理后的图像绘制到画布上。 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()

有两个方法可以跟踪上下文的状态变化。如果你知道将来还要返回某组属性与变换的组合,可以调用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)开始绘制红色矩形

需要注意的是, save()方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。

绘制图像

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

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

如果你想改变绘制后图像的大小,可以再多传入两个参数,分别表示目标宽度和目标高度。通过这种方式来缩放图像并不影响上下文的变换矩阵

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

除了上述两种方式,还可以选择把图像中的某个区域绘制到上下文中。drawImage()方法的这种调用方式总共需要传入 9 个参数:要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度。这样调用drawImage()方法可以获得最多的控制。

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

除了给drawImage()方法传入 HTML <img>元素外,还可以传入另一个<canvas>元素作为其第一个参数。这样,就可以把另一个画布内容绘制到当前画布上。结合使用 drawImage()和其他方法,可以对图像进行各种基本操作。而操作的结果可以通过toDataURL()方法获得(toDataURL()是 Canvas 对象的方法,不是上下文对象的方法。 )。

图像不能来自其他域。如果图像来自其他域,调用toDataURL()会抛出一个错误。

阴影

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

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

渐变

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

var gradient = context.createLinearGradient(30, 30, 70, 70);
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);

为了让渐变覆盖整个矩形,而不是仅应用到矩形的一部分,矩形和渐变对象的坐标必须匹配才行。

这里写图片描述

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

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

模式

模 式 其 实 就 是 重 复 的 图 像 , 可 以 用 来 填 充 或 描 边 图 形 。 要 创 建 一 个 新 模 式 , 可 以 调 用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>元素。

使用图像数据

2D 上下文的一个明显的长处就是,可以通过 getImageData()取得原始图像数据。这个方法接收4 个参数:要取得其数据的画面区域的 x 和 y 坐标以及该区域的像素宽度和高度。

var imageData = context.getImageData(10, 5, 50, 50);
这里返回的对象是 ImageData 的实例。每个 ImageData 对象都有三个属性: width、 height 和data。其中 data 属性是一个数组,保存着图像中每一个像素的数据。在 data 数组中,每一个像素用 4 个元素来保存,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据就保存在数组的第 0 到第3 个元素中。

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

数组中每个元素的值都介于 0 到 255 之间(包括 0 和 255)。能够直接访问到原始图像数据,就能够以各种方式来操作这些数据。

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

合成

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

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

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

在使用 globalCompositionOperation 的情况下,一定要多测试一些浏览器。因为不同浏览器对这个属性的实现仍然存在较大的差别。

参考材料:

JavaScript高级程序设计(第3版)

玩转html5<canvas>画图

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

简介: 新的 HTML5 规范旨在帮助开发人员更轻松的编写出各类 Web 应用,以顺应当前 SaaS,云计算以及 RIA 等技术的最新趋势。在 HTML5 得以广泛推广之前,开发人员通常使用 SVG,VML 等技术进行 Web 绘图操作,但这些基于 XML绘图语言声明式的绘图方式并不能满足复杂绘图操作在性能上的需求,比如 Web 游戏所需要的像素级别的绘图能力。HTML5 canvas 元素的出现填补了这种不足,开发人员可以使用 JavaScript 脚本语言在 canvas 中进行一系列基于命令的图形绘制操作,本文将通过讲解如何使用 canvas 元素进行基本绘图操作,以及完成简单的动画和用户交互任务,阐明 canvas 在帮助构建 Web 图形类应用时所能够提供的能力。更多html5相关信息请关注html5中国:http://www.html5cn.org 背景介绍 HTML5 中新引入的 canvas 元素使得 Web 开发人员在无须借助任何第三方插件(如 Flash,Silverlight)的情况下,可以直接使用 JavaScript 脚本在 Web 页面进行绘图。它首次由苹果公司的 Webkit 框架引入实现,并成功运用在 Safari 浏览器中,读者在 这里可以体验到基于 canvas 的精彩示例。目前,canvas 已成为 HTML5 规范中的事实性标准,并且已经被 Firefox 3.0+, Safari 3.0+, Chrome 3.0+, Opera10.0+ 等浏览器所支持。最近(本文撰写之时),IE 也正式宣称将在其 9.0 版本之后,开始对 canvas 元素进行支持。
参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

owen1190

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值