Canvas如何实现樱花雨

Canvas如何实现樱花雨

一、前言

hi~大家好,我是冰糖。这篇博客是我2023年第一篇博客,在这里先定一个小目标:2023年成为优秀的前端开发者和博主。

那么好,今天我带大家完成一个Canvas的小案例——樱花落。下面是效果图:

在这里插入图片描述

看起来还不错,究竟是怎么实现的呢?我为大家分布讲解

二、定义画布

第一步,初始化画布以及上下文ctx

function startDraw() {
  // 定义画布
  let canvas = document.querySelector("canvas"), ctx;

  // 初始化画布的宽高
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  ctx = canvas.getContext("2d");

  ctx.save() // 保存初始的状态:这一步对后面有用
  ....
}

三、绘制单个花瓣

这里介绍canvas绘制图片的方法。参考链接

let img = new Image();
img.src = "img/huaban.png";

ctx.drawImage(img,0,0,40,40)
// 图片加载完成时开始画
img.onload = function () {
  startDraw()
}

四、定义花瓣类

function huaban(x, y, s, r) {
  this.x = x
  this.y = y
  this.s = s
  this.r = r
}
huaban.prototype.draw = function (ctx) {
  ctx.translate(this.x, this.y)
  ctx.rotate(this.r)
  ctx.drawImage(img, 0, 0, 40 * this.s, 40 * this.s)

  ctx.restore()
  ctx.save()
}
function huabanList() {
  this.list = []
}
huabanList.prototype.draw = function (ctx) {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  this.list.forEach((item) => {
    item.draw(ctx)
  })
}
huabanList.prototype.push = function (item) {
  this.list.push(item)
}
huabanList.prototype.update = function () {
  this.list.forEach((item) => {
    item.update()
  })
}

五、绘制花瓣

通过给定每一个花瓣下所在的坐标(x,y),大小s,以及旋转角度r,绘制出num多少的花瓣

let num = 100
let stop
let newHuabanList = new huabanList()

function startDraw() {
  // 定义画布
  let canvas = document.querySelector("canvas"), ctx;

  // 初始化画布的宽高
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  ctx = canvas.getContext("2d");

  ctx.save()

  // 生成花瓣
  for (let i = 0; i < num; i++) {
    let randomX, randomY, randomS, randomR, newHuaban;
    randomX = getRandom("x");
    randomY = getRandom("y");
    randomR = getRandom("r");
    randomS = getRandom("s");
    newHuaban = new huaban(randomX, randomY, randomS, randomR);
    newHuabanList.push(newHuaban);
  }
  ctx.clearRect(0, 0, window.innerWidth, window.innerHeight)
  // 画花瓣
  newHuabanList.draw(ctx)
  // 动画
  ...待完成
}

function getRandom(option) {
  var ret, random;
  switch (option) {
    case "x":
      // x轴随机坐标
      ret = Math.random() * window.innerWidth;
      break;
    case "y":
      // y轴随机坐标
      ret = Math.random() * window.innerHeight;
      break;
    case "s":
      ret = Math.random();
      break;
    case "r":
      ret = Math.random() * 6;
      break;
	...
  }
  return ret;
}

六、添加动画

上一步完成后花瓣分布在屏幕随机位置,但是并没有移动,我们通过requestAnimationFrame()clearRect()清除画布,然后更新每个花瓣位置,再绘制一遍,递归完成(还需要特判花瓣是否超出屏幕)

function startDraw() {
  ....
  // 动画
  stop = requestAnimationFrame(function () {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
    newHuabanList.update(); // 更新
    newHuabanList.draw(ctx); // 绘制
    stop = requestAnimationFrame(arguments.callee); // 递归重绘
  });
}
// 更新位置
huaban.prototype.update = function () {
  this.x = getRandom("fnx")(this.x, this.y)
  this.y = getRandom("fny")(this.x, this.y)
  this.r = getRandom("fnr")(this.r)
  if (
    // 判断是否超出边界
    this.x > window.innerWidth ||
    this.x < 0 ||
    this.y > window.innerHeight ||
    this.y < 0
  ) {
    // 如果超出边界 则重新生成随机坐标
    this.r = getRandom("fnr");
    if (Math.random() > 0.4) {
      // 如果随机值大于0.4 则重新生成x轴随机坐标
      this.x = getRandom("x");
      this.y = 0;
      this.s = getRandom("s");
      this.r = getRandom("r");
    } else {
      // 如果随机值小于0.4 则重新生成y轴随机坐标
      this.x = window.innerWidth;
      this.y = getRandom("y");
      this.s = getRandom("s");
      this.r = getRandom("r");
    }
  }
}

function getRandom(option) {
  var ret, random;
  switch (option) {
    ...
    case "fnx":
      // x轴随机函数
      random = -0.1 + Math.random() * 1;
      ret = function (x, y) {
        return x + 0.5 * random - 1;
      };
      break;
    case "fny":
      // y轴随机函数
      random = 0.4 + Math.random() * 0.7;
      ret = function (x, y) {
        return y + random;
      };
      break;
    case "fnr":
      // r轴随机函数
      random = Math.random() * 0.02;
      ret = function (r) {
        return r + random;
      };
      break;
  }
  return ret;
}

总结

  1. 完成此案例,得先知道一个花瓣怎么绘制到多个,到动起来
  2. 坑:确定画布大小后需要ctx.save()对画布初始进行保存,后续更改画布位置,比如:旋转,移动后。都需要对画布还原ctx.restore()

最后,留一个源码地址供大家参考源代码,也感谢各位的star和点赞。感谢您的支持!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
CanvasHTML5中新增的元素,它可以用来在网页上绘制图形,制作动画等。通过JavaScript脚本,我们可以在Canvas上绘制各种图形,如线条、矩形、圆形、文字等。CanvasCanvasHTML5中新增的元素,它可以用来在网页上绘制图形,制作动画等。通过JavaScript脚本,我们可以在Canvas上绘制各种图形,如线条、矩形、圆形、文字等。Canvas的绘图原理是在网页上创建一个画布,然后通过JavaScript脚本来控制画布上的像素,从而实现各种绘图效果。Canvas的使用非常灵活,可以通过CSS样式来设置画布的大小和位置,也可以通过JavaScript脚本来动态地改变画布的属性和内容。 下面是一个简单的Canvas绘图示例: 引用: <canvas id="tutorial" width="300" height="300"></canvas> <script type="text/javascript"> function draw(){ var canvas = document.getElementById('tutorial'); if(!canvas.getContext) return; var ctx = canvas.getContext("2d"); //开始代码 ctx.fillStyle = "red"; ctx.fillRect(10, 10, 50, 50); //结束代码 } draw(); </script> 这段代码创建了一个300x300的Canvas画布,并在画布上绘制了一个红色的矩形。其中,ctx是Canvas的上下CanvasHTML5中新增的元素,它可以用来在网页上绘制图形,制作动画等。通过JavaScript脚本,我们可以在Canvas上绘制各种图形,如线条、矩形、圆形、文字等。Canvas的绘图原理是在网页上创建一个画布,然后通过JavaScript脚本来控制画布上的像素,从而实现各种绘图效果。Canvas的使用非常灵活,可以通过CSS样式来设置画布的大小和位置,也可以通过JavaScript脚本来动态地改变画布的属性和内容。 下面是一个简单的Canvas绘图示例: 引用: <canvas id="tutorial" width="300" height="300"></canvas> <script type="text/javascript"> function draw(){ var canvas = document.getElementById('tutorial'); if(!canvas.getContext) return; var ctx = canvas.getContext("2d"); //开始代码 ctx.fillStyle = "red"; ctx.fillRect(10, 10, 50, 50); //结束代码 } draw(); </script> 这段代码创建了一个300x300的Canvas画布,并在画布上绘制了一个红色的矩形。其中,ctx是Canvas的上下文对象,通过它可以控制画布上的像素。 另外,Canvas还可以通过JavaScript脚本来实现动态效果,如引用所示。这段代码创建了一个1000x1000的Canvas画布,并通过JavaScript脚本来实现动态效果。 引用展示了如何使用for循环来实现Canvas的绘图。在这段代码中,我们使用循环来重复绘制一条线段,从而实现了一种简单的图形效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰镇白干

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值