html画布canvas标签的使用(附赠three.js)

66 阅读9分钟

这个canvas笔记更为详细,右上角还附带了three.js教程

对应的B站视频教程

html的画布

在网页中,我们把用于绘制图形的特殊区域也称为“画布”,网页设计师可以在该区域义绘制自定的图形样式。

画布的使用方法

1.创建画布

 <canvas id="画布名称" width="数值" height="数值">
     您的浏览器不支持canvas(当浏览器不支持画布标签会弹出此内容)
 </canvas>

2.获取画布

使用getElementById()方法可以获取网页中的画布对象。 语法格式:

 var canvas = document.getElementById('cavs');

3.准备画笔

有了画布之后,要开始绘图,还需要准备一只画笔,这支画笔就是context对象。context对象也被称为绘制环境,通过该对象,可以在画布中绘制图形。 基本语法格式:

 canvas.getContext('2d');

4.确定初始位置

在绘制图形时,我们首先需要确定从哪里下“笔”,这个下“笔”的位置就是初始位置。在平面中(2d),初始位置可以通过“x,y”的坐标轴来表示。在画布中从最左上角“0,0”开始,x轴向右增大, y轴向下增大。 基本语法格式:

 context.moveTo(100,100);

5.确定末端位置

连线末点用于定义一个端点,并绘制一条从该端点到初始位置的连线。在画布中使用lineTo(x,y)方法来定义连线端点。 基本语法格式:

 context.lineTo(100,100);

6.描边

通过初始位置和连线端点可以绘制一条线,但这条线并不能被看到。这时我们需要为线添加描边,让线变得可见。使用画布中的stroke()方法,可以实现线的可视效果。 基本语法格式:

 context.stroke();

画布的一些方法

颜色、样式和阴影

属性描述
fillStyle设置或返回用于填充绘画的颜色、渐变或模式。
strokeStyle设置或返回用于笔触的颜色、渐变或模式。
shadowColor设置或返回用于阴影的颜色。
shadowBlur设置或返回用于阴影的模糊级别。
shadowOffsetX设置或返回阴影与形状的水平距离。
shadowOffsetY设置或返回阴影与形状的垂直距离。
方法描述
createLinearGradient()创建线性渐变(用在画布内容上)。
createPattern()在指定的方向上重复指定的元素。
createRadialGradient()创建放射状/环形的渐变(用在画布内容上)。
addColorStop()规定渐变对象中的颜色和停止位置。

线条样式

属性描述
lineCap设置或返回线条的结束端点样式。
lineJoin设置或返回两条线相交时,所创建的拐角类型。
lineWidth设置或返回当前的线条宽度。
miterLimit设置或返回最大斜接长度。

矩形

方法描述
rect()创建矩形。
fillRect()绘制"被填充"的矩形。
strokeRect()绘制矩形(无填充)。
clearRect()在给定的矩形内清除指定的像素。

路径

方法描述
fill()填充当前绘图(路径)。
stroke()绘制已定义的路径。
beginPath()起始一条路径,或重置当前路径。
moveTo()把路径移动到画布中的指定点,不创建线条。
closePath()创建从当前点回到起始点的路径。
lineTo()添加一个新点,然后在画布中创建从该点到最后指定点的线条。
clip()从原始画布剪切任意形状和尺寸的区域。
quadraticCurveTo()创建二次贝塞尔曲线。
bezierCurveTo()创建三次贝塞尔曲线。
arc()创建弧/曲线(用于创建圆形或部分圆)。arc(x,y,r,开始角,结束角,方向(默认为false,是顺时针,true为逆时针))
arcTo()创建两切线之间的弧/曲线。
isPointInPath()如果指定的点位于当前路径中,则返回 true,否则返回 false。

转换

方法描述
scale()缩放当前绘图至更大或更小。
rotate()旋转当前绘图。
translate()重新映射画布上的 (0,0) 位置。
transform()替换绘图的当前转换矩阵。
setTransform()将当前转换重置为单位矩阵。然后运行 transform()。

文本

属性描述
font设置或返回文本内容的当前字体属性。
textAlign设置或返回文本内容的当前对齐方式。
textBaseline设置或返回在绘制文本时使用的当前文本基线。
方法描述
fillText()在画布上绘制"被填充的"文本。
strokeText()在画布上绘制文本(无填充)。
measureText()返回包含指定文本宽度的对象。

图像绘制

方法描述
drawImage()向画布上绘制图像、画布或视频。

像素操作

属性描述
width返回 ImageData 对象的宽度。
height返回 ImageData 对象的高度。
data返回一个对象,其包含指定的 ImageData 对象的图像数据。
方法描述
createImageData()创建新的、空白的 ImageData 对象。
getImageData()返回 ImageData 对象,该对象为画布上指定的矩形复制像素数据。
putImageData()把图像数据(从指定的 ImageData 对象)放回画布上。

合成

属性描述
globalAlpha设置或返回绘图的当前 alpha 或透明值。
globalCompositeOperation设置或返回新图像如何绘制到已有的图像上。

其他

方法描述
save()保存当前环境的状态。
restore()返回之前保存过的路径状态和属性。
createEvent()
getContext()
toDataURL()

常用的属性方法详解

线的样式

1、宽度

使用画布中的lineWidth属性可以定义线的宽度,该属性的取值为数值(不带单位),以像素为计量。 基本语法格式:

 context.lineWidth='10';

2、描边颜色

使用画布中的strokeStyle属性可以定义线的描边颜色,该属性的取值为十六进制颜色值或颜色英文。 基本语法格式:

 context.strokeStyle='red';

3、端点形状

默认情况下,线的端点是方形的,通过画布中的lineCap属性可以改变端点的形状。 基本语法格式:

 lineCap=’属性值’
属性值显示效果
butt(默认值)默认效果,无端点,显示直线方形边缘。
round显示圆形端点。
square显示方形端点。

线的路径

闭合路径就是将我们绘制的开放路径,进行封闭处理,多点的路径闭合后会形成特定的形状。在画布中,使用closePath()方法闭合路径。 基本语法格式:

 ctx.closePath();

3、填充路径

通过填充路径的内容区域生成实心的图形。 基本语法格式:

 ctx.fillStyle = '#ff0'
 ctx.fill();

圆的绘制方法

在画布中,使用arc()方法可以绘制圆或弧线。 基本语法格式:

 arc(x,y,r,开始角,结束角,方向)

x和y: x和y表示圆心在x轴和y轴的坐标位置。 r: 表示圆形或弧形的半径,用于确定图形的大小。 开始角:表示初始弧点位置。其中弧点使用数值和“Math.PI”(圆周率,可以理解为180度)表示。 结束角:结束的弧点位置,初始角的设置方式一致。 方向:分为顺时针和逆时针绘。(false和true,默认为true逆时针)

保存画布

使用画布的toblob()方法 .toBlob() 方法创造Blob对象,用以展示canvas上的图片;这个图片文件可以被缓存或保存到本地,由用户代理端自行决定。如不特别指明,图片的类型默认为 image/png,分辨率为96dpi。

URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。

 //URL.createObjectURL() 使用
 ​
 // html代码
 <input type="file" id="file">
 ​
 // js代码
 document.querySelector('#file').onchange = function (e) {
   console.log(e.target.files[0])
   console.log(URL.createObjectURL(e.target.files[0]))
 }
 语法
 canvas.toBlob(callback, type, encoderOptions);
 参数
 callback
 回调函数------可获得一个单独的Blob对象参数。
 type 可选------DOMString类型,指定图片格式,默认格式为image/png。
 encoderOptions 可选-------Number类型,值在01之间,当请求图片格式为image/jpeg或者image/webp时用来指定图片展示质量。如果这个参数的值不在指定类型与范围之内,则使用默认值,其余参数将被忽略。
 返回值
 无。
 异常
 SecurityError
 canvas“被污染”的情况下不能使用此方法
 ​
 ​
 使用时,可以在点击按钮时创建个a标签,添加a标签download下载,并添加保存的格式png,a.download = name + ".png",然后创建a.href="",给a标签添加下载的路径,并且执行a.click(),主动执行a标签的点击事件,最后执行a.remove(),移除a的点击事件即可实现点击按钮下载画布内容,下面为案例代码
 ​
 ​
         //获取input的值
         let name = ""
         let input = document.getElementById("srk")
         input.addEventListener("change", function (e) {
             name = this.value
         })
 ​
 ​
         //保存为图片
         let baocun = document.getElementById("baocun")
         baocun.addEventListener("click", function () {
             canvas.toBlob(function (blob) {
                 let a = document.createElement("a")
                 document.querySelector("body").appendChild(a)
                 a.download = name + ".png"
                 a.href = URL.createObjectURL(blob)
                 a.click()
                 a.remove()
             })
         })

以下是三个小案例,仅供参考

画布签名板(可下载保存)

 <!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>
         /* #huabu {
             width: 400px;
             height: 200px;
             border: 1px solid black;
         } */
     </style>
 </head>
 ​
 <body>
     <canvas id="huabu" width="400px" height="200px" style="border:1px solid #000000;"></canvas>
     <div>
         <input type="text" id="srk" placeholder="请输入图片名称">
         <button id="baocun">保存为图片</button>
         <button id="qingchu" onclick="clearCanvas()">清除画布</button>
     </div>
 ​
     <script>
         //获取画布
         let canvas = document.getElementById("huabu")
         console.log(canvas.getBoundingClientRect());
         let canvasStyle = canvas.getBoundingClientRect()
         let ctx = canvas.getContext("2d")
         let isDrawing = false
         let l = canvas.offsetLeft
         let h = canvas.offsetTop
         canvas.addEventListener('mousedown', function (e) {
             isDrawing = true
             // ctx.moveTo(e.pageX - canvas.offsetLeft, e.pageY - canvas.offsetTop);
             ctx.moveTo(e.pageX - canvasStyle.x, e.pageY - canvasStyle.y);
         })
         canvas.addEventListener('mousemove', function (e) {
             if (isDrawing) {
                 //ctx.lineTo(e.pageX - canvas.offsetLeft, e.pageY - canvas.offsetTop);
                 ctx.lineTo(e.pageX - canvasStyle.x, e.pageY - canvasStyle.y);
                 ctx.strokeStyle = 'red';
                 ctx.stroke();
             }
         })
         document.addEventListener('mouseup', function (e) {
             isDrawing = false
         })
 ​
         //获取input的值
         let name = ""
         let input = document.getElementById("srk")
         input.addEventListener("change", function (e) {
             name = this.value
         })
 ​
 ​
         //保存为图片
         let baocun = document.getElementById("baocun")
         baocun.addEventListener("click", function () {
             canvas.toBlob(function (blob) {
                 let a = document.createElement("a")
                 document.querySelector("body").appendChild(a)
                 a.download = name + ".png"
                 a.href = URL.createObjectURL(blob)
                 a.click()
                 a.remove()
             })
         })
 ​
         //清除画布
         let qingchu = document.getElementById("qingchu")
         qingchu.addEventListener("click", function () {
             canvas.width = canvas.width
             canvas.height = canvas.height
         })
 ​
     </script>
 </body>
 ​
 </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>Document</title>
     <style>
         span {
             position: absolute;
         }
     </style>
 </head>
 ​
 <body>
     <canvas id="cas" width="1000" height="600"></canvas>
     <span></span>
     <script type="text/javascript">
         var canvas = document.getElementById('cas')
         var ctx = canvas.getContext('2d');
 ​
         //头部
 ​
         ctx.beginPath();
         ctx.arc(400, 110, 30, 0, 2 * Math.PI, true);
         ctx.closePath();
         ctx.strokeStyle = '#ff9900';
         ctx.lineWidth = '3';
         ctx.stroke();
         //脖子
         ctx.beginPath();
         ctx.moveTo(400, 140);
         ctx.lineTo(400, 160);
         ctx.lineWidth = 3;
         ctx.stroke();
         //身体
         ctx.beginPath();
         ctx.moveTo(400, 160);
         ctx.lineTo(400, 250);
         ctx.lineWidth = 35;
         ctx.stroke();
         //文件夹
         ctx.beginPath();
         ctx.moveTo(350, 200);
         ctx.lineTo(350, 240);
         ctx.lineTo(450, 240);
         ctx.lineTo(450, 200);
         ctx.closePath();
         ctx.fillStyle = '#cc3333';
         ctx.fill();
         ctx.lineWidth = 2;
         ctx.stroke();
 ​
         //胳膊
         ctx.beginPath();
         ctx.moveTo(400, 165);
         ctx.lineTo(450, 200);
         ctx.lineTo(400, 240);
         ctx.lineWidth = 8;
         ctx.stroke();
         //手掌
         ctx.beginPath();
         ctx.arc(400, 240, 8, 0, 2 * Math.PI, true);
         ctx.fillStyle = '#ff0';
         ctx.fill();
         //腿部
         ctx.beginPath();
         ctx.moveTo(400, 250);
         ctx.lineTo(380, 320);
         ctx.lineTo(370, 380);
         ctx.lineWidth = 9;
         ctx.stroke();
 ​
         ctx.beginPath();
         ctx.moveTo(400, 250);
         ctx.lineTo(420, 380);
         ctx.lineWidth = 9;
         ctx.stroke();
         //脚
         ctx.beginPath();
         ctx.arc(360, 380, 10, 0, 1 * Math.PI, true);
         ctx.closePath();
         ctx.fillStyle = '#ff0'
         ctx.fill();
         ctx.lineWidth = '2';
         ctx.stroke();
 ​
         ctx.beginPath();
         ctx.arc(410, 380, 10, 0, 1 * Math.PI, true);
         ctx.closePath();
         ctx.fillStyle = '#ff0'
         ctx.fill();
         ctx.lineWidth = '2';
         ctx.stroke();
 ​
 ​
         let span = document.querySelector("span")
         document.addEventListener("mousemove", function (e) {
             span.style.top = e.pageY - canvas.offsetTop + 5 + "px"
             span.style.left = e.pageX - canvas.offsetLeft + 15 + "px"
             span.innerHTML = `${e.pageX - canvas.offsetLeft},${e.pageY - canvas.offsetTop}`
         })
     </script>
 </body>
 ​
 </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>Document</title>
     <style>
         span {
             position: absolute;
         }
     </style>
 </head>
 ​
 <body>
     <canvas id="cas" width="400" style="border: 1px solid;" height="400"></canvas>
     <span></span>
     <script type="text/javascript">
         var canvas = document.getElementById("cas")
         var ctx = canvas.getContext('2d');
         ctx.beginPath();
         ctx.arc(100, 100, 60, 0, 2 * Math.PI, true);
         ctx.fillStyle = '#ff0';
         ctx.fill();
 ​
 ​
         ctx.beginPath();
         ctx.strokeStyle = 'black';
         ctx.lineWidth = 5;
         ctx.arc(100, 110, 25, Math.PI / 6, 5 * Math.PI / 6, false);
         ctx.stroke();
 ​
         ctx.beginPath();
         ctx.strokeStyle = 'red';
         ctx.lineWidth = 5;
         ctx.arc(70, 80, 15, Math.PI / 400, Math.PI, true);
         ctx.stroke();
 ​
         ctx.beginPath();
         ctx.strokeStyle = '#fff';
         ctx.lineWidth = 5;
         ctx.arc(130, 80, 15, Math.PI / 400, Math.PI, true);
         ctx.stroke();
 ​
         let span = document.querySelector("span")
         document.addEventListener("mousemove", function (e) {
             span.style.top = e.pageY - canvas.offsetTop + 5 + "px"
             span.style.left = e.pageX - canvas.offsetLeft + 15 + "px"
             span.innerHTML = `${e.pageX - canvas.offsetLeft},${e.pageY - canvas.offsetTop}`
         })  
     </script>
 </body>
 ​
 </html>