Fork me on GitHub

html5-canvas基础

canvas 用法

基础用法

创建画布

1
2
3
<canvas id="my_canvas" width="500px" height="500px" >
您的浏览器不支持canvas,请升级您的浏览器!
</canvas>
  1. canvas为替换内容,如果浏览器不支持canvas,就会显示元素内部的内容
  2. widthheight都是可选属性,用于定义canvas的宽高。默认宽高为300px*150px
  3. id属性用于绘制时,找到该画布。

渲染上下文

canvas元素的getContext()方法可以获取渲染上下文和绘功能,参数’2d’表示开启 2D 绘图。

1
2
let my_canvas=document.getElementById('my_canvas');
let ctx=canvas.getContext('2d');

检查 JS 的支持性

1
2
3
4
5
if(my_canvas.getContext){
let ctx=my_canvas.getContext('2d')
}else{
//不支持canvas
}

绘制图形

矩形

  • fillRect(x,y,width,height) 绘制填充矩形
  • strokeRect(x,y,width,height) 绘制描边矩形
  • clearRect(x,y,width,height) 清除指定矩形区域,让清除部分完全透明
    x,y指画布上所绘制矩形的左上角(相对于画布的左上角(0,0))
    width,height设置矩形的尺寸
1
2
3
4
5
 function draw(ctx) {
ctx.fillRect(10, 10, 100, 100);
ctx.clearRect(20, 20, 80, 80);
ctx.strokeRect(40, 40, 40, 40);
}

矩形

路径/直线

  • beginPath() 开始一条新路径
  • closePath() 闭合路径,会自动将起点和终点连接起来,如果不需要连接,可以不使用。如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。
  • stroke() 绘制图形轮廓
  • fill() 填充路径内容区域的生成的实心图形
  • moveTo() 将笔触移动到指定的坐标(x,y)
  • lineTo() 绘制一条从当前位置到坐标(x,y)上的直线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function draw(ctx) {
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(100, 20);
ctx.lineTo(100, 100);
ctx.closePath()
ctx.stroke();

ctx.beginPath();
ctx.moveTo(150, 20);
ctx.lineTo(230, 20)
ctx.lineTo(230, 100)
ctx.fill()
ctx.closePath()
}

三角形

圆弧

  • arc(x,y,radius,startAngle,endAngle,anticlockwise)
    画一个以(x,y)为圆心,以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认顺时针)来生成。

    • startAngle以及endAngle参数用弧度定义了开始以及结束的弧度,都是以x轴为基准。
      单位是弧度不是角度,弧度=(Math.PI/180)*角度
    • anticlockwisetrue是逆时针,否则为顺时针
  • arcTo(x1,y1,x2,y2,radius)
    从坐标(x1,y1)到坐标(x2,y2)以半径 radius 画一段圆弧,再以直线连接两个控制点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function draw(ctx) {
ctx.beginPath();
let endAngle = (Math.PI / 180) * 360;
ctx.arc(30, 30, 20, 0, endAngle);
ctx.stroke();
ctx.closePath();

ctx.beginPath();
ctx.moveTo(60, 20); // 创建开始点
ctx.lineTo(100, 20); // 创建水平线
ctx.arcTo(150, 20, 150, 70, 50); // 创建弧
ctx.lineTo(150, 100); // 创建垂直线
ctx.stroke();
}

圆弧

贝塞尔曲线

  • quadraticCurveTo(cp1x, cp1y, x, y)
    二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点
  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
    三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点一,x,y为结束点
1
2
3
4
5
6
7
8
9
10
11
12
function draw(ctx) {
ctx.beginPath();
ctx.moveTo(75, 25);
ctx.quadraticCurveTo(25, 25, 25, 62.5);
ctx.quadraticCurveTo(20, 130, 75, 130);
ctx.quadraticCurveTo(75, 160, 65, 160)
ctx.quadraticCurveTo(80, 160, 100, 130)
ctx.quadraticCurveTo(160, 130, 150, 62.5)
ctx.quadraticCurveTo(150, 20, 75, 25)
ctx.stroke()
ctx.closePath()
}

二次贝塞尔

1
2
3
4
5
6
7
8
9
10
11
function draw(ctx) {
ctx.beginPath();
ctx.moveTo(75, 40);
ctx.bezierCurveTo(75, 37, 70, 25, 50, 25);
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5)
ctx.bezierCurveTo(20, 80, 40, 102, 75, 120);
ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5);
ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
ctx.fill();
}

三次贝塞尔

Path2D 对象

返回一个初始化的 Path2D 对象,参数可以是一个路径或 SVG path 数据的字符串,就是创建参数的副本。

1
2
3
new Path2D();
new Path2D(path); //克隆Path对象
new Path2D(svg); //从svg建立Path对象

path2D.addPath(path[,transform])也可以给对象添加新路径或变化矩阵。

1
2
3
4
5
6
7
8
9
10
function draw(ctx) {
let rectangle = new Path2D()
rectangle.rect(10, 10, 50, 50)

let circle = new Path2D()
circle.moveTo(125, 35);
circle.arc(100, 35, 25, 0, 2 * Math.PI)
ctx.stroke(rectangle);
ctx.fill(circle)
}

Path2D

1
2
3
4
function draw(ctx) {
var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
ctx.stroke(p)
}

Path2D1

样式和颜色

  • 填充颜色
    fillStyle=color,设置图形的填充颜色

  • 轮廓颜色
    strokeStyle=color,设置图形轮廓的颜色
    默认填充颜色和轮廓颜色都是黑色('#000'/'black'/rgba(0,0,0,1))的。color可以是颜色值,渐变对象或图案对象。

1
2
3
4
5
6
7
8
function draw(ctx) {
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.fillStyle = `rgb(${Math.floor(255-42.5*i)},${Math.floor(255-42.5*j)},0)`;
ctx.fillRect(j * 25, i * 25, 25, 25)
}
}
}

fillStyle

1
2
3
4
5
6
7
8
9
10
function draw(ctx) {
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.strokeStyle = `rgb(0,${Math.floor(255-42.5*i)},${Math.floor(255-42.5*j)})`;
ctx.beginPath();
ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, 2 * Math.PI, true);
ctx.stroke()
}
}
}

strokeStyle

  • 透明度
    globalAlpha=transparent
    设置整个canvas里所有图形的透明度,范围是 0.0(完全透明)到 1.0(完全不透明)。
    同样可以设置strokeStylefillStyle的值为透明度(rgba)的颜色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
// 画背景
ctx.fillStyle = '#FD0';
ctx.fillRect(0,0,75,75);
ctx.fillStyle = '#6C0';
ctx.fillRect(75,0,75,75);
ctx.fillStyle = '#09F';
ctx.fillRect(0,75,75,75);
ctx.fillStyle = '#F30';
ctx.fillRect(75,75,75,75);
ctx.fillStyle = '#FFF';

// 设置透明度值
ctx.globalAlpha = 0.2;

// 画半透明圆
for (var i=0;i<7;i++){
ctx.beginPath();
ctx.arc(75,75,10+10*i,0,Math.PI*2,true);
ctx.fill();
}
}

globalAlpha

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function draw(ctx) {
//背景
ctx.fillStyle = '#FD0';
ctx.fillRect(0, 0, 220, 50);
ctx.fillStyle = "#6C0";
ctx.fillRect(0, 50, 220, 50);
ctx.fillStyle = "#09F";
ctx.fillRect(0, 100, 220, 50);
ctx.fillStyle = "#F30";
ctx.fillRect(0, 150, 220, 50);
ctx.fillStyle = '#fff';

//画透明度圆
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 4; j++) {
ctx.fillStyle = `rgba(255,255,255,${i*0.1})`;
ctx.fillRect(10 + i * 20, j * 50, 20, 50)

}
}
}

rgba

  • 线型 line styles

    • lineWidth=value,设置线条宽度,默认为 1.0,必须为正数。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
       function draw(ctx) {
      for (let i = 0; i < 10; i++) {
      ctx.beginPath();
      ctx.moveTo(5 + i * 15, 5);
      ctx.lineWidth = i + 1;
      ctx.lineTo(5 + i * 15, 100);
      ctx.stroke()
      ctx.closePath()
      }
      }

      线宽

    • lineCap=type,设置线条末端样式

      • butt:默认,方头与辅助线齐平
      • round:圆头,半径为宽度的一半
      • square:方头,端点处加上了等宽且高度为一半线宽的方块。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function draw(ctx) {
    let lineCap = ['butt', 'round', 'square'];
    //辅助线
    ctx.strokeStyle = '#09f';
    ctx.beginPath();
    ctx.moveTo(10, 10);
    ctx.lineTo(140, 10);
    ctx.moveTo(10, 140);
    ctx.lineTo(140, 140);
    ctx.stroke();
    //线条
    ctx.strokeStyle = 'black';
    for (let i = 0; i < lineCap.length; i++) {
    ctx.lineWidth = 15;
    ctx.lineCap = lineCap[i];
    ctx.beginPath();
    ctx.moveTo(30 + 40 * i, 10);
    ctx.lineTo(30 + 40 * i, 140);
    ctx.stroke();
    ctx.closePath()
    }
    }

线头

  • lineJoin=type,设定线条与线条间结合处的样式
    • round
    • bevel
    • miter,默认
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function draw(ctx) {
let lineJoin = ['round', 'bevel', 'miter'];
for (let i = 0; i < lineJoin.length; i++) {
ctx.beginPath();
ctx.lineWidth = 15;
ctx.lineJoin = lineJoin[i];
ctx.moveTo(20, 20 + i * 50);
ctx.lineTo(70, 70 + i * 50);
ctx.lineTo(120, 20 + i * 50);
ctx.lineTo(170, 70 + i * 50);
ctx.lineTo(220, 20 + i * 50);
ctx.stroke();
ctx.closePath();
}
}

交接处

  • miterLimit=value,限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。
  • getLineDash(),返回一个包含当前虚线的样式,长度为非负偶数的数组。
  • setLineDash(segments),设置当前虚线样式。
  • lineDashOffset=value,设置虚线样式的起始偏移量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var offset = 0;

function draw() {
let my_canvas = document.getElementById('my_canvas');
if (my_canvas.getContext) {
let ctx = my_canvas.getContext('2d');
ctx.clearRect(0, 0, my_canvas.width, my_canvas.height);
ctx.setLineDash([4, 2]); //实线长度,空线长度
ctx.lineDashOffset = -offset;
ctx.strokeRect(10, 10, 100, 100);
} else {
//不支持canvas

}

}

function march() {
offset++;
if (offset > 16) {
offset = 0;
}
draw();
setTimeout(march, 50);
}
march();

蚂蚁线

渐变

  • createLinearGradient(x1, y1, x2, y2)
    渐变起点(x1,y1)终点(x2,y2);
  • createRadialGradient(x1, y1, r1, x2, y2, r2)
    定义两个圆:一个是小圆,是外面大圆的反光,以(x1,y1)为圆点,r1 为圆心,另一个以(x2,y2)为圆心,r2 为半径。
  • gradient.addColorStop(position, color)
    给创建的渐变对象gradient上色,
    position:渐变颜色的所在位置,[0.0, 1.0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function draw(ctx) {
let linegrad = ctx.createLinearGradient(0, 0, 0, 150);
linegrad.addColorStop(0, '#00ABEB');
linegrad.addColorStop(0.5, '#fff');
linegrad.addColorStop(0.5, '#26C000');
linegrad.addColorStop(1, '#fff');
let linegrad1 = ctx.createLinearGradient(0, 50, 0, 95);
linegrad1.addColorStop(0.5, '#000');
linegrad1.addColorStop(1, "rgba(0,0,0,0)")

ctx.fillStyle = linegrad;
ctx.strokeStyle = linegrad1;
ctx.fillRect(0, 0, 150, 150);
ctx.strokeRect(50, 50, 50, 50)
}

第一是背景渐变,
第二种渐变不是从 0.0 开始的,所以 0-0.5 都是黑色的。
线性渐变色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function draw(ctx) {
let radgrad = ctx.createRadialGradient(45, 55, 10, 52, 50, 30);
radgrad.addColorStop(0, '#47d30C');
radgrad.addColorStop(0.9, '#019F62');
radgrad.addColorStop(1, 'rgba(1,159,98,0)');

let radgrad1 = ctx.createRadialGradient(95, 15, 15, 102, 20, 40);
radgrad1.addColorStop(0, '#00C9FF')
radgrad1.addColorStop(0.8, '#00B5E2')
radgrad1.addColorStop(1, 'rgba(0,201,255,0)');

ctx.fillStyle = radgrad1;
ctx.fillRect(0, 0, 150, 150);

ctx.fillStyle = radgrad;
ctx.fillRect(0, 0, 150, 150)
}

镜像渐变色

图案样式

  • createPattern(image,type)
    • image:是一个image对象的引用,或另一个canvas对象。
    • typerepeatrepeat-x,repeat-y,no-repeat
1
2
3
4
5
6
7
8
9
10
function draw(ctx) {
let img = new Image();
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
img.onload = function () {
//创建图案
let ptrn = ctx.createPattern(img, 'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 150, 150)
}
}

图片

阴影 shadows

  • shadowOffsetX=float
  • shadowOffsetY=float
    shadowOffsetXshadowOffsetY 用来设定阴影在XY轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。
  • shadowBlur=float
    用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0。
  • shadowColor=color
    阴影颜色,默认是全透明的黑色。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function draw(ctx) {
    ctx.shadowOffsetX = 2;
    ctx.shadowOffsetY = 2;
    ctx.shadowBlur = 2;
    ctx.shadowColor = "rgba(255,0,0,0.5)";

    ctx.font = '20px times New Roman';
    ctx.fillStyle = "black";
    ctx.fillText('Sample String', 5, 50)
    }

文字阴影

Canvas 填充规则

fill,clip,isPointinPath填充,可以使用以下填充规则:

  • nonzero:non-zero winding rule,默认值
  • evenodd:even-odd winding rule,颜色间隔出现
1
2
3
4
5
6
7
 function draw(ctx) {
ctx.beginPath();
ctx.arc(50, 50, 50, 0, Math.PI * 2);
ctx.arc(50, 50, 30, 0, Math.PI * 2);
ctx.arc(50, 50, 10, 0, Math.PI * 2);
ctx.fill('evenodd')
}

填充规则

绘制文本

  • fillText(text,x,y[,maxWidth])
    指定在(x,y)位置填充指定文本,绘制的最大宽度可选。
  • strokeText(text, x, y [,maxWidth])
    指定在(x,y)位置填充指定文本,绘制的最大宽度可选

    1
    2
    3
    4
    5
    function draw(ctx) {
    ctx.font = '48px serif'
    ctx.fillText('fillText', 10, 50);
    ctx.strokeText('strokeText', 10, 90)
    }

文本

文本样式

  • font=value
    与 css 属性相同,默认10px sans-serif
  • textAlign=value , 文本对齐方式

    • start默认
    • end
    • left
    • right
    • center
  • textBaseline=value,基线对齐选项

    • top
    • hanging
    • middle
    • alphabetic默认
    • ideographic
    • bottom
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function draw(ctx) {
    ctx.strokeStyle = 'red';
    ctx.font = '28px serif'
    ctx.moveTo(0, 40);
    ctx.lineTo(650, 40);
    ctx.stroke();
    ctx.textBaseline = 'top'
    ctx.fillText('top', 10, 40);
    ctx.textBaseline = 'middle'
    ctx.fillText('middle', 60, 40)
    ctx.textBaseline = 'hanging'
    ctx.fillText('hanging', 160, 40)
    ctx.textBaseline = 'alphabetic'
    ctx.fillText('alphabetic', 270, 40)
    ctx.textBaseline = 'ideographic'
    ctx.fillText('ideographic', 410, 40)
    ctx.textBaseline = 'bottom'
    ctx.fillText('bottom', 560, 40)
    }

基线

  • direction=value,文本方向

    • ltr
    • rtl
    • inherit 默认
  • 预测量文本宽度

measureText()
返回有个TextMwtrics对象的宽度、所在像素

绘制图像

获取图像源

  • 获得需要绘制的图片

    • HTMLImageElement
      Image()函数构造出来的元素,或者<img>元素
    • HTMLVideoElement
      <video></video>元素,从视频中抓取当前帧作为一个图像
    • HTMLCanvasElement
      使用另外一个<canvas></canvas>元素作为图片源
    • ImageBitmap
      高性能位图,可以低延迟的绘制。,它可以从上述的所有源以及其它几种源中生成。
  • 使用相同页面内的图片

    获取当前页面的图片引用:

    • document.images集合
    • document.getElementsByTagName()
    • document.getElementById()
  • 使用其他域名下的图片

    如果图片允许跨域访问,可以正常渲染canvas,如果图片不允许跨域访问,会污染当前canvas.

  • 使用其他 canvas 元素

    获取 canvas 元素

    • document.getElementsByTagName()
    • document.getElementById()
  • 由零开始创建图像

    1
    2
    3
    4
    5
    var img=new Image();
    img.onload=function(){
    //执行drawImage语句
    }
    img.src='img.png'
  • 通过data.url方式嵌入图像

    1
    img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';
  • 使用视频帧

    1
    2
    3
    4
    5
    6
    7
    8
    function getMyVideo() {
    var canvas = document.getElementById('canvas');
    if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    return document.getElementById('myvideo');
    }
    }

绘制图片

  • drawImage(image,x,y)

    • image就是用上面的方法获取的图片源,SVG 图像必须在 <svg> 根指定元素的宽度和高度。
    • x,y,绘制图片左上角在画布中的起始坐标
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     function draw(ctx) {
    let img = new Image();
    img.onload = function () {
    ctx.drawImage(img, 0, 0);
    ctx.beginPath();
    ctx.moveTo(30, 96);
    ctx.lineTo(70, 66);
    ctx.lineTo(102, 76);
    ctx.lineTo(170, 15);
    ctx.stroke();
    }
    img.src = 'bird.jpg'
    }
  • drawImage(image,x,y,width,height);
    widthheight用来控制当前canvas画入时应该缩放的大小

1
2
3
4
5
6
7
8
9
10
11
12
13
 function draw(ctx) {
let img = new Image();
img.onload = function () {
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 3; j++) {
ctx.drawImage(img, j * 100, i * 80, 100, 80);
}
}


}
img.src = 'bird.jpg'
}
  • drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight)
    第一个参数同上还是图片源,
    后面 8 个参数,前四个参数定义图像源的切片位置和大小,后四个定义切片的目标显示的位置和大小。
    切片
1
2
3
4
5
6
7
function draw(ctx) {
let img = new Image();
img.onload = function () {
ctx.drawImage(img, 300, 100, 1000, 1100, 10, 10, 200, 200)
}
img.src = 'bird.jpg'
}

渲染 frame

1
2
// Draw frame
ctx.drawImage(document.getElementById('frame'),0,0);
  • 控制图像的缩放行为
    mozImageSmoothingEnabled,默认为true,为false时图像不会平滑的缩放。
    ctx.mozImageSmoothingEnabled = false;

变形 Transformation

状态的保存和恢复

  • save() 保存画布的现在的状态
  • restore()
    恢复canvas状态。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function draw(ctx) {
ctx.fillRect(0, 0, 500, 500);
ctx.save(); //存储黑色矩形

ctx.fillStyle = "#09F"
ctx.fillRect(50, 50, 400, 400)

ctx.save(); //存储蓝色矩形
ctx.fillStyle = 'white';
ctx.globalAlpha = 0.5;
ctx.fillRect(100, 100, 300, 300)

ctx.restore(); //恢复蓝色矩形
ctx.fillRect(150, 150, 200, 200)

ctx.restore(); //恢复黑色矩形
ctx.fillRect(200, 200, 100, 100)

}

保存状态

移动

  • translate(x, y)
    x为左右偏移量,y为上下偏移量
1
2
3
4
5
6
7
8
9
10
11
function draw(ctx) {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
ctx.save();
ctx.fillStyle = `rgb(${51*i},${255-51*i},255)`;
ctx.translate(10 + j * 50, 10 + i * 50);
ctx.fillRect(0, 0, 25, 25);
ctx.restore()
}
}
}

移动

旋转

  • rotate(angle)
    角度(angle)是顺时针方向,以弧度为单位。
    旋转的中心始终是canvas的原点
    旋转

缩放

scale(x,y)
x为水平缩放,y为垂直缩放
x,y都是实数,比 1 小会缩小图形,比 1 大会放大图片,默认为 1。
画布初始情况下, 是以左上角坐标为原点的第一象限。如果为负实数, scale(-1,1)y轴作为对称轴镜像反转,scale(1,-1)x轴作为对称轴镜像反转。

1
2
3
4
5
6
7
8
9
10
11
12
function draw(ctx) {
// //放大
ctx.save();
ctx.scale(10, 3);
ctx.fillRect(1, 10, 10, 10);
ctx.restore();

// //镜像
ctx.scale(-1, 1);
ctx.font = '48px serif';
ctx.fillText('MDN', -135, 120)
}

缩放

变形

  • transform(a,b,c,d,e,f)
    这个方法是将当前的变形矩阵乘上一个基于自身参数的矩阵,如下面的矩阵所示:$\left[ \begin{array}{ccc} a & c & e \ b & d & f \ 0 & 0 & 1 \end{array} \right]$

    • a(m11): 水平方向的缩放
    • b(m12): 水平方向的倾斜偏移
    • c(m21): 竖直方向的倾斜偏移
    • d(m22): 竖直方向的缩放
    • e(m31): 水平方向的移动
    • f(m32): 竖直方向的移动
  • setTransform(a,b,c,d,e,f)
    将当前的变形矩阵重置为单位矩阵,然后用相同的参数调用 transform 方法。该方法是取消了当前变形,然后设置为指定的变形,一步完成。

  • resetTransform()
    重置当前变形为单位矩阵,它和调用以下语句是一样的:ctx.setTransform(1, 0, 0, 1, 0, 0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function draw(ctx) {
let sin = Math.sin(Math.PI / 6);
let cos = Math.cos(Math.PI / 6);
ctx.translate(100, 100);
let c = 0;
for (let i = 0; i <= 12; i++) {
c = Math.floor(255 / 12 * i);
ctx.fillStyle = `rgb(${c},${c},${c})`;
ctx.fillRect(0, 0, 100, 10);
ctx.transform(cos, sin, -sin, cos, 0, 0)
}
ctx.setTransform(-1, 0, 0, 1, 100, 100);
ctx.fillStyle = 'rgba(255,128,255,.5)';
ctx.fillRect(0, 50, 100, 100)
}

转换

组合

globalCompositeOperation=type
设定新绘制图形与原图形的遮盖方式。
目标画布-已有,新图像

  • source-over:默认,在现有画布上下文之上绘制新图形。
  • source-in:新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。
  • source-out: 在不与现有画布内容重叠的地方绘制新图形,重叠部分是透明的。
  • source-atop: 新图形只在与现有画布内容重叠的地方绘制,原有画布非重叠部分不变。
  • destination-over: 在现有的画布内容后面绘制新的图形。
  • destination-in: 现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的。
  • destination-out:现有内容保持在新图形不重叠的地方,其他地方透明。
  • destination-atop:现有的画布只保留与新图形重叠的部分,新的图形是在画布内容后面绘制的。
  • lighter:两个重叠图形的颜色是通过颜色值相加来确定的。
  • copy:只显示新图形。
  • xor:图像中,那些重叠和正常绘制之外的其他地方是透明的。
  • multiply:将顶层像素与底层相应像素相乘,结果是一幅更黑暗的图片。
  • screen:像素被倒转,相乘,再倒转,结果是一幅更明亮的图片。
  • overlaymultiplyscreen的结合,原本暗的地方更暗,原本亮的地方更亮。
  • darken:保留两个图层中最暗的像素。
  • lighten:保留两个图层中最亮的像素。
  • color-dodge:将底层除以顶层的反置。
  • color-burn:将反置的底层除以顶层,然后将结果反过来。
  • hard-light:屏幕相乘(A combination of multiply and screen)类似于叠加,但上下图层互换了。
  • soft-light:用顶层减去底层或者相反来得到一个正值。
  • difference:一个柔和版本的强光(hard-light)。纯黑或纯白不会导致纯黑或纯白。
  • exclusion:和 difference 相似,但对比度较低。

裁切路径

clip()将当前正在构建的路径转换为当前的裁剪路径。
默认情况下,canvas 有一个与它自身一样大的裁切路径(也就是没有裁切效果)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function draw(ctx) {
ctx.fillRect(0, 0, 150, 150);
ctx.translate(75, 75);
ctx.beginPath();
ctx.arc(0, 0, 60, 0, Math.PI * 2, true);
ctx.clip();
//画圆形背景
let lingrad = ctx.createLinearGradient(0, -75, 0, 75);
lingrad.addColorStop(0, "#232256");
lingrad.addColorStop(1, "#143778");
ctx.fillStyle = lingrad;
ctx.fillRect(-75, -75, 150, 150);
//画星星
for (let j = 1; j < 50; j++) {
ctx.save();
ctx.fillStyle = '#fff';
ctx.translate(75 - Math.floor(Math.random() * 150), 75 - Math.floor(Math.random() * 150));
drawStar(ctx, Math.floor(Math.random() * 4) + 2);
ctx.restore()
}

function drawStar(ctx, r) {
ctx.save();
ctx.beginPath();
ctx.moveTo(r, 0);
for (let i = 0; i < 9; i++) {
ctx.rotate(Math.PI / 5);
if (i % 2 === 0) {
ctx.lineTo((r / 0.525731) * 0.200811, 0)
} else {
ctx.lineTo(r, 0)
}
}
ctx.closePath();
ctx.fill();
ctx.restore();
}
}

星星

-------------本文结束感谢阅读-------------