介绍
作用:用于绘制图像。 元素本身并没有绘制能力(它仅仅是图形的容器)
<canvas> 标记和 SVG 以及 VML 之间的差异?
<canvas> 标记和 SVG 以及 VML 之间的一个重要的不同是,<canvas> 有一个基于 JavaScript 的绘图 API,而 SVG 和 VML 使用一个 XML 文档来描述绘图。
这两种方式在功能上是等同的,任何一种都可以用另一种来模拟。从表面上看,它们很不相同,可是,每一种都有强项和弱点。例如,SVG 绘图很容易编辑,只要从其描述中移除元素就行。
要从同一图形的一个 <canvas> 标记中移除元素,往往需要擦掉绘图重新绘制它。
基本API讲解:
<body>
<!-- 创建一个画布-->
<canvas id="can" width="500px" height="500px" style="border: 1px solid red;">aa</canvas>
</body>
<script>
var canvas = document.getElementById('can'); // 获取画布
var context = canvas.getContext('2d'); // 相对于准备画笔
/* 绘制矩形 */
context.fillStyle = 'red' // 填充颜色
context.fillRect(10,30,100,100) // 画出一个有填充颜色的矩形框(默认黑色)
context.strokeStyle='green' // 设置线的颜色
context.strokeRect(50,50,150,150) // 画出一个无填充颜色的矩形框
context.scale(2,2) // 缩放。(x倍数,y倍数)
context.save() // 保存当前画布的状态
context.restore() // 返回上一次save()状态
context.clearRect(20,40,30,20) //清空给矩形内的指定像素。(x,y,w,h)
/* 不规则图形 */
context.beginPath() // 创建一个新路径
context.moveTo(100,50) //定义初始位置的 (向右增大,向下增大)
context.lineTo(80,150) //连接端点的 (定义一个点到初始点)
context.lineTo(40,150) //连接端点的 (定义一个点到初始点)
lineCap='round' //端点形状
context.strokeStyle='green' // 线的颜色
context.lineWidth='5'; //路径(线)的大小
context.closePath() // 封闭路径(线)
context.stroke() // 路径转为轮廓(线显示或描边)
context.fill() // 填充颜色。需要设置这个才能fillStyle填充颜色
/* 圆形 */
context.beginPath() // 创建一个新路径
context.arc(60,60,50,0,Math.PI*2,false) //(x,y,圆的大小,开始角,结束角,顺时针false逆时针true。可省略)
context.closePath() // 封闭路径(线)
context.stroke() // 路径转为轮廓(线显示或描边)
/* 处理图像 */
let image = new Image();
image.src = './3.jpg'
image.onload = function(){
context.drawImage(image,100,100) //图像操作能力。可以用于动态的图像合成
}
let img = canvas.toDataURL('image/jpg') // 把图像转化为base64格式。(图片类型,图片的质量【0-1】默认值是0.92)
console.log(img);
</script>
drawImage 方法有三种形态:
- drawImage(image, dx, dy) 在画布指定位置绘制原图
- drawImage(image, dx, dy, dw, dh) 在画布指定位置上按原图大小绘制指定大小的图
- drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) 剪切图像,并在画布上定位被剪切的部分
参数 描述
image 规定要使用的图像、画布或视频
sx 可选。开始剪切图片的 x 坐标位置
sy 可选。开始剪切图片的 y 坐标位置
sw 可选。被剪切图像的宽度(就是裁剪之前的图片宽度,这里的宽度若小于图片的原宽。则图片多余部分被剪掉;若大于,则会以空白填充)
sh 可选。被剪切图像的高度(就是裁剪之前的图片高度)
dx 在画布上放置图像的 x 坐标位置
dy 在画布上放置图像的 y 坐标位置
dw 可选。要使用的图像的宽度(就是裁剪之后的图片高度,放大或者缩放)
dh 可选。要使用的图像的高度(就是裁剪之后的图片高度,放大或者缩放)
精选小练习
1、基础练习:
<body>
<canvas id="can" width="400px" height="300px" style="border: 1px solid red;"></canvas><br>
<button id="btnRect">绘制矩形</button>
<button id="scale">扩大2倍</button>
<button id="save">保存状态</button>
<button id="restore">恢复上一次状态</button>
</body>
</html>
<!-- <script>
// 写法一
window.addEventListener('load', init, false)
function $(aa) {
return document.getElementById(aa)
}
let ctx
function init() {
var canvas = document.getElementById('can')
ctx = canvas.getContext('2d')
btnRect = $("btnRect");
cale = $("scale");
save = $('save');
restore = $("restore");
btnRect.addEventListener("click", randomX, false);
// btnRect.addEventListener("click", randomX(), false); 这样写,相当于在这里直接调用了
scale.addEventListener("click",ScaleBox,false);
save.addEventListener("click", saveBox, false);
restore.addEventListener("click", restoreBox, false);
}
function randomX() {
var x = parseInt(Math.random() * 100);
var y = parseInt(Math.random() * 100);
ctx.fillStyle = 'rgba(11,22,185,1)';
ctx.fillRect(x, y, 50, 50);
}
function ScaleBox() {
ctx.scale(2, 2);
}
function saveBox() {
ctx.save();
}
function restoreBox() {
ctx.restore();
}
</script>
-->
<script>
// 写法二。触发:绘制矩形---保存状态---扩大两倍---返回上一层状态
function $(id) {
return document.getElementById(id)
}
var canvas = document.getElementById('can')
var ctx = canvas.getContext('2d')
let RANDOM = 200 // 随机数最大值
$('btnRect').addEventListener('click', () => {
let x = parseInt(Math.random() * RANDOM)
let y = parseInt(Math.random() * RANDOM)
ctx.fillRect(x, y, 50, 50)
})
$('scale').addEventListener('click', () => {
RANDOM = 150
ctx.scale(2, 2)
})
$('save').addEventListener('click', () => {
ctx.save() // 保存当前状态
})
$('restore').addEventListener('click', () => {
console.log('restore');
// RANDOM = 200
ctx.restore()
// ctx.save() // 保存当前状态
})
</script>
2、小练习二:小球触碰边缘弹射
<body>
<canvas id="can" width="350px" height="250px" style="border: 1px solid red;">aa</canvas>
</body>
<!-- <script> 写法一:
var canvas = document.getElementById('can');
var ctx = canvas.getContext('2d');
var x = 10
var y = 10
var RANDOM = 10
var WIDTH = canvas.width // Z整个画布的宽度
var HEIGHT = canvas.height // 整个画布的高度
var direction = 1 // 方向
var xx = 1 // x的正方向
var yy = 1 // y的正方向
setInterval(() => {
if (x < RANDOM || x >= WIDTH - RANDOM) {
console.log(xx, x);
// 执行 x>=WIDTH-RANDOM。 正数*负数=负数(-1)
// 执行 x < RANDOM。 负数*负数=正数(1)
xx *= -1
}
if (y < RANDOM || y >= HEIGHT - RANDOM) {
yy *= -1
}
x = x + xx
y = y + yy
ctx.clearRect(0, 0, WIDTH, HEIGHT) // 清空画布
ctx.beginPath()
ctx.arc(x, y, RANDOM, 0, Math.PI * 2, false) //
ctx.closePath() // 封闭路径(线)
ctx.fillStyle = 'red'
ctx.fill()
}, 10)
</script> -->
<script> // 写法二
var canvas = document.getElementById('can');
var ctx = canvas.getContext('2d');
var x = 10
var y = 10
var RANDOM = 10
var WIDTH = canvas.width // Z整个画布的宽度
var HEIGHT = canvas.height // 整个画布的高度
var direction = 1 // 方向
setInterval(() => {
if (direction == 1) { // 运动方向
x++
y++
if(y >= HEIGHT-RANDOM){ // 小球移动到最下面时(底部),进入判断
direction = 2
}
if(x >= WIDTH-RANDOM){
direction = 4
}
} else if (direction == 2) {
x++
y--
if(x >= WIDTH-RANDOM){
direction = 3
}
if(y <= RANDOM){
direction = 1
}
} else if (direction == 3) {
x--
y--
if(y <= RANDOM){
direction = 4
}
if(x <= RANDOM){
direction = 2
}
} else if (direction == 4) {
x--
y++
if(x <= RANDOM){
direction = 1
}
if(y >= HEIGHT-RANDOM){
direction = 3
}
}
ctx.clearRect(0, 0, WIDTH, HEIGHT) // 清空画布
ctx.beginPath()
ctx.arc(x, y, RANDOM, 0, Math.PI * 2, false) //
ctx.closePath() // 封闭路径(线)
ctx.fillStyle = 'red'
ctx.fill()
}, 1)
</script>