Files
particle/js/particle.js
yhl452493373 762eedcff8 initial commit
2021-12-16 13:31:42 +08:00

299 lines
11 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;
/*
* 原项目地址: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;
}
/**
* 获取RGB其中之一随机色范围
* @param color1 颜色1 RGB其中之一
* @param color2 颜色2 RGB其中之一
* @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;
})();