是什么
Canvas(画布)是在 HTML5 中新增的标签用于在网页实时生成图像,可以操作图像内容,是一个可以用 JavaScript 操作的位图(bitmap)。
canvas 的应用领域
游戏:canvas 在基于 Web 的图像显示方面比 Flash 更加立体、更加精巧,canvas 游戏在流畅度和跨平台方面更优秀。
可视化的库:Echart
banner 广告:Canvas 实现动态的广告效果非常合适
图形编辑器:后续 PhotoShop 能够 100%基于 Web 实现
微信读书、腾讯文档均是通过 canvas 实现
使用
创建一个标签
获取 canvas 元素对应的 DOM 对象,这是一个 Canvas 对象
调用 Canvas 对象的 getContext()方法,该方法返回一个 CanvasRenderingContext2D 对象,该对象即可绘制图形
调用 CanvasRenderingContext2D 对象的方法绘图
创建坐标系
在 canvas 中默认坐标系在左上角(X 轴正方向向右、Y 轴正方向向下),可是有的时候需要变换坐标系才能更方便的实现所需的效果,此时需要变换坐标系,canvas 提供了以下几种变换坐标系的方式:
translate(dx,dy):平移坐标系。相当于把原来位于(0,0)位置的坐标原点平移到(dx、dy)点。
rotate(angle):旋转坐标系。该方法控制坐标系统顺时针旋转 angle 弧度。
scale(sx,sy):缩放坐标系。该方法控制坐标系统水平方向上缩放 sx,垂直方向上缩放 sy。
transform(a,b,c,d,e,f):允许缩放、旋转、移动并倾斜当前的环境坐标系,其中 a 表示水平缩放、b 表示水平切斜、c 表示垂直切斜、d 表示垂直缩放、e 表示水平移动、f 表示垂直移动。
function main() {
const canvas = document.getElementById("canvasId");
const ctx = canvas.getContext("2d");
ctx.lineWidth = 4;
// 默认
ctx.save();
ctx.strokeStyle = "#F00";
drawCoordiante(ctx);
ctx.restore();
// 平移
ctx.save();
ctx.translate(150, 150);
ctx.strokeStyle = "#0F0";
drawCoordiante(ctx);
ctx.restore();
// 旋转
ctx.save();
ctx.translate(300, 300);
ctx.rotate(-Math.PI / 2);
ctx.strokeStyle = "#00F";
drawCoordiante(ctx);
ctx.restore();
// 缩放
ctx.save();
ctx.translate(400, 400);
ctx.rotate(-Math.PI / 2);
ctx.scale(0.5, 0.5);
ctx.strokeStyle = "#000";
drawCoordiante(ctx);
ctx.restore();
}
function drawCoordiante(ctx) {
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(120, 0);
ctx.moveTo(0, 0);
ctx.lineTo(0, 80);
ctx.closePath();
ctx.stroke();
}
main();
图形绘制
根据坐标系绘制内容
// 直线
function drawLine(ctx, startX, startY, endX, endY) {
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
}
// 圆弧
function drawCircle(ctx, x, y, R, startAngle, endAngle) {
ctx.arc(x, y, R, startAngle, endAngle);
ctx.stroke();
}
// 贝济埃曲线
function drawBezierCurve(ctx, cpX1, cpY1, cpX, cpY2, endX, endY) {
ctx.bezierCurveTo(cpX1, cpY1, cpX, cpY2, endX, endY);
ctx.stroke();
}
// 二次曲线
function drawQuadraticCurve(ctx, cpX, cpY, endX, endY) {
ctx.quadraticCurveTo(cpX, cpY, endX, endY);
ctx.stroke();
}
// 填充矩形
function drawFillRect(ctx, x, y, width, height) {
ctx.fillRect(x, y, width, height);
}
// 边框矩形
function drawStrokeRect(ctx, x, y, width, height) {
ctx.strokeRect(x, y, width, height);
}
// 填充字符串
function drawFillText(ctx, text, x, y) {
ctx.fillText(text, x, y);
}
// 边框字符串
function drawStrokeText(ctx, text, x, y) {
ctx.strokeText(text, x, y);
}
// 利用路径绘制
function drawFigureByPath(ctx) {
ctx.beginPath();
ctx.moveTo(100, 400);
ctx.lineTo(200, 450);
ctx.lineTo(150, 480);
ctx.closePath();
ctx.fill();
}
// 初始化
function main() {
const canvas = document.getElementById("canvasId");
const ctx = canvas.getContext("2d");
ctx.lineWidth = 2;
ctx.strokeStyle = "#F00";
ctx.fillStyle = "#F00";
ctx.font = "normal 50px 宋体";
drawLine(ctx, 50, 10, 150, 10);
ctx.moveTo(150, 100);
drawCircle(ctx, 100, 100, 50, 0, Math.PI);
ctx.moveTo(300, 100);
drawCircle(ctx, 250, 100, 50, 0, Math.PI / 2);
ctx.moveTo(350, 150);
drawBezierCurve(ctx, 200, 200, 450, 250, 300, 300);
ctx.moveTo(50, 250);
drawQuadraticCurve(ctx, 50, 400, 80, 400);
drawFillRect(ctx, 100, 300, 100, 50);
drawStrokeRect(ctx, 300, 300, 100, 50);
drawFillText(ctx, "I", 100, 400);
drawStrokeText(ctx, "I", 300, 400);
drawFigureByPath(ctx);
}
main();
填充颜色
利用 canvas 绘制图形时势必要上点颜料,通过设置 fillStyle 属性即可设置对应的颜料,对于颜料值主要有以下四种:纯颜色、线性渐变颜色、径向渐变颜色、位图。
// 纯颜色
function useColorFill(ctx) {
ctx.save();
ctx.fillStyle = "#F00";
ctx.fillRect(10, 10, 100, 100);
ctx.restore();
}
// 线性渐变颜色
function useLinearGradientFill(ctx) {
ctx.save();
const lg = ctx.createLinearGradient(110, 10, 210, 10);
lg.addColorStop(0.2, "#F00");
lg.addColorStop(0.5, "#0F0");
lg.addColorStop(0.9, "#00F");
ctx.fillStyle = lg;
ctx.fillRect(120, 10, 100, 100);
ctx.restore();
}
// 径向渐变颜色
function useRadialGradientFill(ctx) {
ctx.save();
const lg = ctx.createRadialGradient(260, 60, 10, 260, 60, 60);
lg.addColorStop(0.2, "#F00");
lg.addColorStop(0.5, "#0F0");
lg.addColorStop(0.9, "#00F");
ctx.fillStyle = lg;
ctx.fillRect(230, 10, 100, 100);
ctx.restore();
}
// 位图填充
function useImageFill(ctx) {
ctx.save();
const image = new Image();
image.src = "https://source.unsplash.com/Xm9-vA_bhm0/300x500";
image.onload = function () {
// 创建位图填充
const imgPattern = ctx.createPattern(image, "repeat");
ctx.fillStyle = imgPattern;
ctx.fillRect(340, 10, 100, 100);
ctx.restore();
};
}
function main() {
const canvas = document.getElementById("canvasId");
const ctx = canvas.getContext("2d");
useRadialGradientFill(ctx);
useImageFill(ctx);
}
main();
填充外部图像
有的时候需要引入外部图片,然后对外部图片进行像素级别的处理,最后进行保存。
绘制图像:drawImage
取得图像数据:getImageData
将修改后的数据重新填充到 Canvas 中:putImageData
输出位图:toDataURL
function main() {
const canvas = document.getElementById("canvasId");
const ctx = canvas.getContext("2d");
const image = document.getElementById("image");
// 绘制图像
ctx.drawImage(image, 0, 0);
// 获取图像数据
const imageData = ctx.getImageData(0, 0, image.width, image.height);
const data = imageData.data;
for (let i = 0, len = data.length; i < len; i += 4) {
const red = data[i];
const green = data[i + 1];
const blue = data[i + 2];
const average = Math.floor((red + green + blue) / 3);
data[i] = average;
data[i + 1] = average;
data[i + 2] = average;
}
imageData.data = data;
ctx.putImageData(imageData, 0, 0);
document.getElementById("result").src = canvas.toDataURL("image/png");
}
实战
<canvas id="canvasId" width="1000px" height="600px"></canvas>
<script>
function main() {
const canvas = document.getElementById("canvasId");
const ctx = canvas.getContext("2d");
ctx.lineWidth = 4;
ctx.strokeStyle = "#000";
ctx.fillStyle = "#ffd8e1";
ctx.translate(320, 320);
drawPigEar(ctx);
ctx.save();
ctx.rotate(Math.PI / 2);
drawPigEar(ctx);
ctx.restore();
drawPigFace(ctx);
ctx.save();
ctx.translate(-100, -100);
drawPigEye(ctx);
ctx.restore();
ctx.save();
ctx.translate(100, -100);
drawPigEye(ctx);
ctx.restore();
ctx.save();
ctx.translate(0, 60);
drawPigNose(ctx);
ctx.restore();
}
function drawPigEar(ctx) {
ctx.save();
ctx.beginPath();
ctx.arc(-250, 0, 250, 0, -Math.PI / 2, true);
ctx.arc(0, -250, 250, -Math.PI, Math.PI / 2, true);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}
function drawPigFace(ctx) {
ctx.save();
ctx.beginPath();
ctx.arc(0, 0, 250, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
}
function drawPigEye(ctx) {
ctx.save();
ctx.fillStyle = "#000";
ctx.beginPath();
ctx.arc(0, 0, 20, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.restore();
}
function drawPigNose(ctx) {
ctx.save();
ctx.fillStyle = "#fca7aa";
ctx.beginPath();
ctx.ellipse(0, 0, 150, 100, 0, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.save();
ctx.translate(-60, 0);
drawPigNostrils(ctx);
ctx.restore();
ctx.save();
ctx.translate(60, 0);
drawPigNostrils(ctx);
ctx.restore();
ctx.restore();
}
function drawPigNostrils(ctx) {
ctx.save();
ctx.fillStyle = "#b55151";
ctx.beginPath();
ctx.ellipse(0, 0, 40, 60, 0, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}
main();
</script>
```