自己实现一个樱花🌸落下的动态-学校的樱花开了,让我们一起去看看吧
樱花🌸落下的动态
最近看到了一个樱花满地飞的视频,于是看到有大佬想着自己用html实现这样一个页面,然后我也去学习学习!其实,主要实现的原理,就是通过canvas画图,将很多樱花随机的生成在不同位置,然后每一帧的时候位置慢慢发生改变!
先看效果
其中里面掉落的樱花就是我们自己通过canvas做出来的。
先看整体布局
可以看到我们只是单纯的设置了一个canvas对象,然后设置了一下背景图片充当背景。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>樱花背景</title>
<style>
body{
background-image: url(https://gitee.com/unfortunately-there-is-no-if/img/raw/master/Image/bg.webp);
background-repeat: no-repeat;
background-size:cover;
}
</style>
</head>
<body>
<canvas></canvas>
</body>
<script src="./script.js"></script>
</html>
js代码
这段代码实现了一个美丽的樱花飘落的效果。它会在页面中生成一个 canvas 元素,然后使用 Canvas API 来绘制樱花(花瓣),并在绘制过程中实现花瓣的飘落效果。除此之外,它还根据鼠标位置来调整花瓣的飘落速度和位置,使整个效果更加动态。
这段代码主要分为三个部分。第一部分是创建了一个 canvas 元素,设置了它的宽高,同时获取了 2D 绘图环境。第二部分是创建了一个樱花类(Sakura),并通过构造函数来初始化每个樱花的位置、速度、透明度等属性。这些属性可以随机生成,使得每个花瓣都有一些差异,增加了整个效果的美感。第三部分是渲染函数(render),它会在每一帧调用樱花类的 animate 方法来更新樱花的位置和状态,并在更新后再次调用 draw 方法来绘制相应的花瓣。
// 获取canvas元素
const canvas = document.querySelector('canvas');
// 设置canvas画布的宽高为浏览器视口宽高
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 使用2d的绘图方式
const ctx = canvas.getContext('2d');
// 定义花瓣的数量
const SAKURA_SUM = 220;
// 花瓣数组
const sakuraArray = [];
/**
* 定义花瓣类
*/
class Sakura {
// 构造方法
constructor() {
// 随机生成花瓣的x, y坐标
this.x = Math.random() * canvas.width;
this.y = (Math.random() * canvas.height * 2) - canvas.height;
// 随机生成花瓣的宽高
this.width = Math.random() * 15 + 30;
this.height = Math.random() * 12 + 25;
// 随机透明度
this.opacity = this.width / 50;
// 设置一个随机数,后面实现旋转角度效果时会用到
this.rotate = Math.random();
// 速度初始化
this.xSpeed = Math.random() * 2 + 1;
this.ySpeed = Math.random() + 1.5;
this.rotateSpeed = Math.random() * 0.02;
}
// 绘制
draw() {
// 当花瓣超过canvas画布边界后,重新设置花瓣的坐标、速度、和转速
// 实现花瓣连续飘落的效果
if (this.x > canvas.width || this.y > canvas.height) {
this.x = -sakuraImg.width; // 刚好藏住
this.y = (Math.random() * canvas.height * 2) - canvas.height;
this.rotate = Math.random();
this.rotateSpeed = Math.random() * 0.02;
this.xSpeed = Math.random() * 2 + 0.5;
this.ySpeed = Math.random() + 1;
}
// ctx.globalAlpha 为 canvas 全局透明度设置基准值,实现绘制出来的花瓣具有透明度效果
ctx.globalAlpha = this.opacity;
// 随机旋转花瓣旋转角度,cos和sin的范围均为[-1, 1],加入调整系数,保证花瓣变形可控
const cos = Math.cos(this.rotate) * [0.2, 0.6][Math.floor(Math.random() * 2)];
const sin = Math.sin(this.rotate) * [0.2, 0.6][Math.floor(Math.random() * 2)];
// 绘制花瓣,将canvas坐标系的原点设置在花瓣的左上角
ctx.setTransform(cos, sin, -sin, cos, this.x, this.y);
ctx.drawImage(
sakuraImg,
0,
0,
this.width * [0.6, 0.8][Math.floor(Math.random() * 2)],
this.height * [0.6,0.8][Math.floor(Math.random() * 2)]
);
ctx.setTransform(1, 0, 0, 1, 0, 0); // 重置canvas坐标系为初始状态
}
// 花瓣动画
animate() {
// 修改花瓣的属性,使花瓣位置发生变化
this.x += this.xSpeed + mouseX * 5;
this.y += this.ySpeed + mouseX * 2;
this.rotate += this.rotateSpeed;
// 绘制花瓣
this.draw();
}
}
/**
* 定义渲染方法
*/
function render() {
// 使用clearRect方法清除画布内的内容,以便下一次绘制新的内容
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 遍历花瓣数组,进行花瓣动画绘制
sakuraArray.forEach(sakura => sakura.animate());
// 使用requestAnimationFrame方法进行高效的动画渲染,保证在浏览器的刷新频率下去更新动画
window.requestAnimationFrame(render);
}
// 加载花瓣图片
const sakuraImg = new Image();
sakuraImg.src = 'https://gitee.com/unfortunately-there-is-no-if/img/raw/master/Image/sakura.png';
// 等花瓣图片加载完毕,将数目为SAKURA_SUM的花瓣实例保存到数组中
sakuraImg.addEventListener('load', () => {
for (let i = 0; i < SAKURA_SUM; i++) {
sakuraArray.push(new Sakura())
}
// 开始渲染花瓣动画
render();
// 监听浏览器窗口大小变化,重新设置canvas的宽高
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
});
// 定义鼠标、触屏事件监听回调函数
let mouseX = 0;
function touchHandler(e) {
// clinetX: 客户端区域的水平坐标 (与页面坐标不同)
// 修改鼠标在窗口中的位置,使花瓣在飘动时受到鼠标位置的影响
mouseX = (e.clientX || e.touches[0].clientX) / window.innerWidth;
}
// 监听鼠标移动事件和触屏移动事件
window.addEventListener('mousemove', touchHandler);
window.addEventListener('touchmove', touchHandler);
源码
转载自:https://juejin.cn/post/7227850227251494969