canvas - 图片裁剪 - 花瓣散落动画

1,226 阅读3分钟

用drawImage 带你做一个花瓣散落的动画

之前我们阅读过canvas的基础api。 但是其中包括有很多较为复杂的api我们直接跳过了。

drawImage 就是其中之一。今天我们就一起来看看他。

drawImage 一个方法包括了两种使用方式:渲染 和 裁剪 。 我们重点看看裁剪。

渲染

在我们渲染图片之前我们需要对图片进行预加载。


function loadImg(url) {
  return new Promise((resolve, reject) => {
    let img = new Image()
    img.onload = function () {
      resolve(img)
    }
    img.src = url
  })
}

在图片加载结束之后我们将整个img对象返回。在这个img对象中我们可以拿到对img的宽高和img的实例。 而这个img的实例就是 我们drawImage的第一个参数。

我们使用drawImage对img,在参数0,0坐标处进行渲染。 我们可以看到效果是,图形将按照元是的像素进行渲染。


let img = await loadImg(imgUrl);
let sw = img.width
let sh = img.height

ctx.drawImage(img, 0, 0)

我们可以设置一个缩放比例 将img的长宽高都进行缩放然后在进行渲染。

  
  let ZC = 0.2 // 缩放比例我们将缩放比例设置成20%
  
  // 在0,0这个点  按照缩放比例 ZC对图片进行渲染
  ctx.drawImage(img, 0, 0, sw * ZC, sh * ZC)
  

裁剪

drawImage 还有一个形变的公式,那就是裁剪

下面这段代码表示:

在图片宽度的43.6%高度的58%处截取 宽度为宽度的12.7%高度的24%的图形,放在画布的0,shZC高度处 按5050的大小显示出来

  ctx.drawImage(img,sw*0.236,sh*0.58,sw*0.127,sh*0.24,0,sh*ZC,50,50)

花瓣飘落动画

动画原理:

  1. 花瓣裁剪 我们首先定义一个花的类文件

    在这个文件中我们顶一个,Flows数组 讲生成花瓣之后的实例都存放在其中。

    另外实例的重点就是play方法讲水平移动 垂直移动的数值计算之后,

    使用我们的图片裁剪裁剪出一朵花瓣,最后在画布中运动。

    好,好这个类就定义完成了。

    看代码。



    let Flows = [] // 飘动雪花数组
    
    class Flow {
    
      constructor(x, y, w, img, sw, sh) {
        this.x = x
        this.y = y
        this.w = w
        this.img = img
        this.sw = sw
        this.sh = sh
        this.g = Math.random() * 3+1 // 重力加速度
        this.v = - (Math.random() * 2) // 水平移动速度
        Flows.push(this)
      }
    
      play() {
        let img = this.img
        let sw = this.sw
        let sh = this.sh
        this.x -= this.v
        this.y += this.g
    
        // 最初始值绘图
        ctx.drawImage(img,sw*0.236,sh*0.58,sw*0.127,sh*0.24,this.x, this.y,100*this.w/10,100*this.w/10)
    
        // 达到零界点清除
        if(this.y > canvas.height){
          this.clear()
        }
    
      }
    
      clear() {
        let index = Flows.indexOf(this)
        Flows.splice(index,1)
      }
    
    }

  1. 花瓣运动

    因为我们封装的图片加载是promise,我想使用异步的方式,

    我们顶一个了一个立即执行函数,在图片加载完成之后 ,我们开启生成花瓣的函数。

    没什么东西可以说的,理解了就很简单。

    看代码。


  let canvas = document.getElementById('canvas')
  let ctx = canvas.getContext('2d')
  canvas.height = window.innerHeight
  canvas.width = window.innerWidth
  
  let imgUrl = 'https://bloggers-1304641141.cos.ap-beijing.myqcloud.com/img/1631072101978.png'

  function loadImg(url) {
    return new Promise((resolve, reject) => {
      let img = new Image()
      img.onload = function () {
        resolve(img)
      }
      img.src = url
    })
  }

  ( async () => {
    let img = await loadImg(imgUrl);
    let sw = img.width
    let sh = img.height
    let ZC = 0.2
    let index = 0
    
    new Flow(Math.random() * canvas.width/2, 0, Math.random() * 8, img, sw, sh)
    new Flow(Math.random() * canvas.width/2, 0, Math.random() * 8, img, sw, sh)
    // 60帧每秒渲染
    setInterval(() => {
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      // // 生产花朵
      if (index % 50 === 0) {
        new Flow(Math.random() * canvas.width, 0, Math.random() * 4+3,img,sw,sh)
      }
      for (let i = 0; i < Flows.length; i++) {
        let element = Flows[i]
        element.play()
      }
      index++
    }, 1000 / 60)

  })()