HTMLCanvasElement


了解HTMLCanvasElement

HTMLCanvasElement可以看成是是所有canvas元素的代称,是一个在浏览器可视窗体中可以全局访问的接口,例如我们在Chrome浏览器控制台执行 window.HTMLCanvasElement,会返回:

f
HTMLCanvasElement()
{ [native code] }

类似的还有HTMLDivElement(对应div元素)、HTMLImageElement(对应img元素)、HTMLParagraphElement(对应

元素)等一列接口,几乎所有的标准HTML标签都有一个个对应的接口名称,然后全部都继承于HTMLElement。

这些接口都是DOM Level 2中出现的,因此,IE9+浏览器才支持,IE8浏览器并不支持。考虑到canvas元素也是IE9+开始支持的,因此,如果你有需要使用HTMLCanvasElement的场景,就无需担心兼容性问题。

通常这些接口会内置一些属性和方法,方便用户使用。我们也可以根据自己需求,自定义一些方法,方便调用。例如,下面这个检测canvas画布上是否有透明或半透明像素点的方法:

// 检测canvas画布上是否有透明或半透明像素点
HTMLCanvasElement.prototype.isSomeAlphaPixel = function () {
    var context = this.getContext('2d');
    // 获取图片像素信息
    var imageData = context.getImageData(0, 0, this.width, this.height).data;
    // 检测有没有透明数据
    var isAlphaBackground = false;
    for (var index = 3; index < imageData.length; index += 4) {
        if (imageData[index] != 255) {
            isAlphaBackground = true;
            break;    
        }
    }
    return isAlphaBackground;
};

此时,页面上任意元素DOM对象都可以调用isSomeAlphaPixel()方法。例如:

var canvas = document.querySelector('canvas');
// 输出true或false
console.log(canvas.isSomeAlphaPixel());

属性

除了id,className,title这类所有HTML元素都拥有的属性外,HTMLCanvasElement还有如下一些符合规范标准的属性。

height

简介

表示canvas画布绘制区域的高度,标准属性值为正整数,单位是像素。如果高度值不合法,例如负数,则会使用默认的150代替。为什么是150而不是其他高度值呢?这个是CSS规范中定义的,作为替换元素,默认的尺寸是300 * 150,canvas元素就是替换元素,因此默认高度是150。由于svg元素也是替换元素,因此,svg默认的尺寸也是300 * 150。

语法

  • 获取高度
let pixel = canvas.height
  • 设置高度
canvas.height = pixel

案例

随机改变画布的高度

<canvas style="background:green;"></canvas>
  • 关键JavaScript代码
canvas.height = 50 + 100 * Math.random()

详细

虽然height标准属性值只能是整数,但是实际上:

  • 如果设置小数,浏览器不会认为是不合法的。基本各个主流浏览器渲染时会忽略小数部分,例如:
<canvas height="88.888" style="background:green;"></canvas>
  • 如果高度是包含单位的,则会自动忽略单位,无论这个单位是px、em还是其他什么,例如:
<canvas height="88em" style="background:green;"></canvas>
  • 如果高度值后面是个完全不合法的字符,则按照前面的数值进行高度解析,例如:
<canvas height="88abc" style="background:green;"></canvas>
  • 如果高度值是负数,则Chrome/Firefox等浏览器下会以150像素的高度呈现,而IE浏览器下高度为0,这个是唯一存在兼容性差异表现的属性值,例如:
<canvas height="-150" style="background:green;"></canvas>
  • 如果高度属性值缺省,则会以150像素高度呈现,这个在所有浏览器下都是如此,例如:
<canvas style="background:green;"></canvas>
和CSS height关系

从视觉表现上而言,CSS的height样式权重大于canvas元素的height属性权重
canvas元素本质上就是一个图片,其很多样式表现和img元素是一致的,例如CSS控制图片尺寸的时候,如果高度缺省,canvas和img元素都是依然保持原始的宽高比例。但是,深究下来和img元素还是有一点区别,就是canvas的等比例特性是强制的,会忽略HTML属性的设置,但img不会这样。例如:

<!-- 这时img的宽度依然是300px,并未保持比例 -->
<img src="./1.jpg" width="300" height="150" style="height:88px;">
<!-- canvas仍保持宽高比例 -->
<canvas width="300" height="150" style="background:green; height:88px;"></canvas>
Canvas绘制CSS与height无关

当我们使用各个Canvas API进行图形图像绘制的时候,其坐标位置,尺寸大小等都是相当于canvas元素的HTML属性height,与CSS height没有任何关系,例如:

<canvas height="150" style="background:green; height:88px;"></canvas>

以canvas元素中心点为圆心画一个圆,则垂直坐标应该是75,是HTML height属性值的一半,而非CSS height值的一半。

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
context.fillStyle = 'orange';
context.arc(150, 75, 75, 0, 2 * Math.PI);
context.fill();

width

简介

表示canvas画布绘制区域的宽度,标准属性值为正整数,单位是像素。如果宽度值不合法,例如负数,则会使用默认的300代替。为什么是300而不是其他宽度值呢?这个是CSS规范中定义的,作为替换元素,默认的尺寸是300 * 150,canvas元素就是替换元素,因此默认宽度是300。由于svg元素也是替换元素,因此,svg默认的尺寸也是300 * 150。

语法

  • 获取宽度
let pixel = canvas.width;
  • 设置宽度
canvas.width = pixel;

案例

随机改变画布的宽度。

<canvas style="background:green;"></canvas>
  • 关键JavaScript代码
canvas.width = 150 + 150 * Math.random();

详细

虽然width标准属性值只能是整数,但是实际上:

  • 如果设置小数,浏览器不会认为是不合法的。基本各个主流浏览器渲染时会忽略小数部分,例如:
<canvas width="188.888" style="background:green;"></canvas>
  • 如果宽度是包含单位的,则会自动忽略单位,无论这个单位是px、em还是其他什么,例如:
<canvas width="188em" style="background:green;"></canvas>
  • 如果宽度值后面是个完全不合法的字符,则按照前面的数值进行宽度解析,例如:
<canvas width="188abc" style="background:green;"></canvas>
  • 如果宽度值是负数,则Chrome/Firefox等浏览器下会以150像素的宽度呈现,而IE浏览器下宽度为0,这个是唯一存在兼容性差异表现的属性值,例如:
<canvas width="-300" style="background:green;"></canvas>
  • 如果宽度值缺省,则会以300像素宽度呈现,这个所有浏览器下都是如此,例如:
<canvas style="background:green;"></canvas>
和CSS width关系

从视觉表现上而言,CSS的width样式权重大于canvas元素的width属性权重
canvas元素本质上就是一个图片,其很多样式表现和img元素是一致的,例如CSS控制图片尺寸的时候,如果高度缺省,canvas和img元素都是依然保持原始的宽高比例。但是,深究下来和img元素还是有一点区别,就是canvas的等比例特性是强制的,会忽略HTML属性的设置,但img不会这样。例如:

<!-- 这时img的高度依然是300px,并未保持比例 -->
<img src="./1.jpg" width="300" height="150" style="width:188px;">
<!-- canvas仍保持宽高比例 -->
<canvas width="300" height="150" style="background:green; width:188px;"></canvas>
Canvas绘制CSS与height无关

当我们使用各个Canvas API进行图形图像绘制的时候,其坐标位置,尺寸大小等都是相当于canvas元素的HTML属性width,与CSS width没有任何关系,例如:

<canvas width="300" style="background:green; width:188px;"></canvas>

以canvas元素中心点为圆心画一个圆,则水平坐标应该是150,是HTML width属性值的一半,而非CSS width值的一半。

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
context.fillStyle = 'orange';
context.arc(150, 75, 75, 0, 2 * Math.PI);
context.fill();

方法

getContext()

简介

getContext()方法可以返回canvas的绘制上下文,“上下文”是计算机领域的一个术语,类似于小说中的藏经阁,现实世界的工具箱,表示一种特殊的环境。在这个环境中,我们就能做一些特殊的事情,对于Canvas而言,我们可以借助其上下文绘制各种图形和效果。

语法

var context = canvas.getContext(contextType, contextAttributes)
  1. 参数contextType(string类型)
参数 描述
‘2d’ 会创建并返回一个CanvasRenderingContext2D对象,主要用来进行2d绘制,也就是二维绘制,平面绘制。
‘webgl’或’experimental-webgl’ 此参数可以返回一个WebGLRenderingContext(WebGL渲染上下文)对象,WebGL(全写Web Graphics Library)是一种3D绘图协议,可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型,无需安装任何其他插件。此参数对应的WebGL版本1(OpenGL ES 2.0)。
‘webgl2’ 此参数可以返回一个WebGL2RenderingContext对象,可以用来绘制三维3D效果。此参数对应的WebGL版本2(OpenGL ES 3.0)。不过目前这个还处于试验阶段,我们实际Kaufman都是使用’webgl’这个参数。
‘bitmaprenderer’ 创建一个ImageBitmapRenderingContext(位图渲染上下文),可以借助给定的ImageBitmap替换Canavs的内容。
2. 参数contextAttributes(Object类型,可选)

参数 | 描述 | contextType值
—|—|
alpha | 表示Canavs是否包含alpha透明通道,如果设置为false,则表示Canvas不支持全透明或者半透明,在绘制带有透明效果的图形或者图像时候速度会更快一些。 | ‘2d’
alpha | 表示Canavs是否包含透明缓冲区。 | ‘webgl’
antialias | 表示是否需要抗边缘锯齿。如果设置为true,图像呈现质量会好一些,但是速度会拖慢。 | ‘webgl’
depth | 表示绘制缓冲区的缓冲深度至少16位。 | ‘webgl’
failIfMajorPerformanceCaveat | 表示如果用户的系统性能比较差,是否继续常见绘制上下文。 | ‘webgl’
powerPreference | 高速用户使用的客户端(如浏览器)我们现在这个WebGL上下文最合适的GPU配置是什么。支持下面关键字值:’default’(让用户的客户端设备自己觉得那个GPU配置是最合适的。这个是此参数的默认值。)、’high-performance’(渲染性能优先,通常更耗掉(如手机,平板等移动设备)。)、’low-power’(省电优先,渲染性能权重可以低一些。) | ‘webgl’
premultipliedAlpha | 表示页面合成器将假定绘图缓冲区包含具有alpha预乘(pre-multiplied alpha)颜色。 | ‘webgl’
preserveDrawingBuffer | 如果值为true,则不会清除缓冲区并保留其值,直到作者清除或覆盖。 | ‘webgl’
stencil | 表示绘图缓冲区具有至少8位的模板缓冲区。 | ‘webgl’
示例:

var gl = canvas.getContext('webgl', {
    antialias: false,
    depth: false,
});
  1. 返回值
    无论getContext()方法中的参数是什么,其返回值都可以称之为RenderingContext,再细分可以包括下面这些:
  • ‘2d’参数值对应的CanvasRenderingContext2D;
  • ‘webgl’或experimental-webgl参数值对应的WebGLRenderingContext;
  • ‘webgl2’参数值对应的WebGL2RenderingContext;
  • ‘bitmaprenderer’参数值对应的ImageBitmapRenderingContext。

案例

<canvas></canvas>
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
// 打印出context对象属性名或方法名
console.dir(context);

更多

基本上,只要我们使用canvas实现功能,getContext()方法调用100%需要使用。甚至可以这么说,只要你想用canvas实现任何平面效果,首先不管三七二十一,先把下面2行写上:

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');

当然如果页面存在多个canvas元素,我们可以自己加个id或者class类名在配合选择器获取。也可以直接create创建,然后append到页面中,例如:

var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
var context = canvas.getContext('2d');

如果希望canvas元素放在body元素最前面,则可以:

var canvas = document.createElement('canvas');
document.body.insertBefore(canvas, document.body.firstElementChild);
var context = canvas.getContext('2d');

toBlob()

简介

toBlob()方法可以Canvas图像对应的Blob对象(binary large object)。此方法可以把Canvas图像缓存在磁盘上,或者存储在内存中,这个往往由浏览器决定。

语法

void canvas.toBlob(callback, mimeType, quality);

这里的void表示无返回值。

  • callback(Function)
    toBlob()方法执行成功后的回调方法,支持一个参数,表示当前转换的Blob对象。
  • mimeType(String,可选)
    mimeType表示需要转换的图像的mimeType类型。默认值是image/png,还可以是image/jpeg,甚至image/webp(前提浏览器支持)等。
  • quality(Number,可选)
    quality表示转换的图片质量。范围是0到1。由于Canvas的toBlob()方法转PNG是无损的,因此,此参数默认是没有效的,除非,指定图片mimeType是image/jpeg或者image/webp,此时默认压缩值是0.92。

案例

案例1(Blob图像上传)

这个案例演示的是Canvas图像转换成Blob二进制对象并使用HTML5 FormData进行Ajax上传。

<canvas></canvas>

假设上面canvas是已经绘制好的图形,我们需要Ajax提交到后台进行保存,则JavaScript代码可以这样:

var canvas = document.querySelector('canvas');
// canvas转为blob并上传
canvas.toBlob(function (blob) {
    var data = new FormData();
    // 装载图片数据
    data.append('image', blob);
    // 图片ajax上传,字段名是image
    var xhr = new XMLHttpRequest();
    // 文件上传成功
    xhr.onload = function() {
        // xhr.responseText就是返回的数据
    };
    // 开始上传
    xhr.open('POST', 'upload.php', true);
    xhr.send(data);    
});
案例2(IMG图像数据为Blob)

如果我们希望把canvas元素图像使用img元素显示,toBlob()和toDataURL()方法都是可以的,但个人推荐使用toBlob()方法(如果不用顾及兼容性)。
blob数据对象是无法直接作为img的src属性值呈现的,需要URL.createObjectURL()方法处理下。
Blob数据转URL地址关键JavaScript代码如下:

canvas.toBlob(function(blob) {
    var url = URL.createObjectURL(blob);
    p.innerHTML = '<img src="'+ url +'">';
}, 'image/jpeg');

另外,如果图片转换交互频繁,性能开销比较大,且图片仅展示无其它数据层面的交互,我们可以使用URL.revokeObjectURL(url)释放资源。不过实际开发页面通常都不复杂,不释放也没关系。

兼容

首先,toBlob()方法IE9浏览器不支持,因为Blob数据格式IE10+才支持。
然后,对于IE浏览器,toBlob()的兼容性有些奇怪,IE10浏览器支持ms私有前缀的toBlob()方法,完整方法名称是msToBlob()。而IE11+,toBlob()方法却不支持。
但是,我们可以基于toDataURL()方法进行polyfill,性能相对会差一些,JavaScript代码如下,参考自MDN:

if (!HTMLCanvasElement.prototype.toBlob) {
  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
    value: function (callback, type, quality) {
      var canvas = this;
      setTimeout(function() {
        var binStr = atob( canvas.toDataURL(type, quality).split(',')[1] );
        var len = binStr.length;
        var arr = new Uint8Array(len);

        for (var i = 0; i < len; i++) {
          arr[i] = binStr.charCodeAt(i);
        }

        callback(new Blob([arr], { type: type || 'image/png' }));
      });
    }
  });
}

toDataURL()

简介

Canvas本质上就是一个位图图像,因此,浏览器提供了若干API可以将Canvas图像转换成可以作为IMG呈现的数据,其中最老牌的方法就是HTMLCanvasElement.toDataURL(),此方法可以返回Canvas图像对应的data URI,也就是平常我们所说的base64地址。

语法

canvas.toDataURL(mimeType, quality);
  1. 参数说明
  • mimeType(String,可选)
    mimeType表示需要转换的图像的mimeType类型。默认值是image/png,还可以是image/jpeg,甚至image/webp(前提浏览器支持)等。
  • quality(Number可选)
    quality表示转换的图片质量。范围是0到1。此参数要想有效,图片的mimeType需要是image/jpeg或者image/webp,其他mimeType值无效。默认压缩质量是0.92。
    根据自己的肉眼分辨,如果使用toDataURL()的quality参数对图片进行压缩,同样的压缩百分比呈现效果要比Adobe Photoshop差一些。
  1. 返回值
    返回base64 data图片数据。

案例

案例1(最基础的使用)
<canvas width="10" height="10"></canvas>
var canvas = document.querySelector('canvas');
var dataURL = canvas.toDataURL();
console.log(dataURL);
// 结果是:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAF0lEQVQoU2NkIBIwEqmOYVQh3pAiOngACmkAC5eMKzgAAAAASUVORK5CYII="
案例2(转换成JPG图片)

如果Canvas中颜色信息非常丰富,如实物照片,则建议指定mime type为image/jpeg,data-URL数据量会大大降低,但质量也依然很OK。例如:

canvas.toDataURL('image/jpeg');

如果Canvas图像本身是2倍图(画布实际尺寸是CSS样式尺寸的2倍+),则图像理论质量0.50.6足矣。但考虑到Canvas本身压缩后的图像品质不算高,实际质量值建议0.60.7。如果是一倍图,则使用默认值即可。

canvas.toDataURL('image/jpeg', 0.6);
案例3(检测浏览器是否支持webp)
var isSupportWebp = !![].map && document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
console.log(isSupportWebp);   // true or false

更多


文章作者: Ron.
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ron. !
  目录