绘制

1.创建

Canvas的创建其实就是一个HTML标签

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 创建</title>
</head>
<body>
<canvas
id="canvas"
width="500"
height="500"
style="box-shadow: 0px 0px 5px #ccc; border-radius: 8px;">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
</body>
</html>
2.属性

id:画布的唯一标识,获取画布的时候可以用它

width:画布的宽度,这里需要说明在不设置画布宽度的时候,默认宽度为300像素

height:画布的高度,这里需要说明在不设置画布高度的时候,默认高度为150像素

style:画布的样式,例如正常情况下画布是没有边框或者阴影的,但上面示例中我们通过style属性给<canvas>标签设置了阴影和圆角样式。

3.绘制上下文

在Canvas的绘制中,Canvas本身是没有绘制能力的,它的所有绘制都是通过JavaScript来实现的

在Canvas没有绘制能力的情况下,JavaScript又如何在Canvas中实现元素的绘制呢?

这还得说到一个东西:绘制上下文

获取Canvas 绘制上下文的方法为:getContext(),正是这个方法让Canvas具备绘制的能力。

语法结构
canvas.getContext(contextType, contextAttributes)

参数说明:

  1. contextType 为绘制上下文的类型,类型参数有:
  • 2d:用于创建一个 CanvasRenderingContext2D 2D绘制上下文。
  • webgl:用于创建一个 WebGLRenderingContext 3D渲染上下文对象。且该类型只支持在实现WebGL版本1的浏览器上可用也就是 OpenGL ES 2.0。
  • webgl2:用于创建一个 WebGL2RenderingContext 3D渲染上下文对象。且该类型只支持在实现WebGL版本2的浏览器上可用也就是 OpenGL ES 3.0。
  • bitmaprenderer:用于创建一个只提供将 canvas 内容替换为指定ImageBitmap功能的ImageBitmapRenderingContext。
  1. contextAttributes 为绘制上下文的属性,这些属性相对比较多,可以设置单个也可以同时设置多个,下面列一下,方便大家了解:
  • 2D类型的参数有: (1)、alpha 它的值为Boolean类型,如果设置为false, 浏览器将认Canvas背景总是不透明的,这样可以做到一些性能提效。(2)、willReadFrequently,值也为Boolean类型,用于表明是否要重复操作,频繁调用getImageData()方法时能节省内存,但是仅Gecko内核浏览器支持。(3)、storage用于表明使用哪种方式存储,默认值 persisten,表示持久化存储。
  • 3D类型的参数有: (1)、alpha 值为Boolean类型,指示画布是否包含alpha缓冲区。 (2)、antialias 值为Boolean类型,指示是否开启抗锯齿。 (3)、depth 值为Boolean类型,表示绘图缓冲区的深度缓冲区至少为16位。 (4)、failIfMajorPerformanceCaveat值为Boolean类型,指示如果系统性能较低,是否创建上下文。 (5)、powerPreference:对用户代理的提示,指示GPU的哪种配置适合WebGL上下文。可能的值是: default: 自动选择模式,自动决定哪种GPU配置最合适,为默认值。 high-performance: 高性能模式,优先考虑渲染性能而不是功耗。 low-power: 节能模式,优先考虑节能而不是渲染性能。 (6)、premultipliedAlpha 值为Boolean类型,表示页面合成器将假定绘图缓冲区包含具有预乘alpha的颜色。 (7)、preserveDrawingBuffer 值为Boolean类型,如果值为true,则不会清除缓冲区并保留其值,直到被清除或被使用者覆盖。 (8)、stencil 值为Boolean类型,表示绘图缓冲区具有至少8位的模板缓冲区。
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');//获取绘制上下文
4.绘制方式

stroke() 描边

fill() 填充

strokeStyle 描边的样式

fillStyle 填充的样式

值得注意的是,strokeStylefillStyle 属性的设置是一次设置永久有效的,想要改变必须重新设置其他值来覆盖原有的值。

5.基本绘制形状
直线

直线的绘制就是设置两个点,然后连接这两个点形成一条直线,那么这两个点如何设置呢?

moveTo(x, y)

设置初始位置,参数为初始位置x和y的坐标点

lineTo(x, y)

设置指定位置,参数为指定位置x和y的坐标点

const canvas = document.getElementById('canvas'); // 获取Canvas
const ctx = canvas.getContext('2d'); // 获取绘制上下文
ctx.strokeStyle = "#f00" // 描边样式设置为红色
// 画一条(50, 50) 到 (400, 50)的直线
ctx.moveTo(50, 50)
ctx.lineTo(400, 50)
ctx.stroke()

// 连续的直线只需要设置一个起始点
ctx.moveTo(50, 100)
ctx.lineTo(50, 400)
ctx.lineTo(400, 400)
ctx.stroke()

直线样式

lineWidth

设置直线的粗细,默认值为1,且属性值必须为正数。

lineCap

设置直线端点显示的样式。可选值为:butt,round 和 square(通过添加一个宽度相等且高度为线条粗细一半的框,使线条末端呈方形)。默认是 butt。

image.png

lineJoin

设置两线段连接处所显示的样子。可选值为:round, bevel 和 miter。默认是 miter。

image.png

三角形
// 绘制一个三角形
ctx.moveTo(50, 100)
ctx.lineTo(50, 400)
ctx.lineTo(400, 400)
ctx.lineTo(50, 100)
ctx.stroke();

// 如果是填充一个三角形,则只需两条直线就行,它会默认闭合。
ctx.beginPath()
ctx.moveTo(200, 200)
ctx.lineTo(400, 200)
ctx.lineTo(400, 370)
ctx.fill();

矩形
// 矩形描边
rect(x, y, width, height)

// 绘制矩形
strokeRect(x, y, width, height)

// 填充矩形
fillRect(x, y, width, height)

上述的三个方法都可以用来绘制矩形,他们的传参都是一样的,其中x和y是起始点的x坐标和y坐标,width为矩形的宽,height为矩形的高。

合成版 strokeRect() fillRect()

圆弧和圆

Canvas提供了绘制圆弧或圆的方法:arc(),该方法提供了给定坐标值(x,y)以后,按给定的半径(r)大小,从给定的起始点(startAngle)位置,默认顺时针方向绘制圆弧或圆到给定的终点(endAngle)。

ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

参数说明:

  • x,y 为圆弧中心或圆的圆心坐标、
  • radius 为圆弧的半径或圆的半径、
  • startAngle 为圆弧或圆的起始点,从x轴方向开始计算,且单位为弧度、
  • endAngle 为圆弧或圆的终点,单位也是为弧度
  • anticlockwise 是一个可选参数,可选值为Boolean类型,用它来表示圆弧或圆的绘制方向,默认为false,顺时针绘制圆弧或圆,true是逆时针

角度转弧度的公式为:弧度 = 角度 * Math.PI / 180

贝塞尔曲线

二次贝塞尔曲线image.png

如图就是一个二次贝塞尔曲线,他的绘制需要一个控制点来控制曲线,具体的语法为:

quadraticCurveTo(cp1x, cp1y, x, y)

参数:

  • cp1x和cp1y为控制点坐标
  • x和y为结束点坐标
ctx.beginPath();
ctx.moveTo(100, 250);
ctx.quadraticCurveTo(250, 100, 400, 250);
ctx.stroke();

image.png

三次贝塞尔曲线

三次贝塞尔曲线和二次贝塞尔曲线不同的是三次贝塞尔曲线有两个控制点。具体的语法为:

ctx.bezierCurveTo(cp1x,cp1y, cp2x,cp2y, x, y)

参数为:

  • cp1x和cp1y为第一个控制点坐标
  • cp2x和cp2y为第二个控制点坐标
  • x和y为结束点坐标
ctx.beginPath();
ctx.moveTo(100, 250);
ctx.bezierCurveTo(150, 100, 350, 100, 400, 250);
ctx.stroke();

image.png20190809163503842.gif

一次贝塞尔曲线:

20190809163745169.gif

二次贝塞尔曲线:

20190809163835500.gif

三次贝塞尔曲线:

20190809163955483.gif

四次贝塞尔曲线:

20190809164018347.gif

五次贝塞尔曲线:

6.路径的开启和闭合

beginPath()

beginPath()方法用于开始一条路径或重置当前的路径

当我们不重新开启一条新路径,两条路径就会默认为是一条路径来绘制,因此就得不到我们想要的效果。想分开绘制我们就需要重新开启新的路径。

closePath()

closePath()方法和beginPath()方法正好相反,用来关闭一条路径,规范的用法其实是他们两个搭配使用,每次绘制都先开启一条新路径,完事关闭该路径

因此每次我们连续绘制时,若需要分开绘制,那么一定要在每次绘制前重新开启新的路径。

7.绘制文本

strokeText()方法是以描边的方式绘制文字的

ctx.strokeText(txt, x, y, maxWidth)

参数:

  • txt:是绘制的文本内容
  • x、y:为绘制文本的起始位置坐标
  • maxWidth:可选参数,为文本绘制的最大宽度。

当文案大于最大宽度时不是裁剪或者换行,而是缩小。

fillText()方法是以填充的方式绘制文字的

ctx.fillText(txt, x, y, maxWidth)

参数:

  • txt:是绘制的文本内容
  • x、y:为绘制文本的起始位置坐标
  • maxWidth:可选参数,为文本绘制的最大宽度。
font

font属性的设置可以改变字号和字体,不设置的情况下默认是:10px sans-serif

textAlign

textAlign属性的设置可以改变文本对齐的方式。默认值是 start,可选值有:leftrightcenterstartend

image.png

如图我们可以看到各个参数对应的效果,我们会发现startleft的效果基本一样,还有endright的效果也基本一样,那么startleftendright是不是等价的呢?答案肯定是否定的。因为如果是等价的那就没必要设置两个属性了。

那他们既然不一样,那他们有什么区别呢?这我们需要结合另一个属性:direction 来看。

direction

direction属性可以设置文本的方向。默认值是 inherit, 可选值为:ltr(文本方向从左向右)、rtl(文本方向从右向左)、inherit(根据情况继承 Canvas元素或者 Document 。)。

direction 属性会对 textAlign 属性产生影响。

如果 direction 属性设置为 ltr,则textAlign属性的 leftstart 的效果相同,rightend 的效果相同,

如果 direction 属性设置为 rtl,则 textAlign属性的 leftend 的效果相同,rightstart 的效果相同。

textBaseline

textBaseline属性设置基于基线对齐的文字垂直方向的对齐方式。默认值是alphabetic,可选值为:tophangingmiddlealphabeticideographicbottom

image.png

8.绘制图像
语法:
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
参数:
  • image:绘制的元素(图像)。
  • sx、sy:裁剪框左上角的坐标。
  • sWidth、sHeight:裁剪框的宽度和高度。
  • dx、dy:绘制元素(图像)时左上角的坐标。
  • dWidth、dHeight:绘制元素(图像)的宽度和高度。如果不设置,则在绘制时image宽度和高度不会缩放,超出画布则图片不完整
var img = new Image();
img.src = '//图片url';
img.onload = function(){
ctx.drawImage(img, 0, 150, 1650, 700, 0, 0, 550, 500);
}