Canvas简单入门
Canvas简单入门
创建canvas
至少需要提供width
和height
属性,才能通知浏览器需要多大位置画图。标签的内容是后备数据,在浏览器不支持canvas
元素时显示。
<canvas id="mycanvas" width="200" height="200">haha</canvas>
可以通过if(canvas.getContext)
来判断浏览器是否支持canvas
。
通过canvas.getContext('2d')
可以获取 2D 绘图上下文。2D 绘图上下文提供了绘制 2D 图形的方法。左边原点(0, 0)在 canvas
元素的左上角,x 坐标向右增长,y 坐标向下增长。
从画布上导出一张 PNG 格式的图片
<body>
<canvas id="mycanvas" width="200" height="200">haha</canvas>
<script>
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
// 获得图像的数据URI
const imgURI = mycanvas.toDataURL("image/png");
console.log(imgURI);
}
</script>
</body>
我们查看控制台可以发现,输出了一串base64
编码,也就是说,canvas.toDataURL
就是将画布 canvas
转换成base64
编码。
填充与描边
- 填充就是以特定的样式填充形状,包括颜色、渐变、图像
- 描边就是只给形状边界着色。
显示效果取决于两个属性:fillStyle
和strokeStyle
。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.fillStyle = "#000";
context.strokeStyle = "red";
}
没有效果? 别急,这是因为我们只是设置了填充和描边而已,想要它生效,还需要绘制出来才能有效果。
绘制矩形
与绘制矩形相关的方法有三个。它们都接收 4 个参数:矩形 x 坐标、矩形 y 坐标、矩形宽度和矩形高度。(单位是像素,但是传参时不需要传单位)
fillRect
strokeRect
clearRect
fillRect
:绘制并填充矩形
fillRect
:以指定颜色在画布上绘制并填充矩形,填充色使用fillStyle
来设置。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.fillStyle = "pink";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgba(0, 0, 0, .1)";
context.fillRect(30, 30, 50, 50);
}
stokeRect
:绘制矩形轮廓
stokeRect
:绘制矩形轮廓,颜色由strokeStyle
来指定。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.strokeStyle = "red";
// 设置描边宽度
context.lineWidth = 5;
context.strokeRect(10, 10, 50, 50);
context.strokeStyle = "blue";
context.fillStyle = "rgba(0, 0, 0, .1)";
context.strokeRect(30, 30, 50, 50);
}
clearRect
:擦除画布中某个区域
clearRect
:擦除画布中某个区域,把擦除的区域变透明。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.fillStyle = "red";
context.fillRect(0, 0, 200, 200);
context.clearRect(50, 50, 100, 100);
}
绘制路径
绘制路径需要先调用beginPath
,表示要开始绘制路径,再调用以下方法来绘制路径。
lineTo(x, y)
:绘制一条从上一个点到(x, y)的直线moveTo(x, y)
:不绘制线条,只是把画笔移动到(x, y)- 更多
绘制完路径后,可以指定fillStyle
属性并调用fill
方法来填充路径,也可以指定strokeStyle
属性并调用stoke
方法来描画路径。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// 创建路径
context.beginPath();
// 绘制圆弧,参数分别是圆心x坐标、圆形y坐标、圆弧半径、圆弧起始点(单位:弧度)、圆弧终点(单位:弧度)、绘制方向(false为顺时针绘制,true为逆时针绘制)
context.arc(100, 100, 99, 0, 2 * Math.PI, true);
// context.fillStyle = 'pink'
// context.fill()
context.strokeStyle = "pink";
context.stroke();
}
还可以调用clip
方法创建一个新的剪切区域。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// 创建路径
context.beginPath();
// 绘制圆弧,参数分别是圆心x坐标、圆形y坐标、圆弧半径、圆弧起始点(单位:弧度)、圆弧终点(单位:弧度)、绘制方向(false为顺时针绘制,true为逆时针绘制)
context.arc(100, 100, 50, 0, 2 * Math.PI, true);
context.fillStyle = "pink";
context.clip();
context.fillRect(0, 0, 100, 100);
}
上面的扇形怎么出来的呢?
我们可以把clip
变成fill
,看下没有被剪切的话,是什么样子。
也就是说,实际上剪切就是两个图形相交部分。
如果使用lineTo
需要注意:没有设置moveTo
时,这个位置并不是(0, 0),而是空,所以第一次的lineTo
没法画出结果。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// 创建路径
context.beginPath();
// context.moveTo(0, 0);
context.lineTo(100, 50);
context.lineTo(200, 0);
context.lineWidth = 8;
context.strokeStyle = "pink";
// 描画路径
context.stroke();
}
没有moveTo
:
有moveTo
:
beginPath 的作用
上面的例子中,beginPath
并没有作用,也就是说上面的例子中,其实有没有beginPath
都一样。那么beginPath
有什么作用呢?
beginPath
表示下面绘制的图形是一个新的路径。具体看下实例。
const context = mycanvas.getContext("2d");
// 创建路径
context.beginPath();
context.moveTo(0, 0);
context.lineTo(100, 50);
context.lineWidth = 8;
context.strokeStyle = "pink";
// 描画路径
context.stroke();
context.lineTo(200, 0);
context.strokeStyle = "purple";
context.stroke();
想要的效果是画出两条不一样颜色的线,但是最后是一种颜色折线,这是因为我们只是用了一次beginPath
,所以就会把这两条线当成同一个路径,最后调用的stroke
就会把原本是粉色的线再用紫色画一遍,所以最终的效果就是只有一条折线。
所以需要使用beginPath
创建新路径,新的路径还是会有没有设置moveTo
时,这个位置并不是(0, 0),而是空的问题,所以需要使用moveTo
设置位置
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// 创建路径
context.beginPath();
context.moveTo(0, 0);
context.lineTo(100, 50);
context.lineWidth = 8;
context.strokeStyle = "pink";
context.stroke();
context.beginPath();
// 创建新的路径,需要重新设置位置
context.moveTo(100, 50);
context.lineTo(200, 0);
context.strokeStyle = "purple";
context.stroke();
}
closePath 的作用
有可能会陷进closePath
是结束路径的误区,认为closePath
就是beginPath
的配套。但是closePath
和beginPath
并不是配套的,它们的功能不一样。所以closePath
之后的路径也不是新的路径,只有beginPath
才行。
而closePath
的作用是将最近绘制的路径闭合,和之前有没有beginPath
无关。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// context.beginPath(); // 有无`beginPath`都没有影响
context.moveTo(10, 10);
context.lineTo(100, 50);
context.lineTo(20, 70);
context.closePath();
context.lineWidth = 8;
context.strokeStyle = "pink";
context.stroke();
}
上面我们只绘制了两条线,但是最终得到的结果是一个三角形,这是因为我们使用closePath
把最近绘制的路径闭合了。
绘制文本
绘制文本有两种方法。
fillText
:使用fillStyle
属性绘制文本strokeText
:使用strokeStyle
属性绘制文本
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.moveTo(10, 10);
context.lineTo(150, 75);
context.lineTo(30, 100);
context.closePath();
context.lineWidth = 1;
context.strokeStyle = "pink";
context.fillStyle = "purple";
context.fillText("CLZ", 50, 60);
context.strokeText("CLZ", 50, 80);
context.stroke();
}
可以通过font
、textAlign
、textBaseline
属性设置文本的字体、对齐方式、基线。
示例:
context.font = "700 16px Arial";
textAlign
:
- 如果是
start
,那么 x 坐标就是文本的左侧坐标 - 如果是
center
,那么 x 坐标就是文本的中心点坐标 - 如果是
end
,那么 x 坐标就是文本的右侧坐标
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.moveTo(10, 10);
context.lineTo(150, 75);
context.lineTo(30, 100);
context.closePath();
context.lineWidth = 1;
context.strokeStyle = "pink";
context.font = "700 16px Arial";
context.fillStyle = "purple";
context.textAlign = "start";
context.strokeText("CLZ", 50, 50);
context.textAlign = "center";
context.fillText("CLZ", 50, 65);
context.textAlign = "end";
context.strokeText("CLZ", 50, 80);
context.stroke();
}
textBaseline
类似
变换
2D 换图上下文支持所有常见的绘制变化。
rotate(a)
:围绕原点把图像旋转 a 弧度
scale(x, y)
:缩放图像
translate(x, y)
:移动原点
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// 创建路径
context.beginPath();
// 绘制圆弧,参数分别是圆心x坐标、圆形y坐标、圆弧半径、圆弧起始点(单位:弧度)、圆弧终点(单位:弧度)、绘制方向(false为顺时针绘制,true为逆时针绘制)
context.arc(100, 100, 50, 0, 2 * Math.PI, true);
context.lineWidth = "8";
context.strokeStyle = "pink";
// 移动原点
context.translate(100, 100);
// 旋转
context.rotate(Math.PI);
// 缩放
context.scale(0.75, 0.75);
// 因为已经移动过原点了,所以这时候(0, 0)就是圆心
context.moveTo(0, 0);
context.lineTo(25, 30);
context.stroke();
}
上面的例子中,已经把很多变化都使用上了,如果想要了解具体例子可以注释掉其他部分。
save 和 restore 的作用
save
方法可以保存应用到绘图上下文的设置和变换,不保存绘图上下文的内容。后续可以通过restore
方法,恢复上下文的设置和变换。save
和restore
的使用类似于栈,后进先出。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.fillStyle = "red";
context.save();
context.fillStyle = "blue";
context.translate(100, 100);
context.save();
context.fillStyle = "purple";
context.translate(-100, -100);
context.fillRect(0, 0, 100, 100);
context.restore();
context.fillRect(0, 0, 100, 100);
context.restore();
context.fillRect(100, 0, 100, 100);
context.restore();
context.fillRect(0, 100, 100, 100);
}
分析:设 XXX 为绘图上下文的设置和变化
- 设置填充色为红色,
save
保存 - 设置填充色为蓝色,移动原点,
save
保存 - 设置填充色为紫色,移动原点,画出紫色的矩形
restore
恢复XXX,此时,原点为(100, 100),填充色为蓝色。画出蓝色的矩形restore
恢复**XXX**,此时,原点为(0, 0),填充色为红色。画出红色的矩形restore
已经没有保存的XXX,所以XXX不会变化
绘制图像
<img src="./avatar.png" alt="">
<canvas id="mycanvas" width="200" height="200">haha</canvas>
通过drawImage
把 HTML 的 img 元素或另一个 canvas 元素绘制到当前画布中。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// 获取图像
const img = document.images[0];
// 在画布的坐标出绘制图像,此时图像和原来的图像一样大,指的是原文件的大小
// context.drawImage(img, 10, 10)
// 传入另外两个参数,设置绘制图像的宽高
context.drawImage(img, 10, 10, 100, 100);
}
只传3个参数,画到画布上的跟原来的图像一样大,但画布没那么大。所以会只有一部分。
传入五个参数,可以让设置图像的宽高,显示完整的图像。
去掉DOM树上的img
上面的做法是需要html
中有img
元素才能执行的.实际上,我们也可以通过image
对象来实现。
即获取图像不再是通过document.images[0]
,而是
const img = new Image();
img.src = "./avatar.png";
另外,绘制图像应该在img
的load
事件回调中调用。
const img = new Image();
img.src = "./avatar.png";
img.onload = () => {
// 传入另外两个参数,设置绘制图像的宽高
context.drawImage(img, 10, 10, 100, 100);
};
还可以接收 9 个参数,实现把原始图像的一部分绘制到画布上。
如:context.drawImage(img, 0, 10, 50, 50, 0, 100, 20, 30)
,从原始图像的(0, 10)开始,50 像素宽、50 像素高,画到画布上(0, 100)开始,宽 40 像素、高 60 像素。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
// 获取图像
const img = document.images[0];
// // 9个参数
context.drawImage(img, 0, 10, 300, 300, 100, 100, 40, 40);
}
下载图像
操作的结果可以使用canvas.toDataURL()
方法获取。
再搭配下载图片的方式就能实现下载图片。(这里用的是a
标签方法)
const a = document.createElement("a");
a.href = mycanvas.toDataURL();
// 获取源图片的名字
a.download = img.src.split("/")[img.src.split("/").length - 1];
a.click();
阴影
设置好阴影有关的属性值,就能够自动为要绘制的形状或路径生成阴影
shadowOffsetX
:阴影相对于形状或路径的 x 坐标偏移。默认为 0shadowOffsetY
:阴影相对于形状或路径的 y 坐标偏移。默认为 0shadowBlur
:阴影的模糊量。默认值为 0,表示不模糊shadowColor
:阴影的颜色。默认为黑色
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
context.shadowOffsetX = 5;
context.shadowOffsetY = 10;
context.shadowBlur = 5;
context.shadowColor = "rgba(0, 0, 0, .2)";
context.fillStyle = "red";
context.fillRect(0, 0, 50, 50);
context.moveTo(100, 100);
context.lineTo(180, 20);
context.lineWidth = 12;
context.stroke();
}
渐变
线性渐变
线性渐变可以调用上下文的createLinearGradient
方法,接收四个参数:起点 x 坐标、起点 y 坐标、终点 x 坐标、终点 y 坐标,创建CanvasGradient
对象。
有了渐变对象后,就需要添加渐变色标了,通过addColorStop
可以添加色标,第一个参数范围为 0~1,第二个参数是 CSS 颜色字符串。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
const gradient = context.createLinearGradient(10, 10, 180, 180);
gradient.addColorStop(0, "red");
gradient.addColorStop(0.5, "blue");
gradient.addColorStop(1, "purple");
context.fillStyle = gradient;
context.fillRect(0, 0, 200, 200);
为了让渐变覆盖整个矩形,渐变的坐标和矩形的坐标应该搭配合适,不然只会显示部分渐变。
还可以调用上下文的createRadialGradient
方法来创建径向渐变。接收 6 个参数,前 3 个参数指定起点圆形中心的 x 坐标、y 坐标和半径,后 3 个参数指定终点圆形中心的 x 坐标和半径。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
let gradient = context.createRadialGradient(100, 100, 20, 100, 100, 80);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
context.fillStyle = gradient;
context.fillRect(0, 0, 200, 200);
}
上面这个渐变,简单理解就是内层圆为半径为 20 像素的纯白圆
,外层圆为 80 像素的白渐变黑圆
,剩余部分就是黑色。
图案
图案适用于填充和描画图形的重复图像。 通过
createPattern
方法,该方法接收两个参数,第一个参数是img
元素,第二个参数是是否重复,和background-repeat
属性一样。
然后,像渐变一样,把pattern
对象赋值给fillStyle
属性即可。
这个图案实际上就有点背景图像的味道了,通过创建pattern
对象,来控制图像的重复。然后,给绘图上下文的fillStyle
赋值,设置填充样式,最后再通过fillRect
来设置图案的位置和大小。
const mycanvas = document.getElementById("mycanvas");
// 确保浏览器支持canvas
if (mycanvas.getContext) {
const context = mycanvas.getContext("2d");
let gradient = context.createRadialGradient(100, 100, 20, 100, 100, 80);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
context.fillStyle = gradient;
context.fillRect(0, 0, 200, 200);
}
相关文章
- ETL-Kettle学习笔记(入门,简介,简单操作)
- 上位机plc编程入门_【新手入门】西门子PLC编程入门学习
- 微搭低代码从入门到精通-02 应用介绍
- 【MySQL入门】MySQL安装及环境搭建(详细简单)
- Shell脚本入门
- Docker简单入门
- 什么是异常处理,Python常见异常类型(入门必读)
- Linux入门必备:从操作到编程(学linux那本书好)
- Redis入门指南:打开Redis数据库之旅(redis入门书籍推荐)
- 初学者也能轻松掌握MySQL(《mysql入门很简单》)
- 学习Oracle:一个简单的入门指南(oracle入门很简单)
- 入门课Linux入门必备:马哥教育快速引导(马哥教育linux)
- Linux SH X:从入门到精通(linuxshx)
- Linux入门之路:书生的美好学习梦想(书生linux)
- ruaMongoDB快速入门:最简单的数据库操作。(mongodbq)
- 用简单步骤快速掌握Redis(redis入门很简单)
- Linux TTY编程入门指南——打开全新终端世界的钥匙(linuxtty编程)
- MySQL入门指南:简单易懂的使用教程(如何mysql)
- 精通MySQL引擎设置:从入门到精通(mysql设置引擎)
- Linux引导项入门:简单易懂的基础知识指南(linux引导项)
- Oracle入门宝典一步一步深入学习Beginners Guide(oracle入门好的书籍)
- MySQL三目运算入门指南(mysql三目运算简单)
- 搭建运行环境入门xmapp与redis(xmapp redis)
- 进入Redis简单的入门指南(如何进入redis目录)
- ASP.NET2.0数据库入门之SQLServer
- js实例入门(简单展开或关闭)
- php下Memcached入门实例解析