在vue3中使用canvas实现雨滴效果

在vue3中使用canvas实现雨滴效果

这是封装的一个组件DotAndRain(

<script setup>
import { ref, onMounted } from "vue";
import { onUnmounted } from "vue";let animationFrameId = null;const el = ref(null);
let canvas = null;
let ctx = null;
let dots = [];
let rains = [];onMounted(() => {canvas = el.value;canvas.width = 162;canvas.height = 146;ctx = canvas.getContext("2d");draw();animate();
});onUnmounted(() => {cancelAnimationFrame(animationFrameId);
});function draw() {const positions = [[[54, 16], 10],[[28, 80], 80],[[130, 114], 120]];for (const arr of positions) {const dot = new Dot(...arr[0]);dot.draw();dots.push(dot);const rain = new Rain(arr[1]);rain.draw();rains.push(rain);}
}function animate() {ctx.clearRect(0, 0, canvas.width, canvas.height);dots.forEach((dot) => {dot.move();});rains.forEach((rain) => {rain.move();});animationFrameId = requestAnimationFrame(animate);
}class Dot {radius = 3;speed = 0.08;range = 10;angle = Math.random() * Math.PI * 2;constructor(x, y) {this.x = x;this.y = y;this.originX = x;this.originY = y;}draw() {ctx.beginPath();ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);const line = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.radius);line.addColorStop(0, "#fff");line.addColorStop(1, "#62E9F9");ctx.fillStyle = line;// ctx.fillStyle = "#62E9F9";ctx.fill();ctx.closePath();}move() {// 计算下一个位置const nextX = this.x + Math.cos(this.angle) * this.speed;const nextY = this.y + Math.sin(this.angle) * this.speed;// 判断是否超出边界if (nextX > this.originX - this.range && nextX < this.originX + this.range && nextY > this.originY - this.range && nextY < this.originY + this.range) {this.x = nextX;this.y = nextY;} else {// 如果超出边界,则随机生成新的角度this.angle = Math.random() * Math.PI * 2;}this.draw();}
}class Rain {alpha = 0.8;width = 2;y = canvas.height;constructor(x) {this.x = x;this.init();}init() {this.alpha = 1;this.speed = Math.random() + 1;this.height = Math.random() * 40 + 30;this.y = canvas.height;}draw() {ctx.beginPath();ctx.lineWidth = 3; //宽度// ctx.globalAlpha = this.alpha; //设置透明度//创建横向渐变颜色,起点坐标至终点坐标const line = ctx.createLinearGradient(this.x, this.y, this.x + this.width, this.y + this.height);line.addColorStop(0, `rgba(62, 192, 255, ${this.alpha})`);line.addColorStop(0.6, `rgba(62, 192, 255, ${this.alpha / 2})`);line.addColorStop(1, "transparent");ctx.strokeStyle = line;ctx.moveTo(this.x, this.y);ctx.lineTo(this.x, this.y + this.height);ctx.closePath();ctx.stroke();}move() {this.alpha -= 0.01;this.y -= this.speed;if (this.y < 0) {this.init();}this.draw();}
}
</script><template><canvas ref="el" style="width: 162px; height: 146px"></canvas>
</template><style scoped lang="scss"></style>

上述代码实现了一个简单的雨滴效果,主要包括绘制雨滴和下落动画两个部分。下面我会详细解释代码中涉及到的关键部分:

1.初始化和绘制:

  • draw() 函数中,首先定义了三个雨滴和雨点的初始位置和大小,并通过循环创建了对应数量的 DotRain 对象,并调用它们的draw() 方法进行绘制。
  • Dot 类用于绘制雨滴的水滴效果,包括设置半径、速度、范围、角度等属性,并实现了 draw()move()
    方法来绘制和移动雨滴。
  • Rain 类用于绘制雨滴的下落效果,包括设置透明度、宽度、高度等属性,并实现了 init()draw()move()
    方法来初始化、绘制和控制雨滴的下落。

2.动画循环:

  • animate() 函数中,使用 requestAnimationFrame()
    创建了一个动画循环,不断清除画布内容并重新绘制雨滴和雨点,实现动态效果。
  • 在每一帧中,分别调用雨滴和雨点对象的 move() 方法,更新它们的位置和状态,并重新绘制在画布上。

3.雨滴效果绘制:

  • Dot 类通过绘制圆形并利用径向渐变填充,实现了水滴的效果,颜色由白色渐变为蓝色。
  • Rain 类通过绘制线条并利用线性渐变描边,实现了雨滴的下落效果,颜色从蓝色透明度逐渐减小到透明。

在App.vue文件中直接使用即可

<script setup>
import assets from '/src/assets/assets_item.png';
import DotAndRain from './components/DotAndRain.vue';
</script><template><div style="position: relative;width: 162px; height: 146px;"><div class="item-shadow"></div><div class="item-bg"></div><DotAndRain/></div>
</template><style scoped>
/* 电子围墙 */
.item-bg {background-image: url("/src/assets/assets_item.png");width: 162px;height: 146px;position: absolute;z-index: 4;
}.item-shadow::before {content: "";position: absolute;left: 0;bottom: 40px;width: 100%;height: 0;z-index: 2;background-image: linear-gradient(0deg, rgba(21, 54, 90, 1), transparent);background-repeat: repeat-y;background-size: 100% 100%;animation: wall 3s linear infinite;
}.item-shadow::after {content: "";position: absolute;left: 0;bottom: 40px;width: 100%;height: 0;z-index: 3;background-image: linear-gradient(0deg, rgba(21, 54, 90, 1), transparent);background-repeat: repeat-y;background-size: 100% 100%;animation: wall 3s linear infinite 1.5s;
}@keyframes wall {0% {height: 0;}20% {opacity: 1;}60% {height: calc(100% - 50px);}100% {opacity: 0;}
}
</style>

实现效果如下:

cavans实现雨滴

cavans快速入门

1.创建cavans

<script setup>
</script><template><div><canvas ref="canvas" height="600px" width="600px"></canvas></div>
</template><style scoped>
canvas {border: 1px solid #ccc;
}

在这里插入图片描述
2.获取CanvasRenderingContext2D对象进行绘制

  • 给canvas添加一个ref属性:
<canvas ref="canvas" height="300px" width="300px"></canvas>
  1. 获取canvas对象:
<script setup>
import { ref} from 'vue';const canvas = ref(null);
</script>
  • 渲染完成后获取CanvasRenderingContext2D对象:
<script setup>
import { ref, onMounted } from 'vue';const canvas = ref(null);
onMounted(() => {const ctx = canvas.value.getContext('2d');
});
</script>
  • 直线、圆圈、圆弧的绘制:
    具体请参考HTML Canvas参考手册
<script setup>
import { ref, onMounted } from 'vue';
const canvas = ref(null);onMounted(() => {const ctx = canvas.value.getContext('2d');//直线绘制// ctx.moveTo(100, 100);// ctx.lineTo(200, 200);// ctx.stroke();//圆圈绘制ctx.beginPath();ctx.arc(100, 75, 50, 0, 2 * Math.PI);ctx.stroke();//圆弧绘制// ctx.beginPath();// ctx.arc(100,75,50,90/180*Math.PI,2*Math.PI);// ctx.stroke();
});
</script>

完整模板如下:

<script setup>
import { ref, onMounted } from 'vue';
const canvas = ref(null);onMounted(() => {const ctx = canvas.value.getContext('2d');ctx.beginPath();ctx.arc(100, 75, 50, 0, 2 * Math.PI);ctx.stroke();
});
</script><template><div><canvas ref="canvas" height="300px" width="300px"></canvas></div>
</template><style scoped>
canvas {border: 1px solid #ccc;
}
</style>

效果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/484132.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

⭐北邮复试刷题LCR 052. 递增顺序搜索树__DFS (力扣119经典题变种挑战)

LCR 052. 递增顺序搜索树 给你一棵二叉搜索树&#xff0c;请 按中序遍历 将其重新排列为一棵递增顺序搜索树&#xff0c;使树中最左边的节点成为树的根节点&#xff0c;并且每个节点没有左子节点&#xff0c;只有一个右子节点。 示例 1&#xff1a; 输入&#xff1a;root [5,…

论文学习 BioNeRF: Biologically Plausible Neural Radiance Fields for View Synthesis

论文学习 BioNeRF: Biologically Plausible Neural Radiance Fields for View Synthesis 前言简介NeRF介绍BioNeRF位置编码提取感知过滤记忆更新纹理推断损失函数 量化验证总结 前言 虽然我不应该再看NeRF相关的东西了&#xff0c;但是我还是觉得这个论文的题目很有意思&#…

一文穿透线程池,从此吊打面试官

目录 一、什么是线程池&#xff1f; 为什么要使用它&#xff1f; 二、什么是Executor框架&#xff1f; 三、什么是阻塞队列&#xff1f;如何使用阻塞队列来实现生产者-消费者模型&#xff1f; 四、常见线程池的快捷创建方式 五、为什么不建议使用 Executors静态工厂构建线…

六、回归与聚类算法 - 欠拟合和过拟合

目录 1、定义 2、原因及解决方法 2.1 正则化 线性回归欠拟合与过拟合线性回归的改进 - 岭回归分类算法&#xff1a;逻辑回归模型保存与加载无监督学习&#xff1a;K-means算法 1、定义 2、原因及解决方法 2.1 正则化

windows极限摸鱼软件(仅6678kb)

时间过得真快啊&#xff0c;不知不觉春节假期就过完了。你已经开始工作了吗&#xff1f;反正我是一直没闲着。 歇的时间久了&#xff0c;一上班这节奏很难一下子转换过来。也可能刚上班&#xff0c;没什么事情做&#xff0c;有点无聊。 &#xff08;好吧&#xff0c;我承认了…

外卖柜平台的设计与实现以及实践与总结

近年来&#xff0c;外卖行业的快速发展推动了外卖配送行业的进步和创新。外卖柜平台作为一种新兴的配送方式&#xff0c;在提高配送效率和服务质量方面具有很大的优势。本文将探讨美团外卖柜平台的设计与实现&#xff0c;以及如何保障其稳定性和安全性。 架构设计 美团外柜平台…

2024最佳住宅代理IP服务商

跨境出海已成为了近几年的最热趋势&#xff0c;大批量的企业开始开拓海外市场&#xff0c;而海外电商领域则是最受欢迎的切入口。新兴的tiktok、Temu&#xff0c;老牌的Amazon、Ebay&#xff0c;热门的Etsy、Mecari等等都是蓝海一片。跨境入门并不难&#xff0c;前期的准备中不…

【鸿蒙 HarmonyOS 4.0】TypeScript开发语言

一、背景 HarmonyOS 应用的主要开发语言是 ArkTS&#xff0c;它由 TypeScript&#xff08;简称TS&#xff09;扩展而来&#xff0c;在继承TypeScript语法的基础上进行了一系列优化&#xff0c;使开发者能够以更简洁、更自然的方式开发应用。值得注意的是&#xff0c;TypeScrip…

2/22作业

1.按位置插入 void insert_pos(seq_p L,datetype value,int pos) { if(LNULL) { printf("入参为空\n"); return; } if(seq_full(L)) { printf("表已满\n"); return; } if(pos>L->len|…

MATLAB 导出可编辑的eps格式图像

任务描述&#xff1a;部分期刊要求提交可编辑的eps格式图像&#xff0c;方便美工编辑对图像进行美化 我试了直接print或者在figure窗口导出&#xff0c;发现导出的文件放到Adobe AI中并不能编辑&#xff0c;经Google找到解决办法&#xff1a; %EPS exportgraphics(gcf,myVect…

鱼哥赠书活动第⑧期:《基础软件之路:企业级实践及开源之路》

鱼哥赠书活动第⑧期&#xff1a;《基础软件之路&#xff1a;企业级实践及开源之路》 作者介绍&#xff1a;1.静态分析工具在当前软件开发流程中的应用2.编译相关技术在静态分析工具中的应用3.编译相关技术在提升软件质量和性能上的更多应用4. 未来展望图书推荐&#xff1a;赠书…

分析型数据库(Apache Doris)是如何实现高效的数据更新?

SelectDB 是基于 Apache Doris &#xff08;分析型数据库&#xff09;构建的现代化数据仓库&#xff0c;支持大规模实时数据上的极速查询分析&#xff0c;主要用于 OLAP 场景下对大规模数据进行快速分析和查询&#xff0c;它支持多维分析、实时查询、增量更新、高效的数据更新等…