社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
使用canvas可以在html5制作出各种绚丽的图表、动画,是制作微信/H5小游戏的基础。
在数学中坐标系是一个十字形的,原点在中间。而在canvas中原点在画布的左上角。
三角函数是初中数学开始学习的知识,但我已经忘记的差不多了,因此这里就多详细整理一下。
sin(α) = y/c
cos(α) = x/c
tan(α) = y/x
sin(α) = y/c
=> α = arcsin(y/c)
cos(α) = x/c
=> α = arccos(c/c)
tan(α) = y/x
=> α = arctan(y/x)
getContext() 方法返回canvas上下文环境,可以在创建渲染上下文的时候设置多个属性:
// 二维渲染
canvas.getContext("2d")
// 三维渲染(OpenGL ES 2.0)
canvas.getContext("webgl")
// 三维渲染(OpenGL ES 3.0)
canvas.getContext("webg2")
// 提供功能去替换指定 canvas 的ImageBitmap内容
canvas.getContext("bitmaprenderer")
通常情况下,我们使用 canvas.getContext("2d")
, 即:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
console.log(ctx); // CanvasRenderingContext2D { ... }
moveTo(x, y) 将笔触移动到指定的坐标x以及y上。
beginPath()
新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
closePath()
闭合路径之后图形绘制命令又重新指向到上下文中。
stroke()
通过线条来绘制图形轮廓。
fill()
通过填充路径的内容区域生成实心的图形。调用fill时,会自动闭合路径。
clip()
将当前正在构建的路径转换为当前的裁剪路径。
lineTo(x, y) 绘制一条从当前位置到指定x以及y位置的直线。如果没有 moveTo 那么第一次 lineTo 的效果等于 moveTo。
lineWidth = value 设置线条宽度。
lineCap = type 设置线条末端样式。
lineJoin = type 设定线条与线条间接合处的样式。
miterLimit = value 限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。
getLineDash() 返回一个包含当前虚线样式,长度为非负偶数的数组。
setLineDash(segments) 设置当前虚线样式。
lineDashOffset = value 设置虚线样式的起始偏移量。
fillRect(x, y, width, height) 绘制一个填充的矩形
strokeRect(x, y, width, height) 绘制一个矩形的边框
clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明。
rect(x, y, width, height) 将一个矩形路径增加到当前路径上
arc(x, y, radius, startAngle, endAngle, anticlockwise) 画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
arcTo(x1, y1, x2, y2, radius) 根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
注意:
arc()
函数中表示角的单位是弧度,不是角度。角度与弧度的js表达式: 弧度=(Math.PI/180)*角度
。
arc()
函数如果不闭合路径并且不填充颜色,那么将显示为圆弧。
quadraticCurveTo(cp1x, cp1y, x, y) 绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) 绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
设置填充颜色
// 这些 fillStyle 的值均为 '橙色'
ctx.fillStyle = "orange";
ctx.fillStyle = "#FFA500";
ctx.fillStyle = "rgb(255,165,0)";
ctx.fillStyle = "rgba(255,165,0,1)";
设置轮廓颜色
ctx.strokeStyle = "orange";
设置透明度值
ctx.globalAlpha = 0.2;
createLinearGradient(xStart,yStart,xEnd,yEnd).addColorStop(offset,color) 线性渐变
createRadialGradient(xStart,yStart,radiusStart,xEnd,yEnd,radiusEnd).addColorStop(offset,color) 径向渐变
xstart
:渐变开始点x坐标
ystart
:渐变开始点y坐标
xEnd
:渐变结束点x坐标
yEnd
:渐变结束点y坐标
radiusStart
:发散开始圆的半径
radiusEnd
:发散结束圆的半径
offset
:设定的颜色离渐变结束点的偏移量(0~1)
color
:绘制时要使用的颜色
shadowOffsetX = float
shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。
shadowOffsetY = float
shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。
shadowBlur = float
shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0。
shadowColor = color
shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。
// 参数: nonzero | evenodd
ctx.fill("evenodd")
“nonzero”是非零环绕原则,也是默认值,“evenodd”为奇偶原则。
通常在填充相交或嵌套路径时使用。
fillText(text, x, y [, maxWidth])
在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.
strokeText(text, x, y [, maxWidth])
在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的.
font = value
当前我们用来绘制文本的样式. 这个字符串使用和 CSS font 属性相同的语法. 默认的字体是 10px sans-serif。
textAlign = value
文本对齐选项. 可选的值包括:start, end, left, right or center. 默认值是 start。
textBaseline = value
基线对齐选项. 可选的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic。
direction = value
文本方向。可能的值包括:ltr, rtl, inherit。默认值是 inherit。
var text = ctx.measureText("foo");
text.width; // 16;
嵌入图片的操作
// 1. new image()
var img = new Image(); // 创建img元素
img.onload = function(){
// 执行drawImage语句
}
img.src = 'myImage.png'; // 设置图片源地址
// 2. data: url
img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';
drawImage(image, x, y, width, height,x2, y2, width2, height2)
其中 image 是 image 或者 canvas 对象;x 和 y 是其在目标 canvas 里的起始坐标;width 和 height,这两个参数用来控制 当向canvas画入时应该缩放的大小;x2/y2/width2/height2定义切片的目标显示位置和大小。
Path2D对象可以把svg等内容画在canvas上。
new Path2D(); // 空的Path对象
new Path2D(path); // 克隆Path对象
new Path2D(d); // 从SVG建立Path对象
var p = new Path2D("M10 10 h 80 v 80 h -80 Z"); // 使用svg路径
var img = new Image();
img.src = 'someimage.png';
var ptrn = ctx.createPattern(img,'repeat');
注意:
与 drawImage 有点不同,你需要确认 image 对象已经装载完毕,否则图案可能效果不对的。
save()、restore()
save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。
translate(x, y)
translate 方法接受两个参数。x 是左右偏移量,y 是上下偏移量,如右图所示。
rotate(angle)
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
scale(x, y)
scale 方法接受两个参数。x,y 分别是横轴和纵轴的缩放因子,它们都必须是正值。值比 1.0 小表示缩小,比 1.0
transform(m11, m12, m21, m22, dx, dy)
m11
:水平方向的缩放
m12
:水平方向的倾斜偏移
m21
:竖直方向的倾斜偏移
m22
:竖直方向的缩放
dx
:水平方向的移动
dy
:竖直方向的移动
// 将当前的变形矩阵重置为单位矩阵
setTransform(m11, m12, m21, m22, dx, dy)
// 重置当前变形为单位矩阵
resetTransform()
globalCompositeOperation = type
这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识遮盖方式的字符串。
source-over
这是默认设置,并在现有画布上下文之上绘制新图形。
source-in
新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。
source-out
在不与现有画布内容重叠的地方绘制新图形
source-atop
新图形只在与现有画布内容重叠的地方绘制。
destination-over
在现有的画布内容后面绘制新的图形。
destination-in
现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的。
destination-out
现有内容保持在新图形不重叠的地方。
destination-atop
现有的画布只保留与新图形重叠的部分,新的图形是在画布内容后面绘制的。
lighter
两个重叠图形的颜色是通过颜色值相加来确定的。
copy
只显示新图形。
xor
图像中,那些重叠和正常绘制之外的其他地方是透明的。
multiply
将顶层像素与底层相应像素相乘,结果是一幅更黑暗的图片。
screen
像素被倒转,相乘,再倒转,结果是一幅更明亮的图片。
overlay
multiply和screen的结合,原本暗的地方更暗,原本亮的地方更亮。
darken
保留两个图层中最暗的像素。
lighten
保留两个图层中最亮的像素。
color-dodge
将底层除以顶层的反置。
color-burn
将反置的底层除以顶层,然后将结果反过来。
hard-light
屏幕相乘(A combination of multiply and screen)类似于叠加,但上下图层互换了。
soft-light
用顶层减去底层或者相反来得到一个正值。
difference
一个柔和版本的强光(hard-light)。纯黑或纯白不会导致纯黑或纯白。
exclusion
和difference相似,但对比度较低。
hue
保留了底层的亮度(luma)和色度(chroma),同时采用了顶层的色调(hue)。
saturation
保留底层的亮度(luma)和色调(hue),同时采用顶层的色度(chroma)。
color
保留了底层的亮度(luma),同时采用了顶层的色调(hue)和色度(chroma)。
luminosity
保持底层的色调(hue)和色度(chroma),同时采用顶层的亮度(luma)。
canvas动画通过重绘出每一帧画面,达到连续的动画效果,重绘是相当费时的,而且性能很依赖于电脑的速度。
除非接下来要画的内容会完全充满 canvas (例如背景图),否则你需要清空所有。最简单的做法就是用 clearRect 方法。
如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。
这一步才是重绘动画帧。
如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。
window.setInterval(function, delay)
当设定好间隔时间后,function会定期执行。
window.setTimeout(function, delay)
在设定好的时间之后执行函数
window.requestAnimationFrame(callback)
告诉浏览器你希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画。
ImageData对象中存储着canvas对象真实的像素数据,它包含以下几个只读属性:
width
图片宽度,单位是像素
height
图片高度,单位是像素
data
Uint8ClampedArray类型的一维数组,包含着RGBA格式的整型数据,范围在0至255之间(包括255)。
当有许多相似图形或重复图像时使用,比如说需要同一个图像的不同尺寸
myEntity.offscreenCanvas = document.createElement("canvas");
myEntity.offscreenCanvas.width = myEntity.width;
myEntity.offscreenCanvas.height = myEntity.height;
myEntity.offscreenContext = myEntity.offscreenCanvas.getContext("2d");
myEntity.render(myEntity.offscreenContext);
ctx.drawImage(myImage, 0.3, 0.5); // no
使用Math.floor()对所有坐标取整
let x = Math.floor(0.3);
let y = Math.floor(0.5);
ctx.drawImage(myImage, x, y);
用多个画布元素去创建不同层次。
可以用div把canvas包裹起来,然后用css设置div的背景图片。
CSS transforms 特性由于调用GPU,因此更快捷。不要将小画布放大,而是去将大画布缩小。
如果不需要透明度,可以在声明渲染的时候先关闭它。
var ctx = canvas.getContext('2d', { alpha: false });
将画布的函数调用集合到一起(例如,画一条折线,而不要画多条分开的直线)
避免不必要的画布状态改变
渲染画布中的不同点,而非整个新状态
尽可能避免 shadowBlur特性
尽可能避免text rendering
使用不同的办法去清除画布(clearRect() vs. fillRect() vs. 调整canvas大小)
有动画,请使用window.requestAnimationFrame() 而非window.setInterval()
请谨慎使用大型物理库
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!