走进HTML5,Canvas一探究竟

欢迎关注个人我的博客分享一些前端技术、面试题、面试技巧等html

简介

Canvas 是 HTML5 新增的一个标签属性,一个可使用脚本在其中绘制图像的 HTML 元素。它能够用来制做照片或者制做简单的动画,甚至能够进行实时的视频处理和渲染。Canvas 是由 HTML 代码配合高度和宽度属性而定义出的可绘制区域。JavaScript 代码能够访问该区域,相似于其余通用的 API,经过一套完整的绘图函数来动态生成图形。前端

应用场景

  1. 游戏
  2. 图表
  3. 动画
  4. HTML5 动效(codepen.io)

如何使用 Canvas

  • 添加 canvas 标签
<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
  • 得到 canvas 元素
const canvas = document.getElementById("myCanvas");
复制代码
  • 得到 canvas 上下文对象
const ctx = canvas.getContext("2d");
// 有两个参数getContext()能够采起。一个是渲染2D元素的标准2d上下文。另外一种使用的webGL技术仍处于起步阶段。所以,大多数状况下,您能够在任何地方找到第二个画布的上下文(截至目前)
复制代码

两个对象

  1. 元素对象(canvas 元素)和上下文对象(经过getContext('2d)方法获取到的 CanvasRenderingContext2D 对象)
  2. 元素对象相对于咱们的画布,上下文对象至关于画笔,咱们接下来的全部操做是基于上下文对象的。

线段

ctx.moveTo(x, y); // 移动到x, y坐标点
ctx.lineTO(x, y); // 从当前点绘制直线到x, y点
ctx.stroke(); // 描边
ctx.lineWidth() = 20; // 设置线段宽度
ctx.closePath(); // 闭合当前路径 和 回到起始点是有区别的
ctx.fill(); // 填充
复制代码
  • 注意:
    • fillstroke方法都是做用在当前的全部子路径
    • 完成一条路径后要从新开始另外一条路径时必须使用 beginPath() 方法,beginPath 开始子路径的一个新的集合

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
ctx.lineWidth = 20;
ctx.moveTo(100, 50);
ctx.lineTo(100, 100);
ctx.lineTo(50, 100);
ctx.closePath();
ctx.strokeStyle = "red";
ctx.stroke();
ctx.moveTo(200, 200);
ctx.strokeStyle = "#000";
ctx.stroke();
复制代码

mhxZM4.png

矩形

// 绘制矩形路径 左上角坐标为(x, y),宽 高为dx dy。
ctx.rect(x, y, dx, dy);
// 填充向一个矩形区域填充颜色。 左上角坐标为(x, y),宽 高为dx dy。
ctx.fillRect(x, y, dx, dy);
// 绘制一个矩形区域的边框。 左上角坐标为(x, y),宽 高为w h。
ctx.strokeRect(x, y, w, h);
// 擦除指定矩形区域的像素颜色,等同于把早先的绘制效果都去除。
ctx.clearRect(x, y, dx, dy);
复制代码

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");

let y = 100;
function draw(y) {
  ctx.fillRect(100, y, 20, 20);
}
const timer = setInterval(() => {
  ctx.clearRect(0, 0, 500, 500);
  draw(y);
  y += 10;
  if (y > 480) {
    clearInterval(timer);
  }
}, 50);
复制代码

mhzstx.gif

弧形

arc(x, y, r, 起始弧度, 结束弧度, 弧形的方向); // 弧形方向为 true 逆时针, false 顺时针
// 角以弧度计
Math.PI / 180 * angle ==> 弧度
复制代码

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 圆形
ctx.beginPath();
ctx.arc(100, 100, 50, 0, (Math.PI / 180) * 360, true);
ctx.stroke();
ctx.closePath();
// 小扇形
ctx.beginPath();
ctx.moveTo(250, 100);
ctx.arc(250, 100, 50, 0, (Math.PI / 180) * 45, false);
ctx.lineTo(250, 100);
ctx.stroke();
ctx.closePath();
// 大扇形
ctx.beginPath();
ctx.moveTo(200, 200);
ctx.arc(200, 200, 50, 0, (Math.PI / 180) * 45, true);
ctx.lineTo(200, 200);
ctx.stroke();
ctx.closePath();
复制代码

m4pJQU.png

圆角

ctx.arcTo(x1, y1, x2, y2, r); // 绘制的弧线与当前点和 x1, y1 和 x2, y2链接都相切
复制代码

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 绘制圆角矩形
ctx.beginPath();
ctx.moveTo(150, 50);
ctx.arcTo(200, 50, 200, 150, 30);
ctx.arcTo(200, 150, 100, 150, 30);
ctx.arcTo(100, 150, 100, 50, 30);
ctx.arcTo(100, 50, 200, 50, 30);
ctx.closePath();
ctx.stroke();
复制代码

m4PJQf.png

贝塞尔曲线

// 二次贝塞尔曲线
// x1, y1 控制点 ex, ey 结束点
quadraticCurveTo(x1, y1, ex, ey);
// 三次贝塞尔曲线
// x1, y1, x2, y2 控制点 ex, ey 结束点
bezierCurveTo(x1, y1, x2, y2, ex, ey);
复制代码

坐标轴转换

translate(dx, dy); // 从新映射画布上的(0, 0)位置
scale(sx, sy); // 缩放当前绘图
rotate(Math.PI); // 旋转当前的绘图
save(); // 保存当前图像状态的一份拷贝
restore(); // 从栈中弹出存储的图像状态并恢复
setTransform(a, b, c, d, e, f); // 先重置再变换
// 参数:水平旋转 水平倾斜 垂直倾斜 垂直缩放 水平移动 垂直移动
transform(a, b, c, d, e, f); // 在以前的基础上变换
复制代码

填充图案

createPattern(image, "repeat | repeat-x | repeat-y | no-repeat");
复制代码

渐变

// 必须在填充渐变的区域里定义渐变,不然没效果
// 线性渐变
createLinearGradient(x1, y1, x2, y2);
// 径向渐变
createRedialGradient(x1, y1, x2, y2);
bg.addColorStop(p, color);
复制代码

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 线性渐变
let gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, "green");
gradient.addColorStop(1, "white");
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);
// 径向渐变
let gradient1 = ctx.createRadialGradient(280, 280, 50, 300, 300, 200);
gradient1.addColorStop(0, "white");
gradient1.addColorStop(1, "green");
ctx.fillStyle = gradient1;
ctx.fillRect(200, 200, 300, 300);
复制代码

m4mVSJ.png

阴影

ctx.shadowColor; // 阴影的颜色,默认为black
ctx.shadowOffsetX; // 阴影的水平位移,默认为0
ctx.shadowOffsetY; // 阴影的垂直位移,默认为0
ctx.shadowBlur; // 阴影的模糊程度,默认为0
// 这里的阴影偏移量不受坐标系变换的影响
复制代码

文本

fillText(); // 在指定位置绘制实心字符
strokeText(); // 在指定位置绘制空心字符
ctx.font; // 指定字型大小和字体,默认值为 10px sans-serif
ctx.textAlign; // 文本的对齐方式,默认值为start
ctx.direction; // 文本的方向,默认值为inherit
ctx.textBaseline; // 文本的垂直位置,默认值为alphabetic
复制代码

m4ng8e.png

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
ctx.font = "Bold 20px Arial";
ctx.strokeText("Hello world", 50, 50);
ctx.fillText("Hello world", 100, 100);
复制代码

m4KZlQ.png

线段样式

  • lineGap 指定线条末端的样式
    • butt(默认值,末端为矩形)
    • round(末端为圆形)
    • square(末端为突出的矩形,矩形宽度不变,高度为线条宽度的一半)。
  • lineJoin 指定线段交点的样式
    • round(交点为扇形)
    • bevel(交点为三角形底边)
    • miter(默认值,交点为菱形)
  • ctx.miterLimit 指定交点菱形的长度,默认为 10

当 lineJoin 是 miter 时,用于控制斜接部分的长度,若是斜接长度超过 miterLimit 的值,变成 bevelgit

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
ctx.lineWidth = 20;
ctx.lineJoin = "miter";
ctx.miterLimit = 20;
ctx.moveTo(100, 100);
ctx.lineTo(200, 100);
ctx.lineTo(100, 110);
ctx.closePath();
ctx.stroke();
复制代码

m411b9.png

裁剪

// 当前路径外的区域不在绘制
ctx.clip();
// 可在clip() 前用save()方法保存,后续经过restore()方法恢复
复制代码

代码示例

<canvas id="myCanvas" width="500" height="500"></canvas>
复制代码
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(200, 200, 50, 0, Math.PI * 2, 0);
ctx.closePath();
ctx.clip();
ctx.fillRect(100, 100, 300, 300);
ctx.strokeRect(100, 100, 400, 400);
复制代码

m48o90.png

全局透明度

ctx.globalAlpha = "0.5";
复制代码

绘制图片

// 第一个参数是img(image,canvas,video)
// 要在 onload 后再绘制
ctx.drawImage();
// 3 个参数
// 起始点坐标
x, y;
// 5个参数
// 起始点坐标及图片所存区域的宽高
x, y, dx, dy;
// 9个参数
// 前四个为所绘制目标元素的起始点和宽高,后四个为canvas绘制的起始点和大小
x1, y1, dx1, dy1, x2, y2, w2, h2;
复制代码
let img = new Image();
img.onload = function() {
  ctx.drawImage();
};
img.src = "";
复制代码

如何解决 Canvas 高分屏模糊问题

在分辨率比较高的屏幕,例如 ip6/6s/mac 等机器上,由于 canvas 绘制的是位图,因此会致使模糊,解决方法是根据屏幕分辨率修改 canvas 样式代码中的宽和高与 canvas 的 width 和 height 属性的比例github


但愿对读完本文的你有帮助、有启发,若是有不足之处,欢迎批评指正交流!web

欢迎关注个人我的博客分享一些前端技术、面试题、面试技巧等面试

辛苦整理良久,还望手动点赞鼓励~canvas


'摘抄'不是单纯的“粘贴->复制”,而是眼到,手到,心到的一字一句敲打下来。ide

博客声明:全部转载的文章、图片仅用于做者本人收藏学习目的,被要求或认为适当时,将标注署名与来源。若不肯某一做品被转用,请及时通知本站,本站将予以及时删除。函数

相关文章
相关标签/搜索