-
参考地址:https://www.runoob.com/w3cnote/html5-canvas-intro.html
这篇文章系统的把canvas的api罗列出来,可以很清晰的了解到canvas能够做哪些事情。学习canvas真的看这一偏就够了,推荐。
练习代码:
<!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> <canvas id="canvas" width="1000" height="1000"></canvas> <body> <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); // 画矩形 ctx.clearRect(0,0,300,300) ctx.fillStyle = "red"; ctx.fillRect(0, 0 , 100, 100); ctx.clearRect(0,0,50,50) ctx.strokeStyle = 'yellow'; ctx.strokeRect(100,100 ,100,100); // 画线(多条) ctx.strokeStyle= "red"; ctx.beginPath() ctx.moveTo(100,0); ctx.lineTo(150,0); ctx.lineTo(150,50); // ctx.closePath();//不封闭 ctx.stroke();//发起描边 // 画闭合图形(划线) 需用到closePath ctx.beginPath(); ctx.strokeStyle= "green" ctx.moveTo(150,0) ctx.lineTo(200,0); ctx.lineTo(200,50); ctx.closePath();//闭合 ctx.stroke(); // 绘制填充三角形 ctx.fillStyle= "red" ctx.beginPath(); ctx.moveTo(200,0) ctx.lineTo(250,0) ctx.lineTo(250,50) ctx.fill();//填充命令 会自动调用closepath // 绘制圆弧 ctx.beginPath() ctx.arc(275,25,25,0,Math.PI / 2,false);// 圆心:275 、 25 半径:25 起始角度 0 结束角度 90 顺时针:false ctx.stroke() // 绘制圆弧 通过两条线的切线画弧线 ctx.beginPath() ctx.moveTo(310,0) //起始点 ctx.arcTo(310,50,360,50,25) //控制点1:310 、 50 控制点2:360 、 50 半径:25 ctx.lineTo(360,50) //结束点 360 、 50 ctx.stroke() // 把以上3个点标出来 ctx.beginPath() ctx.fillStyle = 'black' ctx.fillRect(310,0,10,10) ctx.fillRect(310,50,10,10) ctx.fillRect(360,50,10,10) ctx.fill() // 标注3个点的文字 ctx.beginPath() ctx.fillStyle = "green" ctx.strokeStyle = "green" ctx.font= "14px 宋体" ctx.fillText("起始点",310,10) ctx.fillText("控制点1",310,50) ctx.strokeText("控制点2",360,50) // 绘制二次赛贝尔曲线 起始点、控制点、结束点 ctx.beginPath() ctx.moveTo(400,0) // 起始点 400 、 0 ctx.quadraticCurveTo(400, 50, 450, 50); // 控制点 400 、 50 结束点:450 、 50 ctx.stroke() // 样式调整 // fillStyle 填充颜色 // strokeStyle 描边颜色 // lineWidth 线宽 ctx.lineWidth = 20; //以起始点到结束掉为中心 上下各占一半 ctx.beginPath() ctx.moveTo(450, 10) ctx.lineTo(500,10) ctx.stroke() // 线条末端样式 butt:以方形结束(默认)、round:线段末端以原型结束 、 square:末端以方形结束,末端会多出线条宽度一半的厚度的方形 var lineCaps = ["butt", "round", "square"]; lineCaps.forEach((item,index) => { ctx.beginPath() ctx.moveTo(520 + (40 * index) ,30) ctx.lineTo(520 + (40 * index), 50) ctx.lineCap = item; ctx.lineWidth = 20; ctx.strokeStyle = 'black' ctx.stroke() }) // 画参考线 ctx.beginPath() ctx.moveTo(520,30) ctx.lineTo(600,30) ctx.moveTo(520,50) ctx.lineTo(600,50) ctx.lineWidth = 1; ctx.strokeStyle= 'red' ctx.stroke() // lineJoin 设置线条结合处的样式 round:圆角 、 bevel:平角 、 miter:默认 直角 var lineJoin = ['round', 'bevel', 'miter']; lineJoin.forEach((item,index) => { ctx.lineWidth = 10; ctx.strokeStyle = 'green' ctx.lineJoin = item; ctx.beginPath(); ctx.moveTo(650, 0 + index * 50); ctx.lineTo(700, 50 + index * 50); ctx.lineTo(750, 0 + index * 50); ctx.lineTo(800, 50 + index * 50); ctx.lineTo(850, 0 + index * 50); ctx.stroke(); }) // 虚线 // setLineDash 方法接受一个数组,来指定线段长度与间隙 // lineDashOffset属性设置起始偏移量 ctx.beginPath() ctx.lineWidth = 1 ctx.lineJoin = 'miter'; ctx.setLineDash([20, 5]); // [实线长度, 间隙长度] ctx.lineDashOffset = 0; ctx.strokeRect(900, 30, 80, 80); // 绘制文本 // fillText 填充文本 // strokeText 表变文本 // 文本样式 font 、 textAlign 、 textAlign 、 textBaseline 、 ctx.font = '50px 宋体' ctx.fillStyle = 'orange' ctx.fillText('填充字体',0,250,200);// 文本、x、y、maxWidth(可选) ctx.strokeStyle = 'blue' ctx.strokeText('描边字体',200,250,200)// 文本、 x、y 、 maxWidth(可选) // 画图 drawImage(img,x,y,width,height) // 如果是网络图片,需要在图片加载完再绘制 let img = new Image(); img.src = '../cesium/data/image/1.jpg' img.onload = () => { // ctx.drawImage(img,0,0) // 按图片原始宽高、以原点为起点,绘制在canvas上 ctx.drawImage(img,400,-250,100,50) //缩放 把图片整体缩放,绘制在某一个位置 ctx.drawImage(img,400,100,100,50,550,-250,100,50)// slice切片;默认图片以原点(0,0)位置,按图片的原宽高绘制在canvas上,前4个参数是在图片的某一位置截取一定宽高的区域,后4个参数是,把截取的图片放在canvas画布的某一个位置并设置宽高 } // 状态的保存和恢复 savs 、 restore // 每次save都会把当前的状态想栈中push // 每次restore,都会把栈最后面的pop出去, ctx.fillRect(650,200,50,50); ctx.save() ctx.fillStyle = 'red' ctx.fillRect(700,200,50,50) ctx.save() ctx.fillStyle = '#000' ctx.fillRect(750,200,50,50) ctx.restore();//加载之前的状态 恢复到最近这一次save的状态 也就是 fillStyle = red ctx.fillRect(800,200,50,50) // 变形 translate 用来移动canvas的原点到指定位置 ctx.save() ctx.translate(0,250)//坐标原点移动到 0 、 250 ctx.save() ctx.setLineDash([]);//恢复成实线 ctx.strokeRect(0, 0, 100, 100) ctx.translate(110,0)//坐标原点在当前的基础上向右移动110 也就是初始的(110,250) ctx.strokeRect(0, 0, 100, 100) ctx.save() ctx.restore() ctx.restore() ctx.restore() //原点恢复到初始的 0 、0 ctx.strokeRect(0, 0, 100, 100) // 旋转 rotate(angle) 顺时针 旋转的圆点为坐标原点 ctx.fillStyle = "red"; ctx.save() ctx.setLineDash([]) ctx.translate(250,250) //坐标原点移动到 250、 250 ctx.rotate(Math.PI / 180 * 45); // 顺时针旋转45度 ctx.strokeRect(0,0,60,60) // 要在旋转后画,否则 旋转将不生效 ctx.restore() //恢复到之前的状态 原点在0、0 且坐标系不旋转 ctx.setLineDash([]) ctx.strokeRect(350,250,100,100) ctx.save() // 缩放 scale(x,y) x,y坐标放大多少倍 1.2表示放大1.2倍 0.5表示缩小一半 ctx.scale(2,2) ctx.strokeRect(225,125,50,50); //未放大前的参数为 450 、 250 、 100 、 100 ctx.restore();//恢复到放大前的状态 ctx.strokeRect(550,250,100,100); // 合成 ctx.font='50px 楷体' ctx.strokeStyle='red' ctx.fillText('合成',0,400) ctx.font='10px 楷体' ctx.fillStyle='blue' ctx.fillText('男儿当自强',200,400) ctx.beginPath() ctx.lineWidth = 1; ctx.moveTo(0,405) ctx.lineTo(1000,405) ctx.closePath() ctx.stroke() ctx.save() // globalCompositeOperation // source-over: 后画的把之前的覆盖 默认值 // source-in: 只显示重叠区域 // source-out: 只显示新图像的未与老图像重叠的部分 // source-atop: 新图像仅仅显示与老图像重叠区域。老图像仍然可以显示。 // destination-over:新图像在老图像下面 // destination-in: 仅仅新老图像重叠部分的老图像被显示,其他区域全部透明。 // destination-out: 仅仅老图像与新图像没有重叠的部分。 注意显示的是老图像的部分区域。 // destination-atop:老图像仅仅仅仅显示重叠部分,新图像会显示在老图像的下面。 // lighter:保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的) blue: #0000ff + red: #ff0000 = #ff00ff // darken: 保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的) blue: #0000ff + red: #ff0000 = #000000 // xor: 重叠部分会变成透明。 // copy: 只有新图像会被保留,其余的全部被清除(边透明)。 ctx.translate(0,450)//将坐标原点设置在 0 、 250 ctx.save() ctx.font = '20px 楷体' ctx.fillText('默认 source-over',0,-10) ctx.fillStyle='blue' ctx.fillRect(0,0,100,100) ctx.globalCompositeOperation = "source-over"; ctx.fillStyle='red' ctx.fillRect(50,50,100,100) ctx.save() // 裁剪路径 clip() // 把已经创建的路径转换成裁剪路径。 // 裁剪路径的作用是遮罩。只显示裁剪路径内的区域,裁剪路径外的区域会被隐藏。 // 注意 clip() 只能遮罩在这个方法调用之后绘制的图像,如果是 clip() 方法调用之前绘制的图像,则无法实现遮罩。 ctx.beginPath() ctx.fillText('裁剪 clip',200,-10) ctx.arc(250,50,50,0,Math.PI * 2);//顺时针 ctx.save(); ctx.clip(); ctx.fillStyle = 'blue' ctx.fillRect(200,0,100,100) ctx.restore()//恢复裁剪之前的状态 ctx.fillRect(300,0,100,100) // 动画 我们可以用 setInterval 、 setTimeOut 、 requestAnimationFrame 不断的画canvas,实现动画 ctx.save() let sun,earth,moon,sunLoadSuccess = false,earthLoadSuccess = false,moonLoadSuccess = false; let init = () => { //初始化 ctx.translate(400,0);//将坐标原点移动到 400 、 0 ctx.save() ctx.clearRect(0, 0, 400, 400); //清空所有的内容 ctx.fillStyle = 'black' //画一张400 * 400 的画布 ctx.fillRect(0,0,400,400) sun = new Image(); earth = new Image(); moon = new Image(); sun.src = '../cesium/data/image/sun.jpg' earth.src = '../cesium/data/image/earth.jpg' moon.src = '../cesium/data/image/moon.jpg' sun.onload = () => { sunLoadSuccess = true; draw() } earth.onload = () => { earthLoadSuccess = true; draw() } moon.onload = () => { moonLoadSuccess = true; draw() } } init() var draw = () => { if (sunLoadSuccess && earthLoadSuccess && moonLoadSuccess){ ctx.clearRect(0, 0, 400, 400); //清空所有的内容 ctx.fillStyle = 'black' //画一张400 * 400 的画布 ctx.fillRect(0,0,400,400) ctx.save() ctx.translate(150,150);//圆心 移动到 150 、 150 // 把太阳图片的四角用圆裁剪掉 ctx.arc(50,50,50,0,Math.PI * 2); ctx.save() ctx.clip() ctx.save() ctx.restore()//取消裁剪 //绘制太阳 ctx.drawImage(sun, 0, 0, 100, 100); ctx.restore() // 绘制地球轨道 ctx.translate(50,50);//圆心 移动50 、 50 ctx.beginPath() ctx.strokeStyle = "rgba(255,255,0,0.5)"; ctx.arc(0,0,100,0,Math.PI * 2) ctx.stroke() // 绘制地球 let time = new Date(); ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds()) ctx.translate(-100, 0); ctx.beginPath() // 裁剪一下地球 ctx.arc(0,0,14,0,Math.PI * 2); ctx.save() ctx.clip() ctx.drawImage(earth, -15, -15,30,30) ctx.restore() // 绘制月球轨道 ctx.beginPath(); ctx.strokeStyle = "rgba(255,255,255,.3)"; ctx.arc(0, 0, 40, 0, 2 * Math.PI); ctx.stroke(); //绘制月球 ctx.rotate(2 * Math.PI / 6 * time.getSeconds() + 2 * Math.PI / 6000 * time.getMilliseconds()); ctx.translate(40, 0); ctx.drawImage(moon, -3.5, -3.5); ctx.restore() } requestAnimationFrame(draw) }; draw() </script> </body> </html>
将所有的案例画在一张canvas画布上面。
效果:
其它:
isPointInPath:判断当前点是否在 绘制区域内
ctx.rect(20,20,150,100); if (ctx.isPointInPath(100,100)) { ctx.stroke(); };
measureText: 检查文字宽度
ctx.measureText('达大厦')
-