Canvas初识
什么是Canvas?
HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。
画布是一个矩形区域,您可以控制其每一像素。
canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
创建Canvas元素
向 HTML5 页面添加 canvas 元素。
规定元素的 id、宽度和高度:
<canvas id="myCanvas" width="200" height="100"></canvas>
Canvas坐标系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-axGxgAIc-1612178234725)(images/location.jpg)]
通过JavaScript来绘制
/*获取元素*/ var myCanvas = document.querySelector('#myCanvas'); /*获取绘图工具*/ var context = myCanvas.getContext('2d'); /*设置绘图的起始位置*/ context.moveTo(100,100); /*绘制路径*/ context.lineTo(200,200); /*描边*/ context.stroke();
完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; /*不建议在 css样式设置尺寸 这里只是样式多大 是对画布的拉伸 实际画布还是初始值那么大*/ /*width: 600px; height: 400px;*/ } </style> </head> <body> <!--1.准备画布--> <!--1.1 画布是白色的 而且默认300*150--> <!--1.2 设置画布的大小 width="600" height="400" --> <canvas width="600" height="400" ></canvas> <!--2.准备绘制工具--> <!--3.利用工具绘图--> <script> /*1.获取元素*/ var myCanvas = document.querySelector('canvas'); /*2.获取上下文 绘制工具箱 */ /*是否有3d 暂时没有*/ var ctx = myCanvas.getContext('2d'); /*web gl 绘制3d效果的网页技术*/ /*3.移动画笔*/ ctx.moveTo(100,100); /*4.绘制直线 (轨迹,绘制路径)*/ ctx.lineTo(200,100); /*5.描边*/ ctx.stroke(); </script> </body> </html>
Canvas的基本使用
图形绘制
需要理解些概念:
- 路径的概念
- 路径的绘制
- 描边 stroke()
- 填充 fill()
- 闭合路径
手动闭合
程序闭合 closePath()
- 填充规则(非零环绕)
- 开启新的路径 beginPath()
设置样式
- 画笔的状态
lineWidth 线宽,默认1px
lineCap 线末端类型:(butt默认)、round、square
lineJoin 相交线的拐点 miter(默认)、round、bevel
strokeStyle 线的颜色
fillStyle 填充颜色
setLineDash() 设置虚线
getLineDash() 获取虚线宽度集合
lineDashOffset 设置虚线偏移量(负值向右偏移)
画笔实例练习
渐变色绘制
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; } </style> </head> <body> <canvas width="600" height="400"></canvas> <script> var myCanvas = document.querySelector('canvas'); var ctx = myCanvas.getContext('2d'); /*线是由点构成的*/ ctx.lineWidth = 30; for (var i = 0; i < 255; i++) { ctx.beginPath(); ctx.moveTo(100+i-1,100); ctx.lineTo(100+i,100); ctx.strokeStyle = 'rgb('+i+',0,0)'; ctx.stroke(); } </script> </body> </html>
镂空的房子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; } </style> </head> <body> <canvas width="600" height="400"></canvas> <script> var myCanvas = document.querySelector('canvas'); var ctx = myCanvas.getContext('2d'); /*1.绘制两个正方形 一大200一小100 套在一起*/ ctx.moveTo(100,100); ctx.lineTo(300,100); ctx.lineTo(300,300); ctx.lineTo(100,300); ctx.closePath(); ctx.moveTo(150,150); ctx.lineTo(150,250); ctx.lineTo(250,250); ctx.lineTo(250,150); ctx.closePath(); /*2.去填充*/ //ctx.stroke(); ctx.fillStyle = 'red'; ctx.fill(); /*在填充的时候会遵循非零环绕规则*/ </script> </body> </html>
绘制坐标网格
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; } </style> </head> <body> <canvas width="600" height="400"></canvas> <script> var myCanvas = document.querySelector('canvas'); var ctx = myCanvas.getContext('2d'); /*1.绘制网格*/ /*2.网格的大小*/ var gridSize = 10; var canvasHeight = ctx.canvas.height; var canvasWidth = ctx.canvas.width; /*3.画多少条X轴方向的线 横线的条数 画布高度/小格大小 */ var xLineTotal = Math.floor(canvasHeight / gridSize); for (var i = 0; i <= xLineTotal; i++) { ctx.beginPath(); ctx.moveTo(0, i * gridSize - 0.5 ); ctx.lineTo(canvasWidth, i * gridSize - 0.5); ctx.strokeStyle = '#eee'; ctx.stroke(); } /*4.画多少条Y轴方向的线*/ var yLineTotal = Math.floor(canvasWidth / gridSize); for (var i = 0; i <= yLineTotal; i++) { ctx.beginPath(); ctx.moveTo(i*gridSize - 0.5 ,0); ctx.lineTo(i*gridSize - 0.5 ,canvasHeight); ctx.strokeStyle = '#eee'; ctx.stroke(); } </script> </body> </html>
绘制坐标系
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; } </style> </head> <body> <canvas width="600" height="400"></canvas> <script> var myCanvas = document.querySelector('canvas'); var ctx = myCanvas.getContext('2d'); /*1.绘制坐标系*/ /*2.确定原点*/ /*3.确定距离画布旁边的距离*/ /*4.确定坐标轴的长度*/ /*5.确定箭头的大小 是个等腰三角形 10 */ /*6.绘制箭头填充*/ // 坐标轴与底部的间隔 var space = 20; // 箭头大小 var arrowSize = 10; /*计算原点 x0 y0*/ var canvasWidth = ctx.canvas.width; var canvasHeight = ctx.canvas.height; var x0 = space; var y0 = canvasHeight - space; /*绘制x轴*/ ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(canvasWidth - space, y0); /*箭头*/ ctx.lineTo(canvasWidth - space - arrowSize, y0 + arrowSize / 2); ctx.lineTo(canvasWidth - space - arrowSize, y0 - arrowSize / 2); ctx.lineTo(canvasWidth - space, y0); ctx.fill(); ctx.stroke(); /*绘制y轴*/ ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(space, space); /*箭头*/ ctx.lineTo(space + arrowSize / 2, space + arrowSize); ctx.lineTo(space - arrowSize / 2, space + arrowSize); ctx.lineTo(space, space); ctx.fill(); ctx.stroke(); </script> </body> </html>
绘制坐标点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; } </style> </head> <body> <canvas width="600" height="400"></canvas> <script> var myCanvas = document.querySelector('canvas'); var ctx = myCanvas.getContext('2d'); /*1.绘制点*/ /*2.点的尺寸*/ /*3.以坐标中心绘制点*/ /*点坐标*/ var coordinate = { x:100, y:100 } /*点尺寸*/ var dottedSize = 10; ctx.moveTo(coordinate.x - dottedSize / 2,coordinate.y - dottedSize / 2); ctx.lineTo(coordinate.x + dottedSize / 2,coordinate.y - dottedSize / 2); ctx.lineTo(coordinate.x + dottedSize / 2,coordinate.y + dottedSize / 2); ctx.lineTo(coordinate.x - dottedSize / 2,coordinate.y + dottedSize / 2); ctx.closePath(); ctx.fill(); </script> </body> </html>
绘制折线图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>折线图</title> <style> canvas { border: 1px solid #ccc; } </style> </head> <body> <canvas width="600" height="400"></canvas> <script> /*1.构造函数*/ var LineChart = function (ctx) { /*获取绘图工具*/ this.ctx = ctx || document.querySelector('canvas').getContext('2d'); /*画布的大小*/ this.canvasWidth = this.ctx.canvas.width; this.canvasHeight = this.ctx.canvas.height; /*网格的大小*/ this.gridSize = 10; /*坐标系的间距*/ this.space = 20; /*坐标原点*/ this.x0 = this.space; this.y0 = this.canvasHeight - this.space; /*箭头的大小*/ this.arrowSize = 10; /*绘制点*/ this.dottedSize = 6; /*点的坐标 和数据有关系 数据可视化*/ } /*2.行为方法*/ LineChart.prototype.init = function (data) { this.drawGrid(); this.drawAxis(); this.drawDotted(data); }; /*绘制网格*/ LineChart.prototype.drawGrid = function () { /*x方向的线*/ var xLineTotal = Math.floor(this.canvasHeight / this.gridSize); this.ctx.strokeStyle = '#eee'; for (var i = 0; i <= xLineTotal; i++) { this.ctx.beginPath(); this.ctx.moveTo(0, i * this.gridSize - 0.5); this.ctx.lineTo(this.canvasWidth, i * this.gridSize - 0.5); this.ctx.stroke(); } /*y方向的线*/ var yLineTotal = Math.floor(this.canvasWidth / this.gridSize); for (var i = 0; i <= yLineTotal; i++) { this.ctx.beginPath(); this.ctx.moveTo(i * this.gridSize - 0.5, 0); this.ctx.lineTo(i * this.gridSize - 0.5, this.canvasHeight); this.ctx.stroke(); } }; /*绘制坐标系*/ LineChart.prototype.drawAxis = function () { /*X轴*/ this.ctx.beginPath(); this.ctx.strokeStyle = '#000'; this.ctx.moveTo(this.x0, this.y0); this.ctx.lineTo(this.canvasWidth - this.space, this.y0); this.ctx.lineTo(this.canvasWidth - this.space - this.arrowSize, this.y0 + this.arrowSize / 2); this.ctx.lineTo(this.canvasWidth - this.space - this.arrowSize, this.y0 - this.arrowSize / 2); this.ctx.lineTo(this.canvasWidth - this.space, this.y0); this.ctx.stroke(); this.ctx.fill(); /*Y轴*/ this.ctx.beginPath(); this.ctx.strokeStyle = '#000'; this.ctx.moveTo(this.x0, this.y0); this.ctx.lineTo(this.space, this.space); this.ctx.lineTo(this.space + this.arrowSize / 2, this.space + this.arrowSize); this.ctx.lineTo(this.space - this.arrowSize / 2, this.space + this.arrowSize); this.ctx.lineTo(this.space, this.space); this.ctx.stroke(); this.ctx.fill(); }; /*绘制所有点*/ LineChart.prototype.drawDotted = function (data) { /*1.数据的坐标 需要转换 canvas坐标*/ /*2.再进行点的绘制*/ /*3.把线连起来*/ var that = this; /*记录当前坐标*/ var prevCanvasX = 0; var prevCanvasY = 0; data.forEach(function (item, i) { /* x = 原点的坐标 + 数据的坐标 */ /* y = 原点的坐标 - 数据的坐标 */ console.log("item ="); console.log(item); console.log( "i="+i); var canvasX = that.x0 + item.x; var canvasY = that.y0 - item.y; /*绘制点*/ that.ctx.beginPath(); that.ctx.moveTo(canvasX - that.dottedSize / 2, canvasY - that.dottedSize / 2); that.ctx.lineTo(canvasX + that.dottedSize / 2, canvasY - that.dottedSize / 2); that.ctx.lineTo(canvasX + that.dottedSize / 2, canvasY + that.dottedSize / 2); that.ctx.lineTo(canvasX - that.dottedSize / 2, canvasY + that.dottedSize / 2); that.ctx.closePath(); that.ctx.fill(); /*点的连线*/ /*当时第一个点的时候 起点是 x0 y0*/ /*当时不是第一个点的时候 起点是 上一个点*/ if(i == 0){ that.ctx.beginPath(); that.ctx.moveTo(that.x0,that.y0); that.ctx.lineTo(canvasX,canvasY); that.ctx.stroke(); }else{ /*上一个点*/ that.ctx.beginPath(); that.ctx.moveTo(prevCanvasX,prevCanvasY); that.ctx.lineTo(canvasX,canvasY); that.ctx.stroke(); } /*记录当前的坐标,下一次要用*/ prevCanvasX = canvasX; prevCanvasY = canvasY; }); }; /*3.初始化*/ var data = [ { x: 100, y: 300 }, { x: 200, y: 160 }, { x: 300, y: 240 }, { x: 400, y: 120 }, { x: 500, y: 80 } ]; var lineChart = new LineChart(); lineChart.init(data); </script> </body> </html>
参考文档
w3school
Canvas_API
Canvas图形绘制
矩形绘制
rect(x,y,w,h) 没有独立路径
strokeRect(x,y,w,h) 有独立路径,不影响别的绘制
fillRect(x,y,w,h) 有独立路径,不影响别的绘制
clearRect(x,y,w,h) 擦除矩形区域
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; } </style> </head> <body> <canvas width="600" height="400"></canvas> <script> var myCanvas = document.querySelector('canvas'); var ctx = myCanvas.getContext('2d'); /*绘制矩形路径 不是独立路径*/ ctx.rect(100,100,100,100); ctx.fillStyle = 'green'; ctx.stroke(); ctx.fill(); /*绘制矩形 有自己的独立路径*/ ctx.fillStyle = 'red'; ctx.strokeRect(200,200,100,100); ctx.fillStyle = 'skyblue'; ctx.fillRect(300,300,100,100); /*清除矩形的内容*/ // ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); </script> </body> </html>
createLinearGradient()方法
绘制渐变颜色矩形
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { border: 1px solid #ccc; } /* .linearGradient{ width: 400px; height: 100px; background-image: linear-gradient(to right,pink,blue); }*/ </style> </head> <body> <div class="linearGradient"></div> <canvas width="600" height="400"></canvas> <script> var myCanvas = document.querySelector('canvas'); var ctx = myCanvas.getContext('2d'); /*fillStyle 'pink' '#000' 'rgb()' 'rgba()' */ /*也可以使用一个渐变的方案了填充矩形*/ /*创建一个渐变的方案*/ /*渐变是由长度的*/ /*x0y0 起始点 x1y1 结束点 确定长度和方向*/ var linearGradient = ctx.createLinearGradient(100,100,500,400); linearGradient.addColorStop(0,'pink'); //linearGradient.addColorStop(0.5,'red'); linearGradient.addColorStop(1,'blue'); ctx.fillStyle = linearGradient; ctx.fillRect(100,100,400,100); /*pink---->blue*/ /*回想线性渐变---->要素 方向 起始颜色 结束颜色 */ /*通过两个点的坐标可以控制 渐变方向*/ </script> </body> </html>