diff --git a/README.md b/README.md
index 767349a..fc00f3f 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,49 @@
# particle
-HTML5中,采用JavaScript和Canvas实现运动粒子效果,兼容IE10+,chrome、safari等。
\ No newline at end of file
+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 | 粒子颜色,可为颜色字符串或颜色字符串数组,若为字符串数组,则为\[起始色,终止色],粒子颜色会在该范围内改变 |
diff --git a/index.html b/index.html
new file mode 100755
index 0000000..11bd07b
--- /dev/null
+++ b/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+ 粒子效果
+
+
+
+
+
+
+
+
diff --git a/js/particle.js b/js/particle.js
new file mode 100755
index 0000000..534c4a1
--- /dev/null
+++ b/js/particle.js
@@ -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;
+})();
\ No newline at end of file
diff --git a/preview.gif b/preview.gif
new file mode 100644
index 0000000..55a12e7
Binary files /dev/null and b/preview.gif differ