当前位置 博文首页 > m0_45291815的博客:Canvas基础

    m0_45291815的博客:Canvas基础

    作者:[db:作者] 时间:2021-09-02 19:07

    Canvas手册

    一、理解

    1. 没有学习canvas之前,使用div绘制圆,矩形,线
    2. 没有学习canvas之前,使用js绘制球碰撞,连线,运动
    3. 缺点:生成多个dom元素,让页面布局混乱
    4. canvas:不会生成多个dom元素,单独占用一块区域
    5. canvas:可以转换为图片路基,设置为背景使用,不影响页面布局, 而且动画依然生效
    6. canvas:操作更加便捷,稳定,功能全面

    二、第一步

    1. 创建一个canvas的H5标签,并内敛指定宽高:

      <canvas height="200" width="200"></canvas>

    2. 使用getElementById获取canvas元素,这样可以保证canvas的唯一性:

      canvas = document.getElementById('canvas')

    3. 创建canvas画布操作对象:

      ctx = canvas.getContext('2d');

    4. 兼容,低版本浏览器会将canvas识别为div标签:

      <canvas>你的浏览器不支持 canvas,请升级你的浏览器。</canvas>

    5. anvas转图片存储:

      canvas.toBlob((blob) => {
          此时的blob就是转换为图片文件后的二进制码,可以添加formData进行上传
      }, 'image/png')
      
    6. canvas转图片链接:

      var dataURL = canvas.toDataURL('image/png');
      // 示例
      const back = document.getElementById('back')
      back.style.background = 'url(' + dataURL + ') left top repeat';
      

    三、两个属性

    两个重要属性:面填充 和 边填充

    1、面

    1. 定义填充颜色:ctx.fillStyle = red
    2. 全局透明度:ctx.globalAlpha = 1 范围0-1
    3. 绘制填充:ctx.fill()

    2、边

    1. 定义描边颜色:ctx.strokeStyle = blue

    2. 定义描边宽度:ctx.lineWidth = 5

    3. 定义边的端点:ctx.lineCap = 'butt'

      // butt: 默认值; round: 比定义线长两边各多半圆;square: 比定义线长两边各多矩形

    4. 定义边的连接点:ctx.lineJoin = 'butt'

      // butt: 默认值:尖角;round: 圆角;miter: 平角

    5. 绘制虚线:ctx.setLineDash([10, 4]); 绘制段长围10,间隔4的虚线

      // 数组内每两元素为一组,变量通过ctx.getLineDash获取

    6. 绘制虚线偏移:ctx.lineDashOffset = 2, 虚线偏移量

    7. 倾斜角偏移长度:ctx.miterLimit = number

    8. 绘制描边:ctx.stroke()


    四、绘制

    1、直线路径

    1. 声明画路径:ctx.beginPath();

    2. 声明直线段起点:ctx.moveTo(10, 10)

      // 声明要在相对于canvas左上角,left: 10px, top: 10px; 的地方为线段起点

    3. 声明直线段终点:ctx.lineTo(100, 100)

      // 声明要在(100, 100)的点为线段终点

    4. 声明直线段颜色:ctx.strokeStyle = 'red'

    5. 声明直线段的宽度:ctx.lineWidth = '5'

    6. 绘制描边:ctx.stroke()

      // 将颜色宽度进行边填充,不填充上面定义的线颜色盒宽度不会生效

    7. 关闭画直线的声明:ctx.closePath()

      // 关闭画直线的声明,完成此次绘制

    2、多条直线

    • 将上面的流程多走几遍,设置不同的起点终点
    • 将上面ctx.lineTo多执行几遍,就可以绘制折线,矩形等等

    3、绘制矩形

    1. 通过多条直线绘制围成矩形,然后进行边填充上色

    2. ctx.rect(x, y, width, height); // 声明绘制矩形

    3. ctx.fillStyle = 'red'; // 声明填充颜色

    4. ctx.fill(); // 绘制填充

    5. ctx.fillRect(x, y, width, height); 相当于上面rect + fill

    6. 以底部线平齐:y = 指定平齐线y位置 - height:用户绘制柱状统计图使用

    7. ctx.strokeRect(x, y, width, height); 相当于rect() + stroke(); // 绘制空心矩形

      // 可以先定义线的样式,然后再使用绘制空心矩形

    4、清除画布

    • 得到上面的api后,就可以使用时间函数setTimeOut开始简单动画了
    • 动画时会发现画布会重复绘制图像,导致下一刻的图像覆盖上一刻的图像
    • 这时就需要清除上一刻的图像
    • ctx.clearRect(x, y, width, height); 清除一块画布区域
    • 长尾效果:在清除画布前加上ctx.fillStyle = 'rgba(255,255,255,0.3)';就可以了

    5、圆路径

    1. 圆也属于路径,路径: ctx.beginPath()

    2. arc(x, y, radius, startDeg, endDeg, antic);

      // (x, y)圆心,radius半径, startDeg开始弧度,endDeg结束弧度, antic是否逆时针,默认true

    3. 第二个ctx.beginPath()会终止第一个beginPath(), 既携带一个closePath属性

    4. arcTo(x1, y1, x2, y2, radius); 拉弓弧:一条直线段,拉中间某点形成的弧度

      // (x1, y1)作用点1,(x2, y2)作用点2,radius半径

      /* 案例 */
      const ctx = document.getElementById('canvas'),getContext('2d')
      ctx.beginPath();
      ctx.moveTo(50, 50);
      ctx.arcTo(150, 100, 200, 40, 40);
      ctx.lineTo(200, 40);
      ctx.stroke();
      ctx.closePath();
      
    5. bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); 绘制塞贝尔曲线

      // (cp1x, cp1y)控制点1,(cp2x, cp2y)控制点2,(x, y)结束点

      /* 案例 */
      const ctx = document.getElementById('canvas'),getContext('2d')
      ctx.beginPath();
      ctx.moveTo(50, 50);
      ctx.bezierCurveTo(100, 100, 200, 40, 250, 100);
      ctx.stroke();
      ctx.closePath();
      

    6、填充文字

    1. 文字属性:ctx.font = 10px/10px '微软雅黑'
    2. 居中:ctx.textAlign = 'center'
    3. 颜色还是fillStyle和strokeStyle设置
    4. 绘制面填充文本:ctx.fillText('hello world', 10, 50); 参数: src, x, y
    5. 绘制边填充文本:ctx.strokeText('hello world', 10, 50); 参数: src, x, y

    6、使用图片

    1. 创建图片对象:var img = new Image();

    2. 设置图片来源:img.src = '/path';

    3. 插入图片:

      img.onload = function() {
          ctx.drawImage(img, x, y, width, height, clipX, clipY, clipW, clipH)
          //img对象,(x, y)坐标,width, height图片大小,(clipX, clipY)裁剪切片坐标,       clipWidth, clipHeight切片大小
      }
      
    4. 或插入图片:ctx.drawImage(document.getElementById(img), 0, 0, 100, 100)

    5. 平铺:

      • 将图片大小设置缩小
      • 行列双循环平铺渲染
    6. 相册:

      • 渲染两张图片
      • 相册图片进行切片,相册框不操作
    7. 画廊: 相册带有间距的平铺渲染

    7、颜色渐变

    1、线性渐变

    var lineargradient = ctx.createLinearGradient(0,0,150,150);
    // 表示渐变的起点 (x1,y1) 与终点 (x2,y2)
    lineargradient.addColorStop(0,'white');
    lineargradient.addColorStop(0.5,'white');
    // 可以在0-1之间放很多
    lineargradient.addColorStop(1,'black');
    

    2、径向渐变

    var radialgradient = ctx.createRadialGradient(45,45,10,52,50,30);
    // 前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义结束圆以 (x2,y2) 为原点,半径为 r2 的圆。
    radialgradient.addColorStop(0,'white');
    // 可以在0-1之间放很多
    radialgradient.addColorStop(1,'black');
    

    8、阴影

    1. x轴偏移:ctx.shadowOffsetX = 10;
    2. y轴偏移:ctx.shadowOffsetY = 10;
    3. /糊度:ctx.shadowBlur = 3;
    4. 阴影颜色:ctx.shadowColor = "red";

    9、变形旋转

    1. 保存当前状态:ctx.save();

    2. 释放保存状态:ctx.restore();

      // 上面两个是成对存在的,可以有包裹性

      // 意义:变形后需要保存变形后一刻的快照,才能完成每一帧变化连续动画

    3. 偏移移动:ctx.translate(x, y):x, y 为移动相对自身距离

    4. 中心旋转:ctx.rotate(angle); 只有一个旋转角度参数

      // 改变中心点通过ctx.translate(x, y)改变

    5. 放缩:ctx.scale(x, y); x y 为放缩比例

    6. 使用ctx.translate(0,canvas.height); ctx.scale(1,-1)

      // 以y轴作为对称轴镜像反转

    7. 复合:context.transform(a,b,c,d,e,f);

      // a: 水平缩放绘图, b: 水平倾斜绘图, c: 垂直倾斜绘图, d: 垂直缩放绘图, e: 水平移动绘图, f: 垂直移动绘图.

    10、合并和裁剪

    1. 合成:ctx.globalCompositeOperation = value ?(属性看一遍)

    2. 路径区域裁剪:ctx.clip()

      // 使用线段的方法绘制一块路径,然后使用clip()进行裁剪

    3. 裁剪案例

      /* 案例 剪裁路径是三角形
        context.beginPath();
        context.moveTo(20, 20);
        context.lineTo(200, 80);
        context.lineTo(110, 150);
        context.clip(); // 剪裁
      */
      

    五、动画

    1、鼠标+球 动画

    1. 鼠标移入时获取移入位置,计时器依次创建多个小球对象
    2. 小球对象定义小球大小,半径,位置,小球移动速度,小球半径减小速度
    3. 将小球加入到运动队列
    4. 在外面创建时间函数,轮询运动队列,每次先清除画布,再调用队列里小球的运动函数
    5. 定义小球运动时间函数(window.requestAnimationFrame)
      • 根据定义绘制小球
      • 判断小球半径是否为0,为0将当前小球在运动队列删除,否者继续
      • 根据速度计算小球下一次位置
      • 修改小球定义属性
    6. 完成功能

    2、碰撞检查

    1. 创建小球对象函数
    2. 定义小球初始位置,大小,运动速度
    3. 将小球加入运动队列
    4. 在外面创建时间函数,轮询运动队列,每次先清除画布,再调用队列里小球的运动函数
    5. 定义小球运动函数
      • 根据定义绘制小球
      • 根据小球半径和canvas宽高判断是否碰撞,碰撞速度取反
      • 根据速度计算小球下一次位置
      • 修改小球定义属性
    6. 完成功能

    3、球碰撞+连线

    1. 创建小球对象函数
    2. 定义小球初始位置,大小,运动速度
    3. 将小球加入运动队列
    4. 在外面创建时间函数,轮询运动队列,每次先清除画布,再调用队列里小球的运动函数
      • 先清除画布
      • 轮询运动列表,进行判断
      • 如果存在比自己位置大的,且距离在自定范围的球,开始连线
      • 以自己位置,到条件球位置,连线。
      • 并根据距离远近设置透明度 = 距离/10,(后面的除数更具实际情况判断)
    5. 定义小球运动函数
      • 根据定义绘制小球
      • 根据小球半径和canvas宽高判断是否碰撞,碰撞速度取反
      • 根据速度计算小球下一次位置
      • 修改小球定义属性
    6. 完成功能

    4、车轮滚动

    1. 创建图片对象并引入图片
    2. 使用时间函数或帧(requestAnimationFrame)函数开始运动
    3. 清除画布
    4. 偏移调整中心点,并开始中心旋转
    5. 同时修改图片绘制位置

    5、鼠标+涟漪

    loading…

    6、雨点涟漪

    loading…

    7、click效果

    loading…

    8、眼球跟随

    loading…

    9、太阳系

    loading…

    10、全景

    loading…

    11、鼠标追踪

    loading…

    12、简单小游戏

    loading…

    cs
    下一篇:没有了