This article mainly introduces and introduces Canvas to achieve dazzling particle motion effects (particles generate text). The editor thinks it is quite good, so I will share it with you now and give it as a reference. Let’s follow the editor to take a look, I hope it can help everyone.
Go directly to the code. If you don’t understand, you can read the code comments. You will probably understand the general idea.
html Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas 实现炫丽的粒子运动效果-云库前端</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
canvas {
display: block;
background: #000;
}
body::-webkit-scrollbar{
display: none;
}
.operator-box{
position: fixed;
top: 0;
left: 50%;
border: 1px solid #fff;
background: rgba(255,255,255,0.5);
padding: 20px 10px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.back-type,.back-animate{
margin-right: 20px;
}
.flex-box{
display: flex;
justify-content: center;
align-items: center;
}
#input-text{
line-height: 35px;
width: 260px;
height: 35px;
background: rgba(0, 0, 0,0.7);
color: #fff;
font-size: 16px;
border: none;
outline: none;
text-indent: 12px;
box-shadow: inset 0 0 12px 1px rgba(0,0,0,0.7);
}
#input-text::placeholder{
color: #ccc;
line-height: 55px;
height: 55px;
}
select{
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: none;
padding: 0px 20px 0px 6px;
height: 35px;
color: #fff;
text-align: left;
background: rgba(0, 0, 0,0.7) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAICAYAAAAx8TU7AAAAOUlEQ…R4gPgWEIMAiOYBCS4C8ZDAIrBq4gigNkztQEFMi6AuQHESAPMeXiEMiWfpAAAAAElFTkSuQmCC) no-repeat 190px 12px;
background-size: 5px 8px;
box-shadow: inset 0 0 12px 1px rgba(0,0,0,0.7);
}
</style>
</head>
<body>
<p class="operator-box">
<p class="flex-box">
<p class="back-type">散开类型:
<select name="" id="selectType">
<option value="back">归位</option>
<option value="auto">随机</option>
</select>
</p>
<p class="back-animate">散开效果(对归位有效):
<select class="back-dynamics" id="selectDynamics">
<option value="spring">dynamics.spring</option>
<option value="bounce">dynamics.bounce</option>
<option value="forceWithGravity">dynamics.forceWithGravity</option>
<option value="gravity">dynamics.gravity</option>
<option value="easeInOut">dynamics.easeInOut</option>
<option value="easeIn">dynamics.easeIn</option>
<option value="easeOut">dynamics.easeOut</option>
<option value="linear">dynamics.linear</option>
</select>
</p>
<p class="input-box"><input type="text" placeholder="输入汉字后回车" id="input-text"></p>
</p>
</p>
<script src="dynamics.min.js"></script>
<script src="index.js"></script>
<script>
var iCircle = new Circle();
</script>
</body>
</html>HTML code is not much, just a few operating elements. It’s easy to understand at a glance here. No need to waste too much words. Let’s take a look at the protagonist JavaScript code of this article. However, before looking at the code, we might as well listen to the idea of achieving this effect:
First, we have to generate a bunch of extras ( particles);
Hang the relevant parameters of each particle to some of its own attributes, because every particle will have its own trajectory;
-
Then you have to let them move individually. There are two types of motion (free motion and text-generated motion);
The JavaScript code uses three Canvas canvases, this.iCanvas (home page), this.iCanvasCalculate (used to calculate Text width), this.iCanvasPixel (used to draw text and obtain the position coordinates of the pixel corresponding to the text).
this.iCanvasCalculate and this.iCanvasPixel do not need to be displayed on the page, they are just auxiliary functions.
The following is a great JS implementation code
function Circle() {
var This = this;
this.init();
this.generalRandomParam();
this.drawCircles();
this.ballAnimate();
this.getUserText();
// 窗口改变大小后,生计算并获取画面
window.onresize = function(){
This.stateW = document.body.offsetWidth;
This.stateH = document.body.offsetHeight;
This.iCanvasW = This.iCanvas.width = This.stateW;
This.iCanvasH = This.iCanvas.height = This.stateH;
This.ctx = This.iCanvas.getContext("2d");
}
}
// 初始化
Circle.prototype.init = function(){
//父元素宽高
this.stateW = document.body.offsetWidth;
this.stateH = document.body.offsetHeight;
this.iCanvas = document.createElement("canvas");
// 设置Canvas 与父元素同宽高
this.iCanvasW = this.iCanvas.width = this.stateW;
this.iCanvasH = this.iCanvas.height = this.stateH;
// 获取 2d 绘画环境
this.ctx = this.iCanvas.getContext("2d");
// 插入到 body 元素中
document.body.appendChild(this.iCanvas);
this.iCanvasCalculate = document.createElement("canvas");
// 用于保存计算文字宽度的画布
this.mCtx = this.iCanvasCalculate.getContext("2d");
this.mCtx.font = "128px 微软雅黑";
this.iCanvasPixel = document.createElement("canvas");
this.iCanvasPixel.setAttribute("style","position:absolute;top:0;left:0;");
this.pCtx = null; // 用于绘画文字的画布
// 随机生成圆的数量
this.ballNumber = ramdomNumber(1000, 2000);
// 保存所有小球的数组
this.balls = [];
// 保存动画中最后一个停止运动的小球
this.animte = null;
this.imageData = null;
this.textWidth = 0; // 保存生成文字的宽度
this.textHeight = 150; // 保存生成文字的高度
this.inputText = ""; // 保存用户输入的内容
this.actionCount = 0;
this.ballActor = []; // 保存生成文字的粒子
this.actorNumber = 0; // 保存生成文字的粒子数量
this.backType = "back"; // 归位
this.backDynamics = ""; // 动画效果
this.isPlay = false; // 标识(在生成文字过程中,不能再生成)
}
// 渲染出所有圆
Circle.prototype.drawCircles = function () {
for(var i=0;i<this.ballNumber;i++){
this.renderBall(this.balls[0]);
}
}
// 获取用户输入文字
Circle.prototype.getUserText = function(){
This = this; // 保存 this 指向
ipu = document.getElementById("input-text");
ipu.addEventListener("keydown",function(event){
if(event.which === 13){ // 如果是回车键
ipu.value = ipu.value.trim(); // 去头尾空格
var pat = /[\u4e00-\u9fa5]/; // 中文判断
var isChinese = pat.test(ipu.value);
if(ipu.value.length !=0 && isChinese){
This.inputText = ipu.value;
}else{
alert("请输入汉字");
return;
}
if(This.isPlay){
return
}
This.getAnimateType();
This.getTextPixel();
This.isPlay = true;
}
});
}
// 计算文字的宽
Circle.prototype.calculateTextWidth = function () {
this.textWidth = this.mCtx.measureText(this.inputText).width;
}
// 获取文字像素点
Circle.prototype.getTextPixel = function () {
if(this.pCtx){
this.pCtx.clearRect(0,0,this.textWidth,this.textHeight);
}
this.calculateTextWidth(this.inputText);
this.iCanvasPixel.width = this.textWidth;
this.iCanvasPixel.height = this.textHeight;
this.pCtx = this.iCanvasPixel.getContext("2d");
this.pCtx.font = "128px 微软雅黑";
this.pCtx.fillStyle = "#FF0000";
this.pCtx.textBaseline = "botom";
this.pCtx.fillText(this.inputText,0,110);
this.imageData = this.pCtx.getImageData(0,0,this.textWidth,this.textHeight).data;
this.getTextPixelPosition(this.textWidth,this.textHeight);
}
// 获取文字粒子像素点位置
Circle.prototype.getTextPixelPosition = function (width,height) {
var left = (this.iCanvasW - width)/2;
var top = (this.iCanvasH - height)/2;
var space = 4;
this.actionCount = 0;
for(var i=0;i<this.textHeight;i+=space){
for(var j=0;j<this.textWidth;j+=space){
var index = j*space+i*this.textWidth*4;
if(this.imageData[index] == 255){
if(this.actionCount<this.ballNumber){
this.balls[this.actionCount].status = 1;
this.balls[this.actionCount].targetX = left+j;
this.balls[this.actionCount].targetY = top+i;
this.balls[this.actionCount].backX = this.balls[this.actionCount].x;
this.balls[this.actionCount].backY = this.balls[this.actionCount].y;
this.ballActor.push(this.balls[this.actionCount]);
this.actionCount++;
}
}
}
this.actorNumber = this.ballActor.length;
}
this.animateToText();
}
// 粒子运动到指定位置
Circle.prototype.animateToText = function(){
for(var i=0;i<This.actorNumber;i++){
dynamics.animate(This.ballActor[i], {
x: this.ballActor[i].targetX,
y: this.ballActor[i].targetY
},{
type: dynamics.easeIn,
duration: 1024,
});
}
setTimeout(function(){
This.ballbackType();
},3000);
}
// 粒子原路返回
Circle.prototype.ballBackPosition = function(){
for(var i=0;i<This.actorNumber;i++){
var ball = This.ballActor[i];
dynamics.animate(ball, {
x: ball.backX,
y: ball.backY
},{
type: dynamics[this.backDynamics],
duration: 991,
complete:this.changeStatus(ball)
});
}
}
// 获取类型|动画效果
Circle.prototype.getAnimateType = function() {
var selectType = document.getElementById("selectType");
var selectDynamics = document.getElementById("selectDynamics");
this.backType = selectType.options[selectType.options.selectedIndex].value;
this.backDynamics = selectDynamics.options[selectDynamics.options.selectedIndex].value;
}
// 复位散开
Circle.prototype.ballbackType = function(){
if(this.backType == "back"){
this.ballBackPosition();
}else{
this.ballAutoPosition();
}
this.ballActor = [];
}
// 随机散开
Circle.prototype.ballAutoPosition = function(ball){
for(var i=0;i<this.actorNumber;i++){
this.changeStatus(this.ballActor[i])
}
}
// 更改小球状态
Circle.prototype.changeStatus = function(ball){
ball.status = 0;
if(this.isPlay == true){
this.isPlay = false;
}
}
// 随机生成每个圆的相关参数
Circle.prototype.generalRandomParam = function(){
for(var i=0;i<this.ballNumber;i++){
var ball = {};
ball.size = 1; // 随机生成圆半径
// 随机生成圆心 x 坐标
ball.x = ramdomNumber(0+ball.size, this.iCanvasW-ball.size);
ball.y = ramdomNumber(0+ball.size, this.iCanvasH-ball.size);
ball.speedX = ramdomNumber(-1, 1);
ball.speedY = ramdomNumber(-1, 1);
this.balls.push(ball);
ball.status = 0;
ball.targetX = 0;
ball.targetY = 0;
ball.backX = 0;
ball.backY = 0;
}
}
// 改变圆的位置
Circle.prototype.changeposition = function(){
for(var i=0;i<this.ballNumber;i++){
if( this.balls[i].status == 0){
this.balls[i].x += this.balls[i].speedX;
this.balls[i].y += this.balls[i].speedY;
}
}
}
// 画圆
Circle.prototype.renderBall = function(ball){
this.ctx.fillStyle = "#fff";
this.ctx.beginPath(); // 这个一定要加
this.ctx.arc(ball.x, ball.y, ball.size, 0, 2 * Math.PI);
this.ctx.closePath(); // 这个一定要加
this.ctx.fill();
}
// 小球碰撞判断
Circle.prototype.collision = function(ball){
for(var i=0;i<this.ballNumber;i++){
if(ball.x>this.iCanvasW-ball.size || ball.x<ball.size){
if(ball.x>this.iCanvasW-ball.size){
ball.x = this.iCanvasW-ball.size;
}else{
ball.x = ball.size;
}
ball.speedX = - ball.speedX;
}
if(ball.y>this.iCanvasH-ball.size || ball.y<ball.size){
if(ball.y>this.iCanvasH-ball.size){
ball.y = this.iCanvasH-ball.size;
}else{
ball.y = ball.size;
}
ball.speedY = - ball.speedY;
}
}
}
// 开始动画
Circle.prototype.ballAnimate = function(){
var This = this;
var animateFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
(function move(){
animte = animateFrame(move);
This.ctx.clearRect(0, 0, This.iCanvasW, This.iCanvasH);
This.changeposition();
for(var i=0;i<This.ballNumber;i++){
This.collision(This.balls[i]);
This.renderBall(This.balls[i]);
}
})();
}
// 生成一个随机数
function ramdomNumber(min, max) {
return Math.random() * (max - min) + min;
}After reading the code, I guess I just dazzled my heart, and it didn’t make you want to think about this thing. The desire to create it, for this I know it must be convinced by your eyes and mouth. Online DEMO: Dynamic particle example.
No one is perfect, and the same goes for code. It seems that the code that runs smoothly also has some flaws. Currently, this effect only supports Chinese. As for English, I have to work harder. No matter what, English will definitely join later, it’s just a matter of time. There is also the attribute in the code used to mark whether the generated text can be executed again: this.isPlay, which is still a little flaw. The state change of this.isPlay does not change exactly at the moment when the particles return, but changes the state in advance. But this state will not affect the complete implementation of the effect of this example.
This example uses the dynamics.js library, mainly using some motion functions in it to make the particles move more impressively, that's all.
Related recommendations:
The above is the detailed content of Canvas realizes dazzling particle motion effects. For more information, please follow other related articles on the PHP Chinese website!
How much specificity do @rules have, like @keyframes and @media?Apr 18, 2025 am 11:34 AMI got this question the other day. My first thought is: weird question! Specificity is about selectors, and at-rules are not selectors, so... irrelevant?
Can you nest @media and @support queries?Apr 18, 2025 am 11:32 AMYes, you can, and it doesn't really matter in what order. A CSS preprocessor is not required. It works in regular CSS.
Quick Gulp Cache BustingApr 18, 2025 am 11:23 AMYou should for sure be setting far-out cache headers on your assets like CSS and JavaScript (and images and fonts and whatever else). That tells the browser
In Search of a Stack That Monitors the Quality and Complexity of CSSApr 18, 2025 am 11:22 AMMany developers write about how to maintain a CSS codebase, yet not a lot of them write about how they measure the quality of that codebase. Sure, we have
Datalist is for suggesting values without enforcing valuesApr 18, 2025 am 11:08 AMHave you ever had a form that needed to accept a short, arbitrary bit of text? Like a name or whatever. That's exactly what is for. There are lots of
Front Conference in ZürichApr 18, 2025 am 11:03 AMI'm so excited to be heading to Zürich, Switzerland for Front Conference (Love that name and URL!). I've never been to Switzerland before, so I'm excited
Building a Full-Stack Serverless Application with Cloudflare WorkersApr 18, 2025 am 10:58 AMOne of my favorite developments in software development has been the advent of serverless. As a developer who has a tendency to get bogged down in the details
Creating Dynamic Routes in a Nuxt ApplicationApr 18, 2025 am 10:53 AMIn this post, we’ll be using an ecommerce store demo I built and deployed to Netlify to show how we can make dynamic routes for incoming data. It’s a fairly


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 Chinese version
Chinese version, very easy to use

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

Dreamweaver CS6
Visual web development tools

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

Zend Studio 13.0.1
Powerful PHP integrated development environment






