从入门到精通canvas:基础系列(二)
上一篇漏掉了一个小点,在这里简单讲解一下,就是Canvas的填充方式,使用
fill()
进行填充的时候是有两种填充方式的,默认的是nonzero
,还可以使用evenodd
填充,可以复制下方代码看一下
var ctx = document.getElementById("canvas").getContext("2d");
ctx.beginPath();
ctx.arc(50, 50, 30, 0, Math.PI * 2, true);
ctx.arc(50, 50, 15, 0, Math.PI * 2, true);
ctx.fill("evenodd");
好的,接下来书接上回
文字
canvas有两种方法来进行文本绘制,一种是fillText()
,另一种是strokeText()
,其中还包括一些文本的样式,下面用代码实现一下
<!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>Document</title>
<style>
#canvas {
border: 1px solid black;
}
</style>
</head>
<body onload="fn()">
<canvas id="canvas" width="300" height="150"></canvas>
<script>
function fn () {
const canvas = document.getElementById("canvas")
const cvs = canvas.getContext("2d");
//设置字体大小,font必须包含font-size和font-family两个值。
// 可以选择下面的值,font-style,font-weight,fontvariant,line-height
cvs.font = '48px serif'
// 这个就是一个有填充的文本
// 基线对齐选项
cvs.textBaseline = 'end'
cvs.direction = 'rtl'
cvs.fillText('Hello world', 10, 50)
// 文本对齐选项
cvs.textAlign = 'center'
// 这个就是一个文本边框
cvs.strokeText('Hello world', 10, 100)
// 测量文本的宽度
const text = cvs.measureText('Hello world')
console.log(text.width);
}
</script>
</body>
</html>
上面只是写了一下啊,你可以复制到你的编译器上自己调节看一下是怎么样的,下面会详细讲解一些文字的一些属性
font属性
font下主要包含
-
font-size 这个就是根据你的需求来设置的,也就是文字的大小,默认字体是10px
-
font-family : font-family就是文本的字体样式,使用那种字体,这个可以根据你的实际清空来设置,
serif
,Georgia
,你可以设置这两个来体验一些,看一下效果,但是记住,font-family
,font-style
,font-variant
,必须要写在font-size
前 -
font-width:就是很简单的,来设置字体是否加粗的
-
font-style:可以来设置字体的样式,倾斜度这些,和css的font-style是一样的,normal使用font-family字体,italic选择斜体,当前按文字没用斜体的话就会使用oblique代替
font总体也没有什么好讲的,主要就是一个顺序问题,其它的话都是和css是一样的,是很简单的一个属性设置
textAlign:文本水平对齐方式,可选值有 start
, end
, left
, right
or center
. 默认值是 start
。这个是基于起始点来设置的,例如设置为center
,也就是文本中间与起始点对齐
textBaseline:textBaseline
是 canvas 中用于设置文本垂直对齐方式的属性。这个属性决定了绘制文本时,文本基线(baseline)相对于绘制点的位置。可选的值包括:top
, hanging
, middle
, alphabetic
, ideographic
, bottom
。默认值是 alphabetic
。
这个是基于基线来进行设置的,例如top
表示文本基线与字体最高处的边界对齐。
direction:direction可选值有ltr
, rtl
, inherit
。默认值是 inherit
。即是从左到右(LTR)还是从右到左(RTL)
shadowOffsetX:用来设定阴影在 X 的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0
shadowOffsetX: 和 shadowOffsetY
用来设定阴影在 Y 轴的延伸距离,
shadowBlur: 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0
。
shadowBlur: 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0
。
图像
Canvas的操作能力是很强的,可以用于动态的图像合成或者作为图形的背景,以及游戏界面(Sprites)等等。浏览器支持的任意格式的外部图片都可以使用,比如 PNG、GIF 或者 JPEG。你甚至可以将同一个页面中其他 canvas 元素生成的图片作为图片源。
把图片引入到Canvas里需要两步,首先需要获得一个指向HTMLImageElement
的对象或者另一个Canvas的元素作为源,也可也提供一个URL
的方式来使用图片,然后使用drawImage()
函数将图片绘制到画布上。
可以使用以下Canvas的API作为图像源。
- HTMLImageElment:这些就是
Image()
,构造函数出来的,或者是img
的html元素的src
<!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>Document</title>
</head>
<style>
#canvas {
border: 1px solid #000;
}
</style>
<body>
<canvas id="canvas" width="300" height="500"></canvas>
<img src="./v2-c00cfe7b0ccc86501d1046cdc7da3307_b.jpg" alt="">
<script>
const canvas = document.getElementById("canvas");
cvs = canvas.getContext("2d");
// 通过new image() 绘制图片
// const img = new Image()
// img.onload = () => {
// cvs.drawImage(img, 0, 0)
// }
// img.src = './v2-c00cfe7b0ccc86501d1046cdc7da3307_b.jpg'
// 通过获取元素绘制图片
const img = document.querySelector('img');
img.onload = () => {
cvs.drawImage(img, 0, 0)
}
</script>
</body>
</html>
- HTMLVideoElement:这个是获取一个视频,抓取视频的视频帧,作为图像源的
const canvas = document.getElementById("canvas");
cvs = canvas.getContext("2d");
const video = document.getElementById("video");
video.addEventListener("play", () => {
drawVideoToCanvas();
});
function drawVideoToCanvas () {
if (video.paused || video.ended) {
console.log(video);
return;
}
cvs.drawImage(video, 0, 0, canvas.width, canvas.height);
requestAnimationFrame(drawVideoToCanvas);
}
- HTMLCanvasElement:使用另一个Canvas作为图片源
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
const img = new Image();
img.onload = () => {
cvs1.drawImage(img, 0, 0)
// 用cvs2画cvs1的图片
const canvas2 = document.getElementById('canvas2')
cvs2 = canvas2.getContext('2d')
cvs2.drawImage(canvas1, 0, 0)
}
img.src = './v2-c00cfe7b0ccc86501d1046cdc7da3307_b.jpg'
- ImageBitmap:
ImageBitmap
是HTML5中的一个API,用于表示图像位图。它是一种经过解码和处理的图像数据对象,可以在Canvas上进行绘制,它可以从上述的所有源以及其他几种源中生成,ImageBitmap
在内存中的占用更小,同时提供了更高效的绘制性能,它是一个异步操作,返回一个Promise
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
const img = new Image();
img.onload = () => {
createImageBitmap(img).then((imageBitmap) => {
cvs1.drawImage(imageBitmap, 0, 0)
}).catch((e) => {
console.log(e);
})
}
img.src = './v2-c00cfe7b0ccc86501d1046cdc7da3307_b.jpg'
- 绘制一个简单的折线图,这里我直接用了图片绘制出来了折线的背景,数据是自己写的
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
const img = new Image();
img.onload = () => {
cvs1.drawImage(img, 0, 0, canvas1.width, canvas1.height);
cvs1.beginPath();
cvs1.moveTo(30, 230);
cvs1.lineTo(70, 186);
cvs1.lineTo(103, 136);
cvs1.lineTo(170, 150);
cvs1.lineTo(190, 110);
cvs1.stroke();
}
img.src = './echarts.png'
- drawImage:
drawImage
上面已经用到过了,它主要有八个参数(img,x,y,width,height,x1,y1,width1,height1),(图片,起始位置x,起始位置y,图片宽,图片高,切割x,切割y,切割宽度,切割高度)
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
const img = new Image();
img.onload = () => {
cvs1.drawImage(img, 0, 0, canvas1.width, canvas1.height, 30, 100, 50, 100);
}
img.src = './v2-c00cfe7b0ccc86501d1046cdc7da3307_b.jpg'
控制图像的缩放行为
过度缩放图像可能会导致图像模糊或像素化。您可以通过使用绘图环境的属性来控制是否在缩放图像时使用平滑算法。默认值为true
,即启用平滑缩放。您也可以像这样禁用此功能
-
mozImageSmoothingEnabled:- 这是在使用 Mozilla Firefox 浏览器时,用于禁用图像平滑处理的属性。
mozImageSmoothingEnabled
是 Firefox 特定的属性。 -
webkitImageSmoothingEnabled:- 这是在使用 WebKit 内核(例如 Chrome、Safari)的浏览器时,用于禁用图像平滑处理的属性。
webkitImageSmoothingEnabled
是 WebKit 特定的属性。 -
msImageSmoothingEnabled: - 这是在使用 Microsoft Edge 浏览器时,用于禁用图像平滑处理的属性。
msImageSmoothingEnabled
是 Edge 特定的属性。 -
imageSmoothingEnabled:- 这是一个通用的属性,适用于大多数现代浏览器。它用于禁用图像平滑处理。如果其他特定浏览器的属性不存在或未设置,那么可以使用这个属性来禁用图像平滑处理。
图像平滑处理是一种通过插值算法使图像在缩放或者旋转时显得更平滑的技术。然而,对于某些情况下,比如需要绘制像素风格的图像,可能希望禁用图像平滑处理以保持像素的锐利边缘。
通过将以上属性设置为 false
,可以禁用图像平滑处理,使图像绘制时保持原始的像素外观。需要注意的是,这些属性需要在绘制图像之前进行设置,否则可能不会生效。
变形 Transformations
介绍变形之前先介绍两个绘制复杂图像需要用到的Api,save()
和restore
save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
// 设置绘制样式
cvs1.fillStyle = '#1177b1';
cvs1.strokeStyle = '#ff0000';
cvs1.lineWidth = 3;
// 绘制矩形,并保存当前状态
cvs1.save();
cvs1.fillRect(10, 10, canvas1.width - 20, canvas1.height - 20);
// 修改绘制样式
cvs1.fillStyle = '#e78f8a';
cvs1.strokeStyle = '#0000ff';
cvs1.lineWidth = 5;
// 绘制矩形
cvs1.fillRect(20, 20, canvas1.width - 40, canvas1.height - 40);
// 恢复到之前保存的状态
cvs1.restore();
// 绘制矩形,使用恢复后的绘制样式
cvs1.fillRect(30, 30, canvas1.width - 60, canvas1.height - 60);
// 绘制边框
cvs1.strokeRect(0, 0, canvas1.width, canvas1.height);
通过这个示例,你应该能够观察到 save()
和 restore()
方法在保存和恢复 Canvas 上下文状态以及相关绘制样式方面的作用
- 移动 Translating:它用来移动
canvas
和它的原点到一个不同的位置,translate
方法接受两个参数。x 是左右偏移量,y 是上下偏移量。在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。又,如果你是在一个循环中做位移但没有保存和恢复 canvas 的状态,很可能到最后会发现怎么有些东西不见了,那是因为它很可能已经超出 canvas 范围以外了。
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
cvs1.save();
cvs1.fillStyle = "rgb(" + 51 * i + ", " + (255 - 51 * i) + ", 255)";
cvs1.translate(10 + j * 50, 10 + i * 50);
cvs1.fillRect(0, 0, 25, 25);
cvs1.restore();
}
}
看这个例子,外部循环,从 0 到 2,用于控制行数,内部循环,从 0 到 2,用于控制列数,如果不使用translate
你就只能看到推叠在一起的一个,而且每次循环都会save
保存当前的 Canvas 上下文状态,然后结尾在恢复到之前的状态
- 旋转rotate:
rotate()
是 Canvas 上下文对象的一个方法,用于对绘制进行旋转context.rotate(angle);
其中,angle
是旋转角度,单位为弧度(radians)。正值表示顺时针旋转,负值表示逆时针旋转。在调用rotate()
方法之后,Canvas 上下文对象会按照指定的旋转角度对后续的绘制操作进行变换。这意味着从调用rotate()
开始到调用restore()
恢复之前的状态之间的所有绘制操作都会受到旋转的影响。
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
// 绘制矩形
cvs1.fillStyle = '#1bd66c'
cvs1.fillRect(30, 30, 100, 100);
// 保存当前状态
cvs1.save();
// 旋转45度
cvs1.rotate(Math.PI / 4);
cvs1.fillStyle = 'rgba(35, 169, 242,0.3)'
// 绘制旋转后的矩形
cvs1.fillRect(100, 0, 100, 100);
// 恢复到初始状态
cvs1.restore();
// 绘制未旋转的矩形
cvs1.fillRect(150, 30, 100, 100);
cvs1.save()
cvs1.rotate(Math.PI / 4)
cvs1.fillStyle = 'rgba(255, 214, 96,0.7)'
cvs1.fillRect(230, 0, 100, 100)
当你对绘制进行旋转之后,坐标系统会跟随旋转进行相应的变换
- 缩放Scaling :
Scaling
是图形处理中的一种操作,它可以按比例调整对象的尺寸。在绘图中,你可以通过应用缩放来放大或缩小对象。缩放操作会以一个固定点为中心,按照指定的比例因子对对象进行尺寸的调整。可以想象成在坐标系上相对于该中心点进行伸缩。Scaling
接收两个参数,两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比 1 小,会缩小图形,如果比 1 大会放大图形。默认值为 1,为实际大小。
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
// 绘制矩形
cvs1.fillStyle = '#1bd66c'
// 保存当前状态
cvs1.save();
cvs1.scale(0.7, 0.7)
cvs1.fillRect(30, 30, 100, 100);
// 恢复初始状态
cvs1.restore()
cvs1.fillRect(100, 100, 100, 100);
- 变形transform:
transform
接收五个参数,全都来源于上方讲解的(水平方向的缩放,竖直方向的倾斜偏移,水平方向的倾斜偏移,竖直方向的缩放,水平方向的移动,竖直方向的移动),可以使用setTransform(1, 0, 0, 1, 0, 0)
重置当前变形为单位矩阵,因为如果任意一个参数是无限大,那么变形矩阵也必须被标记为无限大,否则会抛出异常。从根本上来说,该方法是取消了当前变形,然后设置为指定的变形,一步完成
const canvas1 = document.getElementById("canvas1");
cvs1 = canvas1.getContext("2d");
const sin = Math.sin(Math.PI / 6);
const cos = Math.cos(Math.PI / 6);
// 平移画布原点到 (100, 100)
cvs1.translate(100, 100);
let c = 0;
for (var i = 0; i <= 12; i++) {
c = Math.floor((255 / 12) * i);
// 设置矩形填充颜色为灰度渐变
cvs1.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
// 绘制矩形
cvs1.fillRect(0, 0, 100, 10);
// 对画布进行旋转变换
cvs1.transform(cos, sin, -sin, cos, 0, 0);
}
// 设置画布变换矩阵为 (-1, 0, 0, 1, 100, 100)
cvs1.setTransform(-1, 0, 0, 1, 100, 100);
// 设置矩形填充颜色为半透明粉色
cvs1.fillStyle = "rgba(255, 128, 255, 0.5)";
// 绘制矩形
cvs1.fillRect(0, 50, 100, 100)
结尾
下一章会讲解一下Canvas的基础动画效果