sprinkler
Advanced tools
Comparing version 0.4.4 to 0.5.0
// Having index.js makes possible to use sprinkler through browserify. | ||
// Otherwise there will be require path errors. | ||
module.exports = require('./src/sprinkler'); | ||
module.exports = require('./src/sprinkler') |
{ | ||
"name": "sprinkler", | ||
"version": "0.4.4", | ||
"version": "0.5.0", | ||
"description": "Make awesome sprite rain effects on canvas. Give a canvas and a list of image paths and start() to make it rain!", | ||
"keywords": [ | ||
"canvas", | ||
"animation" | ||
"animation", | ||
"sprite", | ||
"rain", | ||
"waterfall" | ||
], | ||
"homepage": "https://github.com/axelpale/sprinkler", | ||
"main": "index.js", | ||
"unpkg": "dist/sprinkler.min.js", | ||
"author": { | ||
@@ -22,23 +26,15 @@ "name": "Akseli Palen", | ||
"devDependencies": { | ||
"gulp": "^3.8.10", | ||
"gulp-rename": "^1.2.0", | ||
"gulp-uglify": "^1.0.2", | ||
"gulp-sourcemaps": "^1.2.8", | ||
"gulp-mocha": "^2.0.0", | ||
"should": "^4.4.2", | ||
"jshint": "latest", | ||
"browserify": "^8.0.3", | ||
"watchify": "^2.2.1", | ||
"uglify-js": "^2.4.16", | ||
"minifyify": "^5.0.0" | ||
"genversion": "^2.2.0", | ||
"standard": "^14.2.0", | ||
"webpack": "^4.40.2", | ||
"webpack-cli": "^3.3.8" | ||
}, | ||
"scripts": { | ||
"start": "python -m SimpleHTTPServer", | ||
"build": "npm run build:bundle && npm run build:min", | ||
"build:bundle": "browserify src/sprinkler.js --standalone Sprinkler -o sprinkler.js", | ||
"build:watch": "watchify src/sprinkler.js --standalone Sprinkler -o sprinkler.js", | ||
"build:min": "browserify src/sprinkler.js --standalone Sprinkler --debug --plugin [minifyify --map sprinkler.min.js.map --output sprinkler.min.js.map] > sprinkler.min.js", | ||
"test": "gulp test", | ||
"lint": "jshint src/*.js test/sprinkler.test.js" | ||
"build": "webpack", | ||
"gv": "genversion src/version.js", | ||
"release": "npm run lint && npm run gv && npm run build && npm publish", | ||
"test": "npm run lint", | ||
"lint": "standard index.js 'src/**/*.js' webpack.config.js" | ||
} | ||
} |
@@ -1,3 +0,5 @@ | ||
# sprinkler.js<sup>v0.4.3</sup> | ||
# sprinkler.js | ||
[![npm](https://badge.fury.io/js/sprinkler.svg)](https://badge.fury.io/js/sprinkler) | ||
With Sprinkler you can create an image rain on canvas. Give it a canvas element and a list of image paths and call start() to make it rain bananas or frogs or anything you can imagine! | ||
@@ -11,7 +13,8 @@ | ||
- [Snowfall](http://rawgit.com/axelpale/sprinkler/master/examples/snowfall.html) | ||
- [Money](http://rawgit.com/axelpale/sprinkler/master/examples/money.html) | ||
- [Fire](http://rawgit.com/axelpale/sprinkler/master/examples/fire.html) | ||
- [Bananas](http://rawgit.com/axelpale/sprinkler/master/examples/bananas.html) | ||
- [Love](http://rawgit.com/axelpale/sprinkler/master/examples/love.html) | ||
- [Snowfall](https://axelpale.github.io/sprinkler/examples/snowfall.html) | ||
- [Money](https://axelpale.github.io/sprinkler/examples/money.html) | ||
- [Fire](https://axelpale.github.io/sprinkler/examples/fire.html) | ||
- [Bananas](https://axelpale.github.io/sprinkler/examples/bananas.html) | ||
- [Love](https://axelpale.github.io/sprinkler/examples/love.html) | ||
- [Rainy Night](https://axelpale.github.io/sprinkler/examples/rainynight.html), suitable for [projection mapping](https://en.wikipedia.org/wiki/Projection_mapping). | ||
@@ -46,2 +49,4 @@ | ||
Install via [npm](https://www.npmjs.com/package/sprinkler): | ||
$ npm install sprinkler | ||
@@ -79,7 +84,7 @@ --- | ||
- `selectImages`, an array of indices of the images to be used | ||
- `selectImages`, an array of indices of the images to be used. Defaults to [0, 1, 2, ..., n] where `n = imagePaths.length - 1`. Use same index multiple times to form weighted distribution. | ||
- `imagesInSecond`, an average number of dropped images in a second | ||
- `zMin` and `zMax`, range for initial scale, __z__, in [0, Inf] | ||
- `rMin` and `rMax`, range for initial __r__otation, in [0, 2*Math.PI] | ||
- `aMin` and `aMax`, range for initial transparency (__a__lpha), in [0, 1] | ||
- `rMin` and `rMax`, range for initial rotation, in [0, 2*Math.PI] | ||
- `aMin` and `aMax`, range for initial transparency (alpha), in [0, 1] | ||
- `dxMin` and `dxMax`, range for horizontal velocity, in [-Inf, Inf] | ||
@@ -86,0 +91,0 @@ - `dyMin` and `dyMax`, range for vertical velocity, in [0, Inf] |
var Particle = function ( x, y, z, r, a, | ||
dx, dy, dz, dr, da, | ||
ddx, ddy, ddz, ddr, dda, | ||
img, w, h) { | ||
this.x = x; | ||
this.y = y; | ||
this.z = z; // scale | ||
this.r = r; | ||
this.a = a; // opacity | ||
this.dx = dx; | ||
this.dy = dy; | ||
this.dz = dz; | ||
this.dr = dr; | ||
this.da = da; | ||
this.ddx = ddx; | ||
this.ddy = ddy; | ||
this.ddz = ddz; | ||
this.ddr = ddr; | ||
this.dda = dda; | ||
var Particle = function ( | ||
x, y, z, r, a, | ||
dx, dy, dz, dr, da, | ||
ddx, ddy, ddz, ddr, dda, | ||
img, w, h | ||
) { | ||
this.x = x | ||
this.y = y | ||
this.z = z // scale | ||
this.r = r | ||
this.a = a // opacity | ||
this.dx = dx | ||
this.dy = dy | ||
this.dz = dz | ||
this.dr = dr | ||
this.da = da | ||
this.ddx = ddx | ||
this.ddy = ddy | ||
this.ddz = ddz | ||
this.ddr = ddr | ||
this.dda = dda | ||
this.img = img; // source image // read-only | ||
this.w = w; // source image width // read-only | ||
this.h = h; // source image height // read-only | ||
}; | ||
this.img = img // source image // read-only | ||
this.w = w // source image width // read-only | ||
this.h = h // source image height // read-only | ||
} | ||
@@ -31,14 +33,14 @@ Particle.prototype.tick = function (dt) { | ||
// seconds | ||
this.x += this.dx * dt; | ||
this.y += this.dy * dt; | ||
this.z += this.dz * dt; | ||
this.r += this.dr * dt; | ||
this.a = Math.min(1, Math.max(0, this.a + this.da * dt)); | ||
this.dx += this.ddx * dt; | ||
this.dy += this.ddy * dt; | ||
this.dz += this.ddz * dt; | ||
this.dr += this.ddr * dt; | ||
this.da += this.dda * dt; | ||
}; | ||
this.x += this.dx * dt | ||
this.y += this.dy * dt | ||
this.z += this.dz * dt | ||
this.r += this.dr * dt | ||
this.a = Math.min(1, Math.max(0, this.a + this.da * dt)) | ||
this.dx += this.ddx * dt | ||
this.dy += this.ddy * dt | ||
this.dz += this.ddz * dt | ||
this.dr += this.ddr * dt | ||
this.da += this.dda * dt | ||
} | ||
exports.Particle = Particle; | ||
exports.Particle = Particle |
@@ -6,54 +6,13 @@ | ||
var loadImages = require('./loadimages'); | ||
var Particle = require('./particle').Particle; | ||
var loadImages = require('./lib/loadimages') | ||
var fitOnResize = require('./lib/fitOnResize') | ||
var extendValid = require('./lib/extendValid') | ||
var hasProp = require('./lib/hasProp') | ||
var Particle = require('./particle').Particle | ||
var stat = require('./stat'); | ||
var randomIn = stat.randomIn; | ||
var randomPick = stat.randomPick; | ||
var samplePoisson = stat.samplePoisson; | ||
var stat = require('./lib/stat') | ||
var randomIn = stat.randomIn | ||
var randomPick = stat.randomPick | ||
var samplePoisson = stat.samplePoisson | ||
var extendValid = function (source, dest) { | ||
// Purpose: fill valid options to default options object. | ||
// Valid option in a source exist in dest and is same type. | ||
// Return | ||
// nothing, modifies dest in place. | ||
var k; | ||
for (k in source) { | ||
if (source.hasOwnProperty(k)) { | ||
if (dest.hasOwnProperty(k)) { | ||
if (typeof source[k] === typeof dest[k]) { | ||
dest[k] = source[k]; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
var makeCanvasAutoFullwindow = function (canvas) { | ||
// Canvas is resized when window size changes, e.g. | ||
// when a mobile device is tilted. | ||
// | ||
// Parameter | ||
// canvas | ||
// HTML Canvas element | ||
// | ||
var resizeCanvas = function () { | ||
canvas.width = window.innerWidth; | ||
canvas.height = window.innerHeight; | ||
}; | ||
// resize the canvas to fill browser window dynamically | ||
window.addEventListener('resize', resizeCanvas, false); | ||
// Initially resized to fullscreen. | ||
resizeCanvas(); | ||
}; | ||
// ********** | ||
// Exceptions | ||
// ********** | ||
//... | ||
// *********** | ||
@@ -64,25 +23,25 @@ // Constructor | ||
var Sprinkler = function (canvas) { | ||
// Parameters: | ||
// canvas: HTML Canvas | ||
// | ||
// All the loaded images are stored here | ||
var sourceImages = []; | ||
// Each load has a separate id and a set of starts. | ||
// New load is created on load call. New start for a load is | ||
// created on start call. | ||
var loads = {}; | ||
var loads = {} | ||
// Images are modeled as particles and stored here | ||
var particles = []; | ||
var particles = [] | ||
// To pause animation loop | ||
var running = false; | ||
var running = false | ||
// number, unix timestamp milliseconds of most recent frame. | ||
var past = null; | ||
var past = null | ||
// Everything is drawn on canvas. | ||
var ctx = canvas.getContext('2d'); | ||
var ctx = canvas.getContext('2d') | ||
// Make canvas resize automatically to full window area | ||
makeCanvasAutoFullwindow(canvas); | ||
fitOnResize(canvas) | ||
@@ -92,7 +51,6 @@ // We use this to add particles in to the model. | ||
// Turn images to particles | ||
var p, w, h, image; | ||
w = canvas.width; | ||
h = canvas.height; | ||
var w = canvas.width | ||
// var h = canvas.height | ||
image = randomPick(options.selectImages); | ||
var image = randomPick(options.selectImages) | ||
@@ -117,14 +75,14 @@ return new Particle( | ||
image.width, image.height | ||
); | ||
}; | ||
) | ||
} | ||
var createParticles = function (options, dt) { | ||
var i; | ||
var particlesInSecond = options.imagesInSecond; | ||
var particlesInDt = dt * particlesInSecond; | ||
var numOfNewParticles = samplePoisson(particlesInDt); | ||
var i | ||
var particlesInSecond = options.imagesInSecond | ||
var particlesInDt = dt * particlesInSecond | ||
var numOfNewParticles = samplePoisson(particlesInDt) | ||
for (i = 0; i < numOfNewParticles; i += 1) { | ||
particles.push(createParticle(options)); | ||
particles.push(createParticle(options)) | ||
} | ||
}; | ||
} | ||
@@ -136,4 +94,4 @@ // Model is simulated forward every frame | ||
// simulation time, seconds | ||
var i, k, l, load, startOptions, h, | ||
bufferParticles, visible, pw, ph, maxRadius; | ||
var i, k, l, load, startOptions, h | ||
var bufferParticles, visible, pw, ph, maxRadius | ||
@@ -145,3 +103,3 @@ // To avoid huge wave of particles, they are created only | ||
for (i = 0; i < particles.length; i += 1) { | ||
particles[i].tick(dt); | ||
particles[i].tick(dt) | ||
} | ||
@@ -151,8 +109,8 @@ | ||
for (k in loads) { | ||
if (loads.hasOwnProperty(k)) { | ||
load = loads[k]; | ||
if (hasProp(loads, k)) { | ||
load = loads[k] | ||
for (l in load) { | ||
if (load.hasOwnProperty(l)) { | ||
startOptions = load[l]; | ||
createParticles(startOptions, dt); | ||
if (hasProp(load, l)) { | ||
startOptions = load[l] | ||
createParticles(startOptions, dt) | ||
} | ||
@@ -167,15 +125,15 @@ } | ||
// by replacing particles array. | ||
h = canvas.height; | ||
bufferParticles = []; | ||
h = canvas.height | ||
bufferParticles = [] | ||
for (i = 0; i < particles.length; i += 1) { | ||
pw = particles[i].w; | ||
ph = particles[i].h; | ||
maxRadius = particles[i].z * Math.max(pw, ph) / 2; | ||
visible = (particles[i].y < h + maxRadius); | ||
pw = particles[i].w | ||
ph = particles[i].h | ||
maxRadius = particles[i].z * Math.max(pw, ph) / 2 | ||
visible = (particles[i].y < h + maxRadius) | ||
if (visible) { | ||
bufferParticles.push(particles[i]); | ||
bufferParticles.push(particles[i]) | ||
} | ||
} | ||
particles = bufferParticles; | ||
}; | ||
particles = bufferParticles | ||
} | ||
@@ -185,10 +143,10 @@ // View is rendered each frame | ||
// Draw; View current model | ||
var i, imgW, imgH; | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
var i, imgW, imgH | ||
ctx.clearRect(0, 0, canvas.width, canvas.height) | ||
for (i = 0; i < particles.length; i += 1) { | ||
ctx.globalAlpha = particles[i].a; | ||
imgW = particles[i].z * particles[i].w; | ||
imgH = particles[i].z * particles[i].h; | ||
ctx.translate(particles[i].x, particles[i].y); | ||
ctx.rotate(particles[i].r); | ||
ctx.globalAlpha = particles[i].a | ||
imgW = particles[i].z * particles[i].w | ||
imgH = particles[i].z * particles[i].h | ||
ctx.translate(particles[i].x, particles[i].y) | ||
ctx.rotate(particles[i].r) | ||
ctx.drawImage( | ||
@@ -199,21 +157,21 @@ particles[i].img, | ||
imgW, imgH | ||
); | ||
ctx.setTransform(1, 0, 0, 1, 0, 0); // resetTransform | ||
ctx.globalAlpha = 1; // reset alpha | ||
) | ||
ctx.setTransform(1, 0, 0, 1, 0, 0) // resetTransform | ||
ctx.globalAlpha = 1 // reset alpha | ||
} | ||
}; | ||
} | ||
var startAnimationLoop = function loopFn() { | ||
var present, dt; | ||
var startAnimationLoop = function loopFn () { | ||
var present, dt | ||
// Time difference from previous frame in milliseconds | ||
present = Date.now(); | ||
dt = (past === null) ? 0 : present - past; | ||
past = present; | ||
present = Date.now() | ||
dt = (past === null) ? 0 : present - past | ||
past = present | ||
// Update Model | ||
tickModel(dt / 1000); // secs | ||
tickModel(dt / 1000) // secs | ||
// Draw; View current model | ||
tickView(); | ||
tickView() | ||
@@ -223,17 +181,13 @@ // Recursion | ||
if (running) { | ||
window.requestAnimationFrame(loopFn); | ||
window.requestAnimationFrame(loopFn) | ||
} | ||
}; | ||
} | ||
var startAnimation = function () { | ||
if (!running) { | ||
running = true; | ||
startAnimationLoop(); | ||
running = true | ||
startAnimationLoop() | ||
} | ||
}; | ||
} | ||
var stopAnimation = function () { | ||
running = false; | ||
}; | ||
this.load = function (imagePaths, callback) { | ||
@@ -248,10 +202,13 @@ // Parameter | ||
// 'InvalidOptionsError' | ||
loadImages(imagePaths, function then(err, imageElements) { | ||
if (err) { callback(err, null); return; } | ||
loadImages(imagePaths, function (err, imageElements) { | ||
if (err) { | ||
callback(err, null) | ||
return | ||
} | ||
// loads is browsed through when creating particles. | ||
var loadId = Math.random().toString(); | ||
loads[loadId] = {}; | ||
var loadId = Math.random().toString() | ||
loads[loadId] = {} | ||
var start = function start(options) { | ||
var start = function (options) { | ||
// Parameter | ||
@@ -261,7 +218,7 @@ // options | ||
// with it multiple times. | ||
var i, defaultOptions; | ||
var i, defaultOptions | ||
// Default parameter | ||
if (typeof options === 'undefined') { | ||
options = {}; | ||
options = {} | ||
} | ||
@@ -271,3 +228,3 @@ | ||
if (Object.prototype.toString.call(options) !== '[object Object]') { | ||
throw 'InvalidOptionsError'; | ||
throw new Error('Invalid options object') | ||
} | ||
@@ -279,54 +236,65 @@ | ||
selectImages: imageElements, | ||
zMin: 0.38, zMax: 1, | ||
rMin: 0, rMax: 2 * Math.PI, | ||
aMin: 1, aMax: 1, | ||
dxMin: -1, dxMax: 1, | ||
dyMin: 100, dyMax: 100, | ||
dzMin: 0, dzMax: 0, | ||
drMin: -1, drMax: 1, | ||
daMin: 0, daMax: 0, | ||
ddxMin: 0, ddxMax: 0, | ||
ddyMin: 0, ddyMax: 0, | ||
ddzMin: 0, ddzMax: 0, | ||
ddrMin: 0, ddrMax: 0, | ||
ddaMin: 0, ddaMax: 0, | ||
zMin: 0.38, | ||
zMax: 1, | ||
rMin: 0, | ||
rMax: 2 * Math.PI, | ||
aMin: 1, | ||
aMax: 1, | ||
dxMin: -1, | ||
dxMax: 1, | ||
dyMin: 100, | ||
dyMax: 100, | ||
dzMin: 0, | ||
dzMax: 0, | ||
drMin: -1, | ||
drMax: 1, | ||
daMin: 0, | ||
daMax: 0, | ||
ddxMin: 0, | ||
ddxMax: 0, | ||
ddyMin: 0, | ||
ddyMax: 0, | ||
ddzMin: 0, | ||
ddzMax: 0, | ||
ddrMin: 0, | ||
ddrMax: 0, | ||
ddaMin: 0, | ||
ddaMax: 0, | ||
imagesInSecond: 7, | ||
stopAfter: Infinity, | ||
onStop: function noop() {} | ||
}; | ||
onStop: function () {} // no-op | ||
} | ||
// Push all valid options to defaultOptions. | ||
extendValid(options, defaultOptions); | ||
extendValid(options, defaultOptions) | ||
// selectImages needs still to be defined. | ||
// Map image indices to actual image objects. | ||
if (options.hasOwnProperty('selectImages')) { | ||
defaultOptions.selectImages = []; | ||
if (hasProp(options, 'selectImages')) { | ||
defaultOptions.selectImages = [] | ||
for (i = 0; i < options.selectImages.length; i += 1) { | ||
defaultOptions.selectImages[i] = imageElements[options.selectImages[i]]; | ||
defaultOptions.selectImages[i] = imageElements[options.selectImages[i]] | ||
} | ||
} | ||
options = defaultOptions; | ||
options = defaultOptions | ||
var startId = Math.random().toString(); | ||
loads[loadId][startId] = options; | ||
var startId = Math.random().toString() | ||
loads[loadId][startId] = options | ||
startAnimation(); | ||
return function stop() { | ||
delete loads[loadId][startId]; | ||
}; | ||
}; | ||
startAnimation() | ||
return function stop () { | ||
delete loads[loadId][startId] | ||
} | ||
} | ||
callback(null, start); | ||
}); | ||
}; | ||
}; | ||
callback(null, start) | ||
}) | ||
} | ||
} | ||
exports.create = function (canvas, options) { | ||
return new Sprinkler(canvas, options); | ||
}; | ||
return new Sprinkler(canvas, options) | ||
} | ||
// ************* | ||
@@ -339,9 +307,7 @@ // Extendability | ||
// s.myFunction() | ||
exports.extension = Sprinkler.prototype; | ||
exports.extension = Sprinkler.prototype | ||
// ******* | ||
// Version | ||
// ******* | ||
exports.version = '0.4.3'; | ||
exports.version = require('./version') |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
49817
4
15
152
0
452
1