initial commit
This commit is contained in:
46
README.md
46
README.md
@@ -1,3 +1,49 @@
|
||||
# particle
|
||||
|
||||
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