HTML5 Canvas原生使用

最近接了一个机场监控的B端项目,里面涉及使用到了Canvas技术,这里一边学习,一边分享一下开发中遇到的一些问题;

1.Canvas简介

是H5新增的可以通过javascript来绘制图像,甚至可以进行实时视频处理和渲染;
Canvas是由HTML代码配合高度和宽度属性而定义出的可绘制区域。Javascript代码可以访问该区域,通过一套完整的绘图函数来动态生成图形;

2.Canvas基本使用

2.1 canvas基础

<canvas id="tutorial" width="300" height="300"></canvas>
//1.是一个类似于标签元素的用法
//2.可直接通过width,height来设置标签区域的大小
//3.如果不给他设置高度、宽度,则默认width:300,height为150,单位都是px。
//4.不建议使用css属性来设置<canvas>的宽高;
//5.canvas有浏览器兼容性问题

2.2 渲染上下文

canvas会创建一个固定大小的画布,会公开一个活多个渲染上下文,使用渲染上下文来绘制和处理要展示的内容。

var canvas = document.getElementById('tutorial');
//获得 2d 上下文对象
var ctx = canvas.getContext('2d');
//可以添加“检测支持性”代码
if(canvas.getContext){
//如果支持
	var ctx=canvas.getContext('2d')
}else{
//不支持
  }

3.绘制形状

3.1栅格(grid)和坐标空间

如下图所示,canvas 元素默认被网格所覆盖。通常来说网格中的一个单元相当于 canvas 元素中的一像素。栅格的起点为左上角,坐标为 (0,0) 。所有元素的位置都相对于原点来定位。所以图中蓝色方形左上角的坐标为距离左边(X 轴)x 像素,距离上边(Y 轴)y 像素,坐标为 (x,y)。
在这里插入图片描述

3.2 绘制矩形

canvas提供了三种方法绘制矩形:

  • 1.fillRect(x,y.width,height): 绘制一个填充的矩形;
  • 2.strokeRect(x,y,width,height): 绘制一个矩形的边框;
  • 3.clearReactx,y,width,height): 清除指定的矩形区域,然后这块区域会变的完全透明。
function draw(){
    var canvas = document.getElementById('tutorial');
    if(!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.fillRect(10, 10, 100, 50);     // 绘制矩形,填充的默认颜色为黑色
    ctx.strokeRect(10, 70, 100, 50);   // 绘制矩形边框
    
}
draw();

在这里插入图片描述

ctx.clearRect(15, 15, 50, 25);

在这里插入图片描述

4.绘制路径(path)

使用路径绘制图形需要一些额外的步骤:

  1. 创建路径起始点
    beginPath(): 新建一条路径,路径一旦创建成功,图形绘制命令被指向到路径上生成路径;

  2. 调用绘制方法去绘制出路径
    moveTo(x,y): 把画笔移动到指定的坐标(x,y)。相当于设置路径的起始点坐标;

  3. 把路径封闭
    closePath(): 闭合路径之后,图形绘制命令又重新指向到上下文中

  4. 一旦路径生成,通过描边或填充路径区域来渲染区域
    stroke():通过线条来绘制图形轮廓
    fill():通过填充路径的内容区域生成实心的图形

4.1绘制三角形边框

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(50, 50);
    ctx.lineTo(200, 50);
    ctx.lineTo(200, 200);
      ctx.closePath(); //虽然我们只绘制了两条线段,但是closePath会closePath,仍然是一个3角形
    ctx.stroke(); //描边。stroke不会自动closePath()
}
draw();

在这里插入图片描述

//填充三角形
 ctx.fill(); //填充闭合区域。如果path没有闭合,则fill()会自动闭合路径。

在这里插入图片描述

4.2绘制圆弧

有两个方法可以绘制圆弧:
1、arc(x, y, r, startAngle, endAngle, anticlockwise): 以(x, y) 为圆心,以r 为半径,从 startAngle 弧度开始到endAngle弧度结束。anticlosewise 是布尔值,true 表示逆时针,false 表示顺时针(默认是顺时针)。
注意:

  1. 这里的度数都是弧度。
  2. 0 弧度是指的 x 轴正方向。
radians=(Math.PI/180)*degrees   //角度转换成弧度

2、arcTo(x1, y1, x2, y2, radius): 根据给定的控制点和半径画一段圆弧,最后再以直线连接两个控制点。

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
    ctx.stroke();
}
draw();

在这里插入图片描述

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(50, 50);
      //参数1、2:控制点1坐标   参数3、4:控制点2坐标  参数4:圆弧半径
    ctx.arcTo(200, 50, 200, 200, 100);
    ctx.stroke();
}
draw();

在这里插入图片描述
arcTo方法的说明
这个方法可以这样理解。绘制的弧形是由两条切线所决定。

第 1 条切线:起始点和控制点1决定的直线。

第 2 条切线:控制点1 和控制点2决定的直线。

其实绘制的圆弧就是与这两条直线相切的圆弧。

4.3绘制贝塞尔曲线

贝塞尔曲线是由线段和节点组成的,节点是可拖动的支点,线段像可伸缩的皮筋;
在这里插入图片描述

//绘制二次贝塞尔曲线
quadraticCurveTo(cp1x, cp1y, x, y)
//参数1和2:控制点坐标
//参数3和4:结束点坐标
function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(10, 200); //起始点
    var cp1x = 40, cp1y = 100;  //控制点
    var x = 200, y = 200; // 结束点
    //绘制二次贝塞尔曲线
    ctx.quadraticCurveTo(cp1x, cp1y, x, y);
    ctx.stroke();
 
}
draw();
//绘制三次贝塞尔曲线:
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
//参数1和2:控制点1的坐标
//参数3和4:控制点2的坐标
//参数5和6:结束点的坐标
function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(40, 200); //起始点
    var cp1x = 20, cp1y = 100;  //控制点1
    var cp2x = 100, cp2y = 120;  //控制点2
    var x = 200, y = 200; // 结束点
    //绘制二次贝塞尔曲线
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
    ctx.stroke();
 
    ctx.beginPath();
    ctx.rect(40, 200, 10, 10);
    ctx.rect(cp1x, cp1y, 10, 10);
    ctx.rect(cp2x, cp2y, 10, 10);
    ctx.rect(x, y, 10, 10);
    ctx.fill();
 
}
draw();

在这里插入图片描述

5.添加样式和颜色

5.1颜色

1.fillStyle = color 设置图形的填充颜色
2.strokeStyle = color 设置图形轮廓颜色
注意:一旦设置了strokeStyle或者fillStyle的值,那么这个新值就会成为新绘制的图形的默认值。如果要给每个图形上不同的颜色,需要重新设置fillStyle或strokeStyle的值。

function draw(){
  var canvas = document.getElementById('tutorial');
  if (!canvas.getContext) return;
  var ctx = canvas.getContext("2d");
  for (var i = 0; i < 6; i++){
    for (var j = 0; j < 6; j++){
    //设置填充颜色
      ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ',' + Math.floor(255 - 42.5 * j) + ',0)';
      //给对应的矩形填充颜色
      ctx.fillRect(j * 50, i * 50, 50, 50);
      //设置边框颜色
      ctx.strokeStyle = `rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
      //给边框设置颜色
      ctx.strokeRect(j * 50, i * 50, 40, 40);
    }
  }
}
draw();
function randomInt(from, to){
    return parseInt(Math.random() * (to - from + 1) + from);
}

在这里插入图片描述

5.2 Transparency(透明度)

1.可使用globalAlpha = transparencyValue: 属性来绘制透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。
2. 除此可使用rgba()设置透明度

5.3 line style

线宽。只能是正值。默认是 1.0。
起始点和终点的连线为中心,上下各占线宽的一半。

ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(100, 10);
ctx.lineWidth = 10;
ctx.stroke();
 
ctx.beginPath();
ctx.moveTo(110, 10);
ctx.lineTo(160, 10)
ctx.lineWidth = 20;
ctx.stroke()

在这里插入图片描述

5.4 lineCap = type

线条末端样式。
共有 3 个值:

  1. butt:线段末端以方形结束
  2. round:线段末端以圆形结束
  3. square:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。
var lineCaps = ["butt", "round", "square"];
 
for (var i = 0; i < 3; i++){
    ctx.beginPath();
    ctx.moveTo(20 + 30 * i, 30);
    ctx.lineTo(20 + 30 * i, 100);
    ctx.lineWidth = 20;
    ctx.lineCap = lineCaps[i];
    ctx.stroke();
}
 

在这里插入图片描述

5.5 lineJoin = type

同一个path内,设定线条与线条接和处的样式。
共有三个值 round、bevel 和 miter;

  1. round通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。圆角的半径是线段的宽度。
  2. bevel 在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角。
  3. miter(默认) 通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。
function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
 
    var lineJoin = ['round', 'bevel', 'miter'];
    ctx.lineWidth = 20;
 
    for (var i = 0; i < lineJoin.length; i++){
        ctx.lineJoin = lineJoin[i];
        ctx.beginPath();
        ctx.moveTo(50, 50 + i * 50);
        ctx.lineTo(100, 100 + i * 50);
        ctx.lineTo(150, 50 + i * 50);
        ctx.lineTo(200, 100 + i * 50);
        ctx.lineTo(250, 50 + i * 50);
        ctx.stroke();
    }
 
}
draw();

在这里插入图片描述

5.6虚线

用 setLineDash 方法和 lineDashOffset 属性来制定虚线样式。 setLineDash 方法接受一个数组,来指定线段与间隙的交替;lineDashOffset属性设置起始偏移量。

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
 
    ctx.setLineDash([20, 5]);  // [实线长度, 间隙长度]
    ctx.lineDashOffset = -0;
    ctx.strokeRect(50, 50, 210, 210);
}
draw();

在这里插入图片描述

6.绘制文本

绘制文本的两个方法
canvas提供了两种方法来渲染文本;

  1. fillText(text, x, y [, maxWidth]) 在指定的 (x,y) 位置填充指定的文本,绘制的最大宽度是可选的。
  2. strokeText(text, x, y [, maxWidth]) 在指定的 (x,y) 位置绘制文本边框,绘制的最大宽度是可选的。
var ctx;
function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    ctx = canvas.getContext("2d");
    ctx.font = "100px sans-serif"
    ctx.fillText("天若有情", 10, 100);
    ctx.strokeText("天若有情", 10, 200)
}
draw();
//1.font-value 当前我们用来绘制文本的样式。这个字符串使用和CSS font属性相同的语法。默认的字体是10px sans-serif。
//2.textAlign=value 文本对齐选项。可选的值包括:start,end,left,right or center。默认值是start.
//3.textBaseline = value 基线对齐选项。可选的值包括:top,hanging,middle,bottom等
//4.direction=value 文本方向。可能的值包括:ltr,rtl,inherit。默认值是inherit。

在这里插入图片描述

7. 绘制图片

7.1 创建图片

var img = new Image();   // 创建一个<img>元素
img.src = 'myImage.png'; // 设置图片源地址
//脚本执行后图片开始装载。

绘制img

//参数1:要绘制的img
//参数2、3:绘制的 img在canvas中的坐标
var img= new Image();//创建img元素
img.onload = function(){
	ctx.drawImage(img,0,0)
}
img.src = 'myImage.png'; //设置图片地址

7.2缩放图片

drawImage()也可以再添加两个参数:width和height,这两个参数用来控制当像canvas画入时应该缩放的大小;

drawImage(image, x, y, width, height)

7.3切片(slice)

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

第一个参数和其它的是相同的,都是一个图像或者另一个canvas的引用;
其它8个参数:
前4个是定义图像源的切片位置和大小,后4个则是定义切片的目标显示位置和大小;
在这里插入图片描述

8.状态的保存和恢复

save()和restore()方法都是用来保存和恢复canvas状态的,都没有参数。
Canvas的状态就是当前画面应用中所有样式和变形的一个快照;

8.1 save方法

Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。
一个绘画的状态包括:

  1. 当前应用的变形(即移动,旋转和缩放)
  2. strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值
  3. 当前的裁切路径(clipping path)

可以调用多次save方法,类似于数组的push()方法。

8.2 restore方法

每一次调用restore方法,上一个保存的状态就能从栈中弹出,所有设定都恢复(类似于数组的pop())。

9变形

9.1translate(x,y)

用来移动canvas的原点到指定位置;
translate 方法接受两个参数。x 是左右偏移量,y 是上下偏移量;
在这里插入图片描述

9.2 rotate(angle)

旋转坐标轴。只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。旋转的中心是坐标原点

var ctx;
function draw(){
  var canvas = document.getElementById('tutorial1');
  if (!canvas.getContext) return;
  var ctx = canvas.getContext("2d");
 
  ctx.fillStyle = "red";
  ctx.save();
 
  ctx.translate(100, 100);
  ctx.rotate(Math.PI / 180 * 45);
  ctx.fillStyle = "blue";
  ctx.fillRect(0, 0, 100, 100);
  ctx.restore();
 
  ctx.save();
  ctx.translate(0, 0);
  ctx.fillRect(0, 0, 50, 50)
  ctx.restore();
}
draw();

在这里插入图片描述

9.3scale

scale(x,y);可以用来增减图形在canvas中的像素数目,对形状、位图进行缩小或者放大。scale接收两个参数,x,y分别是横轴和纵轴的缩放因子,值比1.0小表示缩小,比1.0大则表示放大;
默认情况下,canvas 的 1 单位就是 1 个像素。举例说,如果我们设置缩放因子是 0.5,1 个单位就变成对应 0.5 个像素,这样绘制出来的形状就会是原先的一半。同理,设置为 2.0 时,1 个单位就对应变成了 2 像素,绘制的结果就是图形放大了 2 倍。

9.4 transform(变形矩阵)

transform(a,b,c,d,e,f)

在这里插入图片描述

10.合成

在前面的所有例子中、,我们总是将一个图形画在另一个之上,对于其他更多的情况,仅仅这样是远远不够的。比如,对合成的图形来说,绘制顺序会有限制。不过,我们可以利用 globalCompositeOperation 属性来改变这种状况。

globalCompositeOperation = type
var ctx;
function draw(){
    var canvas = document.getElementById('tutorial1');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
 
    ctx.fillStyle = "blue";
    ctx.fillRect(0, 0, 200, 200);
 
    ctx.globalCompositeOperation = "source-over"; //全局合成操作
    ctx.fillStyle = "red";
    ctx.fillRect(100, 100, 200, 200);
}
draw();

注:下面的展示中,蓝色是原有的,红色是新的。

type 是下面 13 种字符串值之一:

10.1 这是默认设置,

新图像会覆盖在原有图像。
在这里插入图片描述

10.2 source-in

仅仅会出现新图像与原来图像重叠的部分,其他区域都变成透明的。(包括其他的老图像区域也会透明)
在这里插入图片描述

10.3 source-out

仅仅显示新图像与老图像没有重叠的部分,其余部分全部透明。(老图像也不显示)
在这里插入图片描述

10.4 source-atop

新图像仅仅显示与老图像重叠区域。老图像仍然可以显示。
在这里插入图片描述

10.5 destination-over

新图像会在老图像的下面。
在这里插入图片描述

10.6 destination-in

仅仅新老图像重叠部分的老图像被显示,其他区域全部透明。
在这里插入图片描述

10.7 destination-out

仅仅老图像与新图像没有重叠的部分。注意显示的是老图像的部分区域。
在这里插入图片描述

10.8 destination-atop

老图像仅仅仅仅显示重叠部分,新图像会显示在老图像的下面。
在这里插入图片描述

10.9 lighter

新老图像都显示,但是重叠区域的颜色做加处理。
在这里插入图片描述

10.10 darken

保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的)
在这里插入图片描述

10.11 lighten

保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的)
在这里插入图片描述

10.12 xor

重叠部分会变成透明。
在这里插入图片描述

10.13 copy

只有新图像会被保留,其余的全部被清除(边透明)。
在这里插入图片描述

11.裁剪路径

clip() 把已经创建的路径转换成裁剪路径。裁剪路径的作用是遮罩。只显示裁剪路径内的区域,裁剪路径外的区域会被隐藏。
注意:clip() 只能遮罩在这个方法调用之后绘制的图像,如果是 clip() 方法调用之前绘制的图像,则无法实现遮罩。

var ctx;
function draw(){
    var canvas = document.getElementById('tutorial1');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
 
    ctx.beginPath();
    ctx.arc(20,20, 100, 0, Math.PI * 2);
    ctx.clip();
 
    ctx.fillStyle = "pink";
    ctx.fillRect(20, 20, 100,100);
}
draw();

在这里插入图片描述

12.动画

动画的基本步骤

  1. 清空 canvas 再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是 clearRect() 方法。
  2. 保存 canvas 状态 如果在绘制的过程中会更改 canvas 的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,则最好保存下 canvas 的状态
  3. 绘制动画图形这一步才是真正的绘制动画帧
  4. 恢复 canvas 状态如果你前面保存了 canvas 状态,则应该在绘制完成一帧之后恢复 canvas 状态

控制动画

我们可用通过 canvas 的方法或者自定义的方法把图像会知道到 canvas 上。正常情况,我们能看到绘制的结果是在脚本执行结束之后。
一般用到下面三个方法:
setInterval()
setTimeout()
requestAnimationFrame()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值