美文网首页JavaScript < ES5、ES6、ES7、… >
JavaScript 高级程序设计(第15章 使用 Canvas

JavaScript 高级程序设计(第15章 使用 Canvas

作者: yinxmm | 来源:发表于2018-08-17 22:57 被阅读27次

    第15章 使用 Canvas 绘图

    1. 基本用法

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

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

    (2) <canvas>元素对应的 DOM 元素对象也有 width 和 height 属性,可以随意修 改。而且,也能通过 CSS 为该元素添加样式,如果不添加任何样式或者不绘制任何图形,在页面中是看 不到该元素的。

    (3)getContext()方法:取得绘图上下文对象的引用,传入上下文的名字。传入"2d",就可以取得 2D 上下文对象。

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

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

    2. 2D 上下文

    (1) 填充和描边

    填充,就是用指定的样式(颜色、渐变或图像)填
    充图形。fillStyle 属性
    描边,就是只在图形的边缘画线。strokeStyle属性

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

    (2) 绘制矩形

    与矩形有关的方法包括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);
    }
    

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

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

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

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

    (3) 绘制路径

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

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

    (4) 创建了路径后,接下来有几种可能的选择。

    1. closePath():绘制一条连接到路径起点的线条。
    2. fill():填充路径,使用fillStyle 填充。
    3. stroke():对路径描边,描边使用的是 strokeStyle。
    4. 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();
    }
    

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

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

    (4) 绘制文本

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

    (1) font:表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定,例如"10px Arial"。
    (2) textAlign:表示文本对齐方式。可能的值有"start"、"end"、"left"、"right"和"center"。
    (3) textBaseline:表示文本的基线。可能的值有"top"、"hanging"、"middle"、"alphabetic"、
    "ideographic"和"bottom"。

    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.fi llText("12", 100, 40);
    //终点对齐
    context.textAlign = "end";
     context.fi llText("12", 100, 60);
    

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

    measureText()方法利用 font、textAlign 和 textBaseline 的当前值计算指定文本的大小
    这个方法接收一个参数,即要绘制的文本;返回一个 TextMetrics 对象。返回的对象目前只有一个width 属性,但将来还会增加更多度量属性。

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

    (5) 变换

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


    5. 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.rotate(1);
            //绘制分针
            context.moveTo(0,0);
            context.lineTo(0, -85);
            //绘制时针 
            context.moveTo(0, 0); 
            context.lineTo(-65, 0);
            //描边路径
            context.stroke();
    }
    

    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)开始绘制红色矩形
    

    (6) 绘制图像

    drawImage() 方法:想把一幅图像绘制到画布上。

    调用这个方法的3种参数组合:

    • 传入一个 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 坐标、目标图像的宽度、目标图像的高度。
    context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);
    

    (7) 阴影

    1. shadowColor:用 CSS 颜色格式表示的阴影颜色,默认为黑色。
    2. shadowOffsetX:形状或路径 x 轴方向的阴影偏移量,默认为 0。
    3. shadowOffsetY:形状或路径 y 轴方向的阴影偏移量,默认为 0。
    4. 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);
    

    (8) 渐变

    1. createLinearGradient()方法(线性渐变),这个方法接收 4 个参数:起点的 x 坐标、起点的 y 坐 标、终点的 x 坐标、终点的 y 坐标。调用这个方法后,它就会创建一个指定大小的渐变,并返回 CanvasGradient 对象的实例。
    2. 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);
    

    确保渐变 与形状对齐:

    function createRectLinearGradient(context, x, y, width, height){
            return context.createLinearGradient(x, y, x+width, y+height);
    }
    
    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);
    
    1. createRadialGradient()方法(径向渐变[放射渐变]),接收 6 个参 数,对应着两个圆的圆心和半径。前三个参数指定的是起点圆的原心(x 和 y)及半径,后三个参数指 定的是终点圆的原心(x 和 y)及半径。
    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);
    

    (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)设置 为模式对象,只表示在某个特定的区域内显示重复的图像,而不是要从某个位置开始绘制重复的图像。

    (10) 使用图像数据

    1. getImageData()取得原始图像数据。这个方法接收 4 个参数:要取得其数据的画面区域的 x 和 y 坐标以及该区域的像素宽度和高度。
    var imageData = context.getImageData(10, 5, 50, 50);
    
    1. 这里返回的对象是 ImageData 的实例。每个 ImageData 对象都有三个属性:width、height 和data。
    2. 其中 data 属性是一个数组,保存着图像中每一个像素的数据。在 data 数组中,每一个像素用4 个元素来保存,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据就保存在数组的第 0 到第3 个元素中。

    通过修改图像数据,可以像下面这样创建一个简单的灰阶过滤器:

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

    (11) 合成

    1. globalAlpha 是一个介于 0 和 1 之间的值(包括 0 和 1),用于指定所有绘制的透 明度。默认值为 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;
    
    1. globalCompositionOperation表示后绘制的图形怎样与先绘制的图形结合。这个 属性的值是字符串,可能的值如下:
      (1) source-over(默认值):后绘制的图形位于先绘制的图形上方。
      (2) source-in:后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明。
      (3) source-out:后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明。
      (4) source-atop:后绘制的图形与先绘制的图形重叠的部分可见,先绘制图形不受影响。
      (5) destination-over:后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见。
      (6) destination-in:后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明。
      (7) destination-out:后绘制的图形擦除与先绘制的图形重叠的部分。
      (8) destination-atop:后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明。
      (9) lighter:后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮。
      (10) copy:后绘制的图形完全替代与之重叠的先绘制图形。
      (11) xor:后绘制的图形与先绘制的图形重叠的部分执行“异或”操作。

    3. WebGL

    (1) 类型化数组

    1. 类型化数组的核心就是一个名为ArrayBuffer 的类型。每个 ArrayBuffer 对象表示的只是内存 中指定的字节数,但不会指定这些字节用于保存什么类型的数据。通过 ArrayBuffer 所能做的,就是 为了将来使用而分配一定数量的字节。
    var buffer = new ArrayBuffer(20);
    
    1. 创建了 ArrayBuffer 对象后,能够通过该对象获得的信息只有它包含的字节数,方法是访问其byteLength 属性:
    var bytes = buffer.byteLength;
    
    *视图

    使用 ArrayBuffer(数组缓冲器类型)的一种特别的方式就是用它来创建数组缓冲器视图。其中, 最常见的视图是 DataView,通过它可以选择 ArrayBuffer 中一小段字节。

    (1) 在创建 DataView 实例的时候传入一个 ArrayBuffer、一个可选的字节偏移量(从该字节开始选择)和一个可选的要选 择的字节数。

    //基于整个缓冲器创建一个新视图
    var view = new DataView(buffer);
    //创建一个开始于字节 9 的新视图
    var view = new DataView(buffer, 9);
    //创建一个从字节 9 开始到字节 18 的新视图
    var view = new DataView(buffer, 9, 10);
    

    (2) DataView 对象会把字节偏移量以及字节长度信息分别保存在 byteOffsetbyteLength 属性中。

    alert(view.byteOffset);
    alert(view.byteLength);
    

    (3) DataView 支持的数据类型以及相应的读写方法:



    var buffer = new ArrayBuffer(20),
        view = new DataView(buffer),
        value;
    view.setUint16(0, 25);
    view.setUint16(2, 50); //不能从字节 1 开始,因为 16 位整数要用 2B 
    value = view.getUint16(0);
    
    var buffer = new ArrayBuffer(20),
        view = new DataView(buffer),
        value;
    view.setUint16(0, 25);
    value = view.getInt8(0);
    alert(value); //0
    
    *类型化视图

    类型化视图一般也被称为类型化数组,因为它们除了元素必须是某种特定的数据类型外,与常规的 数组无异。

    类型化视图也分几种,而且它们都继承了 DataView。

    (1) Int8Array:表示 8 位二补整数。
    (2) Uint8Array:表示 8 位无符号整数。
    (3) Int16Array:表示 16 位二补整数。
    (4) Uint16Array:表示 16 位无符号整数。
    (5) Int32Array:表示 32 位二补整数。
    (6) Uint32Array:表示 32 位无符号整数。
    (7) Float32Array:表示 32 位 IEEE 浮点值。
    (8) Float64Array:表示 64 位 IEEE 浮点值。

    1. 由于这些视图都继承自 DataView,因而可以使用相同的构造函数参数来实例化。第一个参数是要 使用 ArrayBuffer 对象,第二个参数是作为起点的字节偏移量(默认为 0),第三个参数是要包含的字 节数。三个参数中只有第一个是必需的。
    //创建一个新数组,使用整个缓冲器
    var int8s = new Int8Array(buffer);
    //只使用从字节 9 开始的缓冲器
    var int16s = new Int16Array(buffer, 9);
    //只使用从字节 9 到字节 18 的缓冲器
    var uint16s = new Uint16Array(buffer, 9, 10);
    
    1. 每个视图构造函数都有一个名为 BYTES_PER_ELEMENT的属性,表示类型化数组的每个元素需要多 少字节。
    //需要 10 个元素空间
    var int8s = new Int8Array(buffer, 0, 10 * Int8Array.BYTES_PER_ELEMENT);
    //需要 5 个元素空间
    var uint16s = new Uint16Array(buffer, int8s.byteOffset + int8s.byteLength,  5 * Uint16Array.BYTES_PER_ELEMENT);
    
    1. 使用类型化视图时,可以通过方括号语法访问每一个数据成员,可以通过 length 属性确定数组中有多少元素。
    for (var i=0, len=int8s.length; i < len; i++){
        console.log("Value at position " + i + " is " + int8s[i]);
    }
    
    1. 类型化视图还有一个方法,即 subarray(),使用这个方法可以基于底层数组缓冲器的子集创建一 个新视图。这个方法接收两个参数:开始元素的索引和可选的结束元素的索引。返回的类型与调用该方 法的视图类型相同。
    var uint16s = new Uint16Array(10),
            sub = uint16s.subarray(2, 5);
    

    (2) WebGL上下文

    1. 在支持的浏览器中,WebGL 的名字叫"experimental-webgl",如果浏览器不支持 WebGL, 那么取得该上下文时会返回 null。
    var drawing = document.getElementById("drawing");
    //确定浏览器支持<canvas>元素 if (drawing.getContext){
        var gl = drawing.getContext("experimental-webgl");
        if (gl){
    //使用 WebGL }
    }
    
    1. 通过给 getContext()传递第二个参数,可以为 WebGL 上下文设置一些选项。这个参数本身是一 个对象,可以包含下列属性。

    (1) alpha:值为 true,表示为上下文创建一个 Alpha 通道缓冲区;默认值为 true。
    (2) depth:值为 true,表示可以使用 16 位深缓冲区;默认值为 true。
    (3) stencil:值为 true,表示可以使用 8 位模板缓冲区;默认值为 false。
    (4) antialias:值为 true,表示将使用默认机制执行抗锯齿操作;默认值为 true。
    (5) premultipliedAlpha:值为 true,表示绘图缓冲区有预乘 Alpha 值;默认值为 true。
    (6) preserveDrawingBuffer:值为 true,表示在绘图完成后保留绘图缓冲区;默认值为 false。建议确实有必要的情况下再开启这个值,因为可能影响性能。

    var drawing = document.getElementById("drawing");
    //确定浏览器支持<canvas>元素
     if (drawing.getContext){
            var gl = drawing.getContext("experimental-webgl", { alpha: false}); 
     if (gl){
            //使用 WebGL
      }
    }
    
    *常量

    在 WebGL 中,保存在上下文对象中的这些常量都没有 GL_前缀。

    *方法命名
    1. 方法名的后缀会包含参数个数(1 到 4) 和接收的数据类型(f 表示浮点数,i 表示整数)。例如,gl.uniform4f()意味着要接收 4 个浮点数,而 gl.uniform3i()则表示要接收 3 个整数。
    2. 也有很多方法接收数组参数而非一个个单独的参数。这样的方法其名字中会包含字母 v(即 vector, 矢量)。因此,gl.uniform3iv()可以接收一个包含 3 个值的整数数组。
    *准备绘图

    在实际操作 WebGL 上下文之前,一般都要使用某种实色清除<canvas>,为绘图做好准备。

    1. clearColor()方法来指定要使用的颜色值,该方法接收 4 个参数:红、绿、蓝和透明度。 每个参数必须是一个 0 到 1 之间的数值,表示每种分量在最终颜色中的强度。
    2. clear()方法传入的参数 gl.COLOR_BUFFER_BIT告诉 WebGL 使用之前定义的颜色来填充相应区 域。
    gl.clearColor(0,0,0,1);   //black
    gl.clear(gl.COLOR_BUFFER_BIT);
    
    *视口与坐标

    开始绘图之前,通常要先定义 WebGL 的视口(viewport)。默认情况下,视口可以使用整个<canvas> 区域。

    1.viewport()方法改变视口大小,传入 4 个参数:(视口相对于<canvas>元素的) x 坐标、y 坐标、宽度和高度。

    1. 视口坐标的原点(0,0)在<canvas>元素的左下角,x
      轴和 y 轴的正方向分别是向右和向上。
    2. 视口内部的坐标系与定义视口的坐标系也不一样。在视口内部,坐标原点(0,0)是视口的中心 点,因此视口左下角坐标为(-1,-1),而右上角坐标为(1,1)。
    *缓冲区

    顶点信息保存在 JavaScript 的类型化数组中,使用之前必须转换到 WebGL 的缓冲区。

    1. gl.createBuffer()创建缓冲区。
    2. gl.bindBuffer()绑定到 WebGL 上下文。
    3. gl.bufferData()数据填充缓冲区。
    4. gl.bufferData()的最后一个参数用于指定使用缓冲区的方式,取值范围是如下几个常量。
      (1) gl.STATIC_DRAW:数据只加载一次,在多次绘图中使用。
      (2) gl.STREAM_DRAW:数据只加载一次,在几次绘图中使用。
      (3) gl.DYNAMIC_DRAW:数据动态改变,在多次绘图中使用。
    5. drawElements()输出缓冲区的内容,也可以传入 gl.ELEMENT_ARRAY_BUFFER。
    6. gl.deleteBuffer()释放内存。
    var buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.5, 1]), gl.STATIC_DRAW);
    gl.deleteBuffer(buffer);
    

    相关文章

      网友评论

        本文标题:JavaScript 高级程序设计(第15章 使用 Canvas

        本文链接:https://www.haomeiwen.com/subject/ickxiftx.html