diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..2545065
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,30 @@
+# Change log
+## 1.1.0
+
+- shapes and images can now be used together in an array to mix basic shapes and custom images;
+ ```js
+ let mySparticles = new Sparticles( el, {
+
+ shape: ["circle", "image"],
+ imageUrl: "./snowflake.png"
+
+ })
+ ```
+
+- fixed some performance / looping errors
+- refactored/renamed a lot of prototype methods
+
+- added the ability to write custom shapes in the off-chance that's
+ better/easier than using a custom svg-image
+ ```js
+ // first make sure the Sparticles is ready in page.
+ // then you can add a custom offScreenCanvas before initialising.
+ Sparticles.prototype.offScreenCanvas.doge = function(style, color, canvas) {
+ // code for custom shape here, access to "this" object
+ // which is the Sparticles prototype.
+ };
+ // then initialise your sparticles instance with the custom shape
+ let mySparticles = new Sparticles( el, { shape: "doge" });
+
+
+ ```
diff --git a/README.md b/README.md
index d15e34e..ecce24e 100644
--- a/README.md
+++ b/README.md
@@ -178,16 +178,16 @@ option | type | default
**[maxAlpha](#maxAlpha)** | `Number` | `1` | maximum alpha value of every particle
**[minSize](#minSize)** | `Number` | `1` | minimum size of every particle
**[maxSize](#maxSize)** | `Number` | `10` | maximum size of every particle
-**[style](#style)** | `String` | `fill` | fill style of particles (one of; "fill", "stroke" or "both")
**[bounce](#bounce)** | `Boolean` | `false` | should the particles bounce off edge of canvas
**[drift](#drift)** | `Number` | `1` | the "driftiness" of particles which have a horizontal/vertical direction
**[glow](#glow)** | `Number` | `0` | the glow effect size of each particle
**[twinkle](#twinkle)** | `Boolean` | `false` | particles to exhibit an alternative alpha transition as "twinkling"
+**[style](#style)** | `String` | `fill` | fill style of particles (one of; "fill", "stroke" or "both")
+**[shape](#shape)** | `String`/`Array` | `circle` | shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
**[color](#color)** | `String`/`Array` | `random` | css color as string, or array of color strings (can also be "random")
**[randomColor](#randomColor)** | `Function` | `randomHsl()` | function for returning a random color when the color is set as "random"
**[randomColorCount](#randomColorCount)** | `Function` | `randomHsl()` | function for returning a random color when the color is set as "random"
-**[shape](#shape)** | `String`/`Array` | `circle` | shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
-**[imageUrl](#imageUrl)** | `String`/`Array` | | if shape is "image", define an image url (can be data-uri, should be square (1:1 ratio))
+**[imageUrl](#imageUrl)** | `String`/`Array` | | if shape is "image", define an image url (can be data-uri, **should be square (1:1 ratio)**)
---
@@ -411,8 +411,9 @@ particle shape from an image when combined with `imageUrl`](#imageUrl).
Determine the custom image to be used for all the particles.
If an array of urls (`[ "http://my.image/shape.png", "http://my.svg/shape.svg" ]`) is given, then each particle
will be assigned a random image as it's shape from the array.
+**This image should be a square (1:1)**
-This only applies [if the `shape` is set to `"image"`](#shape).
+`imageUrl` only has an effect [if a `shape` in the array is; `"image"`](#shape).
# methods
diff --git a/dist/sparticles.esm.js b/dist/sparticles.esm.js
index 44d0142..26b9982 100644
--- a/dist/sparticles.esm.js
+++ b/dist/sparticles.esm.js
@@ -1,6 +1,6 @@
/**!
* Sparticles - Lightweight, High Performance Particles in Canvas
- * @version 1.0.3
+ * @version 1.1.0
* @license MPL-2.0
* @author simeydotme
* @website http://sparticlesjs.dev
@@ -209,8 +209,11 @@ var round = function round(value) {
var Sparticle = function Sparticle(parent) {
if (parent) {
this.canvas = parent.canvas;
- this.images = parent.images;
this.settings = parent.settings;
+ this.colors = parent.colors;
+ this.shapes = parent.shapes;
+ this.images = parent.images;
+ this.styles = parent.styles;
this.ctx = parent.canvas.getContext("2d");
this.setup();
this.init();
@@ -236,9 +239,10 @@ Sparticle.prototype.setup = function () {
this.dy = this.getDeltaY();
this.dd = this.getDriftDelta();
this.dr = this.getRotationDelta();
- this.shape = this.getShapeOrImage();
- this.style = this.getStyle();
this.color = this.getColor();
+ this.shape = this.getShape();
+ this.image = this.getImage();
+ this.style = this.getStyle();
this.rotation = _.rotate ? radian(random(0, 360)) : 0;
this.vertical = _.direction > 150 && _.direction < 210 || _.direction > 330 && _.direction < 390 || _.direction > -30 && _.direction < 30;
this.horizontal = _.direction > 60 && _.direction < 120 || _.direction > 240 && _.direction < 300;
@@ -351,27 +355,42 @@ Sparticle.prototype.isTouchingEdge = function () {
Sparticle.prototype.getColor = function () {
- if (Array.isArray(this.settings.color)) {
+ if (this.settings.color === "random") {
+ return randomArray(this.colors);
+ } else if (Array.isArray(this.settings.color)) {
return randomArray(this.settings.color);
+ } else {
+ return this.settings.color;
}
};
/**
- * get a random shape or image for the particle from the
- * array of shapes set in the options object, or the array
- * of images, if the shape is set to "image"
- * @returns {String} - random shape or image from shape or image array
+ * get a random shape for the particle from the
+ * array of shapes set in the options object
+ * @returns {String} - random shape from shape array
*/
-Sparticle.prototype.getShapeOrImage = function () {
- var shape = this.settings.shape;
+Sparticle.prototype.getShape = function () {
+ if (this.settings.shape === "random") {
+ return randomArray(this.shapes);
+ } else if (Array.isArray(this.settings.shape)) {
+ return randomArray(this.settings.shape);
+ } else {
+ return this.settings.shape;
+ }
+};
+/**
+ * get the image for the particle from the array
+ * of possible image urls
+ * @returns {String} - random imageUrl from imageUrl array
+ */
+
- if (Array.isArray(shape)) {
- if (shape[0] === "image" && this.images) {
- return randomArray(this.images);
- } else {
- return randomArray(shape);
- }
+Sparticle.prototype.getImage = function () {
+ if (Array.isArray(this.settings.imageUrl)) {
+ return randomArray(this.settings.imageUrl);
+ } else {
+ return this.settings.imageUrl;
}
};
/**
@@ -382,7 +401,7 @@ Sparticle.prototype.getShapeOrImage = function () {
Sparticle.prototype.getStyle = function () {
- return randomArray(this.settings.style);
+ return randomArray(this.styles);
};
/**
* get a random delta (velocity) for the particle
@@ -646,10 +665,12 @@ Sparticle.prototype.updateDrift = function () {
};
Sparticle.prototype.render = function (canvasses) {
- var particleCanvas = canvasses[this.color][this.shape];
+ var particleCanvas;
- if (this.settings.shape[0] !== "image") {
+ if (this.shape !== "image") {
particleCanvas = canvasses[this.color][this.shape][this.style];
+ } else {
+ particleCanvas = canvasses[this.color][this.shape][this.image];
}
var canvasSize = particleCanvas.width;
@@ -694,16 +715,16 @@ Sparticle.prototype.renderRotate = function () {
* @param {Number} [options.maxAlpha=1] - maximum alpha value of every particle
* @param {Number} [options.minSize=1] - minimum size of every particle
* @param {Number} [options.maxSize=10] - maximum size of every particle
- * @param {String} [options.style=fill] - fill style of particles (one of; "fill", "stroke" or "both")
* @param {Boolean} [options.bounce=false] - should the particles bounce off edge of canvas
* @param {Number} [options.drift=1] - the "driftiness" of particles which have a horizontal/vertical direction
* @param {Number} [options.glow=0] - the glow effect size of each particle
* @param {Boolean} [options.twinkle=false] - particles to exhibit an alternative alpha transition as "twinkling"
+ * @param {String} [options.style=fill] - fill style of particles (one of; "fill", "stroke" or "both")
+ * @param {(String|String[])} [options.shape=circle] - shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
+ * @param {(String|String[])} [options.imageUrl=] - if shape is "image", define an image url (can be data-uri, must be square (1:1 ratio))
* @param {(String|String[])} [options.color=random] - css color as string, or array of color strings (can also be "random")
* @param {Function} [options.randomColor=randomHsl(index,total)] - a custom function for setting the random colors when color="random"
* @param {Number} [options.randomColorCount=3] - the number of random colors to generate when color is "random"
- * @param {(String|String[])} [options.shape=circle] - shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
- * @param {(String|String[])} [options.imageUrl=] - if shape is "image", define an image url (can be data-uri, must be square (1:1 ratio))
* @param {Number} [width] - the width of the canvas element
* @param {Number} [height=width] - the height of the canvas element
* @returns {Object} - reference to a new Sparticles instance
@@ -762,9 +783,10 @@ var Sparticles = function Sparticles(node, options, width, height) {
var _this = this;
this.sparticles = [];
- this.createColorArray();
- this.createShapeArray();
- this.createStyleArray();
+ this.colors = this.getColorArray();
+ this.shapes = this.getShapeArray();
+ this.styles = this.getStyleArray();
+ this.imageUrls = this.getImageArray();
this.setupMainCanvas();
this.setupOffscreenCanvasses(function () {
_this.createSparticles();
@@ -897,27 +919,19 @@ var Sparticles = function Sparticles(node, options, width, height) {
*/
-Sparticles.prototype.createColorArray = function () {
- var _ = this.settings;
- var isArray = Array.isArray(_.color);
- var isRandom = false;
-
- if (!isArray) {
- _.color = [_.color];
- }
-
- isRandom = _.color.some(function (c) {
+Sparticles.prototype.getColorArray = function () {
+ var colors = Array.isArray(this.settings.color) ? this.settings.color : [this.settings.color];
+ var isRandom = colors.some(function (c) {
return c === "random";
});
if (isRandom) {
- // it would be silly to have an array of too many colours.
- for (var i = 0; i < _.randomColorCount; i++) {
- _.color[i] = _.randomColor(i, _.randomColorCount);
+ for (var i = 0; i < this.settings.randomColorCount; i++) {
+ colors[i] = this.settings.randomColor(i, this.settings.randomColorCount);
}
}
- return _.color;
+ return colors;
};
/**
* convert the input shape to an array if it isn't already
@@ -925,24 +939,26 @@ Sparticles.prototype.createColorArray = function () {
*/
-Sparticles.prototype.createShapeArray = function () {
- var _ = this.settings;
- var isArray = Array.isArray(_.shape);
- var isRandom = false;
-
- if (!isArray) {
- _.shape = [_.shape];
- }
-
- isRandom = _.shape.some(function (c) {
+Sparticles.prototype.getShapeArray = function () {
+ var shapes = Array.isArray(this.settings.shape) ? this.settings.shape : [this.settings.shape];
+ var isRandom = shapes.some(function (c) {
return c === "random";
});
if (isRandom) {
- _.shape = ["square", "circle", "star", "diamond"];
+ shapes = ["square", "circle", "triangle"];
}
- return _.shape;
+ return shapes;
+};
+/**
+ * convert the imageUrl option to an array if it isn't already
+ * @returns {Array} - array of image urls for use in rendering
+ */
+
+
+Sparticles.prototype.getImageArray = function () {
+ return Array.isArray(this.settings.imageUrl) ? this.settings.imageUrl : [this.settings.imageUrl];
};
/**
* convert the input style to an array
@@ -950,14 +966,16 @@ Sparticles.prototype.createShapeArray = function () {
*/
-Sparticles.prototype.createStyleArray = function () {
- if (this.settings.style !== "fill" && this.settings.style !== "stroke") {
- this.settings.style = ["fill", "stroke"];
+Sparticles.prototype.getStyleArray = function () {
+ var styles = this.settings.style;
+
+ if (styles !== "fill" && styles !== "stroke") {
+ styles = ["fill", "stroke"];
} else {
- this.settings.style = [this.settings.style];
+ styles = [styles];
}
- return this.settings.style;
+ return styles;
};
/**
* set up the canvas and bind to a property for
@@ -986,62 +1004,64 @@ Sparticles.prototype.setupMainCanvas = function () {
Sparticles.prototype.setupOffscreenCanvasses = function (callback) {
var _this3 = this;
+ var colors = this.colors.filter(function (item, index) {
+ return _this3.colors.indexOf(item) === index;
+ });
+ var shapes = this.shapes.filter(function (item, index) {
+ return _this3.shapes.indexOf(item) === index;
+ });
+ var styles = this.styles.filter(function (item, index) {
+ return _this3.styles.indexOf(item) === index;
+ });
+ var imageUrls = this.imageUrls.filter(function (item, index) {
+ return _this3.imageUrls.indexOf(item) === index;
+ });
+ var imageCount = colors.length * imageUrls.length;
+ var canvasCount = colors.length * shapes.length * styles.length;
+ var imagesLoaded = 0;
+ var canvassesCreated = 0;
this.canvasses = this.canvasses || {};
- this.settings.color.forEach(function (color) {
+ colors.forEach(function (color) {
_this3.canvasses[color] = _this3.canvasses[color] || {};
+ shapes.forEach(function (shape) {
+ _this3.canvasses[color][shape] = _this3.canvasses[color][shape] || {};
- if (_this3.settings.shape[0] === "image") {
- _this3.loadAndDrawImages(color, callback);
- } else {
- _this3.settings.shape.forEach(function (shape) {
- _this3.canvasses[color][shape] = _this3.canvasses[color][shape] || {};
-
- _this3.settings.style.forEach(function (style) {
- _this3.canvasses[color][shape][style] = document.createElement("canvas");
- var canvas = _this3.canvasses[color][shape][style];
- var ctx = canvas.getContext("2d");
-
- switch (shape) {
- case "square":
- _this3.drawOffscreenCanvasForSquare(canvas, ctx, color, style);
-
- if (callback) callback();
- break;
+ if (shape === "image") {
+ imageUrls.forEach(function (imageUrl, i) {
+ var image = new Image();
+ var imageCanvas = document.createElement("canvas");
+ _this3.canvasses[color][shape][imageUrl] = imageCanvas;
- case "line":
- _this3.drawOffscreenCanvasForLine(canvas, ctx, color, style);
+ image.onload = function () {
+ imagesLoaded++;
- if (callback) callback();
- break;
+ _this3.drawOffscreenCanvasForImage(image, color, imageCanvas);
- case "triangle":
- _this3.drawOffscreenCanvasForTriangle(canvas, ctx, color, style);
+ if (callback && imagesLoaded === imageCount) {
+ callback();
+ }
+ };
- if (callback) callback();
- break;
+ image.onerror = function () {
+ console.error("failed to load source image: ", imageUrl);
+ };
- case "diamond":
- _this3.drawOffscreenCanvasForDiamond(canvas, ctx, color, style);
-
- if (callback) callback();
- break;
-
- case "star":
- _this3.drawOffscreenCanvasForStar(canvas, ctx, color, style);
-
- if (callback) callback();
- break;
+ image.src = imageUrl;
+ });
+ } else {
+ styles.forEach(function (style) {
+ var canvas = document.createElement("canvas");
+ _this3.canvasses[color][shape][style] = canvas;
+ canvassesCreated++;
- case "circle":
- default:
- _this3.drawOffscreenCanvasForCircle(canvas, ctx, color, style);
+ _this3.drawOffscreenCanvas(shape, style, color, canvas);
- if (callback) callback();
- break;
+ if (callback && canvassesCreated === canvasCount) {
+ callback();
}
});
- });
- }
+ }
+ });
});
};
/**
@@ -1109,17 +1129,61 @@ Sparticles.prototype.renderColor = function (ctx, style) {
}
};
/**
- * create, setup and render an offscreen canvas for a
- * Square Particle of the given color
+ * pass-through the needed parameters to the offscreen canvas
+ * draw function associated with the given shape
+ * @param {String} shape - shape of the canvas to draw (eg: "circle")
+ * @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
* @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
+ * @returns {HTMLCanvasElement} - the created offscreen canvas
+ */
+
+
+Sparticles.prototype.drawOffscreenCanvas = function (shape, style, color, canvas) {
+ return this.offScreenCanvas[shape].call(this, style, color, canvas);
+};
+/**
+ * object of shapes to draw
+ */
+
+
+Sparticles.prototype.offScreenCanvas = {};
+/**
+ * create, setup and render an offscreen canvas for a
+ * Circle Particle of the given color
+ * @param {String} style - style (either "fill" or "stroke")
* @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
+ * @returns {HTMLCanvasElement} - the created offscreen canvas
+ */
+
+Sparticles.prototype.offScreenCanvas.circle = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
+ var size = this.settings.maxSize;
+ var lineSize = this.getLineSize(size);
+ var glowSize = this.getGlowSize(size);
+ var canvasSize = size + lineSize + glowSize;
+ canvas.width = canvasSize;
+ canvas.height = canvasSize;
+ this.renderGlow(ctx, color, size);
+ this.renderStyle(ctx, color, lineSize, style);
+ ctx.beginPath();
+ ctx.ellipse(canvasSize / 2, canvasSize / 2, size / 2, size / 2, 0, 0, 360);
+ this.renderColor(ctx, style);
+ return canvas;
+};
+/**
+ * create, setup and render an offscreen canvas for a
+ * Square Particle of the given color
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForSquare = function (canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.square = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1136,15 +1200,15 @@ Sparticles.prototype.drawOffscreenCanvasForSquare = function (canvas, ctx, color
/**
* create, setup and render an offscreen canvas for a
* Line/Curve Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForLine = function (canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.line = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize * 2;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1166,15 +1230,15 @@ Sparticles.prototype.drawOffscreenCanvasForLine = function (canvas, ctx, color,
/**
* create, setup and render an offscreen canvas for a
* Triangle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForTriangle = function (canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.triangle = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1197,15 +1261,15 @@ Sparticles.prototype.drawOffscreenCanvasForTriangle = function (canvas, ctx, col
/**
* create, setup and render an offscreen canvas for a
* Diamond Sparkle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForDiamond = function (canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.diamond = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize;
var half = size / 2;
var lineSize = this.getLineSize(size);
@@ -1233,15 +1297,15 @@ Sparticles.prototype.drawOffscreenCanvasForDiamond = function (canvas, ctx, colo
/**
* create, setup and render an offscreen canvas for a
* Star Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForStar = function (canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.star = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = 52;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1297,85 +1361,19 @@ Sparticles.prototype.drawOffscreenCanvasForStar = function (canvas, ctx, color,
this.renderColor(ctx, style);
return canvas;
};
-/**
- * create, setup and render an offscreen canvas for a
- * Circle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
- * @param {String} style - style (either "fill" or "stroke")
- * @returns {HTMLCanvasElement} - the created offscreen canvas
- */
-
-
-Sparticles.prototype.drawOffscreenCanvasForCircle = function (canvas, ctx, color, style) {
- var size = this.settings.maxSize;
- var lineSize = this.getLineSize(size);
- var glowSize = this.getGlowSize(size);
- var canvasSize = size + lineSize + glowSize;
- canvas.width = canvasSize;
- canvas.height = canvasSize;
- this.renderGlow(ctx, color, size);
- this.renderStyle(ctx, color, lineSize, style);
- ctx.beginPath();
- ctx.ellipse(canvasSize / 2, canvasSize / 2, size / 2, size / 2, 0, 0, 360);
- this.renderColor(ctx, style);
- return canvas;
-};
-/**
- * set up the needed array for referencing the images in the Sparticle()
- * instance, then loop through each image and load it before running the callback
- * @param {String} color - the color of the image that we're loading
- * @param {Function} callback - callback function to run after images load
- */
-
-
-Sparticles.prototype.loadAndDrawImages = function (color, callback) {
- var _this4 = this;
-
- var imgUrls = this.settings.imageUrl;
- var imageUrls = Array.isArray(imgUrls) ? imgUrls : [imgUrls];
- var imageCount = imageUrls.length;
- var imagesLoaded = 0;
- this.images = [];
- imageUrls.forEach(function (imageUrl, i) {
- _this4.images.push("image" + i);
-
- _this4.canvasses[color]["image" + i] = document.createElement("canvas");
- var canvas = _this4.canvasses[color]["image" + i];
- var ctx = canvas.getContext("2d");
- var image = new Image();
-
- image.onload = function () {
- imagesLoaded++;
-
- _this4.drawImageOffscreenCanvas(image, canvas, ctx, color);
-
- if (callback && imagesLoaded === imageCount) {
- callback();
- }
- };
-
- image.onerror = function () {
- console.error("failed to load source image: ", imageUrl);
- };
-
- image.src = imageUrl;
- });
-};
/**
* create, setup and render an offscreen canvas for a
* Custom Image Particle of the given color
* @param {HTMLImageElement} image - the image element that has loaded
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
* @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawImageOffscreenCanvas = function (image, canvas, ctx, color) {
+Sparticles.prototype.drawOffscreenCanvasForImage = function (image, color, canvas) {
var size = image.width;
+ var ctx = canvas.getContext("2d");
canvas.width = size;
canvas.height = size;
ctx.drawImage(image, 0, 0, size, size, 0, 0, size, size);
diff --git a/dist/sparticles.js b/dist/sparticles.js
index 2daab26..a6d3021 100644
--- a/dist/sparticles.js
+++ b/dist/sparticles.js
@@ -1,6 +1,6 @@
/**!
* Sparticles - Lightweight, High Performance Particles in Canvas
- * @version 1.0.3
+ * @version 1.1.0
* @license MPL-2.0
* @author simeydotme
* @website http://sparticlesjs.dev
@@ -212,8 +212,11 @@ var Sparticles = (function () {
var Sparticle = function Sparticle(parent) {
if (parent) {
this.canvas = parent.canvas;
- this.images = parent.images;
this.settings = parent.settings;
+ this.colors = parent.colors;
+ this.shapes = parent.shapes;
+ this.images = parent.images;
+ this.styles = parent.styles;
this.ctx = parent.canvas.getContext("2d");
this.setup();
this.init();
@@ -239,9 +242,10 @@ var Sparticles = (function () {
this.dy = this.getDeltaY();
this.dd = this.getDriftDelta();
this.dr = this.getRotationDelta();
- this.shape = this.getShapeOrImage();
- this.style = this.getStyle();
this.color = this.getColor();
+ this.shape = this.getShape();
+ this.image = this.getImage();
+ this.style = this.getStyle();
this.rotation = _.rotate ? radian(random(0, 360)) : 0;
this.vertical = _.direction > 150 && _.direction < 210 || _.direction > 330 && _.direction < 390 || _.direction > -30 && _.direction < 30;
this.horizontal = _.direction > 60 && _.direction < 120 || _.direction > 240 && _.direction < 300;
@@ -354,27 +358,42 @@ var Sparticles = (function () {
Sparticle.prototype.getColor = function () {
- if (Array.isArray(this.settings.color)) {
+ if (this.settings.color === "random") {
+ return randomArray(this.colors);
+ } else if (Array.isArray(this.settings.color)) {
return randomArray(this.settings.color);
+ } else {
+ return this.settings.color;
}
};
/**
- * get a random shape or image for the particle from the
- * array of shapes set in the options object, or the array
- * of images, if the shape is set to "image"
- * @returns {String} - random shape or image from shape or image array
+ * get a random shape for the particle from the
+ * array of shapes set in the options object
+ * @returns {String} - random shape from shape array
*/
- Sparticle.prototype.getShapeOrImage = function () {
- var shape = this.settings.shape;
+ Sparticle.prototype.getShape = function () {
+ if (this.settings.shape === "random") {
+ return randomArray(this.shapes);
+ } else if (Array.isArray(this.settings.shape)) {
+ return randomArray(this.settings.shape);
+ } else {
+ return this.settings.shape;
+ }
+ };
+ /**
+ * get the image for the particle from the array
+ * of possible image urls
+ * @returns {String} - random imageUrl from imageUrl array
+ */
+
- if (Array.isArray(shape)) {
- if (shape[0] === "image" && this.images) {
- return randomArray(this.images);
- } else {
- return randomArray(shape);
- }
+ Sparticle.prototype.getImage = function () {
+ if (Array.isArray(this.settings.imageUrl)) {
+ return randomArray(this.settings.imageUrl);
+ } else {
+ return this.settings.imageUrl;
}
};
/**
@@ -385,7 +404,7 @@ var Sparticles = (function () {
Sparticle.prototype.getStyle = function () {
- return randomArray(this.settings.style);
+ return randomArray(this.styles);
};
/**
* get a random delta (velocity) for the particle
@@ -649,10 +668,12 @@ var Sparticles = (function () {
};
Sparticle.prototype.render = function (canvasses) {
- var particleCanvas = canvasses[this.color][this.shape];
+ var particleCanvas;
- if (this.settings.shape[0] !== "image") {
+ if (this.shape !== "image") {
particleCanvas = canvasses[this.color][this.shape][this.style];
+ } else {
+ particleCanvas = canvasses[this.color][this.shape][this.image];
}
var canvasSize = particleCanvas.width;
@@ -697,16 +718,16 @@ var Sparticles = (function () {
* @param {Number} [options.maxAlpha=1] - maximum alpha value of every particle
* @param {Number} [options.minSize=1] - minimum size of every particle
* @param {Number} [options.maxSize=10] - maximum size of every particle
- * @param {String} [options.style=fill] - fill style of particles (one of; "fill", "stroke" or "both")
* @param {Boolean} [options.bounce=false] - should the particles bounce off edge of canvas
* @param {Number} [options.drift=1] - the "driftiness" of particles which have a horizontal/vertical direction
* @param {Number} [options.glow=0] - the glow effect size of each particle
* @param {Boolean} [options.twinkle=false] - particles to exhibit an alternative alpha transition as "twinkling"
+ * @param {String} [options.style=fill] - fill style of particles (one of; "fill", "stroke" or "both")
+ * @param {(String|String[])} [options.shape=circle] - shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
+ * @param {(String|String[])} [options.imageUrl=] - if shape is "image", define an image url (can be data-uri, must be square (1:1 ratio))
* @param {(String|String[])} [options.color=random] - css color as string, or array of color strings (can also be "random")
* @param {Function} [options.randomColor=randomHsl(index,total)] - a custom function for setting the random colors when color="random"
* @param {Number} [options.randomColorCount=3] - the number of random colors to generate when color is "random"
- * @param {(String|String[])} [options.shape=circle] - shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
- * @param {(String|String[])} [options.imageUrl=] - if shape is "image", define an image url (can be data-uri, must be square (1:1 ratio))
* @param {Number} [width] - the width of the canvas element
* @param {Number} [height=width] - the height of the canvas element
* @returns {Object} - reference to a new Sparticles instance
@@ -765,9 +786,10 @@ var Sparticles = (function () {
var _this = this;
this.sparticles = [];
- this.createColorArray();
- this.createShapeArray();
- this.createStyleArray();
+ this.colors = this.getColorArray();
+ this.shapes = this.getShapeArray();
+ this.styles = this.getStyleArray();
+ this.imageUrls = this.getImageArray();
this.setupMainCanvas();
this.setupOffscreenCanvasses(function () {
_this.createSparticles();
@@ -900,27 +922,19 @@ var Sparticles = (function () {
*/
- Sparticles.prototype.createColorArray = function () {
- var _ = this.settings;
- var isArray = Array.isArray(_.color);
- var isRandom = false;
-
- if (!isArray) {
- _.color = [_.color];
- }
-
- isRandom = _.color.some(function (c) {
+ Sparticles.prototype.getColorArray = function () {
+ var colors = Array.isArray(this.settings.color) ? this.settings.color : [this.settings.color];
+ var isRandom = colors.some(function (c) {
return c === "random";
});
if (isRandom) {
- // it would be silly to have an array of too many colours.
- for (var i = 0; i < _.randomColorCount; i++) {
- _.color[i] = _.randomColor(i, _.randomColorCount);
+ for (var i = 0; i < this.settings.randomColorCount; i++) {
+ colors[i] = this.settings.randomColor(i, this.settings.randomColorCount);
}
}
- return _.color;
+ return colors;
};
/**
* convert the input shape to an array if it isn't already
@@ -928,24 +942,26 @@ var Sparticles = (function () {
*/
- Sparticles.prototype.createShapeArray = function () {
- var _ = this.settings;
- var isArray = Array.isArray(_.shape);
- var isRandom = false;
-
- if (!isArray) {
- _.shape = [_.shape];
- }
-
- isRandom = _.shape.some(function (c) {
+ Sparticles.prototype.getShapeArray = function () {
+ var shapes = Array.isArray(this.settings.shape) ? this.settings.shape : [this.settings.shape];
+ var isRandom = shapes.some(function (c) {
return c === "random";
});
if (isRandom) {
- _.shape = ["square", "circle", "star", "diamond"];
+ shapes = ["square", "circle", "triangle"];
}
- return _.shape;
+ return shapes;
+ };
+ /**
+ * convert the imageUrl option to an array if it isn't already
+ * @returns {Array} - array of image urls for use in rendering
+ */
+
+
+ Sparticles.prototype.getImageArray = function () {
+ return Array.isArray(this.settings.imageUrl) ? this.settings.imageUrl : [this.settings.imageUrl];
};
/**
* convert the input style to an array
@@ -953,14 +969,16 @@ var Sparticles = (function () {
*/
- Sparticles.prototype.createStyleArray = function () {
- if (this.settings.style !== "fill" && this.settings.style !== "stroke") {
- this.settings.style = ["fill", "stroke"];
+ Sparticles.prototype.getStyleArray = function () {
+ var styles = this.settings.style;
+
+ if (styles !== "fill" && styles !== "stroke") {
+ styles = ["fill", "stroke"];
} else {
- this.settings.style = [this.settings.style];
+ styles = [styles];
}
- return this.settings.style;
+ return styles;
};
/**
* set up the canvas and bind to a property for
@@ -989,62 +1007,64 @@ var Sparticles = (function () {
Sparticles.prototype.setupOffscreenCanvasses = function (callback) {
var _this3 = this;
+ var colors = this.colors.filter(function (item, index) {
+ return _this3.colors.indexOf(item) === index;
+ });
+ var shapes = this.shapes.filter(function (item, index) {
+ return _this3.shapes.indexOf(item) === index;
+ });
+ var styles = this.styles.filter(function (item, index) {
+ return _this3.styles.indexOf(item) === index;
+ });
+ var imageUrls = this.imageUrls.filter(function (item, index) {
+ return _this3.imageUrls.indexOf(item) === index;
+ });
+ var imageCount = colors.length * imageUrls.length;
+ var canvasCount = colors.length * shapes.length * styles.length;
+ var imagesLoaded = 0;
+ var canvassesCreated = 0;
this.canvasses = this.canvasses || {};
- this.settings.color.forEach(function (color) {
+ colors.forEach(function (color) {
_this3.canvasses[color] = _this3.canvasses[color] || {};
+ shapes.forEach(function (shape) {
+ _this3.canvasses[color][shape] = _this3.canvasses[color][shape] || {};
- if (_this3.settings.shape[0] === "image") {
- _this3.loadAndDrawImages(color, callback);
- } else {
- _this3.settings.shape.forEach(function (shape) {
- _this3.canvasses[color][shape] = _this3.canvasses[color][shape] || {};
-
- _this3.settings.style.forEach(function (style) {
- _this3.canvasses[color][shape][style] = document.createElement("canvas");
- var canvas = _this3.canvasses[color][shape][style];
- var ctx = canvas.getContext("2d");
-
- switch (shape) {
- case "square":
- _this3.drawOffscreenCanvasForSquare(canvas, ctx, color, style);
-
- if (callback) callback();
- break;
+ if (shape === "image") {
+ imageUrls.forEach(function (imageUrl, i) {
+ var image = new Image();
+ var imageCanvas = document.createElement("canvas");
+ _this3.canvasses[color][shape][imageUrl] = imageCanvas;
- case "line":
- _this3.drawOffscreenCanvasForLine(canvas, ctx, color, style);
+ image.onload = function () {
+ imagesLoaded++;
- if (callback) callback();
- break;
+ _this3.drawOffscreenCanvasForImage(image, color, imageCanvas);
- case "triangle":
- _this3.drawOffscreenCanvasForTriangle(canvas, ctx, color, style);
+ if (callback && imagesLoaded === imageCount) {
+ callback();
+ }
+ };
- if (callback) callback();
- break;
+ image.onerror = function () {
+ console.error("failed to load source image: ", imageUrl);
+ };
- case "diamond":
- _this3.drawOffscreenCanvasForDiamond(canvas, ctx, color, style);
-
- if (callback) callback();
- break;
-
- case "star":
- _this3.drawOffscreenCanvasForStar(canvas, ctx, color, style);
-
- if (callback) callback();
- break;
+ image.src = imageUrl;
+ });
+ } else {
+ styles.forEach(function (style) {
+ var canvas = document.createElement("canvas");
+ _this3.canvasses[color][shape][style] = canvas;
+ canvassesCreated++;
- case "circle":
- default:
- _this3.drawOffscreenCanvasForCircle(canvas, ctx, color, style);
+ _this3.drawOffscreenCanvas(shape, style, color, canvas);
- if (callback) callback();
- break;
+ if (callback && canvassesCreated === canvasCount) {
+ callback();
}
});
- });
- }
+ }
+ });
});
};
/**
@@ -1112,17 +1132,61 @@ var Sparticles = (function () {
}
};
/**
- * create, setup and render an offscreen canvas for a
- * Square Particle of the given color
+ * pass-through the needed parameters to the offscreen canvas
+ * draw function associated with the given shape
+ * @param {String} shape - shape of the canvas to draw (eg: "circle")
+ * @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
* @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
+ * @returns {HTMLCanvasElement} - the created offscreen canvas
+ */
+
+
+ Sparticles.prototype.drawOffscreenCanvas = function (shape, style, color, canvas) {
+ return this.offScreenCanvas[shape].call(this, style, color, canvas);
+ };
+ /**
+ * object of shapes to draw
+ */
+
+
+ Sparticles.prototype.offScreenCanvas = {};
+ /**
+ * create, setup and render an offscreen canvas for a
+ * Circle Particle of the given color
+ * @param {String} style - style (either "fill" or "stroke")
* @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
+ * @returns {HTMLCanvasElement} - the created offscreen canvas
+ */
+
+ Sparticles.prototype.offScreenCanvas.circle = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
+ var size = this.settings.maxSize;
+ var lineSize = this.getLineSize(size);
+ var glowSize = this.getGlowSize(size);
+ var canvasSize = size + lineSize + glowSize;
+ canvas.width = canvasSize;
+ canvas.height = canvasSize;
+ this.renderGlow(ctx, color, size);
+ this.renderStyle(ctx, color, lineSize, style);
+ ctx.beginPath();
+ ctx.ellipse(canvasSize / 2, canvasSize / 2, size / 2, size / 2, 0, 0, 360);
+ this.renderColor(ctx, style);
+ return canvas;
+ };
+ /**
+ * create, setup and render an offscreen canvas for a
+ * Square Particle of the given color
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
- Sparticles.prototype.drawOffscreenCanvasForSquare = function (canvas, ctx, color, style) {
+ Sparticles.prototype.offScreenCanvas.square = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1139,15 +1203,15 @@ var Sparticles = (function () {
/**
* create, setup and render an offscreen canvas for a
* Line/Curve Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
- Sparticles.prototype.drawOffscreenCanvasForLine = function (canvas, ctx, color, style) {
+ Sparticles.prototype.offScreenCanvas.line = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize * 2;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1169,15 +1233,15 @@ var Sparticles = (function () {
/**
* create, setup and render an offscreen canvas for a
* Triangle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
- Sparticles.prototype.drawOffscreenCanvasForTriangle = function (canvas, ctx, color, style) {
+ Sparticles.prototype.offScreenCanvas.triangle = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1200,15 +1264,15 @@ var Sparticles = (function () {
/**
* create, setup and render an offscreen canvas for a
* Diamond Sparkle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
- Sparticles.prototype.drawOffscreenCanvasForDiamond = function (canvas, ctx, color, style) {
+ Sparticles.prototype.offScreenCanvas.diamond = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = this.settings.maxSize;
var half = size / 2;
var lineSize = this.getLineSize(size);
@@ -1236,15 +1300,15 @@ var Sparticles = (function () {
/**
* create, setup and render an offscreen canvas for a
* Star Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
- Sparticles.prototype.drawOffscreenCanvasForStar = function (canvas, ctx, color, style) {
+ Sparticles.prototype.offScreenCanvas.star = function (style, color, canvas) {
+ var ctx = canvas.getContext("2d");
var size = 52;
var lineSize = this.getLineSize(size);
var glowSize = this.getGlowSize(size);
@@ -1300,85 +1364,19 @@ var Sparticles = (function () {
this.renderColor(ctx, style);
return canvas;
};
- /**
- * create, setup and render an offscreen canvas for a
- * Circle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
- * @param {String} style - style (either "fill" or "stroke")
- * @returns {HTMLCanvasElement} - the created offscreen canvas
- */
-
-
- Sparticles.prototype.drawOffscreenCanvasForCircle = function (canvas, ctx, color, style) {
- var size = this.settings.maxSize;
- var lineSize = this.getLineSize(size);
- var glowSize = this.getGlowSize(size);
- var canvasSize = size + lineSize + glowSize;
- canvas.width = canvasSize;
- canvas.height = canvasSize;
- this.renderGlow(ctx, color, size);
- this.renderStyle(ctx, color, lineSize, style);
- ctx.beginPath();
- ctx.ellipse(canvasSize / 2, canvasSize / 2, size / 2, size / 2, 0, 0, 360);
- this.renderColor(ctx, style);
- return canvas;
- };
- /**
- * set up the needed array for referencing the images in the Sparticle()
- * instance, then loop through each image and load it before running the callback
- * @param {String} color - the color of the image that we're loading
- * @param {Function} callback - callback function to run after images load
- */
-
-
- Sparticles.prototype.loadAndDrawImages = function (color, callback) {
- var _this4 = this;
-
- var imgUrls = this.settings.imageUrl;
- var imageUrls = Array.isArray(imgUrls) ? imgUrls : [imgUrls];
- var imageCount = imageUrls.length;
- var imagesLoaded = 0;
- this.images = [];
- imageUrls.forEach(function (imageUrl, i) {
- _this4.images.push("image" + i);
-
- _this4.canvasses[color]["image" + i] = document.createElement("canvas");
- var canvas = _this4.canvasses[color]["image" + i];
- var ctx = canvas.getContext("2d");
- var image = new Image();
-
- image.onload = function () {
- imagesLoaded++;
-
- _this4.drawImageOffscreenCanvas(image, canvas, ctx, color);
-
- if (callback && imagesLoaded === imageCount) {
- callback();
- }
- };
-
- image.onerror = function () {
- console.error("failed to load source image: ", imageUrl);
- };
-
- image.src = imageUrl;
- });
- };
/**
* create, setup and render an offscreen canvas for a
* Custom Image Particle of the given color
* @param {HTMLImageElement} image - the image element that has loaded
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
* @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
- Sparticles.prototype.drawImageOffscreenCanvas = function (image, canvas, ctx, color) {
+ Sparticles.prototype.drawOffscreenCanvasForImage = function (image, color, canvas) {
var size = image.width;
+ var ctx = canvas.getContext("2d");
canvas.width = size;
canvas.height = size;
ctx.drawImage(image, 0, 0, size, size, 0, 0, size, size);
diff --git a/dist/sparticles.min.js b/dist/sparticles.min.js
index b041e89..3907201 100644
--- a/dist/sparticles.min.js
+++ b/dist/sparticles.min.js
@@ -1,9 +1,9 @@
/**!
* Sparticles - Lightweight, High Performance Particles in Canvas
- * @version 1.0.3
+ * @version 1.1.0
* @license MPL-2.0
* @author simeydotme
* @website http://sparticlesjs.dev
* @repository https://github.com/simeydotme/sparticles.git
*/
-var Sparticles=function(){"use strict";function t(t,e,i){return e in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}function e(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);e&&(s=s.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,s)}return i}function i(i){for(var s=1;s0&&void 0!==arguments[0]?arguments[0]:function(){},e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:60;this.fps=e,this.handler=t;var i=0;this.start=function(){var t=this;if(!this.started){var e=performance.now(),s=1e3/this.fps;i=requestAnimationFrame((function r(n){var a=n-e;i=requestAnimationFrame(r),a>=s-0&&(t.handler(a),e=n-a%s)})),this.started=!0}},this.stop=function(){cancelAnimationFrame(i),this.started=!1}},r=function(t){return[Math.cos(a(t-90)),Math.sin(a(t-90))]},n=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return Math.max(e,Math.min(i,t))},a=function(t){return t*Math.PI/180},h=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Math.random();return e<=t?i=t:(0!==t||1!==e)&&e>t&&(i=i*(e-t)+t),i},o=function(t){return t[Math.floor(h(0,t.length))]},c=function(){var t=p(h(0,360)),e=p(h(90,100)),i=p(h(45,85));return"hsl(".concat(t,",").concat(e,"%,").concat(i,"%)")},l=function(t){return t>h()},p=function(t){return.5+t|0},d=function(t){return t?(this.canvas=t.canvas,this.images=t.images,this.settings=t.settings,this.ctx=t.canvas.getContext("2d"),this.setup(),this.init()):console.warn("Invalid parameters given to Sparticle()",arguments),this};d.prototype.setup=function(){var t=this.settings;this.frame=0,this.frameoffset=p(h(0,360)),this.size=p(h(t.minSize,t.maxSize)),this.da=this.getAlphaDelta(),this.dx=this.getDeltaX(),this.dy=this.getDeltaY(),this.dd=this.getDriftDelta(),this.dr=this.getRotationDelta(),this.shape=this.getShapeOrImage(),this.style=this.getStyle(),this.color=this.getColor(),this.rotation=t.rotate?a(h(0,360)):0,this.vertical=t.direction>150&&t.direction<210||t.direction>330&&t.direction<390||t.direction>-30&&t.direction<30,this.horizontal=t.direction>60&&t.direction<120||t.direction>240&&t.direction<300},d.prototype.init=function(){var t=this.settings,e=this.canvas;this.alpha=0,(t.speed>0||0===t.alphaSpeed)&&(this.alpha=h(t.minAlpha,t.maxAlpha)),t.bounce?(this.px=p(h(2,e.width-this.size-2)),this.py=p(h(2,e.height-this.size-2))):(this.px=p(h(2*-this.size,e.width+this.size)),this.py=p(h(2*-this.size,e.height+this.size)))},d.prototype.reset=function(){this.setup(),this.py<0?this.py=this.canvas.height+2*this.size:this.py>this.canvas.height&&(this.py=0-2*this.size),this.px<0?this.px=this.canvas.width+2*this.size:this.px>this.canvas.width&&(this.px=0-2*this.size)},d.prototype.bounce=function(){this.settings.direction;(this.py<=0||this.py+this.size>=this.canvas.height)&&(this.dy=-this.dy,this.horizontal&&(this.dd=-this.dd)),(this.px<=0||this.px+this.size>=this.canvas.width)&&(this.dx=-this.dx,this.vertical&&(this.dd=-this.dd))},d.prototype.isOffCanvas=function(){var t=0-2*this.size,e=this.canvas.height+2*this.size,i=this.canvas.width+2*this.size;return this.pxi||this.pye},d.prototype.isTouchingEdge=function(){var t=this.canvas.height-this.size,e=this.canvas.width-this.size;return this.px<0||this.px>e||this.py<0||this.py>t},d.prototype.getColor=function(){if(Array.isArray(this.settings.color))return o(this.settings.color)},d.prototype.getShapeOrImage=function(){var t=this.settings.shape;if(Array.isArray(t))return"image"===t[0]&&this.images?o(this.images):o(t)},d.prototype.getStyle=function(){return o(this.settings.style)},d.prototype.getDelta=function(){var t=.1*this.settings.speed;return this.settings.speed&&this.settings.parallax?t+this.size*this.settings.parallax/50:t},d.prototype.getDeltaVariance=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=this.settings.speed||10;return t>0?h(-t,t)*e/100:0},d.prototype.getDeltaX=function(){var t=this.getDelta(),e=this.getDeltaVariance(this.settings.xVariance);return r(this.settings.direction)[0]*t+e},d.prototype.getDeltaY=function(){var t=this.getDelta(),e=this.getDeltaVariance(this.settings.yVariance);return r(this.settings.direction)[1]*t+e},d.prototype.getAlphaDelta=function(){var t=this.settings.alphaVariance,e=h(1,t+1);return l(.5)&&(e=-e),e},d.prototype.getDriftDelta=function(){return this.settings.drift?h(this.settings.drift-this.settings.drift/2,this.settings.drift+this.settings.drift/2):0},d.prototype.getRotationDelta=function(){var t=0;return this.settings.rotate&&this.settings.rotation&&(t=a(h(.5,1.5)*this.settings.rotation),l(.5)&&(t=-t)),t},d.prototype.update=function(){return this.frame+=1,this.updatePosition(),this.updateAlpha(),this},d.prototype.updateAlpha=function(){return this.settings.alphaSpeed>0&&(this.settings.twinkle?this.alpha=this.updateTwinkle():this.alpha=this.updateFade()),this.alpha},d.prototype.updateFade=function(){var t=this.da/1e3*this.settings.alphaSpeed*.5,e=this.alpha+t,i=this.da>0&&e>this.settings.maxAlpha,s=this.da<0&ðis.settings.maxAlpha,s=t=1&&!(arguments[0]instanceof HTMLElement)&&(e=arguments[0],r=arguments[1],n=arguments[2],t=void 0),r&&!n&&(n=r);var a={alphaSpeed:10,alphaVariance:1,bounce:!1,color:"random",randomColor:c,randomColorCount:3,composition:"source-over",count:50,direction:180,drift:1,glow:0,imageUrl:"",maxAlpha:1,maxSize:10,minAlpha:0,minSize:1,parallax:1,rotate:!0,rotation:1,shape:"circle",speed:10,style:"fill",twinkle:!1,xVariance:2,yVariance:2};return this.el=t||document.body,this.settings=i({},a,{},e),this.resizable=!r&&!n,this.width=this.resizable?this.el.clientWidth:r,this.height=this.resizable?this.el.clientHeight:n,this.init=function(){var t=this;return this.sparticles=[],this.createColorArray(),this.createShapeArray(),this.createStyleArray(),this.setupMainCanvas(),this.setupOffscreenCanvasses((function(){t.createSparticles(),t.start()})),window.addEventListener("resize",this),this},this.handleEvent=function(t){var e=this;"resize"===t.type&&(clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout((function(){e.resizable&&(e.width=e.el.clientWidth,e.height=e.el.clientHeight,e.setCanvasSize().resetSparticles())}),200))},this.start=function(){var t=this;return this.loop||(this.loop=new s((function(e){t.drawFrame(e)}))),this.loop.start(),this},this.stop=function(){return this.loop.stop(),this},this.destroy=function(){for(var t in this.stop(),this.el.removeChild(this.canvas),window.removeEventListener("resize",this),this)this.hasOwnProperty(t)&&delete this[t];return this},this.setCanvasSize=function(t,e){return t&&(this.resizable=!1),this.width=t||this.width,this.height=e||this.height,this.canvas.width=this.width,this.canvas.height=this.height,this},this.resetSparticles=this.createSparticles=function(){this.sparticles=[],this.ctx.globalCompositeOperation=this.settings.composition;for(var t=0;te.size})),this.sparticles},this.init()};return u.prototype.createColorArray=function(){var t=this.settings;if(Array.isArray(t.color)||(t.color=[t.color]),t.color.some((function(t){return"random"===t})))for(var e=0;e0&&void 0!==arguments[0]?arguments[0]:function(){},e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:60;this.fps=e,this.handler=t;var i=0;this.start=function(){var t=this;if(!this.started){var e=performance.now(),s=1e3/this.fps;i=requestAnimationFrame((function n(r){var a=r-e;i=requestAnimationFrame(n),a>=s-0&&(t.handler(a),e=r-a%s)})),this.started=!0}},this.stop=function(){cancelAnimationFrame(i),this.started=!1}},n=function(t){return[Math.cos(a(t-90)),Math.sin(a(t-90))]},r=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return Math.max(e,Math.min(i,t))},a=function(t){return t*Math.PI/180},h=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Math.random();return e<=t?i=t:(0!==t||1!==e)&&e>t&&(i=i*(e-t)+t),i},o=function(t){return t[Math.floor(h(0,t.length))]},l=function(){var t=p(h(0,360)),e=p(h(90,100)),i=p(h(45,85));return"hsl(".concat(t,",").concat(e,"%,").concat(i,"%)")},c=function(t){return t>h()},p=function(t){return.5+t|0},g=function(t){return t?(this.canvas=t.canvas,this.settings=t.settings,this.colors=t.colors,this.shapes=t.shapes,this.images=t.images,this.styles=t.styles,this.ctx=t.canvas.getContext("2d"),this.setup(),this.init()):console.warn("Invalid parameters given to Sparticle()",arguments),this};g.prototype.setup=function(){var t=this.settings;this.frame=0,this.frameoffset=p(h(0,360)),this.size=p(h(t.minSize,t.maxSize)),this.da=this.getAlphaDelta(),this.dx=this.getDeltaX(),this.dy=this.getDeltaY(),this.dd=this.getDriftDelta(),this.dr=this.getRotationDelta(),this.color=this.getColor(),this.shape=this.getShape(),this.image=this.getImage(),this.style=this.getStyle(),this.rotation=t.rotate?a(h(0,360)):0,this.vertical=t.direction>150&&t.direction<210||t.direction>330&&t.direction<390||t.direction>-30&&t.direction<30,this.horizontal=t.direction>60&&t.direction<120||t.direction>240&&t.direction<300},g.prototype.init=function(){var t=this.settings,e=this.canvas;this.alpha=0,(t.speed>0||0===t.alphaSpeed)&&(this.alpha=h(t.minAlpha,t.maxAlpha)),t.bounce?(this.px=p(h(2,e.width-this.size-2)),this.py=p(h(2,e.height-this.size-2))):(this.px=p(h(2*-this.size,e.width+this.size)),this.py=p(h(2*-this.size,e.height+this.size)))},g.prototype.reset=function(){this.setup(),this.py<0?this.py=this.canvas.height+2*this.size:this.py>this.canvas.height&&(this.py=0-2*this.size),this.px<0?this.px=this.canvas.width+2*this.size:this.px>this.canvas.width&&(this.px=0-2*this.size)},g.prototype.bounce=function(){this.settings.direction;(this.py<=0||this.py+this.size>=this.canvas.height)&&(this.dy=-this.dy,this.horizontal&&(this.dd=-this.dd)),(this.px<=0||this.px+this.size>=this.canvas.width)&&(this.dx=-this.dx,this.vertical&&(this.dd=-this.dd))},g.prototype.isOffCanvas=function(){var t=0-2*this.size,e=this.canvas.height+2*this.size,i=this.canvas.width+2*this.size;return this.pxi||this.pye},g.prototype.isTouchingEdge=function(){var t=this.canvas.height-this.size,e=this.canvas.width-this.size;return this.px<0||this.px>e||this.py<0||this.py>t},g.prototype.getColor=function(){return"random"===this.settings.color?o(this.colors):Array.isArray(this.settings.color)?o(this.settings.color):this.settings.color},g.prototype.getShape=function(){return"random"===this.settings.shape?o(this.shapes):Array.isArray(this.settings.shape)?o(this.settings.shape):this.settings.shape},g.prototype.getImage=function(){return Array.isArray(this.settings.imageUrl)?o(this.settings.imageUrl):this.settings.imageUrl},g.prototype.getStyle=function(){return o(this.styles)},g.prototype.getDelta=function(){var t=.1*this.settings.speed;return this.settings.speed&&this.settings.parallax?t+this.size*this.settings.parallax/50:t},g.prototype.getDeltaVariance=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=this.settings.speed||10;return t>0?h(-t,t)*e/100:0},g.prototype.getDeltaX=function(){var t=this.getDelta(),e=this.getDeltaVariance(this.settings.xVariance);return n(this.settings.direction)[0]*t+e},g.prototype.getDeltaY=function(){var t=this.getDelta(),e=this.getDeltaVariance(this.settings.yVariance);return n(this.settings.direction)[1]*t+e},g.prototype.getAlphaDelta=function(){var t=this.settings.alphaVariance,e=h(1,t+1);return c(.5)&&(e=-e),e},g.prototype.getDriftDelta=function(){return this.settings.drift?h(this.settings.drift-this.settings.drift/2,this.settings.drift+this.settings.drift/2):0},g.prototype.getRotationDelta=function(){var t=0;return this.settings.rotate&&this.settings.rotation&&(t=a(h(.5,1.5)*this.settings.rotation),c(.5)&&(t=-t)),t},g.prototype.update=function(){return this.frame+=1,this.updatePosition(),this.updateAlpha(),this},g.prototype.updateAlpha=function(){return this.settings.alphaSpeed>0&&(this.settings.twinkle?this.alpha=this.updateTwinkle():this.alpha=this.updateFade()),this.alpha},g.prototype.updateFade=function(){var t=this.da/1e3*this.settings.alphaSpeed*.5,e=this.alpha+t,i=this.da>0&&e>this.settings.maxAlpha,s=this.da<0&ðis.settings.maxAlpha,s=t=1&&!(arguments[0]instanceof HTMLElement)&&(e=arguments[0],n=arguments[1],r=arguments[2],t=void 0),n&&!r&&(r=n);var a={alphaSpeed:10,alphaVariance:1,bounce:!1,color:"random",randomColor:l,randomColorCount:3,composition:"source-over",count:50,direction:180,drift:1,glow:0,imageUrl:"",maxAlpha:1,maxSize:10,minAlpha:0,minSize:1,parallax:1,rotate:!0,rotation:1,shape:"circle",speed:10,style:"fill",twinkle:!1,xVariance:2,yVariance:2};return this.el=t||document.body,this.settings=i({},a,{},e),this.resizable=!n&&!r,this.width=this.resizable?this.el.clientWidth:n,this.height=this.resizable?this.el.clientHeight:r,this.init=function(){var t=this;return this.sparticles=[],this.colors=this.getColorArray(),this.shapes=this.getShapeArray(),this.styles=this.getStyleArray(),this.imageUrls=this.getImageArray(),this.setupMainCanvas(),this.setupOffscreenCanvasses((function(){t.createSparticles(),t.start()})),window.addEventListener("resize",this),this},this.handleEvent=function(t){var e=this;"resize"===t.type&&(clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout((function(){e.resizable&&(e.width=e.el.clientWidth,e.height=e.el.clientHeight,e.setCanvasSize().resetSparticles())}),200))},this.start=function(){var t=this;return this.loop||(this.loop=new s((function(e){t.drawFrame(e)}))),this.loop.start(),this},this.stop=function(){return this.loop.stop(),this},this.destroy=function(){for(var t in this.stop(),this.el.removeChild(this.canvas),window.removeEventListener("resize",this),this)this.hasOwnProperty(t)&&delete this[t];return this},this.setCanvasSize=function(t,e){return t&&(this.resizable=!1),this.width=t||this.width,this.height=e||this.height,this.canvas.width=this.width,this.canvas.height=this.height,this},this.resetSparticles=this.createSparticles=function(){this.sparticles=[],this.ctx.globalCompositeOperation=this.settings.composition;for(var t=0;te.size})),this.sparticles},this.init()};return u.prototype.getColorArray=function(){var t=Array.isArray(this.settings.color)?this.settings.color:[this.settings.color];if(t.some((function(t){return"random"===t})))for(var e=0;e {
- s.createColorArray();
- s.createShapeArray();
- s.createStyleArray();
- s.setupOffscreenCanvasses(function() {
- s.createSparticles();
- });
+ if( window.mySparticles && window.mySparticles instanceof Sparticles ) {
+ try {
+ window.mySparticles.destroy();
+ } catch(e) {
+ document.querySelector("main").removeChild( s.canvas );
+ }
+ }
+ window.initSparticles();
};
+
var rerenderColors = function(v) {
- if (colorType.type === "rainbow") {
- s.settings.color = "rainbow";
+ if (colorType.type === "random") {
+ options.color = "random";
} else if (colorType.type === "single") {
- s.settings.color = colors.color1;
+ options.color = colors.color1;
} else {
- s.settings.color = Object.keys(colors).map(i => {
+ options.color = Object.keys(colors).map(i => {
return colors[i];
});
}
@@ -123,33 +148,33 @@ window.initGui = function() {
const gui = new dat.GUI({ load: options });
const part = gui.addFolder("Particles");
part.open();
- part.add(s.settings, "count", 1, 500, 1).onFinishChange(rerender);
- part.add(s.settings, "shape", shapes).onFinishChange(rerender);
- part.add(s.settings, "style", styles).onFinishChange(rerender);
- part.add(s.settings, "rotate").onFinishChange(rerender);
- part.add(s.settings, "bounce").onFinishChange(rerender);
+ part.add(options, "count", 1, 500, 1).onFinishChange(rerender);
+ part.add(options, "shape", shapes).onFinishChange(rerender);
+ part.add(options, "style", styles).onFinishChange(rerender);
+ part.add(options, "rotate").onFinishChange(rerender);
+ part.add(options, "bounce").onFinishChange(rerender);
const image = part.addFolder("Image");
- // image.add(s.settings, "imageUrl").onFinishChange(rerender);
- part.add(s.settings, "minSize", 1, 50, 1).onFinishChange(rerender);
- part.add(s.settings, "maxSize", 1, 50, 1).onFinishChange(rerender);
+ // image.add(options, "imageUrl").onFinishChange(rerender);
+ part.add(options, "minSize", 1, 50, 1).onFinishChange(rerender);
+ part.add(options, "maxSize", 1, 50, 1).onFinishChange(rerender);
const anim = gui.addFolder("Animation");
- anim.add(s.settings, "direction", 0, 360, 1).onFinishChange(rerender);
- anim.add(s.settings, "speed", 0, 100, 0.1).onFinishChange(rerender);
- anim.add(s.settings, "rotation", 0, 100, 0.1).onFinishChange(rerender);
+ anim.add(options, "direction", 0, 360, 1).onFinishChange(rerender);
+ anim.add(options, "speed", 0, 100, 0.1).onFinishChange(rerender);
+ anim.add(options, "rotation", 0, 100, 0.1).onFinishChange(rerender);
const move = anim.addFolder("Movement");
- move.add(s.settings, "parallax", 0, 10, 0.1).onFinishChange(rerender);
- move.add(s.settings, "drift", 0, 30, 0.01).onFinishChange(rerender);
- move.add(s.settings, "xVariance", 0, 20, 0.1).onFinishChange(rerender);
- move.add(s.settings, "yVariance", 0, 20, 0.1).onFinishChange(rerender);
+ move.add(options, "parallax", 0, 10, 0.1).onFinishChange(rerender);
+ move.add(options, "drift", 0, 30, 0.01).onFinishChange(rerender);
+ move.add(options, "xVariance", 0, 20, 0.1).onFinishChange(rerender);
+ move.add(options, "yVariance", 0, 20, 0.1).onFinishChange(rerender);
const vis = gui.addFolder("Visual");
- vis.add(s.settings, "glow", 0,150).onFinishChange(rerender);
- vis.add(s.settings, "composition", composites).onFinishChange(rerender);
+ vis.add(options, "glow", 0,150).onFinishChange(rerender);
+ vis.add(options, "composition", composites).onFinishChange(rerender);
const alpha = vis.addFolder("Alpha");
- alpha.add(s.settings, "twinkle").onFinishChange(rerender);
- alpha.add(s.settings, "minAlpha", -2, 2, 0.1).onFinishChange(rerender);
- alpha.add(s.settings, "maxAlpha", -2, 2, 0.1).onFinishChange(rerender);
- alpha.add(s.settings, "alphaSpeed", 0, 50, 1).onFinishChange(rerender);
- alpha.add(s.settings, "alphaVariance", 0, 20, 1).onFinishChange(rerender);
+ alpha.add(options, "twinkle").onFinishChange(rerender);
+ alpha.add(options, "minAlpha", -2, 2, 0.1).onFinishChange(rerender);
+ alpha.add(options, "maxAlpha", -2, 2, 0.1).onFinishChange(rerender);
+ alpha.add(options, "alphaSpeed", 0, 50, 1).onFinishChange(rerender);
+ alpha.add(options, "alphaVariance", 0, 20, 1).onFinishChange(rerender);
const color = vis.addFolder("Color");
color.open();
color.add(colorType, "type", colorOptions).onFinishChange(rerenderColors);
diff --git a/package.json b/package.json
index 5d5000a..89c1a16 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "sparticles",
- "version": "1.0.3",
+ "version": "1.1.0",
"description": "Lightweight, High Performance Particles in Canvas",
"main": "dist/sparticles.esm.js",
"files": [
diff --git a/src/sparticle.js b/src/sparticle.js
index 14c62f4..6a5a186 100644
--- a/src/sparticle.js
+++ b/src/sparticle.js
@@ -9,8 +9,11 @@ import { cartesian, clamp, radian, random, randomArray, roll, round } from "./he
export const Sparticle = function(parent) {
if (parent) {
this.canvas = parent.canvas;
- this.images = parent.images;
this.settings = parent.settings;
+ this.colors = parent.colors;
+ this.shapes = parent.shapes;
+ this.images = parent.images;
+ this.styles = parent.styles;
this.ctx = parent.canvas.getContext("2d");
this.setup();
this.init();
@@ -35,9 +38,10 @@ Sparticle.prototype.setup = function() {
this.dy = this.getDeltaY();
this.dd = this.getDriftDelta();
this.dr = this.getRotationDelta();
- this.shape = this.getShapeOrImage();
- this.style = this.getStyle();
this.color = this.getColor();
+ this.shape = this.getShape();
+ this.image = this.getImage();
+ this.style = this.getStyle();
this.rotation = _.rotate ? radian(random(0, 360)) : 0;
this.vertical =
(_.direction > 150 && _.direction < 210) ||
@@ -143,25 +147,40 @@ Sparticle.prototype.isTouchingEdge = function() {
* @returns {String} - random color from color array
*/
Sparticle.prototype.getColor = function() {
- if (Array.isArray(this.settings.color)) {
+ if (this.settings.color === "random") {
+ return randomArray(this.colors);
+ } else if (Array.isArray(this.settings.color)) {
return randomArray(this.settings.color);
+ } else {
+ return this.settings.color;
}
};
/**
- * get a random shape or image for the particle from the
- * array of shapes set in the options object, or the array
- * of images, if the shape is set to "image"
- * @returns {String} - random shape or image from shape or image array
+ * get a random shape for the particle from the
+ * array of shapes set in the options object
+ * @returns {String} - random shape from shape array
*/
-Sparticle.prototype.getShapeOrImage = function() {
- const shape = this.settings.shape;
- if (Array.isArray(shape)) {
- if (shape[0] === "image" && this.images) {
- return randomArray(this.images);
- } else {
- return randomArray(shape);
- }
+Sparticle.prototype.getShape = function() {
+ if (this.settings.shape === "random") {
+ return randomArray(this.shapes);
+ } else if (Array.isArray(this.settings.shape)) {
+ return randomArray(this.settings.shape);
+ } else {
+ return this.settings.shape;
+ }
+};
+
+/**
+ * get the image for the particle from the array
+ * of possible image urls
+ * @returns {String} - random imageUrl from imageUrl array
+ */
+Sparticle.prototype.getImage = function() {
+ if (Array.isArray(this.settings.imageUrl)) {
+ return randomArray(this.settings.imageUrl);
+ } else {
+ return this.settings.imageUrl;
}
};
@@ -171,7 +190,7 @@ Sparticle.prototype.getShapeOrImage = function() {
* @returns {String} - either "fill" or "stroke"
*/
Sparticle.prototype.getStyle = function() {
- return randomArray(this.settings.style);
+ return randomArray(this.styles);
};
/**
@@ -411,9 +430,11 @@ Sparticle.prototype.updateDrift = function() {
};
Sparticle.prototype.render = function(canvasses) {
- let particleCanvas = canvasses[this.color][this.shape];
- if (this.settings.shape[0] !== "image") {
+ let particleCanvas;
+ if (this.shape !== "image") {
particleCanvas = canvasses[this.color][this.shape][this.style];
+ } else {
+ particleCanvas = canvasses[this.color][this.shape][this.image];
}
const canvasSize = particleCanvas.width;
const scale = this.size / canvasSize;
diff --git a/src/sparticles.js b/src/sparticles.js
index 2d75214..821b573 100644
--- a/src/sparticles.js
+++ b/src/sparticles.js
@@ -22,16 +22,16 @@ import { Sparticle } from "./sparticle.js";
* @param {Number} [options.maxAlpha=1] - maximum alpha value of every particle
* @param {Number} [options.minSize=1] - minimum size of every particle
* @param {Number} [options.maxSize=10] - maximum size of every particle
- * @param {String} [options.style=fill] - fill style of particles (one of; "fill", "stroke" or "both")
* @param {Boolean} [options.bounce=false] - should the particles bounce off edge of canvas
* @param {Number} [options.drift=1] - the "driftiness" of particles which have a horizontal/vertical direction
* @param {Number} [options.glow=0] - the glow effect size of each particle
* @param {Boolean} [options.twinkle=false] - particles to exhibit an alternative alpha transition as "twinkling"
+ * @param {String} [options.style=fill] - fill style of particles (one of; "fill", "stroke" or "both")
+ * @param {(String|String[])} [options.shape=circle] - shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
+ * @param {(String|String[])} [options.imageUrl=] - if shape is "image", define an image url (can be data-uri, must be square (1:1 ratio))
* @param {(String|String[])} [options.color=random] - css color as string, or array of color strings (can also be "random")
* @param {Function} [options.randomColor=randomHsl(index,total)] - a custom function for setting the random colors when color="random"
* @param {Number} [options.randomColorCount=3] - the number of random colors to generate when color is "random"
- * @param {(String|String[])} [options.shape=circle] - shape of particles (any of; circle, square, triangle, diamond, line, image) or "random"
- * @param {(String|String[])} [options.imageUrl=] - if shape is "image", define an image url (can be data-uri, must be square (1:1 ratio))
* @param {Number} [width] - the width of the canvas element
* @param {Number} [height=width] - the height of the canvas element
* @returns {Object} - reference to a new Sparticles instance
@@ -85,9 +85,10 @@ const Sparticles = function(node, options, width, height) {
*/
this.init = function() {
this.sparticles = [];
- this.createColorArray();
- this.createShapeArray();
- this.createStyleArray();
+ this.colors = this.getColorArray();
+ this.shapes = this.getShapeArray();
+ this.styles = this.getStyleArray();
+ this.imageUrls = this.getImageArray();
this.setupMainCanvas();
this.setupOffscreenCanvasses(() => {
this.createSparticles();
@@ -203,60 +204,54 @@ const Sparticles = function(node, options, width, height) {
* convert the input color to an array if it isn't already
* @returns {Array} - array of colors for use in rendering
*/
-Sparticles.prototype.createColorArray = function() {
- const _ = this.settings;
- const isArray = Array.isArray(_.color);
- let isRandom = false;
-
- if (!isArray) {
- _.color = [_.color];
- }
-
- isRandom = _.color.some(c => c === "random");
+Sparticles.prototype.getColorArray = function() {
+ let colors = Array.isArray(this.settings.color) ? this.settings.color : [this.settings.color];
+ const isRandom = colors.some(c => c === "random");
if (isRandom) {
- // it would be silly to have an array of too many colours.
- for (let i = 0; i < _.randomColorCount; i++) {
- _.color[i] = _.randomColor(i, _.randomColorCount);
+ for (let i = 0; i < this.settings.randomColorCount; i++) {
+ colors[i] = this.settings.randomColor(i, this.settings.randomColorCount);
}
}
- return _.color;
+ return colors;
};
/**
* convert the input shape to an array if it isn't already
* @returns {Array} - array of shapes for use in rendering
*/
-Sparticles.prototype.createShapeArray = function() {
- const _ = this.settings;
- const isArray = Array.isArray(_.shape);
- let isRandom = false;
-
- if (!isArray) {
- _.shape = [_.shape];
- }
-
- isRandom = _.shape.some(c => c === "random");
+Sparticles.prototype.getShapeArray = function() {
+ let shapes = Array.isArray(this.settings.shape) ? this.settings.shape : [this.settings.shape];
+ const isRandom = shapes.some(c => c === "random");
if (isRandom) {
- _.shape = ["square", "circle", "star", "diamond"];
+ shapes = ["square", "circle", "triangle"];
}
- return _.shape;
+ return shapes;
+};
+
+/**
+ * convert the imageUrl option to an array if it isn't already
+ * @returns {Array} - array of image urls for use in rendering
+ */
+Sparticles.prototype.getImageArray = function() {
+ return Array.isArray(this.settings.imageUrl) ? this.settings.imageUrl : [this.settings.imageUrl];
};
/**
* convert the input style to an array
* @returns {Array} - array of styles for use in rendering
*/
-Sparticles.prototype.createStyleArray = function() {
- if (this.settings.style !== "fill" && this.settings.style !== "stroke") {
- this.settings.style = ["fill", "stroke"];
+Sparticles.prototype.getStyleArray = function() {
+ let styles = this.settings.style;
+ if (styles !== "fill" && styles !== "stroke") {
+ styles = ["fill", "stroke"];
} else {
- this.settings.style = [this.settings.style];
+ styles = [styles];
}
- return this.settings.style;
+ return styles;
};
/**
@@ -281,57 +276,57 @@ Sparticles.prototype.setupMainCanvas = function() {
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
Sparticles.prototype.setupOffscreenCanvasses = function(callback) {
+ const colors = this.colors.filter((item, index) => this.colors.indexOf(item) === index);
+ const shapes = this.shapes.filter((item, index) => this.shapes.indexOf(item) === index);
+ const styles = this.styles.filter((item, index) => this.styles.indexOf(item) === index);
+ const imageUrls = this.imageUrls.filter((item, index) => this.imageUrls.indexOf(item) === index);
+ const imageCount = colors.length * imageUrls.length;
+ const canvasCount = colors.length * shapes.length * styles.length;
+ let imagesLoaded = 0;
+ let canvassesCreated = 0;
+
this.canvasses = this.canvasses || {};
- this.settings.color.forEach(color => {
+ colors.forEach(color => {
this.canvasses[color] = this.canvasses[color] || {};
- if (this.settings.shape[0] === "image") {
- this.loadAndDrawImages(color, callback);
- } else {
- this.settings.shape.forEach(shape => {
- this.canvasses[color][shape] = this.canvasses[color][shape] || {};
-
- this.settings.style.forEach(style => {
- this.canvasses[color][shape][style] = document.createElement("canvas");
- const canvas = this.canvasses[color][shape][style];
- const ctx = canvas.getContext("2d");
-
- switch (shape) {
- case "square":
- this.drawOffscreenCanvasForSquare(canvas, ctx, color, style);
- if (callback) callback();
- break;
-
- case "line":
- this.drawOffscreenCanvasForLine(canvas, ctx, color, style);
- if (callback) callback();
- break;
-
- case "triangle":
- this.drawOffscreenCanvasForTriangle(canvas, ctx, color, style);
- if (callback) callback();
- break;
-
- case "diamond":
- this.drawOffscreenCanvasForDiamond(canvas, ctx, color, style);
- if (callback) callback();
- break;
-
- case "star":
- this.drawOffscreenCanvasForStar(canvas, ctx, color, style);
- if (callback) callback();
- break;
-
- case "circle":
- default:
- this.drawOffscreenCanvasForCircle(canvas, ctx, color, style);
- if (callback) callback();
- break;
+ shapes.forEach(shape => {
+ this.canvasses[color][shape] = this.canvasses[color][shape] || {};
+
+ if (shape === "image") {
+ imageUrls.forEach((imageUrl, i) => {
+ let image = new Image();
+ const imageCanvas = document.createElement("canvas");
+ this.canvasses[color][shape][imageUrl] = imageCanvas;
+
+ image.onload = () => {
+ imagesLoaded++;
+ this.drawOffscreenCanvasForImage(image, color, imageCanvas);
+ if (callback && imagesLoaded === imageCount) {
+ callback();
+ }
+ };
+
+ image.onerror = () => {
+ console.error("failed to load source image: ", imageUrl);
+ };
+
+ image.src = imageUrl;
+ });
+ } else {
+ styles.forEach(style => {
+ const canvas = document.createElement("canvas");
+ this.canvasses[color][shape][style] = canvas;
+ canvassesCreated++;
+
+ this.drawOffscreenCanvas(shape, style, color, canvas);
+
+ if (callback && canvassesCreated === canvasCount) {
+ callback();
}
});
- });
- }
+ }
+ });
});
};
@@ -395,15 +390,57 @@ Sparticles.prototype.renderColor = function(ctx, style) {
};
/**
- * create, setup and render an offscreen canvas for a
- * Square Particle of the given color
+ * pass-through the needed parameters to the offscreen canvas
+ * draw function associated with the given shape
+ * @param {String} shape - shape of the canvas to draw (eg: "circle")
+ * @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
* @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
+ * @returns {HTMLCanvasElement} - the created offscreen canvas
+ */
+Sparticles.prototype.drawOffscreenCanvas = function(shape, style, color, canvas) {
+ return this.offScreenCanvas[shape].call(this, style, color, canvas);
+};
+
+/**
+ * object of shapes to draw
+ */
+Sparticles.prototype.offScreenCanvas = {};
+
+/**
+ * create, setup and render an offscreen canvas for a
+ * Circle Particle of the given color
+ * @param {String} style - style (either "fill" or "stroke")
* @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
+ * @returns {HTMLCanvasElement} - the created offscreen canvas
+ */
+Sparticles.prototype.offScreenCanvas.circle = function(style, color, canvas) {
+ const ctx = canvas.getContext("2d");
+ const size = this.settings.maxSize;
+ const lineSize = this.getLineSize(size);
+ const glowSize = this.getGlowSize(size);
+ const canvasSize = size + lineSize + glowSize;
+ canvas.width = canvasSize;
+ canvas.height = canvasSize;
+ this.renderGlow(ctx, color, size);
+ this.renderStyle(ctx, color, lineSize, style);
+ ctx.beginPath();
+ ctx.ellipse(canvasSize / 2, canvasSize / 2, size / 2, size / 2, 0, 0, 360);
+ this.renderColor(ctx, style);
+ return canvas;
+};
+
+/**
+ * create, setup and render an offscreen canvas for a
+ * Square Particle of the given color
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForSquare = function(canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.square = function(style, color, canvas) {
+ const ctx = canvas.getContext("2d");
const size = this.settings.maxSize;
const lineSize = this.getLineSize(size);
const glowSize = this.getGlowSize(size);
@@ -421,13 +458,13 @@ Sparticles.prototype.drawOffscreenCanvasForSquare = function(canvas, ctx, color,
/**
* create, setup and render an offscreen canvas for a
* Line/Curve Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForLine = function(canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.line = function(style, color, canvas) {
+ const ctx = canvas.getContext("2d");
const size = this.settings.maxSize * 2;
const lineSize = this.getLineSize(size);
const glowSize = this.getGlowSize(size);
@@ -450,13 +487,13 @@ Sparticles.prototype.drawOffscreenCanvasForLine = function(canvas, ctx, color, s
/**
* create, setup and render an offscreen canvas for a
* Triangle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForTriangle = function(canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.triangle = function(style, color, canvas) {
+ const ctx = canvas.getContext("2d");
const size = this.settings.maxSize;
const lineSize = this.getLineSize(size);
const glowSize = this.getGlowSize(size);
@@ -480,13 +517,13 @@ Sparticles.prototype.drawOffscreenCanvasForTriangle = function(canvas, ctx, colo
/**
* create, setup and render an offscreen canvas for a
* Diamond Sparkle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForDiamond = function(canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.diamond = function(style, color, canvas) {
+ const ctx = canvas.getContext("2d");
const size = this.settings.maxSize;
const half = size / 2;
const lineSize = this.getLineSize(size);
@@ -543,13 +580,13 @@ Sparticles.prototype.drawOffscreenCanvasForDiamond = function(canvas, ctx, color
/**
* create, setup and render an offscreen canvas for a
* Star Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
* @param {String} style - style (either "fill" or "stroke")
+ * @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawOffscreenCanvasForStar = function(canvas, ctx, color, style) {
+Sparticles.prototype.offScreenCanvas.star = function(style, color, canvas) {
+ const ctx = canvas.getContext("2d");
const size = 52;
const lineSize = this.getLineSize(size);
const glowSize = this.getGlowSize(size);
@@ -606,77 +643,17 @@ Sparticles.prototype.drawOffscreenCanvasForStar = function(canvas, ctx, color, s
return canvas;
};
-/**
- * create, setup and render an offscreen canvas for a
- * Circle Particle of the given color
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
- * @param {String} color - the color to fill/stroke with
- * @param {String} style - style (either "fill" or "stroke")
- * @returns {HTMLCanvasElement} - the created offscreen canvas
- */
-Sparticles.prototype.drawOffscreenCanvasForCircle = function(canvas, ctx, color, style) {
- const size = this.settings.maxSize;
- const lineSize = this.getLineSize(size);
- const glowSize = this.getGlowSize(size);
- const canvasSize = size + lineSize + glowSize;
- canvas.width = canvasSize;
- canvas.height = canvasSize;
- this.renderGlow(ctx, color, size);
- this.renderStyle(ctx, color, lineSize, style);
- ctx.beginPath();
- ctx.ellipse(canvasSize / 2, canvasSize / 2, size / 2, size / 2, 0, 0, 360);
- this.renderColor(ctx, style);
- return canvas;
-};
-
-/**
- * set up the needed array for referencing the images in the Sparticle()
- * instance, then loop through each image and load it before running the callback
- * @param {String} color - the color of the image that we're loading
- * @param {Function} callback - callback function to run after images load
- */
-Sparticles.prototype.loadAndDrawImages = function(color, callback) {
- const imgUrls = this.settings.imageUrl;
- const imageUrls = Array.isArray(imgUrls) ? imgUrls : [imgUrls];
- const imageCount = imageUrls.length;
- let imagesLoaded = 0;
- this.images = [];
-
- imageUrls.forEach((imageUrl, i) => {
- this.images.push("image" + i);
- this.canvasses[color]["image" + i] = document.createElement("canvas");
- const canvas = this.canvasses[color]["image" + i];
- const ctx = canvas.getContext("2d");
- const image = new Image();
-
- image.onload = () => {
- imagesLoaded++;
- this.drawImageOffscreenCanvas(image, canvas, ctx, color);
- if (callback && imagesLoaded === imageCount) {
- callback();
- }
- };
-
- image.onerror = () => {
- console.error("failed to load source image: ", imageUrl);
- };
-
- image.src = imageUrl;
- });
-};
-
/**
* create, setup and render an offscreen canvas for a
* Custom Image Particle of the given color
* @param {HTMLImageElement} image - the image element that has loaded
- * @param {HTMLCanvasElement} canvas - the canvas element
- * @param {CanvasRenderingContext2D} ctx - the canvas context
* @param {String} color - the color to fill/stroke with
+ * @param {HTMLCanvasElement} canvas - the canvas element
* @returns {HTMLCanvasElement} - the created offscreen canvas
*/
-Sparticles.prototype.drawImageOffscreenCanvas = function(image, canvas, ctx, color) {
+Sparticles.prototype.drawOffscreenCanvasForImage = function(image, color, canvas) {
const size = image.width;
+ const ctx = canvas.getContext("2d");
canvas.width = size;
canvas.height = size;
ctx.drawImage(image, 0, 0, size, size, 0, 0, size, size);