299 lines
11 KiB
JavaScript
Executable File
299 lines
11 KiB
JavaScript
Executable File
;
|
||
/*
|
||
* 原项目地址: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;
|
||
})(); |