JavaScript第十五章使用 Canvas 绘图

这篇博客详细介绍了JavaScript中使用Canvas进行2D绘图的各种操作,包括填充和描边、绘制矩形、路径、文本、图像以及变换等。还涉及到了阴影、渐变、模式、图像数据处理和WebGL的相关概念。内容涵盖Canvas的基本用法、2D上下文的属性和方法,以及WebGL的设置和错误处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JavaScript第十五章使用 Canvas 绘图

  • <canvas>元素基本用法

使用 元素,必须先设置其 width 和 height 属性,指定可以绘图的区域大小。出现在开始和结束标签中的内容是后备信息,如果浏览器不支持 元素,就会显示这些信息。在使用 元素之前,首先要检测 getContext() 方法是否存在,这一步非常重要。使用 toDataURL() 方法,可以导出在 元素上绘制的图像

  • 2D 上下文

    • 填充和描边

    填充,就是用指定的样式(颜色、渐变或图像)填充图形;描边,就是只在图形的边缘画线。 大多数 2D 上下文操作都会细分为填充和描边两个操作,而操作的结果取决于两个属性: fillStyle 和 strokeStyle 。

    • 绘制矩形

    矩形是唯一一种可以直接在 2D 上下文中绘制的形状。与矩形有关的方法包括 fillRect() 、strokeRect() 和 clearRect() 。这三个方法都能接收 4 个参数:矩形的 x 坐标、矩形的 y 坐标、矩形宽度和矩形高度。这些参数的单位都是像素。 fillRect() 方法在画布上绘制的矩形会填充指定的颜色
    strokeRect() 方法在画布上绘制的矩形会使用指定的颜色描边。
    clearRect() 方法用于清除画布上的矩形区域。

    • 绘制路径

    通过路径可以创造出复杂的形状和线条。要绘制路径,首先必须调用 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() 所绘制的独立的形状。

    • 绘制文本

    绘制文本主要有两个方法: fillText() 和 strokeText() 。这两个方法都可以接收 4 个参数:要绘制的文本字符串、x 坐标、y 坐标和可选的最大像素宽度。
    font :表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定,例如 “10px Arial” 。
    textAlign :表示文本对齐方式。可能的值有 “start” 、 “end” 、 “left” 、 “right” 和 “center” 。建议使用 “start” 和 “end” ,不要使用 “left” 和 “right” ,因为前两者的意思更稳妥,能同时适合从左到右和从右到左显示(阅读)的语言。
    textBaseline :表示文本的基线。可能的值有 “top” 、 “hanging” 、 “middle” 、 “alphabetic” 、“ideographic” 和 “bottom” 。

    • 变换

    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) :直接修改变换矩阵。
    etTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) :将变换矩阵重置为默认状态,然后再调用 transform() 。

    • 绘制图像

    使用 drawImage()方法。根据期望的最终结果不同,调用这个方法时,可以使用三种不同的参数组合。
    context.drawImage(image, 10, 10);
    改变绘制后图像的大小,可以再多传入两个参数,分别表示目标宽度和目标高度。context.drawImage(image, 50, 10, 20, 30);
    把图像中的某个区域绘制到上下文中。 drawImage() 方法的这种调
    用方式总共需要传入 9 个参数:要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度。context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);

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

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

    • 渐变

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

    • 模式

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

    • 使用图像数据

    通过 getImageData() 取得原始图像数据。这个方法接收4 个参数:要取得其 数据的画面区域的 x 和 y 坐标以及该区域的像素宽度和高度。返回的对象是 ImageData 的实例。每个 ImageData 对象都有三个属性: width 、 height 和data 。其中 data 属性是一个数组,保存着图像中每一个像素的数据。在 data 数组中,每一个像素用4 个元素来保存,分别表示红、绿、蓝和透明度值

    • 合成

    globalAlpha 和 globalComposition-Operation 。其中, globalAlpha 是一个介于 0 和 1 之间的值(包括 0和 1),用于指定所有绘制的透明度。默认值为 0。如果所有后续操作都要基于相同的透明度,就可以先把 globalAlpha 设置为适当值,然后绘制,最后再把它设置回默认值 0。

  • WebGL

    • 类型化数组

    类型化数组也是数组,只不过其元素被设置为特定类型的值。类型化数组的核心就是一个名为 ArrayBuffer 的类型。每个 ArrayBuffer 对象表示的只是内存中指定的字节数,但不会指定这些字节用于保存什么类型的数据。通ArrayBuffer 所能做的,就是为了将来使用而分配一定数量的字节。var buffer = new ArrayBuffer(20);

    • 视图

    ArrayBuffer (数组缓冲器类型)的一种特别的方式就是用它来创建数组缓冲器视图。

    • 类型化视图

    类型化视图一般也被称为类型化数组,因为它们除了元素必须是某种特定的数据类型外,与常规的数组无异。
    Int8Array :表示 8 位二补整数。
    Uint8Array :表示 8 位无符号整数。
    Int16Array :表示 16 位二补整数。
    Uint16Array :表示 16 位无符号整数。
    Int32Array :表示 32 位二补整数。
    Uint32Array :表示 32 位无符号整数。
    Float32Array :表示 32 位 IEEE 浮点值。
    Float64Array :表示 64 位 IEEE 浮点值。

    • WebGL上下文

    如果浏览器不支持 WebGL,那么取得该上下文时会返回 null 。在使用 WebGL 上下文时,务必先检测一下返回值。
    通过给 getContext() 传递第二个参数,可以为 WebGL 上下文设置一些选项。这个参数本身是一个对象,可以包含下列属性。
    alpha :值为 true ,表示为上下文创建一个 Alpha 通道缓冲区;默认值为 true 。
    depth :值为 true ,表示可以使用 16 位深缓冲区;默认值为 true 。
    stencil :值为 true ,表示可以使用 8 位模板缓冲区;默认值为 false 。
    antialias :值为 true ,表示将使用默认机制执行抗锯齿操作;默认值为 true 。
    premultipliedAlpha :值为 true ,表示绘图缓冲区有预乘 Alpha 值;默认值为 true 。
    preserveDrawingBuffer :值为 true ,表示在绘图完成后保留绘图缓冲区;默认值为 false 。建议确实有必要的情况下再开启这个值,因为可能影响性能。

    • 常量

    常量在 OpenGL 中都带前缀 GL_ 。比如说,GL_COLOR_BUFFER_BIT 常量在 WebGL上下文中就是 gl.COLOR_BUFFER_BIT 。WebGL 以这种方式支
    持大多数 OpenGL 常量(有一部分常量是不支持的)。

    • 方法命名

    方法名的后缀会包含参数个数(1 到 4)和接收的数据类型( f 表示浮点数, i 表示整数)。也有很多方法接收数组参数而非一个个单独的参数。这样的方法其名字中会包含字母 v(即 vector,矢量)。

    • 准备绘图

    操作 WebGL 上下文之前,一般都要使用某种实色清除 ,为绘图做好准备。为此,首先必须使用 clearColor() 方法来指定要使用的颜色值,该方法接收 4 个参数:红、绿、蓝和透明度。每个参数必须是一个 0 到 1 之间的数值,表示每种分量在最终颜色中的强度。

    • 视口与坐标

    默认情况下,视口可以使用整个
    区域。要改变视口大小,可以调用 viewport() 方法并传入 4 个参数:(视口相对于 元素的)x 坐标、y 坐标、宽度和高度。

    • 缓冲区

    顶点信息保存在 JavaScript 的类型化数组中,使用之前必须转换到 WebGL 的缓冲区。要创建缓冲区,可以调用 gl.createBuffer() ,然后使用 gl.bindBuffer() 绑定到 WebGL 上下文。

    • 错误

    WebGL 操作一般不会抛出错误。为了知道是否有错误发生,必须在调用某个可能出错的方法后,手工调用 gl.getError() 方法。这个方法返回一个表示错误类型的常量。
    gl.NO_ERROR :上一次操作没有发生错误(值为 0)。
    gl.INVALID_ENUM :应该给方法传入 WebGL 常量,但却传错了参数。
    gl.INVALID_VALUE :在需要无符号数的地方传入了负值。
    gl.INVALID_OPERATION :在当前状态下不能完成操作。
    gl.OUT_OF_MEMORY :没有足够的内存完成操作。
    gl.CONTEXT_LOST_WEBGL :由于外部事件(如设备断电)干扰丢失了当前 WebGL 上下文。

    • 着色器

    WebGL 中有两种着色器:顶点着色器和片段(或像
    素)着色器。顶点着色器用于将 3D 顶点转换为需要渲染的 2D 点。片段着色器用于准确计算要绘制的,每个像素的颜色。WebGL 着色器的独特之处也是其难点在于,它们并不是用 JavaScript 写的。这些着色器是使用 GLSL(OpenGL Shading Language,OpenGL 着色语言)写的,GLSL 是一种与 C 和 JavaScript完全不同的语言。

    • 编写着色器

    每个着色器都有一个 main() 方法,该方法在绘图期间会重复执行。为着色器传递数据的方式有两种:Attribute 和 Uniform。通过 Attribute 可以向顶点着色器中传入顶点信息,通过 Uniform 可以向任何着色器传入常量值。Attribute 和 Uniform 在 main() 方法外部定义,分别使用关键字 attribute 和uniform 。在这两个值类型关键字之后,是数据类型和变量名。

    • 为着色器传入值

    面定义的着色器都必须接收一个值才能工作。为了给着色器传入这个值,必须先找到要接收这个值的变量。对于 Uniform变量,可以使gl.getUniformLocation() ,这个方法返回一个对象,表示Uniform变量在内存中的位置。然后可以基于变量的位置来赋值。

    • 调试着色器和程序

    可以在操作之后调用 gl.getShaderParameter() ,取得着色器的编译状态:
    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){ alert(gl.getShaderInfoLog(vertexShader)); }

    • 绘图

    WebGL 只能绘制三种形状:点、线和三角。其他所有形状都是由这三种基本形状合成之后,再绘制到三维空间中的。执行绘图操作要调用 gl.drawArrays() 或 gl.drawElements() 方法,前者用于数组缓冲区,后者用于元素数组缓冲区。
    gl.drawArrays() 或 gl.drawElements() 的第一个参数都是一个常量,表示要绘制的形状。

    • 纹理

    要创建一个新纹理,可以调用 gl.createTexture() ,
    然后再将一幅图像绑定到该纹理。如果图像尚未加载到内存中,可能需要创建一个 Image 对象的实例,以便动态加载图像。图像加载完成之前,纹理不会初始化,因此,必须在 load 事件触发后才能设置纹理。

    • 读取像素

    通过 WebGL 上下文也能读取像素值。读取像素值的方法 readPixels() 与
    OpenGL 中的同名方法只有一点不同,即最后一个参数必须是类型化数组。像素信息是从帧缓冲区读取,然后保存在类型化数组中。 readPixels() 方法的参数有:x、y、宽度、高度、图像格式、数据类型和类型化数组。前 4 个参数指定读取哪个区域中的像素。图像格式参数几乎总是 gl.RGBA 。数据类型参数用于指定保存在类型化数组中的数据的类型,但有以下限制。
    如果类型是 gl.UNSIGNED_BYTE ,则类型化数组必须是 Uint8Array 。
    如果类型是 gl.UNSIGNED_SHORT_5_6_5 、l.UNSIGNED_SHORT_4_4_4_4 或 gl.UNSIGNED_SHORT_5_5_5_1 ,则类型化数组必须是 Uint16Array 。

    • 支持

    Firefox 4+和 Chrome 都实现了 WebGL API。Safari 5.1 也实现了 WebGL,但默认是禁用的。WebGL比较特别的地方在于,某个浏览器的某个版本实现了它,并不一定意味着就真能使用它。某个浏览器支持 WebGL,至少意味着两件事:首先,浏览器本身必须实现了 WebGL API;其次,计算机必须升级显
    示驱动程序。

  • 小结

    <canvas> 元素提供了一组 JavaScript API,让我们可以动态地创建图形和图像。图形是在一个特定的上下文中创建的,而上下文对象目前有两种。第一种是 2D上下文,可以执行原始的绘图操作。第二种是 3D 上下文,即 WebGL 上下文。WebGL 是从 OpenGL ES 2.0 移植到浏览器中的,而 OpenGLES 2.0 是游戏开发人员在创建计算机图形图像时经常使用的一种语言。目前,主流浏览器的较新版本大都已经支持 <canvas>标签。同样地,这些版本的浏览器基本上也
    都支持 2D 上下文。但对于 WebGL 而言,目前还只有 Firefox 4+和 Chrome 支持它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值