- canvas 最早由Apple引入WebKit,用于Mac OS X 的 Dashboard,后来又在Safari和Google Chrome被实现。
- 基于 Gecko 1.8的浏览器,比如 Firefox 1.5,同样支持这个元素
- canvas元素是WhatWG Web applications 1.0规范的一部分,也包含于HTML 5中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas{
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
// 3. 移动画笔
ctx.moveTo(100, 100);
// 4. 绘制直线
ctx.lineTo(300, 100);
// 5. 描边
ctx.stroke();
</script>
</body>
</html>
运行结果:
什么是Canvas?
- HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。
- 画布是一个矩形区域,我们可以控制其每一像素。
- canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
创建Canvas元素?
- 向 HTML5 页面添加 canvas 元素
- 规定元素的 id、宽度和高度
- 代码示例
<canvas id="myCanvas" width="200" height="100"></canvas>
Canvas坐标系?
JavaScript绘制?
/*获取元素*/
var myCanvas = document.querySelector('#myCanvas');
/*获取绘图工具*/
var context = myCanvas.getContext('2d');
/*设置绘图的起始位置*/
context.moveTo(100,100);
/*绘制路径*/
context.lineTo(200,200);
/*描边*/
context.stroke();
Canvas的基本使用?
-
路径的绘制
1)描边 stroke()
2)填充 fill()
3)图示 -
开启新的路径
多场景绘制的之后,一定要开启新的路径:beginPath() -
闭合路径
手动闭合
程序闭合 closePath()
- 不同场景绘制开启新的路径beginPath()
- 绘制其实就是一个点到一个点,最后填充或描边
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
#canvas {
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
// 3.变量
let space = 20, arrowSize = 10;
let cWidth = ctx.canvas.width;
let cHeight = ctx.canvas.height;
// console.log(cWidth, cHeight);
// 起始点
let x0 = space, y0 = cHeight - space;
// 4. 绘制x轴
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(cWidth - space, y0);
// 箭头
ctx.lineTo(cWidth - space - arrowSize, y0 + arrowSize / 2);
ctx.lineTo(cWidth - space - arrowSize, y0 - arrowSize / 2);
ctx.lineTo(cWidth - space, y0);
// 填充
ctx.fill();
// 描边
ctx.stroke();
// 5. 绘制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>
运行结果:
- rect(x,y,w,h) 没有独立路径
- strokeRect(x,y,w,h) 有独立路径,不影响别的绘制
- fillRect(x,y,w,h) 有独立路径,不影响别的绘制
- learRect(x,y,w,h) 擦除矩形区域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
// 3. 绘制矩形
/*
ctx.rect(100, 100, 200, 100);
ctx.fillStyle = 'blue';
ctx.stroke();
ctx.fill();
*/
// 4. 其它方式
// ctx.fillRect(100, 100, 200, 100);
ctx.strokeRect(100, 100, 200, 100);
// 5. 清空矩形
// ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
</script>
</body>
</html>
运行结果:
- createLinearGradient(x,y,x1,y1)渐变方案
- addColorStop()增加中途渐变色
- ctx.fillStyle = linearGradient 将渐变方案应用在填充上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#box{
width: 400px;
height: 200px;
background: linear-gradient(to right, yellow, purple);
}
#canvas {
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<div id="box"></div>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
// 3. 渐变方案
let linearGradient = ctx.createLinearGradient(100, 100, 400, 400);
linearGradient.addColorStop(0, 'red');
linearGradient.addColorStop(0.5, 'purple');
linearGradient.addColorStop(1, 'yellow');
// 4. 绘制
ctx.fillStyle = linearGradient;
ctx.fillRect(100, 100, 400, 400);
</script>
</body>
</html>
运行结果:
arc() context.arc(x,y,r,sAngle,eAngle,counterclockwise);
- x 圆心横坐标
- y 圆心纵坐标
- r 半径
- startAngle 开始角度
- endAngle 结束角度
- anticlockwise 是否逆时针方向绘制(默认false表示顺时针;true表示逆时针)
- 角度以π为单位,90°为0.5π
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
/*
圆弧
*/
let w = ctx.canvas.width;
let h = ctx.canvas.height;
ctx.arc(w/2, h/2, 100, 0, 2 * Math.PI, false);
ctx.stroke();
</script>
</body>
</html>
绘制一个圆等分颜色随机
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
let w = ctx.canvas.width;
let h = ctx.canvas.height;
// 3. 分成多少份
let num = 50;
// 4. 一份多少弧度
let angle = 2 * Math.PI / num;
// 5. 圆点
let x0 = w / 2;
let y0 = h / 2;
// 6. 获取随机颜色
let getRandomColor = () => {
let r = Math.floor(Math.random() * 256);
let g = Math.floor(Math.random() * 256);
let b = Math.floor(Math.random() * 256);
return `rgb(${r},${g},${b})`;
};
// 7. 绘制
for (let i = 0; i < num; i++) {
// 7.1 起始角度
let startAngle = i * angle;
// 7.2 结束角度
let endAngle = (i+1) * angle;
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.arc(x0, y0, 180, startAngle, endAngle, false);
// 随机颜色
ctx.fillStyle = getRandomColor();
ctx.fill();
}
</script>
</body>
</html>
运行结果:
drawImage()
- 三个参数drawImage(img,x,y)
img 图片对象、canvas对象、video对象
x,y 图片绘制的左上角 - 五个参数drawImage(img,x,y,w,h)
img 图片对象、canvas对象、video对象
x,y 图片绘制的左上角
w,h 图片绘制尺寸设置(图片缩放,不是截取) - 九个参数drawImage(img,x,y,w,h,x1,y1,w1,h1)
img 图片对象、canvas对象、video对象
x,y,w,h 图片中的一个矩形区域
x1,y1,w1,h1 画布中的一个矩形区域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<img src="img/s1.jpg" alt="">
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
// 3. 内存中创建图片标签
/*let img = document.createElement('img');
img.src = 'img/s1.jpg';*/
let image = new Image();
image.src = 'img/s1.jpg';
image.addEventListener('load', ()=>{
// console.log(image);
// 3.1 绘制图片到画布 3个参数
// ctx.drawImage(image, 100, 100);
// 5个参数
/*
图片对象
起始点 x, y
绘制图片的宽度和高度 不是裁剪而是缩放
*/
// ctx.drawImage(image, 100, 100, 300, 300);
// 9个参数
/*
image: CanvasImageSource,
sx: number, 截取起始点
sy: number, 截取起始点
sw: number, 截取图片的多大区域 width
sh: number, 截取图片的多大区域 height
dx: number, 绘制起始点
dy: number, 绘制起始点
dw: number, 绘制图片的宽度和高度 不是裁剪而是缩放
dh: number 绘制图片的宽度和高度 不是裁剪而是缩放
*/
ctx.drawImage(image, 100, 100, 600, 800, 100, 100, 200, 200);
});
</script>
</body>
</html>
运行结果:
- strokeText()、fillText()两种方式绘制
- textAlign 设置水平对齐方式
- textBaseline设置基准对齐方式
- font 设置字体
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
border: 1px solid #ccc;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<script>
// 1. 获取画布
let canvas = document.querySelector('#canvas');
// 2. 获取上下文 绘制的工具箱
let ctx = canvas.getContext('2d');
// 3. 文字
let str = '喜欢IT, 就来撩课!';
// 4. 画布的尺寸
let w = ctx.canvas.width;
let h = ctx.canvas.height;
// 5. 画十字架在画布的最中间
ctx.beginPath();
ctx.moveTo(0, h / 2 - 0.5);
ctx.lineTo(w, h / 2 - 0.5);
ctx.moveTo(w / 2 - 0.5, 0);
ctx.lineTo(w / 2 - 0.5, h);
ctx.strokeStyle = '#ccc';
ctx.stroke();
// 6. 绘制文本
ctx.beginPath();
let x0 = w/2;
let y0 = h/2;
ctx.strokeStyle = 'purple';
/*
text: string,
x: number,
y: number,
maxWidth?: number
*/
// 设置字体
ctx.font = '60px Microsoft YaHei';
// 设置水平居中 left right
ctx.textAlign = 'center'; // "start" | "end" | "left" | "right" | "center"
// 设置垂直居中
ctx.textBaseline = 'middle'; // "top" | "hanging" | "middle" | "alphabetic" | "ideographic" | "bottom"
// ctx.strokeText(str, x0, y0);
ctx.fillStyle = 'blue';
ctx.fillText(str, x0, y0);
</script>
</body>
</html>
运行结果:
canvas中图片的旋转是基于上下文的,也就是说旋转的话是整体旋转。
因此,在旋转的时候,要重新规划上下文。
用到两个方法。
save()和restore()。
save()
- 用来保存Canvas的状态。
- save之后,可以调用Canvas的平移、缩放、旋转、错切、裁剪等操作。
restore()
- 用来恢复Canvas之前保存的状态。
- 防止save后对Canvas执行的操作对后续的绘制有影响。
使用理由
- 在Canvas中,特定元素的旋转平移等操作实际上是对整个画布进行了操作
- 如果不对canvas进行save以及restore操作,那么每一次糊涂都会在上一次的基础上进行操作,最后导致错位。
- 比如如果相对于起始点每次30°递增旋转:30、60、90.如果不使用save以及restore,就会变成30、90、150.每一次在前一次的基础上进行了旋转。
- save是入栈,restore是出栈。
<script>
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(0,20);
ctx.stroke();
</script>
<script>
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
ctx.translate(canvas.width /2,canvas.height /2);
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(0,20);
ctx.stroke();
</script>
rotate()旋转
<script>
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
ctx.rotate(-90 / 180 * Math.PI);
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(0,20);
ctx.stroke();
</script>