• Canvas入门


    转载自 Segmentfault-小白也能看懂的H5 Canvas

    Canvas 对象是 HTML5 中新增的。但Canvas也是常见的前端技术,但是由于API众多,使用复杂,且对程序员的数学功底、空间想象能力乃至审美都有一定要求,所以真正擅长canvas的前端并不多,但并不代表大家就学不好canvas。我在此将常用的canvas使用场景罗列出来希望能帮助到大家。

    一、创建Canvas

    Canvas的创建很简单,只需要一个<canvas>标签足以,而内部复杂的实现都交给浏览器搞定。

    html:

    <canvas id="canvas"></canvas>

    所有的绘制动作都需要在canvas上下文(context)中进行,因此我们需要先创建一个上下文。

    js:

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    除了2d,上下文还可以设置为:webglwebgl2bitmaprenderer

    二、设置canvas尺寸

    js:

    canvas.width = 600;
    canvas.height = 600;

    若要满屏显示可以:

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    三、绘制矩形

    1. 实心矩形(fillRect)

    绘制实心矩形最简单的是用 fillRect(x, y, width, height) 方法,参数中 x, y 表示矩形左上角的坐标;widthheight 分别表示矩形的宽、高。使用方法如下:

    js:

    // 设置填充颜色
    ctx.fillStyle = 'skyblue';
    // 绘制实心矩形
    ctx.fillRect(20, 20, 150, 100);

    效果:

    2. 空心矩形(strokeRect)

    与绘制实心矩形类似的是使用 strokeRect(x, y, width, height) 方法绘制空心矩形。参数与 fillText 方法一致。

    js:

    // 设置线宽
    ctx.lineWidth = 5;
    // 设置绘制颜色
    ctx.strokeStyle = 'chocolate';
    // 绘制空心矩形
    ctx.strokeRect(20, 20, 150, 100);

    效果:

    3. 清空矩形区域(clearRect)

    当要重绘canvas中的内容时(比如动画),我们需要先使用 clearRect(x, y, width, height) 清空canvas。

    js:

    ctx.fillStyle = 'skyblue';
    ctx.fillRect(20, 20, 150, 100);
    // 清除画布中的矩形区域
    ctx.clearRect(25, 25, 140, 90);

    效果:

    四、绘制文字

    1. 实心文字(fillText)

    绘制文字也是canvas的基本功能,实心文字可以使用 fillText(text, x, y [, maxWidth]) 方法,参数中 text 表示绘制的文字;x, y 为文字起点的坐标;maxWidth 为可选参数,表示文字的最大宽度,如果文字超过该最大宽度那么浏览器将会通过调整字间距、字体或者压缩文字来适应最大宽度。

    js:

    // 设置绘制颜色
    ctx.fillStyle = 'purple';
    // 设置字体
    ctx.font = '30px Arial';
    // 绘制实心颜色
    ctx.fillText('Hello World', 220, 50);

    效果:

    2. 空心文字(strokeText)

    类似的,空心文字可以使用 strokeText(text, x, y [, maxWidth]) 绘制,参数与 fillText 方法一致:

    js:

    // 设置线宽
    ctx.lineWidth = 3;
    // 设置文字颜色
    ctx.strokeStyle = 'orange';
    // 设置字体
    ctx.font = '50px Arial';
    // 绘制空心文字
    ctx.strokeText('Hello World', 180, 50);

    效果:

    五、路径(Path)

     顾名思义,通过Path我们可以定义一段段路径(或直线、或曲线)来组合出我们想要的图形。

    1. 矩形

    使用Path也可以绘制矩形,和 fillRectstrokeRect一样的效果,但是多一个步骤。使用 rect(x, y, width, height) 方法可以向当前路径添加一个矩形,该方法只会改变路径但不会直接渲染出矩形,所以还需要执行 fill() 或 stroke() 方法:

    js:

    ctx.rect(200, 20, 200, 100);
    ctx.fillStyle = 'deeppink';
    ctx.fill();

    效果:

    或者,空心矩形:

    ctx.rect(200, 20, 200, 100);
    ctx.lineWidth = 3;
    ctx.strokeStyle = 'deeppink';
    ctx.stroke();

    效果:

    2. 三角形

    用路径可以绘制各种自定义的图形,比如三角形:

    js:

    // 开始绘制路径
    ctx.beginPath();
    // 移动至起点
    ctx.moveTo(200, 20);
    // 绘制线段
    ctx.lineTo(300, 20);
    ctx.lineTo(250, 150);
    ctx.lineTo(200, 20);
    // 绘制路径
    ctx.stroke();

    效果:

    或者在绘制最后一边的时候可以使用ctx.closePath(),使路径闭合。

    我们也可以将闭合的路径填充颜色,以实现实心三角形的绘制:

    js:

    ctx.beginPath();
    ctx.moveTo(200, 20);
    ctx.lineTo(300, 20);
    ctx.lineTo(250, 150);
    // 闭合路径
    ctx.closePath();
    // 设置填充颜色
    ctx.fillStyle = 'coral';
    // 填充路径
    ctx.fill();

    效果:

    3. 弧线

    (1)标准圆弧

    Canvas中没有专门绘制圆的方法,而是使用更加通用的方法arc(x, y, radius, startAngle, endAngle [, anticlockwise]) 绘制弧线,参数中 x, y 为圆心坐标;radius 为圆的半径; startAngle 为弧的初始角度;endAngle 为弧的结束角度;anticlockwise 表示是否以逆时针方向绘制路径。例如绘制圆,可以写成:

    js:

    ctx.beginPath();
    ctx.arc(300, 300, 60, 0, Math.PI * 2, true);
    ctx.stroke();

    效果:

    (2)二次方曲线

    Canvas也支持绘制二次方曲线,使用 quadraticCurveTo(cpx, cpy, x, y) 方法,参数为两个点的坐标,其中 cpx, cpy 为控制点的坐标;x, y 为结束点的坐标。使用方法如下:

    js:

    ctx.beginPath();
    ctx.moveTo(150, 400);
    ctx.quadraticCurveTo(300, 0, 450, 400);
    ctx.stroke();

    效果:

    (3)贝塞尔曲线

    类似的,canvas还支持绘制常见的贝塞尔曲线,使用 bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y),参数中 cp1x, cp1y 为第一控制点的坐标;cp2x, cp2y 为第二控制点的坐标;x, y 为结束点的坐标。一个简单的贝塞尔曲线可以表示如下:

    js:

    ctx.beginPath();
    ctx.moveTo(100, 400);
    ctx.bezierCurveTo(200, 200, 400, 400, 500, 200);
    ctx.stroke();

    效果:

    六、显示图片

    我们也可以将图片绘制到canvas上面,使用 drawImage() 方法。drawImage()方法有三个重载:

    drawImage(image, dx, dy);
    drawImage(image, dx, dy, dWidth, dHeight);
    drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

    各参数的含义为:

    image: 被绘制到canvas上面的图片源,支持多种类型:CSSImageValueHTMLImageElementSVGImageElementHTMLVideoElementHTMLCanvasElementImageBitmapOffscreenCanvas

    dx: 在canvas上水平方向绘制的起点

    dy: 在canvas上垂直方向绘制的起点

    dWidth: 在canvas上绘制图片的宽度

    dHeight: 在canvas上绘制图片的高度

    sx: 原始图片上水平方向裁剪的起点

    sy: 原始图片上垂直方向裁剪的起点

    sWidth: 原始图片上水平方向裁剪的宽度

    sHeight: 原始图片上垂直方向裁剪的高度

    前两个重载比较好理解,就是在canvas上绘制出完整的源图片,并且可以通过设置宽高控制图片的缩放。第三个重载即在canvas上绘制出源图片的一部分,可以形象表示为:

    图片源以 HTMLImageElement 为例,在canvas上绘制图片可以这么实现:

    html:

    <img id="source" style="display: none;" src="https://unsplash.it/500/300?image=1074" alt="source">

    js:

    const image = document.getElementById('source');
    image.addEventListener('load', e => {
      ctx.drawImage(image, 50, 150, 500, 300);
    });

    效果:

    七、绘制动画

    使用canvas配合 requestAnimationFrame 可以很方便的实现一些动画效果,比如实现一个圆从左往右移动的动画:

    js:

    /**
     * 定义圆
     */
    const circle = {
      x: 30, // 水平方向的坐标
      y: 300, // 垂直方向的坐标
      size: 30, // 圆的半径
      dx: 5, // 水平坐标的变化值
      dy: 4 // 垂直坐标的变化值
    }
    
    /**
     * 绘制圆
     */
    function drawCirle() {
      ctx.beginPath();
      ctx.arc(circle.x, circle.y, 30, 0, Math.PI * 2);
      ctx.fillStyle = 'purple';
      ctx.fill();
    }
    
    /**
     * 更新canvas实现动画效果
     */
    function update() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      drawCirle();
      circle.x += circle.dx;
      requestAnimationFrame(update);
    }
    
    update();

    效果:

     我们也可以给小球加上碰撞检测,让它在canvas里面来回弹:

    js:

    function update() {
      ...
    
      if (circle.x + circle.size > canvas.width || circle.x - circle.size < 0) {
        circle.dx *= -1;
      }
    
      requestAnimationFrame(update);
    }

    效果:

    或者我们可以实现用键盘控制圆的移动:

    js:

    /**
     * 定义圆
     */
    const circle = {
      x: 300, // 水平方向的坐标
      y: 300, // 垂直方向的坐标
      size: 30, // 圆的半径
      dx: 0, // 水平坐标的变化值
      dy: 0, // 垂直坐标的变化值
      speed: 10 // 移动速度
    }
    
    /**
     * 绘制圆
     */
    function drawCirle() {
      ctx.beginPath();
      ctx.arc(circle.x, circle.y, 30, 0, Math.PI * 2);
      ctx.fillStyle = 'purple';
      ctx.fill();
    }
    
    /**
     * 更新canvas实现动画效果
     */
    function update() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      circle.x += circle.dx;
      circle.y += circle.dy;
      // 边界碰撞检测
      const leftMost = circle.size; 
      const rightMost = canvas.width - circle.size; 
      const topMost = circle.size; 
      const bottomMost = canvas.height - circle.size; 
      if (circle.x < leftMost) {
        circle.x = leftMost;
      }
      if (circle.x > rightMost) {
        circle.x = rightMost;
      }
      if (circle.y < topMost) {
        circle.y = topMost;
      }
      if (circle.y > bottomMost) {
        circle.y = bottomMost;
      }
      // 绘制圆
      drawCirle();
      requestAnimationFrame(update);
    }
    
    /**
     * 开始移动
     */
    function move(e) {
      const { key } = e;
      if (key === 'ArrowUp' || key === 'Up') {
        circle.dy = -circle.speed;
      } else if (key === 'ArrowDown' || key === 'Down') {
        circle.dy = circle.speed;
      } else if (key === 'ArrowLeft' || key === 'Left') {
        circle.dx = -circle.speed;
      } else if (key === 'ArrowRight' || key === 'Right') {
        circle.dx = circle.speed;
      }
    }
    
    /**
     * 停止移动
     */
    function stop(e) {
      if (
        e.key == 'Right' ||
        e.key == 'ArrowRight' ||
        e.key == 'Left' ||
        e.key == 'ArrowLeft' ||
        e.key == 'Up' ||
        e.key == 'ArrowUp' ||
        e.key == 'Down' ||
        e.key == 'ArrowDown'
      ) {
        circle.dx = 0;
        circle.dy = 0;
      }
    }
    
    document.addEventListener('keydown', move);
    document.addEventListener('keyup', stop);
    update();

    效果:

    八、Canvas库

    由于canvas非常的强大,但是API较为复杂,所以业界出现了很多基于canvas的库,让大家使用canvas更加简单,下面列出一些供大家选择:

    • Fabric.js 开源的canvas库,支持SVG和canvas互转
    • EaselJS 可以轻松使用HTML5 Canvas元素。可用于创建游戏,生成艺术作品以及其他高度图形化创作
    • KonvaJS 用于桌面和移动应用程序的HTML5 2d canvas库
    • PixiJS HTML5创建引擎:使用最快,最灵活的2D WebGL渲染器创建精美的数字内容
    • Paper.js 矢量图形脚本中的瑞士军刀 - 使用HTML5 Canvas将Scriptographer移植到JavaScript和浏览器
    • P5.js p5.js是一个客户端JS平台,它使艺术家,设计师,学生和任何人都可以学习编码并在网络上创造性地表达自己
    • Three.js 使用WebGL渲染器创建易于使用,轻巧的3D库。该库还提供了Canvas 2D,SVG和CSS3D渲染器
    • D3.js D3.js是一个JavaScript库,用于根据数据处理文档。 D3帮助您使用HTML,SVG和CSS使数据栩栩如生

    关于canvas就给大家介绍到这里,希望有朝一日大家都能用canvas画出心中最美的风景!

  • 相关阅读:
    数组相关常见的三种错误
    JMeter连接MYSQL数据库并进行操作详解
    JMeter实现动态关联——两个接口在不同的线程组
    Android : kernel中添加虚拟文件节点
    Android O : 系统原生锁屏密码位数限制及自动检查
    Android O : DNS列表获取及IPv4/IPv6优先级修改
    Android 打印调用栈的方法
    Android TV : 系统分区配置及增加私有分区
    Android TV : Mstar平台Audio Path及声音曲线配置
    Android TV : Mstar平台 GPIO 调试
  • 原文地址:https://www.cnblogs.com/lfri/p/12234524.html
Copyright © 2020-2023  润新知