zoukankan      html  css  js  c++  java
  • 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画出心中最美的风景!

  • 相关阅读:
    toj 2819 Travel
    toj 2807 Number Sort
    zoj 2818 Prairie dogs IV
    zoj 1276 Optimal Array Multiplication Sequence
    toj 2802 Tom's Game
    toj 2798 Farey Sequence
    toj 2815 Searching Problem
    toj 2806 Replace Words
    toj 2794 Bus
    css截取字符
  • 原文地址:https://www.cnblogs.com/lfri/p/12234524.html
Copyright © 2011-2022 走看看