canvas简介
以前,web上的动画都是由flash制作的,例如动画广告、游戏等。但是flash由许多缺点:要安装flash插件,漏洞多,卡顿、不流畅等…
h5提出的canvas标签,使得制作动画等变得轻量级
canvas基本使用
在页面中使用canvas,只需要在页面上添加一个canvas标签即可<canvas></canvas>
。
canvas标签有两个属性:width
和height
,注意canvas的宽和高不要用css控制,负责会造成图片失真。
使用js绘制canvas步骤
- 获取画布,即获取到canvas的DOM元素
getElementById()
等- 得到画布的上下文,有两个:2d和3d。所有的图像绘制都是通过上下文的方法或者属性进行设置的
getContext('2d')
- 绘制图形(所有颜色先设置,后绘制)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="myCanvas" width="300" height="400"></canvas>
<script>
// 1.获取画布元素
let myCanvas = document.getElementById('myCanvas');
// 2.获取上下文
let ctx = myCanvas.getContext('2d')
// 3.绘制图形--先设置颜色,后绘制元素
ctx.fillStyle = 'orange'
ctx.fillRect(10, 10, 100, 100)
</script>
</body>
</html>
canvas的像素化
canvas一旦绘制图形成功,就会被像素化
,也就是说canvas没有能力葱画布上再次得到这个图形,没有办法再去修改已经在画布上的内容。
如果想要这个canvas上的图形移动,就必须按照清屏-更新-渲染
的逻辑进行编程,也就是重新画一次。这也是canvas的动画思想
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="myCanvas" width="300" height="400"></canvas>
<script>
const myCanvas = document.getElementById('myCanvas');
const ctx = myCanvas.getContext('2d')
let left = 0;
ctx.fillStyle = 'orange'
// 要重新绘制新图形 -- 擦除--更新--渲染
setInterval(() => {
// 擦除现有图形
ctx.clearRect(0,0,300,400)
// 重新绘制
ctx.fillRect(left++, 10, 40, 40)
}, 10)
</script>
</body>
</html>
面向对象思维实现canvas
因为canvas不能得到已经绘制的对象,所以我们要维持对象的状态,此时我们使用面向对象的方式来维持canvas需要的属性和状态。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="myCanvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 创建一个矩形对象
class Rect {
constructor(x, y, width, height, color) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
}
update() {
++this.x
}
render() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
let rect1 = new Rect(0,20,20,10,'blue');
let rect2 = new Rect(0,100,30,30,'green')
setInterval(() => {
ctx.clearRect(0,0,500,500);
rect1.update();
rect1.render();
rect2.update();
rect2.render();
}, 10)
</script>
</body>
</html>
canvas的绘制功能
绘制矩形
绘制填充一个矩形fillRect(x,y,width,height)
ctx.fillStyle='bule'
ctx.fillRect(0,0,200,50)
绘制一个矩形边框strokeRect(x,y,width,height)
ctx.strokeStyle='green'
ctx.strokeRect(0,70,200,50)
清除画布clearRect(x,y,width,height)
ctx.clearRect(0,0,600,600)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onClick="drawFillRect()">填充矩形</button>
<button onClick="drawStokeRect()">矩形边框</button>
<button onClick="clearRect()">擦除</button>
<canvas id="myCanvas" width="200" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d');
// 绘制填充矩形
function drawFillRect() {
ctx.clearRect(0,0, 200, 200)
ctx.fillStyle = 'green'
ctx.fillRect(50, 50, 60, 70);
}
// 绘制矩形边框
function drawStokeRect() {
ctx.clearRect(0,0, 200, 200)
ctx.strokeStyle = 'red';
ctx.strokeRect(50, 50, 70, 70);
}
// 清除
function clearRect() {
ctx.clearRect(0, 0, 200, 200)
}
</script>
</body>
</html>
绘制路径
绘制路径的作用是为了设置一个不规则的多边形状态路径都是闭合的
绘制路径的步骤
- 开始路径并设置路径的起点
beginPath()
,也可通过moveTo(x,y)
移动开始点到某位置- 绘制路径(多次)
lineTo(x,y)
- 闭合路径
closePath()
- 填充或者绘制已经封闭路径的形状
stroke()
、fill()
在绘制路径时如果不封闭路径,会自动封闭(只针对fill)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="myCanvas" width="200" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'orange'
ctx.strokeStyle = 'blue'
// 1. 开始路径
ctx.beginPath();
// 2.绘制开始点
ctx.moveTo(10, 20);
// 3.绘制路径
ctx.lineTo(20,100);
ctx.lineTo(100, 100),
ctx.lineTo(200,90);
// 4.闭合路径
ctx.closePath()
// 5.填充或描边
ctx.fill()
ctx.stroke()
</script>
</body>
</html>
绘制圆弧
arc(x,y,radius,startAngle,endAngle,anticclockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
x,y:圆心
radius:半径
startAngle,endAngle:圆弧的起始位置,一个圆是2π,即2*Math.PI
,0为三点钟方向
anticclockwise:顺时针还是逆时针,默认为false,顺时针
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="myCanvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.strokeStyle = 'red';
// 以100,100为圆心,100为半径,从0到90顺时针的圆弧
ctx.beginPath();
ctx.arc(100, 100, 100, 0, 0.5 * Math.PI, false)
ctx.stroke()
ctx.closePath()
// 绘制圆弧, 以100,100为圆心,100为半径,从0到90逆时针的圆弧
ctx.beginPath();
ctx.arc(300, 300,80, 0, 0.5 * Math.PI, true)
ctx.fill()
</script>
</body>
</html>
透明度
ctx.globalAlpha
,值为0到1的数字
线型
- 线的粗细
lineWidth
:默认为1.0,属性值为数字,没有单位 - 线的形状
lineCap
:可选值为butt:线段末端以方形结束、round:线段末端圆形结束、square:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。
- 两段连接处的样式
lineJoin
:可选值round、bevel、miter
- 虚线的样式
setLineDash([n1,n2,n3,n4...])
,表示虚线的交替状态,最少接收两个参数,奇数位置表示画线的长度,偶数位置表示间隔长度,lineDashOffset
:可以设置虚线的起始偏移量
文本
font
设置文字样式textAlign
设置文字水平对齐方式,可选值left, center, right, end, start
,默认start
fillText('文本', x, y)
渐变
渐变有两种方式:线性渐变和径向渐变
线性渐变
createLinerGradient(x1,y1,x2,y2)
,指定渐变的开始点和结束点addColorStop(n, color)
,n为0到1的值,表示当前渐变的位置,color表示渐变的颜色
径向渐变
createRadialGradient(x1,y1,r1,x2,y2,r2)
,指定渐变的开始圆形和结束圆形的xy坐标以及半径addColorStop(n, color)
,n为0到1的值,表示当前渐变的位置,color表示渐变的颜色
阴影
shadowOffsetX,shadowOffsetY
,偏移量shadowBlur
,模糊值shadowColor
,阴影颜色
图片
- 创建一个image元素
let img = new Image()
- 设置img的src
- 在图片加载完成后(onLoad)绘制图片:
drawImage(image, x, y, width, height, cx, cy, cwidth, cheight)
, width,height可选,如果没有则宽高保持原图片宽高。四个参数表示图片的位置和宽高。如果有8个参数,代表的是从x,y的位置开始,切下宽为width高为height的图形切片,将切片拉伸为cwidth,cheight的图片再放到cx,cy的位置
变形
canvas的变形指的是整个画布的变形,而不是元素的变形。
因为变形实际上是将整个画布进行变形,所以一旦变形操作多了,会让会不变得不可控。下面先学习保存和恢复画布状态。
save()保存画布状态;restore() 恢复canvas状态
这两个API的使用相当于一个入栈出栈的过程:save()入栈,restore()出栈。
一个绘画状态包括:
- 当前应用的变形(即移动,旋转和缩放等)
- 以下这些属性:
strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, direction, imageSmoothingEnabled
- 当前的裁切路径(clipping path)
变形之前先备份
,变形完成后恢复,不要影响下一次的操作
- 移动
translate(x, y)
- 旋转
rotate(deg:number)
- 缩放
scale(xScale:number, yScale:number)
合成
合成其实就是我们常见的蒙版状态,本质就是如何进行压盖,如何进行显示
globalCompositeOpration