Canvas
基本用法
-
绘制矩形的三种方式
- fillRect(x, y, width, height) 绘制填充矩形
- strokeRect(x, y, width, height) 绘制一个矩形的边框
- clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明。
-
绘制路径
- beginPath() 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。 (函数准备绘制一个新的形状路径开始)
- moveTo(x, y) 要在设置路径(beginPath)之后专门指定你的起始位置。
- closePath() 闭合路径之后图形绘制命令又重新指向到上下文中。
- stroke() 通过线条来绘制图形轮廓。
- fill() 通过填充路径的内容区域生成实心的图形。
-
moveTo 移动笔触
- 将笔触移动到指定的坐标 x 以及 y 上。
绘制直线: lineTo(x, y) 绘制一条从
当前位置
到指定 (x,y) 位置
的直线。-
绘制圆弧:
- arc(x, y, radius, startAngle, endAngle, anticlockwise): 画一个以(x,y)为圆心的以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按照 anticlockwise 给定的方向(默认为顺时针)来生成。
- arcTo(x1, y1, x2, y2, radius): 根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
- 弧度=(Math.PI/180)*角度。
// 弧度方向 (顺时针的计算) 2 * PI 3/2 * PI 0 PI
-
二次/三次贝塞尔曲线
- quadraticCurveTo(cp1x, cp1y, x, y)
- bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
-
直接在画布上绘制矩形的三个额外方法
- rect(x, y, width, height) 当该方法执行的时候,moveTo() 方法自动设置坐标参数(0,0)。也就是说,当前笔触自动重置回默认坐标。
-
Path2D 对象: 用来缓存或记录绘画命令
-
Path2D.addPath(path [, transform])
new Path2D(); // 空的 Path 对象 new Path2D(path); // 克隆 Path 对象 new Path2D(d); // 从 SVG 建立 Path 对象 const rectangle = new Path2D(); rectangle.rect(10, 10, 50, 50); const circle = new Path2D(); circle.moveTo(125, 35); circle.arc(100, 35, 25, 0, 2 * Math.PI); ctx.stroke(rectangle); ctx.fill(circle);
-
使用 svg Paths
// 先移动到点 (M10 10) 然后再水平移动 80 个单位(h 80),然后下移 80 个单位 (v 80),接着左移 80 个单位 (h -80),再回到起点处 (z)。 const p = new Path2D("M10 10 h 80 v 80 h -80 Z");
-
使用样式和颜色
-
色彩 Colors
- ctx.fillStyle = color 设置图形的填充颜色
- ctx.strokeStyle = color 设置图形轮廓的颜色
// 这些 fillStyle 的值均为 '橙色' ctx.fillStyle = "orange"; ctx.fillStyle = "#FFA500"; ctx.fillStyle = "rgb(255,165,0)"; ctx.fillStyle = "rgba(255,165,0,1)";
-
设置全局对象的透明度值: ctx.globalAlpha = 0.2; 取值在[0, 1]
- globalAlpha是让整个画布变的透明了
- 使用之前save, 使用完成之后restore
-
线型 Line styles
-
影响描边样式的因素
- strokeStyle
- lineWidth
- lineCap 描边断点样式 butt/round/square ...
- lineJoin 描边拐点类型 milter/round/bevel ...
- meterLimit
ctx.lineWidth = value; 设置线条宽度。
ctx.lineCap = type; 设置线条末端样式。 (butt,round 和 square。默认是 butt。)
ctx.lineJoin = type; 设定线条与线条间接合处的样式。(round, bevel 和 miter。默认是 miter。)
ctx.miterLimit = numberValue; 限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。 (只适用于lineJoin="milter"的情况, 裁掉拐角
ctx.getLineDash() 返回一个包含当前虚线样式,长度为非负偶数的数组。
ctx.setLineDash(segments) 设置当前虚线样式。setLineDash([20,30,40]) (20长度实线,30虚线, 40实线)
ctx.lineDashOffset = numberValue 设置虚线样式的起始偏移量。
-
-
使用虚线
- 用 setLineDash 方法和 lineDashOffset 属性来制定虚线样式。setLineDash 方法接受一个数组,来指定线段与间隙的交替;lineDashOffset 属性设置起始偏移量。
-
渐变 Gradients
- 线性渐变: createLinearGradient(x1, y1, x2, y2)
- createLinearGradient 方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。
- 径向渐变: createRadialGradient(x1, y1, r1, x2, y2, r2)
- createRadialGradient 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。
- gradient.addColorStop(rate, color) rate 值域从 0 到 1, 表示渐变的比例点位
const linearGradient = ctx.createLinearGradient(0, 0, 150, 150); const radialGradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100); linearGradient.addColorStop(0, "white"); radialGradient.addColorStop(1, "black"); ctx.fillStyle = linearGradient;
- gradient.addColorStop(position, color), position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。color 参数必须是一个有效的 CSS 颜色值(如 #FFF,rgba(0,0,0,1),等等)。
- 线性渐变: createLinearGradient(x1, y1, x2, y2)
-
纹理 - 图案样式 Patterns
- createPattern(image, type) 该方法接受两个参数。Image 可以是一个 Image 对象的引用,或者另一个 canvas 对象。Type 必须是下面的字符串值之一:repeat,repeat-x,repeat-y 和 no-repeat。
// 创建图案 const pattern = ctx.createPattern(img, "repeat"); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 150, 150);
-
阴影 Shadows
- 横向偏移: shadowOffsetX = float
- 纵向偏移: shadowOffsetY = float
- 模糊度: shadowBlur = float
- shadowColor = color
const ctx = document.getElementById("canvas").getContext("2d"); ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; ctx.shadowBlur = 2; ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; ctx.font = "20px Times New Roman"; ctx.fillStyle = "Black"; ctx.fillText("Sample String", 5, 30);
-
ctx.fill('nonzero' | 'evenodd') 填充规则
- 填充规则根据某处在路径的外面或者里面来决定该处是否被填充
绘制文本
-
文本属性
- 字体font ctx.font = 'bold 18px serif';
- 水平对齐
- 垂直对齐
-
绘制文本
- fillText(text, x, y [, maxWidth]) 在指定的 (x,y) 位置填充指定的文本,绘制的最大宽度是可选的。
- strokeText(text, x, y [, maxWidth]) 在指定的 (x,y) 位置绘制文本边框,绘制的最大宽度是可选的。
-
有样式的文本
- ctx.font = value; 使用和 CSS font 属性相同的语法。默认的字体是 10px sans-serif。
- ctx.textAlign = value;
- ctx.textBaseline = value; (top middle bottom hanging alphabetic ideographic)
- ctx.direction = value;
-
预测量文本宽度
- measureText() 将返回一个 TextMetrics 对象的宽度、所在像素,这些体现文本特性的属性。
使用图片
-
引入图像到 canvas 里需要以下两步基本操作:
- 获得一个指向 HTMLImageElement 的对象或者另一个 canvas 元素的引用作为源,也可以通过提供一个 URL 的方式来使用图片
- 使用 drawImage()函数将图片绘制到画布上
-
绘制图片
- drawImage(image, x, y, width?, height?) 绘图 + 位移 + 缩放: 在canvas中(x,y)坐标处绘制宽度为width高度为height区域的图片
- drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) 绘图+裁剪+移动+缩放, 用于控制做切片显示的。 后 4 个则是定义切片的目标显示位置和大小。
sx: 相机视口位置横向坐标 (相当于画布左侧区域移动了sx) 对图像进行了横向裁剪
sy: 相机视口位置纵向坐标 (相当于画布左侧区域移动了sy) 对图像进行了纵向裁剪
sWidth: 相机视口的宽度 (将相机视口里的内容放置在渲染区域)
sHeight: 相机视口的宽度 (将相机视口里的内容放置在渲染区域)
在画布上放置图像的 dx 坐标位置。
在画布上放置图像的 dy 坐标位置。
要使用的图像的宽度。dWidth(伸展或缩小图像)
要使用的图像的高度。dHeight(伸展或缩小图像)
-
缩放时启用平滑缩放
ctx.mozImageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.msImageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false;
变形 transformations
-
状态的保存和恢复
- ctx.save(); ,每当 save()方法被调用后,当前的状态就被推送到栈中保存。
- 当前应用的变形(即移动,旋转和缩放,见下)
- 以及下面这些属性:
strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, direction, imageSmoothingEnabled
- 当前的裁切路径(clipping path)
- ctx.restore();
- 可以调用任意多次 save 方法。每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。
- ctx.save(); ,每当 save()方法被调用后,当前的状态就被推送到栈中保存。
-
移动 Translate (将画布进行移动)
- translate(x, y) 方法接受两个参数。x 是左右偏移量,y 是上下偏移量
function draw() { let ctx = document.getElementById("canvas").getContext("2d"); 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(Math.PI / 4) ,它用于以原点(0, 0)为中心顺时针旋转 canvas。
scale(x, y) 方法可以
缩放画布的水平和垂直的单位
。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比 1 小,会缩小图形,如果比 1 大会放大图形。默认值为 1,为实际大小。-
transform(a, b, c, d, e, f) 将当前的变形矩阵乘上一个基于自身参数的矩阵
// 如下面的矩阵所示: [ a c e b d f 0 0 1 ] a (m11) 水平方向的缩放 b(m12) 竖直方向的倾斜偏移 c(m21) 水平方向的倾斜偏移 d(m22) 竖直方向的缩放 e(dx) 水平方向的移动 f(dy) 竖直方向的移动
- setTransform(a, b, c, d, e, f)
- resetTransform() 重置当前变形为单位矩阵,它和调用以下语句是一样的:ctx.setTransform(1, 0, 0, 1, 0, 0);
组合 Compositing
-
ctx.globalCompositeOperation 不仅可以在已有图形后面再画新图形,还可以用来遮盖指定区域,清除画布中的某些部分(清除区域不仅限于矩形,像 clearRect()方法做的那样)以及更多其他操作。
-
路径裁切 clip() 将当前正在构建的路径转换为当前的裁剪路径。
- 状态save
- 定义路径
- clip
- 绘制其他图形 (之后绘制的图形只显示在这个路径之中)
- 状态restore (用完路径裁剪之后, 仍然想绘制其他的话)
像素操作
-
ImageData 对象
data:Uint8ClampedArray [r,g,b,a, r,g,b,a, r,g,b,a, ...]
width 图片宽度,单位是像素
height 图片高度,单位是像素
data Uint8ClampedArray 类型的一维数组,包含着 RGBA 格式的整型数据,范围在 0 至 255 之间(包括 255)。data 属性返回一个 Uint8ClampedArray,它可以被使用作为查看初始像素数据。每个像素用 4 个 1bytes 值 (按照红,绿,蓝和透明值的顺序; 这就是"RGBA"格式) 来代表。每个颜色值部份用 0 至 255 来代表。
Uint8ClampedArray 包含高度 × 宽度 × 4 bytes 数据,索引值从 0 到 (高度 × 宽度 ×4)-1
// 要读取图片中位于第 50 行,第 200 列的像素的蓝色(0=R.1=G,2=B)部份 blueComponent = imageData.data[50 * (imageData.width * 4) + 200 * 4 + 2]; // 根据行、列读取某像素点的 R/G/B/A 值的公式: imageData.data[50 * (imageData.width * 4) + 200 * 4 + 0 / 1 / 2 / 3]; // 使用 Uint8ClampedArray.length 属性来读取像素数组的大小(以 bytes 为单位): const numBytes = imageData.data.length;
-
创建 ImageData 对象
- const myImageData = ctx.createImageData(width, height); 创建了一个新的具体特定尺寸的 ImageData 对象。所有像素被预设为透明黑。
- const myImageData = ctx.createImageData(anotherImageData); 创建一个被 anotherImageData 对象指定的相同像素的 ImageData 对象。这个新的对象像素全部被预设为透明黑。这个并非复制了图片数据。
-
得到场景像素数据
- const myImageData = ctx.getImageData(left, top, width, height);
-
在场景中写入像素数据
- ctx.putImageData(myImageData, dx, dy, x,y,w,h); dx 和 dy 参数表示您希望在场景内左上角绘制的像素数据所得到的设备坐标。 x,y,w,h表示选取相对图片位置的坐标取宽度为w高度h的区域渲染
const invert = function () { ctx.drawImage(img, 0, 0); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; for (let i = 0; i < data.length; i += 4) { data[i] = 255 - data[i]; // red data[i + 1] = 255 - data[i + 1]; // green data[i + 2] = 255 - data[i + 2]; // blue } ctx.putImageData(imageData, 0, 0); };
-
缩放与反锯齿
- 反锯齿默认是启用的,关闭它以看到清楚的像素。可以通过切换 imageSmoothingEnabled 属性查看不同的效果(不同浏览器需要不同前缀)。
-
保存图片
- canvas.toDataURL('image/png')
- canvas.toDataURL('image/png', quality); quality 提供从 0 到 1 的品质量,1 表示最好品质,0 基本不被辨析但有比较小的文件大小。
- canvas.toBlob(callback, type, encoderOptions) 创建了一个在画布中的代表图片的 Blob 对像。