; /* * 原项目地址: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; })();