initial commit
This commit is contained in:
48
README.md
48
README.md
@@ -1,3 +1,49 @@
|
|||||||
# particle
|
# particle
|
||||||
|
|
||||||
HTML5中,采用JavaScript和Canvas实现运动粒子效果,兼容IE10+,chrome、safari等。
|
HTML5中,采用JavaScript和Canvas实现运动粒子效果,兼容IE10+,chrome、safari等。
|
||||||
|
|
||||||
|
本项目基于 [https://github.com/AnCIity/ui-login-canvas](https://github.com/AnCIity/ui-login-canvas) 修改
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
用法:
|
||||||
|
```javascript
|
||||||
|
var particle = new Particle({
|
||||||
|
canvas: document.getElementById('canvas'),
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
ballNumber: 100,
|
||||||
|
ballMinSize: 1,
|
||||||
|
ballMaxSize: 5,
|
||||||
|
fps: 24,
|
||||||
|
color: 'rgba(84, 23, 196, 0.75)'
|
||||||
|
});
|
||||||
|
|
||||||
|
particle.reDraw({
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
ballNumber: 100,
|
||||||
|
ballMinSize: 1,
|
||||||
|
ballMaxSize: 5,
|
||||||
|
color: 'rgba(84, 23, 196, 0.75)'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
方法:
|
||||||
|
|
||||||
|
| 方法名 | 方法数说明 |
|
||||||
|
| ------ | ------ |
|
||||||
|
|new Particle(options)|实例化粒子动画对象|
|
||||||
|
|instance.reDraw(options)|重绘粒子动画,此方法未new Particle()的实例对象上的方法|
|
||||||
|
|
||||||
|
参数options说明:
|
||||||
|
|
||||||
|
| 参数名 | 参数类型 | 参数说明 |
|
||||||
|
| ------ | ------ | ------ |
|
||||||
|
| canvas | HTMLCanvasElement | 即通过原生js获取到的canvas对象 |
|
||||||
|
| width | number | 粒子效果宽度,不设为自动获取canvas宽度 |
|
||||||
|
| height | number | 粒子效果高度,不设为自动获取canvas高度 |
|
||||||
|
| ballNumber | number | 粒子个数,越大越多,越多相对越卡 |
|
||||||
|
| ballMinSize | number | 粒子最小尺寸,粒子尺寸减少到此值后,反向缓慢增加到最大尺寸 |
|
||||||
|
| ballMaxSize | number | 粒子最大尺寸,粒子尺寸增加到此值后,反向缓慢减少到最小尺寸 |
|
||||||
|
| fps | number | 动画帧数,一半设为24就可以了 |
|
||||||
|
| color | string 或 string array | 粒子颜色,可为颜色字符串或颜色字符串数组,若为字符串数组,则为\[起始色,终止色],粒子颜色会在该范围内改变 |
|
||||||
|
|||||||
40
index.html
Executable file
40
index.html
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hans">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||||
|
<title>粒子效果</title>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #010223;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<script type="text/javascript" src="js/particle.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var particle = new Particle({
|
||||||
|
canvas: document.getElementById('canvas'),
|
||||||
|
fps: 24,
|
||||||
|
ballNumber: 100,
|
||||||
|
ballMinSize: 1,
|
||||||
|
ballMaxSize: 5,
|
||||||
|
color: 'rgba(84, 23, 196, 0.75)'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
299
js/particle.js
Executable file
299
js/particle.js
Executable file
@@ -0,0 +1,299 @@
|
|||||||
|
;
|
||||||
|
/*
|
||||||
|
* 原项目地址:https://github.com/AnCIity/ui-login-canvas
|
||||||
|
* 原作者:AnCity
|
||||||
|
* 修改:yhl452493373
|
||||||
|
* 不依赖外部库,仅使用canvas
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
/**
|
||||||
|
* 生成颜色范围内随机色
|
||||||
|
* https://stackoverflow.com/questions/25193110/random-color-between-two-selected-rgb-colors-javascript 最下方答案
|
||||||
|
* @param color1 颜色1
|
||||||
|
* @param color2 颜色2
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var randomColor = function (color1, color2) {
|
||||||
|
this.regs = {
|
||||||
|
"hex3": /^#([a-f\d])([a-f\d])([a-f\d])$/i,
|
||||||
|
"hex6": /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,
|
||||||
|
"rgb": /^rgb\s*\(\s*([\d.]+%?)\s*,\s*([\d.]+%?)\s*,\s*([\d.]+%?)\s*\)$/
|
||||||
|
};
|
||||||
|
|
||||||
|
this.colorObject1 = this.getValues(color1);
|
||||||
|
this.colorObject2 = this.getValues(color2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将传颜色字符串转为带rgb数值的对象
|
||||||
|
* @param color 颜色
|
||||||
|
* @returns 转换结果,若为false,则转换失败,说明颜色字符串错误
|
||||||
|
*/
|
||||||
|
randomColor.prototype.getValues = function (color) {
|
||||||
|
var values = false;
|
||||||
|
for (var prop in this.regs) {
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
if (this.regs[prop].test(color)) {
|
||||||
|
values = {};
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
values.r = color.replace(this.regs[prop], "$1");
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
values.g = color.replace(this.regs[prop], "$2");
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
values.b = color.replace(this.regs[prop], "$3");
|
||||||
|
if (prop === "rgb") {
|
||||||
|
values.r = Number(values.r);
|
||||||
|
values.g = Number(values.g);
|
||||||
|
values.b = Number(values.b);
|
||||||
|
} else {
|
||||||
|
values.r = parseInt(values.r, 16);
|
||||||
|
values.g = parseInt(values.g, 16);
|
||||||
|
values.b = parseInt(values.b, 16);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成随机色
|
||||||
|
* @returns {string|boolean}
|
||||||
|
*/
|
||||||
|
randomColor.prototype.getColor = function () {
|
||||||
|
if (this.colorObject1 && this.colorObject2) {
|
||||||
|
var random = Math.random();
|
||||||
|
var r = randomColor.getRandom(this.colorObject1.r, this.colorObject2.r, random);
|
||||||
|
var g = randomColor.getRandom(this.colorObject1.g, this.colorObject2.g, random);
|
||||||
|
var b = randomColor.getRandom(this.colorObject1.b, this.colorObject2.b, random);
|
||||||
|
return "#" + r + g + b;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串补位,如将a,左侧补位变为0a
|
||||||
|
*
|
||||||
|
* @param str 需要补位的字符串
|
||||||
|
* @param pad_length 补位后字符串的长度
|
||||||
|
* @param pad_string 用于补位的字符串
|
||||||
|
* @param pad_type 补位方式
|
||||||
|
* @returns {string|*}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
randomColor.str_pad = function (str, pad_length, pad_string, pad_type) {
|
||||||
|
var len = pad_length - str.length;
|
||||||
|
if (len < 0) {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
var pad = new Array(len + 1).join(pad_string);
|
||||||
|
if (pad_type === "STR_PAD_LEFT") {
|
||||||
|
return pad + str
|
||||||
|
}
|
||||||
|
return str + pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取R,G,B其中之一随机色范围
|
||||||
|
* @param color1 颜色1 R,G,B其中之一
|
||||||
|
* @param color2 颜色2 R,G,B其中之一
|
||||||
|
* @param percent 随机到的范围百分比
|
||||||
|
* @returns {string|*}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
randomColor.getRandom = function (color1, color2, percent) {
|
||||||
|
var color = color1 + Math.floor((color2 - color1) * percent);
|
||||||
|
if (color < 0)
|
||||||
|
color = 0;
|
||||||
|
return randomColor.str_pad(color.toString(16), 2, "0", "STR_PAD_LEFT");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义插件对象
|
||||||
|
*
|
||||||
|
* @param options {{
|
||||||
|
* canvas:HTMLCanvasElement
|
||||||
|
* width:number?,
|
||||||
|
* height:number?,
|
||||||
|
* ballNumber:number,
|
||||||
|
* ballMinSize:number,
|
||||||
|
* ballMaxSize:number,
|
||||||
|
* fps:number,
|
||||||
|
* color:string|[string,string]
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
var particle = function (options) {
|
||||||
|
this.ball = [];
|
||||||
|
this.canvas = options.canvas;
|
||||||
|
if (this.canvas.style.width !== '' || this.canvas.style.height !== '') {
|
||||||
|
throw new Error('请勿在粒子动效的canvas上的style中添加width,仅允许通过参数传递')
|
||||||
|
} else if (this.canvas.getAttribute('width') != null || this.canvas.getAttribute('height') != null) {
|
||||||
|
throw new Error('请勿在粒子动效的canvas上的添加width、height属性,仅允许通过参数传递')
|
||||||
|
}
|
||||||
|
this.canvas.width = options.width || parseInt(getComputedStyle(this.canvas).width);
|
||||||
|
this.canvas.height = options.height || parseInt(getComputedStyle(this.canvas).height);
|
||||||
|
this.canvas.style.width = this.canvas.width + 'px';
|
||||||
|
this.canvas.style.height = this.canvas.height + 'px';
|
||||||
|
this.context = this.canvas.getContext('2d');
|
||||||
|
this.ballNumber = options.ballNumber
|
||||||
|
this.ballMinSize = options.ballMinSize;
|
||||||
|
this.ballMaxSize = options.ballMaxSize;
|
||||||
|
this.color = options.color;
|
||||||
|
if (this.color instanceof Array) {
|
||||||
|
if (this.color.length > 1)
|
||||||
|
this.randomColor = new randomColor(this.color[0], this.color[1]);
|
||||||
|
else
|
||||||
|
this.color = options.color[0];
|
||||||
|
}
|
||||||
|
var that = this;
|
||||||
|
this.__draw(true);
|
||||||
|
self.setInterval(function () {
|
||||||
|
that.__draw(false);
|
||||||
|
}, 1000 / options.fps);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件重设方法
|
||||||
|
*
|
||||||
|
* @param options {{
|
||||||
|
* width:number?,
|
||||||
|
* height:number?,
|
||||||
|
* ballNumber:number?,
|
||||||
|
* ballMinSize:number?,
|
||||||
|
* ballMaxSize:number?,
|
||||||
|
* color:string?
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
particle.prototype.reDraw = function (options) {
|
||||||
|
if (options) {
|
||||||
|
if (options.hasOwnProperty('width')) {
|
||||||
|
this.canvas.width = options.width;
|
||||||
|
this.canvas.style.width = this.canvas.width+'px';
|
||||||
|
}
|
||||||
|
if (options.hasOwnProperty('height')) {
|
||||||
|
this.canvas.height = options.height;
|
||||||
|
this.canvas.style.height = this.canvas.height+'px';
|
||||||
|
}
|
||||||
|
if (options.hasOwnProperty('ballNumber'))
|
||||||
|
this.ballNumber = options.ballNumber;
|
||||||
|
if (options.hasOwnProperty('ballMinSize'))
|
||||||
|
this.ballMinSize = options.ballMinSize;
|
||||||
|
if (options.hasOwnProperty('ballMaxSize'))
|
||||||
|
this.ballMaxSize = options.ballMaxSize;
|
||||||
|
if (options.hasOwnProperty('color')) {
|
||||||
|
this.color = options.color;
|
||||||
|
if (this.color instanceof Array) {
|
||||||
|
if (this.color.length > 0)
|
||||||
|
this.randomColor = new randomColor(this.color[0], this.color[1]);
|
||||||
|
else
|
||||||
|
this.color = options.color[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.__draw(true);
|
||||||
|
} else {
|
||||||
|
this.canvas.style.width = '';
|
||||||
|
this.canvas.style.height = '';
|
||||||
|
this.canvas.width='';
|
||||||
|
this.canvas.height='';
|
||||||
|
this.canvas.width = parseInt(getComputedStyle(this.canvas).width);
|
||||||
|
this.canvas.height = parseInt(getComputedStyle(this.canvas).height);
|
||||||
|
this.canvas.style.width = this.canvas.width+'px';
|
||||||
|
this.canvas.style.height = this.canvas.height+'px';
|
||||||
|
this.__draw(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制点
|
||||||
|
* @param force 是否强制绘制。为true时,会清空并重新生成所有点并重新绘制点,用于初始化;为false时,不会重新生成点,会清空并重绘点
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
particle.prototype.__draw = function (force) {
|
||||||
|
//初始化小球数据
|
||||||
|
if (force) {
|
||||||
|
this.ball = [];
|
||||||
|
this.__ballConfigure();
|
||||||
|
}
|
||||||
|
|
||||||
|
//重绘canvas
|
||||||
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
var i = 0;
|
||||||
|
while (i < this.ballNumber) {
|
||||||
|
//绘制小球
|
||||||
|
this.context.beginPath();
|
||||||
|
if (this.ball[i].size > 0)
|
||||||
|
this.context.arc(this.ball[i].x, this.ball[i].y, this.ball[i].size, 0, Math.PI * 2, true);
|
||||||
|
this.context.closePath();
|
||||||
|
this.context.fillStyle = this.ball[i].color;
|
||||||
|
this.context.fill();
|
||||||
|
//赋予小球加速度
|
||||||
|
this.ball[i].x += this.ball[i].vx;
|
||||||
|
this.ball[i].y += this.ball[i].vy;
|
||||||
|
this.ball[i].size -= this.ball[i].sizeReduce;
|
||||||
|
if (this.ball[i].size < this.ballMinSize || this.ball[i].size <= 0) {
|
||||||
|
this.ball[i].size = this.ballMinSize;
|
||||||
|
this.ball[i].sizeReduce *= -1;
|
||||||
|
this.ball[i].color = this.__randomColor();
|
||||||
|
} else if (this.ball[i].size > this.ballMaxSize) {
|
||||||
|
this.ball[i].size = this.ballMaxSize;
|
||||||
|
this.ball[i].sizeReduce *= -1;
|
||||||
|
}
|
||||||
|
//防止小球出界
|
||||||
|
if (this.ball[i].x <= 0 || this.ball[i].x >= this.canvas.width) {
|
||||||
|
this.ball[i].vx = -this.ball[i].vx;
|
||||||
|
}
|
||||||
|
if (this.ball[i].y <= 0 || this.ball[i].y >= this.canvas.height) {
|
||||||
|
this.ball[i].vy = -this.ball[i].vy;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据配置生成小球并放入数组
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
particle.prototype.__ballConfigure = function () {
|
||||||
|
//获取随机小球配置
|
||||||
|
var j = 0;
|
||||||
|
while (j < this.ballNumber) {
|
||||||
|
this.ball[j] = {
|
||||||
|
x: Math.ceil(Math.random() * this.canvas.width),
|
||||||
|
y: Math.ceil(Math.random() * this.canvas.height),
|
||||||
|
vx: particle.__noZeroRandom(-1, 1),
|
||||||
|
vy: particle.__noZeroRandom(-1, 1),
|
||||||
|
size: particle.__noZeroRandom(this.ballMinSize, this.ballMaxSize),
|
||||||
|
color: this.__randomColor(),
|
||||||
|
sizeReduce: 0.1
|
||||||
|
};
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 利用 randomColor 生成范围随机色,如果没有范围,则返回指定色
|
||||||
|
*
|
||||||
|
* @returns {*|string|string[]}
|
||||||
|
*/
|
||||||
|
particle.prototype.__randomColor = function () {
|
||||||
|
return this.color instanceof Array ? this.randomColor.getColor() : this.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成不为0随机数,直接挂载到对象上,而非实例上
|
||||||
|
* @param min 最小
|
||||||
|
* @param max 最大
|
||||||
|
* @returns {number} 生成值
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
particle.__noZeroRandom = function (min, max) {
|
||||||
|
var k = 0;
|
||||||
|
while (k === 0) {
|
||||||
|
k = Math.floor(Math.random() * (max - min + 1) + min);
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.Particle = particle;
|
||||||
|
})();
|
||||||
BIN
preview.gif
Normal file
BIN
preview.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 MiB |
Reference in New Issue
Block a user