canvas 基础

本文基本上能够用来当作 canvas 的一个基本参考。基本涵盖了全部的 canvas 内容,固然,不包括使用 canvas 来处理的高级应用。css

线

基本的有:css3

画线

基本的架构为:web

ctx.beginPath(); // 开始画线,里面没有任何参数
ctx.moveTo(x,y); // 定义起始点
ctx.lineTo(x,y); // 定义过程点
// 还能够定义线宽,线的颜色
ctx.stroke();  // 开始划线,里面没任何参数

line

// 简单就是 
ctx.moveTo(x,y)
ctx.lineTo(x,y)

lineWidth

控制线宽算法

ctx.lineWidth = 20; // 单位默认为 px

lineColor

线颜色定义可使用:chrome

ctx.strokeStyle = "#fff";

lineCap

定义线两端的格式为:canvas

context.lineCap = 'butt';

该属性有 3 个取值:butt,round,square。分别为:数组

lineCap

lineJoin

用来描述,多个路径之间的链接方式。基本取值有:round,bevel,miter。浏览器

context.beginPath();
      context.moveTo(379, 150);
      context.lineTo(429, 50);
      context.lineTo(479, 150);
      context.lineJoin = 'bevel';
      context.stroke();

详情为:架构

lineJoin

曲线

曲线和线段
基本区现有: 弧线,二次曲线,贝塞尔曲线。ide

arcTo

基本格式为:

ctx.arcTo(cx1, cy1, x2, y2, radius);

一样,使用 moveTo 或者 lineTo 肯定第一个起始点。

context.beginPath();
    context.moveTo(100, 225);             // P0
    context.arcTo(228, 40, 530, 70, 89); // P1, P2 and the radius
    context.lineTo(530, 70);             // P2 
    context.stroke();

上面,P2 点用到了 lineTo。 这有什么影响吗?有的。
若是没定义 lineTo,圆弧可能并不会过到 P2 点,由于圆弧实际的算法为:

arcTo

它只会肯定最终圆弧的范围的大小,并不会关注 P2 点是否链接。若是没定义 lineTo 的话,结果为:

no_lineTo

Quadratic Curve

该是用来画二次曲线的:

ctx.quadraticCurveTo(cpx, cpy, x, y);

他一般结合 moveTo 来找到 3 个点,肯定二次函数。

ctx.beginPath();
ctx.moveTo(50,20);  // x 轴上的点 (50,20)
ctx.quadraticCurveTo(230, 30, 50, 100); // 控制点为 (230,30)。
// 另外 x 轴上的点为 (50,100)
ctx.stroke();

屏幕快照 2016-10-12 20.16.31.png-10.2kB

bezier Curve

该 tag 是用来画贝塞尔曲线的,即经过定义 4 个点,便可肯定,线的形状,具体格式为:

// 这里定义了两个控制点,一个基准点
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

上面说到 4 个点,还有一个点是经过 moveTo 来定义的。基本格式为:

ctx.beginPath();
ctx.moveTo(50,20);
ctx.bezierCurveTo(230, 30, 150, 60, 50, 100);
ctx.stroke();

如图:

bezier

实际计算方法是取中点,而后取过中点的切线。

bezier

图形

基本的简单图形有:,圆,椭圆,自定义图形.
图形方面一般是结合,ctx.fill() 来进行触发渲染的操做。

rect()

该API 用来在 canvas 上画一个。

// 基本格式为
ctx.rect(x, y, width, height);
ctx.fill();

// 或者使用二者的结合属性
ctx.fillRect(x, y, width, height);

看 API 应该很容易就知道,这个是用来干啥的了。
rect 默认颜色是 black。固然,你也能够经过使用 fillStyle 来显示的改变颜色。

ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);

矩形框

上面那种形式,是用来画图形内容,接着,咱们可使用 strokeRect() 来画一个矩形边框使用。
基本格式为:

ctx.strokeRect(x, y, width, height);

实际画法。

ctx.strokeStyle = "green";
ctx.strokeRect(10, 10, 100, 100);

这里,直接使用 stroke 便可,不须要在显示触发渲染啥的了。画边框,固然可使用 line 相关的属性,好比,定义线宽。

ctx.lineWidth = 5;

实际上,结合 rect 也能够来画一个矩形框:

context.beginPath();
      context.rect(188, 50, 200, 100);
      context.fillStyle = 'yellow';
      context.fill();
      context.lineWidth = 7;
      context.strokeStyle = 'black';
      context.stroke();  // 触发画边框的效果

arc

基本格式为:

// 默认为逆时针
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

startAngle 是从 x 轴正方向,顺时针计算角度。
详细demo:

ctx.arc(75, 75, 50, 0, 2 * Math.PI);

// 顺时针画圆
ctx.arc(75, 75, 50, 0, 2 * Math.PI,false);

好比,另外画一个半圆。

context.beginPath();
      context.arc(288, 75, 70, 0, Math.PI, false);
      context.closePath();  // 封闭图形
      context.lineWidth = 5;
      context.fillStyle = 'red';
      context.fill();
      context.strokeStyle = '#550000';
      context.stroke();

ellipse*

这个 API 是最近提出来的,比较新。因此,兼容性须要考虑。基本格式为:

// x,y 肯定长轴,短轴的位置
// rotation 按照 x 轴正方向,按照 anticlockwise 的设置进行旋转,也是弧度制
// startAngle,endAngle 也是按照 x 轴正方向来的
ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);

他的角度表示都是 弧度制(radians)。
看个实例:

ctx.beginPath();
ctx.ellipse(100, 100, 50, 75, 45 * Math.PI/180, 0, 2 * Math.PI);
ctx.stroke();

图为:

image_1auueo1qd1ott1hsmiau1npa1kh89.png-4.1kB

固然,你也可使用 fill 等,来填充相关颜色。

自定义图形

若是你想画一个自定义图形的话,须要结合 line 相关的标签。最后使用 closePath() 来显示封闭图形。
closePath API 的实际做用是: 当你当前的点已经和起始点重合,那么 do nothing。不然,将当前点和起始点用直线链接起来,构成封闭图形,这样才可能使用 fill 相关来进行填充。

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

      // begin custom shape
      context.beginPath();
      context.moveTo(170, 80);
      context.bezierCurveTo(130, 100, 130, 150, 230, 150);
      context.bezierCurveTo(250, 180, 320, 180, 340, 150);
      context.bezierCurveTo(420, 150, 420, 120, 390, 100);
      context.bezierCurveTo(430, 40, 370, 30, 340, 50);
      context.bezierCurveTo(320, 5, 250, 20, 250, 50);
      context.bezierCurveTo(200, 5, 150, 20, 170, 80);

      // complete custom shape
      context.closePath();
      context.lineWidth = 5;
      context.strokeStyle = 'blue';
      context.stroke();

最后必定要记得使用 closePath() 这样,才能达到完整图形的效果。

填充

关于填充有:基本颜色填充,渐变填充,图片填充。基本的颜色填充会涉及到两个,一个是 fillStyle,还有一个是 strokeStyle。两个的基本形似是如出一辙的:

// 填充基本颜色值,好比 #fff
ctx.fillStyle = color;
// 填充渐变值,好比 createLinear 建立的渐变等
ctx.fillStyle = gradient;
// 一般用来贴图用的值
ctx.fillStyle = pattern;

颜色填充

这个就不过说了,就是填 RGB 值。

ctx.fillStyle = "blue";

渐变色填充

渐变色有两种,一个是线性渐变:createLinearGradient(),一个是中心渐变:createRadialGradient()。 他们可使用一个共同的 API : addColorStop()。来设置间隔色。基本格式为:

addColorStop(offset, color);
  • offset: 为 [0,1] 之间的数

  • color: rgb 的值

var gradient = ctx.createLinearGradient(0,0,200,0);
gradient.addColorStop(0,"green");
gradient.addColorStop(1,"white");
ctx.fillStyle = gradient;
ctx.fillRect(10,10,200,100);

createLinearGradient()

线性渐变的内容是:

ctx.createLinearGradient(x0, y0, x1, y1);

两个点肯定一条直线,而后将颜色按照这个线段进行渐变。

实例:

image_1auuik89a9ba1kj8tq21eurvcm.png-12.3kB

代码为:

gradient.addColorStop(0,'red');
gradient.addColorStop(1,'black');
ctx.fillStyle=gradient;
ctx.fillRect(0,0,320,320);

createRadialGradient()

中心渐变内容为:

ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);

以及上就是两个圆,而后按照顺序,将颜色渐变,固然中间也能够添加多段。

实例:

canvas-radial

代码为:

let gradient = ctx.createRadialGradient(200,200,0,200,200,160);
        gradient.addColorStop(0,'red');
        gradient.addColorStop(1,'white');
        ctx.fillStyle=gradient;
        ctx.arc(200,200,160,0,2*Math.PI);
        ctx.fill();

pattern - 贴图

这一块应该算是 canvas 牛逼的地方,可以和图形相关的元素结合起来的关键点。格式为:

ctx.createPattern(image, repetition);
  • image: 该类型的取值有不少,好比 image,video,cavnas,imageData,blob 等。

    • HTMLImageElement (< img>)

    • HTMLVideoElement (< video>)

    • HTMLCanvasElement (< canvas>)

    • CanvasRenderingContext2D

    • ImageBitmap

    • ImageData

    • Blob

  • repetition:该取值内容就很简单,至关于 background 同样,用来设置图片的重复形式。

    • repeat (默认值)

    • repeat-x

    • repeat-y

    • no-repeat

这里就举一个贴图的列子:

// FROM MDN
var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
img.onload = function() {
  var pattern = ctx.createPattern(img, 'repeat');
  ctx.fillStyle = pattern;
  ctx.fillRect(0,0,400,400);
};

图片处理

图片处理相关的 API 有不少,这里先说最基本的,drawImage()。它有 3 种基本形式:

void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

分别说一下:

简单绘制

void ctx.drawImage(image, dx, dy);

简单的 3 个参数,就用来肯定图片在 canvas 上的位置,不进行任何缩放。

simple_draw

缩放绘制

基本格式为:

void ctx.drawImage(image, dx, dy, dWidth, dHeight);

经过, dWidth 和 dHeight 来肯定在 canvas 中绘制的大小,能够放大和缩小。

scale_image

代码为:

let img = new Image();
img.onload = function(){
        ctx.drawImage(img,20,20,150,100);
}
img.src = "...";

裁剪绘制

基本格式为:

void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

其中,sx,sy,sWidth,sHeight 用来肯定在原来图片上,截取图像的区域。

sheight

具体代码为:

let img = new Image();
img.onload = function(){
        ctx.drawImage(img,20,20,60,95,60,60,100,200);
}
img.src = "...";

字体处理

在 canvas 里,还有显示文字的一个 trick 。文字方面的话,没什么特别的就是基本的 style, szie ,color 等。 通常结合 fillText/stokeText API 一块儿使用,进行绘制。这里两个 API 的区别也很普通,就是简单的 填充实心字体 和 边界字体。

context.font = 'italic 40pt Calibri';
context.fillText('Hello World!', 150, 100);

先简单说一下,这两个 API。他们的格式,基本上是同样的:

ctx.strokeText(text, x, y [, maxWidth]);
  • x,y 用来肯定 text 的左下角起始点。很重要,是左下角!

  • maxWidth: 用来肯定 text 渲染的宽度,若是字体大了,则会自动缩小,不会换行。

strokeText

代码为:

ctx.font="20px serif";
ctx.strokeText("I dont Know how to Do",20,20,200);

字体-font

定义一个最简单的字体,使用的是:

ctx.font=value;

value 的值,就是通常的 css font 属性的值。默认为: 10px sans-serif

ctx.font = "48px serif";

这里,还可使用比较新的 API FontFace() 来使用在线字体:

var f = new FontFace("font-name", "url(x)");
  f.load().then(function() {
    ctx.font="20px font-name";
    ctx.fillText("ABC",100,100);
});

字体颜色

字体的颜色相关和上面图形同样,一样使用的是 fillStylestrokeStyle 这里就不赘述了。

字体边框粗细

定义粗细的话,一样使用 lineWidth 便可。

字体的排列

基本格式为:

// 默认为 start
ctx.textAlign = "left" || "right" || "center" || "start" || "end";

这里,并非用来定义字体在 canvas 中的排列位置,而是用来定义,基准点相对于字体的位置。
经常使用的就是居中布局:

text_align

代码为:

ctx.font="20px serif";
ctx.textAlign='center';
ctx.strokeText("I dont Know how to Do",200,200);

其他的取值,好比 left,right 都是相对于该点进行绘制的。
好比,取 right/end:

right

基线位置

基本格式为:

// 默认值为: ideographic
ctx.textBaseline = "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom";

该属性和 baseline 差很少,是用来肯定基线在字体的哪个位置。 在定位的时候,线是不动的,动的是字。
详情参考:

baseline

测量字体

若是想知道当前字体的宽度,可使用 measureText API 来完成。基本使用也很简单:

var text = ctx.measureText("foo"); // TextMetrics object
text.width; // 16;

固然,这个属性返回的对象上面,还挂载了不少其余测量值,不过兼容性比较差。关键点在于,能够结合该 API 来画出分行的字体内容。简单的说来就是经过将字符串拆分,判断渲染字符串是否超过本行的宽度,进而决定是否将标识点 y 轴值加 lineheight。
简单看个算法:

function wrapText(context, text, x, y, maxWidth, lineHeight) {
        // 经过使用 ' ' 进行字符的拆分 (这里就不针对中文了)
        var words = text.split(' ');
        var line = '';

        for(var n = 0; n < words.length; n++) {
         // 判断行
          var testLine = line + words[n] + ' ';
          // 测量渲染的宽度
          var metrics = context.measureText(testLine);
          var testWidth = metrics.width;
          if (testWidth > maxWidth && n > 0) {
           // 超过,则下一该行
            context.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
          }
          else {
            line = testLine;
          }
        }
        context.fillText(line, x, y);
      }
      
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      var maxWidth = 400;
      var lineHeight = 25;
      var x = (canvas.width - maxWidth) / 2;
      var y = 60;
      var text = 'All the world \'s a stage, and all the men and women merely players. They have their exits and their entrances; And one man in his time plays many parts.';

      context.font = '16pt Calibri';
      context.fillStyle = '#333';

      wrapText(context, text, x, y, maxWidth, lineHeight);

canvas 中的变换

关于变化,最基本的就是 translate, scale,skew 等。在 canvas 中,这些就是针对于 canvas 坐标系来的。

translate

这是用来进行原点平移的变化。基本格式为:

ctx.translate(x, y);
  • x: 当前坐标系在 x 轴向的移动方向

  • y:当前坐标在 y 轴向的移动方向

固然,还有对应的 2D 变换矩阵,这和 transform 属性同样。可使用下列的变换:

ctx.setTransform(1, 0, 0, 1, x, y);

rotate

这是用来旋转坐标系的。基本格式为:

// 里面的参数是弧度,可使用 Math.PI 来进行转换
ctx.rotate(angle);

例如:

ctx.rotate(45 * Math.PI / 180);
ctx.fillRect(70,0,100,30);

当在旋转时,在矩阵中是根据 sin 函数来表示的旋转角度的值。

ctx.setTransform(cosθ,sinθ,-sinθ,cosθ,0,0) // 就是 cs-sc

scale

缩放坐标系,基本格式为:

ctx.scale(x, y);

它表达的意思是:

  • x: 将 x 轴放大/缩小 x 倍。即,设置的像素值会乘以该 x 值.

  • y: 将 y 轴放大/缩小 y 倍。即,设置的像素值会乘以该 y 值.

看个 demo:

ctx.scale(10, 3);
ctx.fillRect(10,10,10,10);
// 最后的结果就是,在 (100,30) 点,画出 width: 100,height: 30 的矩形。

另外,你还能够利用这个属性做颠倒:

ctx.scale(-1, 1); // x 轴对称
ctx.font = "48px serif";
ctx.fillText("Hello world!", -320, 120); // x 轴的值须要设为负数
ctx.setTransform(1, 0, 0, 1, 0, 0); // 还原坐标

它对应于矩阵的表达就是:

setTransform(A, 0, 0, B, 0,0);
// X 轴放大 A 倍
// Y 轴放大 B 倍

矩阵变换

矩阵变换的 API 和 css3 动画中的没啥区别:

ctx.setTransform(a, b, c, d, e, f);

最常使用的是用来进行坐标还原。由于,它每一次变换都是覆盖掉上一次变化,因此,还原坐标常使用:

ctx.setTransform(1,0,0,1,0,0);

不过,除了这个方法外,其余变换都是基于已经变化后的坐标来变换的。

transform

该 API 和 setTransform 有些不一样。setTransform 至关于重置,而 transform 会基于前一个变换结果,接着进行变换。它的使用方式和 setTransform 差很少。

ctx.transform(a, b, c, d, e, f);

resetTransform

至关于就是 setTransform(1,0,0,1,0,0)的封装。

ctx.resetTransform();

state stack

在 canvas 里面,由于有时候操做比较多,可能会形成来回变换坐标。这时候,就可使用 canvas 里面的状态管理。save & restore,这两个方法至关于 stack 的 push & pop 方法。一个入栈,一个出栈。那么,这些状态会保存什么呢?

  • 变形操做,基本的移动,缩放,旋转,矩阵变换等。

  • 裁剪区域

  • dash list

  • 以及相关的笔触,填充状态。好比: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin。

不过,它仅仅只是做为一个状态进行保存的。当结合 restore 一块儿,才会发挥它应该有的效果。

ctx.save();
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);
ctx.restore();
// 恢复原始的 fillStyle 内容
ctx.fillRect(150, 75, 100, 100);

composite

在 canvas 中的层合并,涉及到阴影,裁剪等效果。

阴影特效

关于 canvas 中的阴影涉及到 4 个API。

  • shadowBlur

  • shadowColor

  • shadowOffsetX

  • shadowOffsetY

分别介绍一下:

shadowBlur

这是用来添加阴影的,基本格式为:

ctx.shadowBlur = level;

level 的值默认为 0,表示不存在阴影。而且,不能取 Negative, Infinity or NaN。level 表示的意义只在于,规定阴影模糊的范围而已。须要注意,一旦你设置了 shadoeBlur,那么接下来,在 canvas 上画的全部元素,都会带上阴影的效果,即便是透明元素。因此,通常状况下能够手动回撤:

ctx.shadowBlur = 0;

或者,结合 save 和 restore 来进行状态回撤。

ctx.save();
ctx.shadowBlur = 5;
ctx.fillRect(0,0,400,400);
ctx.restore();

shadowColor

用来设置阴影的颜色值,默认是不透明的黑色。

blurColor

基本格式为:

// color 默认为 “black”
ctx.shadowColor = color;

shadowOffsetX/Y

这个实际上和 box-shadow 设置的阴影效果是同样的,用来定义阴影相对于原始图形的偏移量。基本格式为:

// offset 默认值为 0,至关于取 canvas 上的像素值
// 能够为负值,但不能取 Infinity or NaN
ctx.shadowOffsetX = offset;

实例为:

// 在 x 轴上移动阴影
ctx.shadowOffsetX = 10;
// 在 Y 轴上移动阴影
ctx.shadowOffsetY = 10;

透明度

在 canvas 里面,定义颜色通常只支持 RGB 的格式,若是想要设置透明颜色的话,则须要使用 globalAlpha 属性值。基本格式为:

// value 为 [0.0,1.0] 
// 默认值为 0.0,表示不透明
ctx.globalAlpha = value;

看个 demo:

ctx.globalAlpha = 0.5;

ctx.fillStyle = "blue";
ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = "red";
ctx.fillRect(50, 50, 100, 100);

globalAlpha

裁剪效果

在 canvas 里面,通常使用的是 clip API 来进行对屏幕的裁剪。基本格式为:

// 最经常使用
void ctx.clip();
// fillRule 主要有两种,下面再解释
void ctx.clip(fillRule);
// 这里就是将须要画的路径,当参数传到 clip 里
void ctx.clip(path, fillRule);

fillRule

先解释一下 fillRule:
经常使用的 fillRule 有两种,一种是 nonzero,一种是 even-odd 。主要做用就是用来判断重叠区域是否属于裁剪区域。ok,什么叫重叠区域呢?就是:

fillRule

这种状况下,canvas 怎么判断这样的区域是否重叠呢?
默认的算法是 nonzero。

nonzero

P

它具体的过程是,在重叠区域中,选择一个 P 点,而后随机的按照一个方向,作无限长的射线,检测该线和边界的交叉点,判断接触位置是 顺时针仍是逆时针。若是为顺时针则 -1,若是为逆时针则 +1。统计最终的结果,若是为 0 则说明,该区域在外部,不然在内部。
因此,上面的结果是 -2,不是 0,则表示在内部。

even-odd rule

even-odd

该算法主要约定的是,统计射线和边界相交的次数,若是为偶数,则表示不在内部,若是为奇数,则表示在内部。

因此,根据该算法,上面的结果为 2 (偶数),则不在内部。

不过,在大多数状况下,这你都不须要过多关心。接下来,咱们来实践一下,如何绘制裁剪区域。这里,咱们就能够将 clip 方法想象为 stroke 方法。在 clip 前,先手动绘制路径,绘制完成后,即可以触发 clip 进行裁剪就 ok 了。

ctx.beginPath();
ctx.ellipse(100,100,30,50,0,0,2*Math.PI);
ctx.clip();
ctx.fillRect(100,100,30,50);

实际样式为:

clip_area

图层重叠的效果

图层重叠用到的 API 为: globalCompositeOperation。它的做用主要是用来规定,两个重叠图层绘制的效果。基本格式为:

globalCompositeOperation = type

基本的取值,能够参考: globalCompositeOperation - 取值内容

canvas 的图像处理

canvas 中的图像处理内容很少,基本上有 3 个API:createImageData(),putImageData(),getImageData()。第一个就是用来截屏用的,第二/三个就是用来获取图片的基本信息,在关于 image 有个比较重要的概念就是 imagedata。

  • imageData:实际上就是完整的图片内容。它是底层像素的上层表示,其挂载了 3 个属性。

    • width: 图片的宽

    • height:图片的高

    • data: 是 Uint8ClampedArray 格式,实际上一个一维数组,按顺序,每一个像素点占 4 位,里面包含了 RGBA 的内容,每一位都是 0-255 大小的数。最后透明度有点特殊,取值为 [0-255] 表示不透明。若是须要用到 css 的 rgba 中,须要 /255。例如: [0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255] ,4个点。

  • 最常获取到 imagedata 就是经过 createImageData。注意,经过 image 是不能获取 imagedata 的,imagedata 只能经过 createImageData 来获取和建立。

ctx.rect(10, 10, 100, 100);
ctx.fill();

let imagedata = ctx.createImageData(100, 100);

createImageData

用来手动建立一个空图片内容,默认的像素都是透明的黑色,基本格式为:

ImageData ctx.createImageData(width, height);
ImageData ctx.createImageData(imagedata);
  • width/height:用来设置当前 imgObj 的大小。

  • imagedata:得到一个已知 imgObj 的大小,注意这里不是复制,只是 copy imagedata 的 width/height。

目前来讲,它的用途,还不知道在哪里~

getImageData

该 API 经常用来做为图片分析,由于它能够直接获取 canvas 上像素的内容,而后进行相关操做。基本格式为:

ctx.getImageData(x, y, width, height);
  • x,y 用来指定截取像素的起始点

  • widht/height 用来指定截取像素点的宽/高

例如:

ctx.fillRect(0,0,200,200);
let new_one = ctx.getImageData(0,0,2,2);

该属性最大的用处在于,用来做为取色器。经过,传入 canvas 里的坐标,来获取指定位置的颜色值。

ctx.fillRect(0,0,200,200);
let new_one = ctx.getImageData(0,0,1,1);
let backColor = function(data){
       return `(${data[0]},${data[1]},${data[2]},${data[3]/255})`;
}

putImageData

该属性经常用来做为,像素的填写。基本格式为:

void ctx.putImageData(imagedata, dx, dy);
void ctx.putImageData(imagedata, dx, dy, startX, startY, width, height);

主要所一下第二种形式吧:

  • dx/y 表明在 canvas 上绘制的绘制

  • startX/Y 表示相对于图片其实的位置

  • width/height 表示获取的宽/高

具体的含义为:

ctx.fillRect(0,0,100,100);
var imagedata = ctx.getImageData(0,0,100,100); // 获取部分图像信息
ctx.putImageData(imagedata, 150, 0, 20, 20, 25, 25);
ctx.strokeRect(150,0,100,100);

putImageData API 详解

该经常用来做为放大预览,灰度处理,导出图片等。详情能够参考: 图片像素处理。总而言之,putImageData 常做为处理图片自己,而 drawImage 经常使用于建立另一新的 canvas。

生成 URI

这应该算一种快速生成图片格式的方法吧。该是经过算法,将图像中的像素点转化为序列值(也就是文本),咱们能够直接将文本放入 img.src 中,便可显示图片。
在 canvas 中生成 URI 须要使用:

canvas.toDataURL(type, encoderOptions);

该 API 是直接挂在到 canvas 下的。

  • type: 用来设置导出图片类型,默认为:image/png。可选值有:image/jpeg,image/webp(chrome支持)。

  • encoderOptions[Number]:用来设置压缩比。只针对于 image/jpeg or webp 有用。一般取值为 0-1。默认值为 0.92。

DataURI 的基本格式为:

data:[<mediatype>][;base64],<data>
// 例如:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ9oADAMBAAIRAxEAPwD/AD/6AP/Z

生成的 DataURI 是根据 canvas 的大小来肯定的。

var canvas = document.getElementById("canvas"); // canvas size: 5x5
var dataURL = canvas.toDataURL(); // 生成的大小为 5x5

不过并非,任何图片都能生成 DataURI 的,有些浏览器因为内存的限制,对 DataURI 的长度也会有所限制。例如:Opera 限制为 65000 characters。

Canvas Animation

使用 Canvas 来作动画,咱们须要了解幕布的盖帘--擦除,绘制。基本的 API 有: clearRect, requestAnimation

clearRect

该 API 用来清空一块幕布,基本格式为:

ctx.clearRect(x, y, width, height);

用来清除指定区域的内容。

  • x,y:用来指定区域的起始位置

  • width,height:指定区域的宽高

通常来讲,一般是用来清除整个 canvas 内容。

ctx.clearRect(0, 0, canvas.width, canvas.height);

使用 requestAnimationFrame

主要仍是依靠循环调用 RAF,来实现流畅动画。看一个 demo

地球_canvas

var sun = new Image();
var moon = new Image();
var earth = new Image();
function init(){
  // online
 earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
  sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
  moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';

  // local
  earth.src = 'Canvas_earth.png';
  sun.src='Canvas_sun.png';
  window.requestAnimationFrame(draw);
}


function draw(){
  let canvas = document.getElementsByTagName('canvas')[0],
      ctx = canvas.getContext('2d'),
      width = canvas.width,
      height = canvas.height;
    // ctx.globalCompositeOperation = 'destination-over';
    ctx.clearRect(0,0,width,height);
    ctx.drawImage(sun,0,0,width,height);
    ctx.fillStyle= 'rgba(0,0,0,0.4)';
    ctx.strokeStyle = 'rgba(0,50,50,0.5)';
    ctx.arc(width/2,height/2,width/3,0,2*Math.PI);
  
  
    ctx.stroke();
    // ctx.fill();
  
    ctx.save();
    //earth
    let date = new Date();

    ctx.translate(width/2,height/2);
    // 公转
    ctx.rotate ((2*Math.PI)*1*(date.getSeconds()/60 + date.getMilliseconds()/60000) );
    ctx.translate(width/3,0);
    // 自转
    ctx.rotate ((2*Math.PI)*25*(date.getSeconds()/60 + date.getMilliseconds()/60000) );
    ctx.drawImage(earth,-earth.width/2,-earth.height/2);
    ctx.save();
    ctx.translate(20,0);
    ctx.drawImage(moon,-moon.width/2,-moon.height/2);

    ctx.restore();
    ctx.restore();
    window.requestAnimationFrame(draw);
}
init();
相关文章
相关标签/搜索