sprinkler
Advanced tools
Comparing version 0.4.1 to 0.4.2
{ | ||
"name": "sprinkler", | ||
"version": "0.4.1", | ||
"version": "0.4.2", | ||
"description": "Make awesome sprite rain effects on canvas. Give a canvas and a list of image paths and start() to make it rain!", | ||
@@ -29,11 +29,16 @@ "keywords": [ | ||
"jshint": "latest", | ||
"watch": "^0.13.0" | ||
"browserify": "^8.0.3", | ||
"watchify": "^2.2.1", | ||
"uglify-js": "^2.4.16", | ||
"minifyify": "^5.0.0" | ||
}, | ||
"scripts": { | ||
"start": "python -m SimpleHTTPServer", | ||
"build": "gulp", | ||
"build:watch": "watch 'npm run build' src/", | ||
"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/sprinkler.js test/sprinkler.test.js" | ||
"lint": "jshint src/*.js test/sprinkler.test.js" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
# sprinkler.js<sup>v0.4.1</sup> | ||
# sprinkler.js<sup>v0.4.2</sup> | ||
@@ -3,0 +3,0 @@ 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! |
764
sprinkler.js
@@ -1,279 +0,246 @@ | ||
// ***************************** | ||
// UMD pattern commonjsStrict.js | ||
// https://github.com/umdjs/umd | ||
// ***************************** | ||
(function (root, factory) { | ||
'use strict'; | ||
if (typeof define === 'function' && define.amd) { | ||
// AMD. Register as an anonymous module. | ||
define(['exports'], factory); | ||
} else if (typeof exports === 'object') { | ||
// CommonJS & Node | ||
factory(exports); | ||
} else { | ||
// Browser globals | ||
factory((root.Sprinkler = {})); | ||
} | ||
}(this, function (exports) { | ||
'use strict'; | ||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Sprinkler=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
module.exports = function loadImages(imgSrcs, then) { | ||
// then(err, imgElements) | ||
// Calls then after all the images were loaded. | ||
var i, imgs, numberOfImages, onload, onloadsCalled, | ||
thereWasError, thereWasSuccess; | ||
numberOfImages = imgSrcs.length; | ||
thereWasSuccess = false; | ||
thereWasError = false; | ||
imgs = []; | ||
onloadsCalled = 0; | ||
onload = function () { | ||
// Note: | ||
// this = Image | ||
if (!thereWasError) { | ||
onloadsCalled += 1; | ||
var isFinalImage = (onloadsCalled === numberOfImages); | ||
if (isFinalImage) { | ||
thereWasSuccess = true; | ||
then(null, imgs); | ||
} | ||
} | ||
}; | ||
// **************** | ||
// Helper functions | ||
// **************** | ||
onerror = function (errMsg) { | ||
// Note: | ||
// this = Image | ||
var loadImages = function (imgSrcs, then) { | ||
// then(err, imgElements) | ||
// Calls then after all the images were loaded. | ||
var i, imgs, numberOfImages, onload, onloadsCalled, thereWasError; | ||
numberOfImages = imgSrcs.length; | ||
thereWasError = false; | ||
// No errors after success. | ||
if (!thereWasSuccess) { | ||
thereWasError = true; | ||
then(errMsg, null); | ||
} | ||
imgs = []; | ||
// Prevent firing the default event handler | ||
// https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.onerror#Parameters | ||
return true; | ||
}; | ||
onloadsCalled = 0; | ||
onload = function () { | ||
// Note: | ||
// this = Image | ||
if (!thereWasError) { | ||
onloadsCalled += 1; | ||
var isFinalImage = (onloadsCalled === numberOfImages); | ||
if (isFinalImage) { | ||
then(null, imgs); | ||
} | ||
} | ||
}; | ||
for (i = 0; i < imgSrcs.length; i += 1) { | ||
imgs.push(new Image()); | ||
imgs[i].onload = onload; | ||
imgs[i].onerror = onerror; | ||
imgs[i].src = imgSrcs[i]; | ||
} | ||
}; | ||
onerror = function (errMsg) { | ||
// Note: | ||
// this = Image | ||
thereWasError = true; | ||
then(errMsg, null); | ||
},{}],2:[function(require,module,exports){ | ||
// Prevent firing the default event handler | ||
// https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.onerror#Parameters | ||
return true; | ||
}; | ||
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; | ||
for (i = 0; i < imgSrcs.length; i += 1) { | ||
imgs.push(new Image()); | ||
imgs[i].onload = onload; | ||
imgs[i].onerror = onerror; | ||
imgs[i].src = imgSrcs[i]; | ||
} | ||
}; | ||
this.img = img; // source image // read-only | ||
this.w = w; // source image width // read-only | ||
this.h = h; // source image height // read-only | ||
}; | ||
var randomIn = function (min, max) { | ||
// Continuous uniform distribution. | ||
// Return x: min <= x < max | ||
var d = max - min; | ||
return min + d * Math.random(); | ||
}; | ||
Particle.prototype.tick = function (dt) { | ||
// Parameter | ||
// 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; | ||
}; | ||
var randomPick = function (array) { | ||
// Return one randomly picked element. | ||
// Discrete uniform distribution. | ||
var min = 0; | ||
var max = array.length; | ||
var continuousIndex = randomIn(min, max); | ||
var discreteIndex = Math.floor(continuousIndex); | ||
var i = discreteIndex; | ||
return array[i]; | ||
}; | ||
exports.Particle = Particle; | ||
var samplePoisson = function (rate) { | ||
// Purpose: number of images to drop in each interval. | ||
// Take a sample from poisson distribution. | ||
// https://en.wikipedia.org/wiki/Poisson_distribution#Generating_Poisson-distributed_random_variables | ||
var L, k, p, u; | ||
L = Math.exp(-rate); | ||
k = 0; | ||
p = 1; | ||
do { | ||
k += 1; | ||
u = Math.random(); | ||
p *= u; | ||
} while (p > L); | ||
return k - 1; | ||
}; | ||
},{}],3:[function(require,module,exports){ | ||
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]; | ||
} | ||
// **************** | ||
// Helper functions | ||
// **************** | ||
var loadImages = require('./loadimages'); | ||
var Particle = require('./particle').Particle; | ||
var stat = require('./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(); | ||
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(); | ||
}; | ||
// TODO Remove useless parameters | ||
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 | ||
}; | ||
Particle.prototype.tick = function (dt) { | ||
// Parameter | ||
// 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; | ||
}; | ||
// ********** | ||
// Exceptions | ||
// ********** | ||
//... | ||
// ********** | ||
// Exceptions | ||
// ********** | ||
//... | ||
// *********** | ||
// Constructor | ||
// *********** | ||
var Sprinkler = function (canvas) { | ||
// *********** | ||
// Constructor | ||
// *********** | ||
// All the loaded images are stored here | ||
var sourceImages = []; | ||
var Sprinkler = function (canvas) { | ||
// 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 = {}; | ||
// All the loaded images are stored here | ||
var sourceImages = []; | ||
// Images are modeled as particles and stored here | ||
var particles = []; | ||
// 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 = {}; | ||
// To pause animation loop | ||
var running = false; | ||
// Images are modeled as particles and stored here | ||
var particles = []; | ||
// number, unix timestamp milliseconds of most recent frame. | ||
var past = null; | ||
// To pause animation loop | ||
var running = false; | ||
// Everything is drawn on canvas. | ||
var ctx = canvas.getContext('2d'); | ||
// number, unix timestamp milliseconds of most recent frame. | ||
var past = null; | ||
// Make canvas resize automatically to full window area | ||
makeCanvasAutoFullwindow(canvas); | ||
// Everything is drawn on canvas. | ||
var ctx = canvas.getContext('2d'); | ||
// We use this to add particles in to the model. | ||
var createParticle = function (options) { | ||
// Turn images to particles | ||
var p, w, h, image; | ||
w = canvas.width; | ||
h = canvas.height; | ||
// Make canvas resize automatically to full window area | ||
makeCanvasAutoFullwindow(canvas); | ||
image = randomPick(options.selectImages); | ||
// We use this to add particles in to the model. | ||
var createParticle = function (options) { | ||
// Turn images to particles | ||
var p, w, h, image; | ||
w = canvas.width; | ||
h = canvas.height; | ||
return new Particle( | ||
randomIn(0, w), // x, randomize start point | ||
-options.zMax * Math.max(image.width, image.height) / 2, // y, maxRadius above canvas top | ||
randomIn(options.zMin, options.zMax), // z, scale | ||
randomIn(options.rMin, options.rMax), // rotation | ||
randomIn(options.aMin, options.aMax), // a, alpha, opacity | ||
randomIn(options.dxMin, options.dxMax), // dx, horizontal movement | ||
randomIn(options.dyMin, options.dyMax), // dy, falling speed | ||
randomIn(options.dzMin, options.dzMax), // dz | ||
randomIn(options.drMin, options.drMax), // dr, rotation speed, rads/sec | ||
randomIn(options.daMin, options.daMax), // da | ||
randomIn(options.ddxMin, options.ddxMax), // ddx | ||
randomIn(options.ddyMin, options.ddyMax), // ddy | ||
randomIn(options.ddzMin, options.ddzMax), // ddz | ||
randomIn(options.ddrMin, options.ddrMax), // ddr | ||
randomIn(options.ddaMin, options.ddaMax), // dda | ||
image, | ||
image.width, image.height | ||
); | ||
}; | ||
image = randomPick(options.selectImages); | ||
var createParticles = function (options, dt) { | ||
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)); | ||
} | ||
}; | ||
return new Particle( | ||
randomIn(0, w), // x, randomize start point | ||
-options.zMax * Math.max(image.width, image.height) / 2, // y, maxRadius above canvas top | ||
randomIn(options.zMin, options.zMax), // z, scale | ||
randomIn(options.rMin, options.rMax), // rotation | ||
randomIn(options.aMin, options.aMax), // a, alpha, opacity | ||
randomIn(options.dxMin, options.dxMax), // dx, horizontal movement | ||
randomIn(options.dyMin, options.dyMax), // dy, falling speed | ||
randomIn(options.dzMin, options.dzMax), // dz | ||
randomIn(options.drMin, options.drMax), // dr, rotation speed, rads/sec | ||
randomIn(options.daMin, options.daMax), // da | ||
randomIn(options.ddxMin, options.ddxMax), // ddx | ||
randomIn(options.ddyMin, options.ddyMax), // ddy | ||
randomIn(options.ddzMin, options.ddzMax), // ddz | ||
randomIn(options.ddrMin, options.ddrMax), // ddr | ||
randomIn(options.ddaMin, options.ddaMax), // dda | ||
image, | ||
image.width, image.height | ||
); | ||
}; | ||
// Model is simulated forward every frame | ||
var tickModel = function (dt) { | ||
// Parameter | ||
// dt | ||
// simulation time, seconds | ||
var i, k, l, load, startOptions, h, | ||
bufferParticles, visible, pw, ph, maxRadius; | ||
var createParticles = function (options, dt) { | ||
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)); | ||
// To avoid huge wave of particles, they are created only | ||
// if dt is close to given framerate. | ||
if (dt < 0.5) { | ||
// Simulate each particle | ||
for (i = 0; i < particles.length; i += 1) { | ||
particles[i].tick(dt); | ||
} | ||
}; | ||
// Model is simulated forward every frame | ||
var tickModel = function (dt) { | ||
// Parameter | ||
// dt | ||
// simulation time, seconds | ||
var i, k, l, load, startOptions, h, | ||
bufferParticles, visible, pw, ph, maxRadius; | ||
// To avoid huge wave of particles, they are created only | ||
// if dt is close to given framerate. | ||
if (dt < 0.5) { | ||
// Simulate each particle | ||
for (i = 0; i < particles.length; i += 1) { | ||
particles[i].tick(dt); | ||
} | ||
// Create particles. Each start call has its own configuration. | ||
for (k in loads) { | ||
if (loads.hasOwnProperty(k)) { | ||
load = loads[k]; | ||
for (l in load) { | ||
if (load.hasOwnProperty(l)) { | ||
startOptions = load[l]; | ||
createParticles(startOptions, dt); | ||
} | ||
// Create particles. Each start call has its own configuration. | ||
for (k in loads) { | ||
if (loads.hasOwnProperty(k)) { | ||
load = loads[k]; | ||
for (l in load) { | ||
if (load.hasOwnProperty(l)) { | ||
startOptions = load[l]; | ||
createParticles(startOptions, dt); | ||
} | ||
@@ -283,186 +250,209 @@ } | ||
} | ||
} | ||
// Clean up. | ||
// Remove particles that are out of screen | ||
// by replacing particles array. | ||
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); | ||
if (visible) { | ||
bufferParticles.push(particles[i]); | ||
} | ||
// Clean up. | ||
// Remove particles that are out of screen | ||
// by replacing particles array. | ||
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); | ||
if (visible) { | ||
bufferParticles.push(particles[i]); | ||
} | ||
particles = bufferParticles; | ||
}; | ||
} | ||
particles = bufferParticles; | ||
}; | ||
// View is rendered each frame | ||
var tickView = function () { | ||
// Draw; View current model | ||
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.drawImage( | ||
particles[i].img, | ||
-Math.floor(imgW / 2), // gravity to image center | ||
-Math.floor(imgH / 2), | ||
imgW, imgH | ||
); | ||
ctx.setTransform(1, 0, 0, 1, 0, 0); // resetTransform | ||
ctx.globalAlpha = 1; // reset alpha | ||
} | ||
}; | ||
// View is rendered each frame | ||
var tickView = function () { | ||
// Draw; View current model | ||
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.drawImage( | ||
particles[i].img, | ||
-Math.floor(imgW / 2), // gravity to image center | ||
-Math.floor(imgH / 2), | ||
imgW, imgH | ||
); | ||
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; | ||
// Time difference from previous frame in milliseconds | ||
present = Date.now(); | ||
dt = (past === null) ? 0 : present - past; | ||
past = present; | ||
// Update Model | ||
tickModel(dt / 1000); // secs | ||
// Update Model | ||
tickModel(dt / 1000); // secs | ||
// Draw; View current model | ||
tickView(); | ||
// Draw; View current model | ||
tickView(); | ||
// Recursion | ||
// Allow only one viewLoop recursion at a time. | ||
if (running) { | ||
window.requestAnimationFrame(loopFn); | ||
} | ||
}; | ||
// Recursion | ||
// Allow only one viewLoop recursion at a time. | ||
if (running) { | ||
window.requestAnimationFrame(loopFn); | ||
} | ||
}; | ||
var startAnimation = function () { | ||
if (!running) { | ||
running = true; | ||
startAnimationLoop(); | ||
} | ||
}; | ||
var stopAnimation = function () { | ||
running = false; | ||
}; | ||
/*var loads = { | ||
loadId: { | ||
startId: {opt} | ||
} | ||
var startAnimation = function () { | ||
if (!running) { | ||
running = true; | ||
startAnimationLoop(); | ||
} | ||
[{opt1}, {opt2}], | ||
[{opt1}, {opt3}] | ||
];*/ | ||
}; | ||
var stopAnimation = function () { | ||
running = false; | ||
}; | ||
this.load = function (imagePaths, callback) { | ||
// Parameter | ||
// imagePaths | ||
// array | ||
// callback | ||
// function (err, start) | ||
// | ||
// Throw | ||
// 'InvalidOptionsError' | ||
loadImages(imagePaths, function then(err, imageElements) { | ||
if (err) { callback(err, null); return; } | ||
this.load = function (imagePaths, callback) { | ||
// Parameter | ||
// imagePaths | ||
// array | ||
// callback | ||
// function (err, start) | ||
loadImages(imagePaths, function then(err, imageElements) { | ||
if (err) { callback(err, null) } | ||
// 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 i, defaultOptions; | ||
loads[loadId].images = imageElements; | ||
// Default parameter | ||
if (typeof options === 'undefined') { | ||
options = {}; | ||
} | ||
var start = function start(options) { | ||
var i, defaultOptions; | ||
if (typeof options === 'undefined') options = {}; | ||
// Invalid parameter | ||
if (Object.prototype.toString.call(options) !== '[object Object]') { | ||
throw 'InvalidOptionsError'; | ||
} | ||
// Various start options | ||
defaultOptions = { | ||
type: 'default', | ||
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, | ||
imagesInSecond: 7, | ||
stopAfter: Infinity, | ||
onStop: function noop() {} | ||
}; | ||
// Various start options | ||
defaultOptions = { | ||
type: 'default', | ||
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, | ||
imagesInSecond: 7, | ||
stopAfter: Infinity, | ||
onStop: function noop() {} | ||
}; | ||
// Map image indices to actual image objects. | ||
if (options.hasOwnProperty('selectImages')) { | ||
for (i = 0; i < options.selectImages.length; i += 1) { | ||
options.selectImages[i] = imageElements[options.selectImages[i]]; | ||
} | ||
// Map image indices to actual image objects. | ||
if (options.hasOwnProperty('selectImages')) { | ||
for (i = 0; i < options.selectImages.length; i += 1) { | ||
options.selectImages[i] = imageElements[options.selectImages[i]]; | ||
} | ||
} | ||
// Push all valid options to defaultOptions. | ||
extendValid(options, defaultOptions); | ||
options = defaultOptions; | ||
// Push all valid options to defaultOptions. | ||
extendValid(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); | ||
}; | ||
exports.create = function (canvas, options) { | ||
return new Sprinkler(canvas, options); | ||
}; | ||
// **************** | ||
// Instance methods | ||
// **************** | ||
// ... | ||
// ************* | ||
// Extendability | ||
// ************* | ||
// Usage | ||
// var s = Sprinkler.create(...) | ||
// Sprinkler.extension.myFunction = function (...) {...} | ||
// s.myFunction() | ||
exports.extension = Sprinkler.prototype; | ||
// ************** | ||
// Module methods | ||
// ************** | ||
// exports.someMethod = ... | ||
// ******* | ||
// Version | ||
// ******* | ||
exports.version = '0.4.2'; | ||
},{"./loadimages":1,"./particle":2,"./stat":4}],4:[function(require,module,exports){ | ||
exports.randomIn = function (min, max) { | ||
// Continuous uniform distribution. | ||
// Return x: min <= x < max | ||
var d = max - min; | ||
return min + d * Math.random(); | ||
}; | ||
exports.randomPick = function (array) { | ||
// Return one randomly picked element. | ||
// Discrete uniform distribution. | ||
var min = 0; | ||
var max = array.length; | ||
var continuousIndex = exports.randomIn(min, max); | ||
var discreteIndex = Math.floor(continuousIndex); | ||
var i = discreteIndex; | ||
return array[i]; | ||
}; | ||
// ************* | ||
// Extendability | ||
// ************* | ||
// Usage | ||
// var s = Sprinkler.create(...) | ||
// Sprinkler.extension.myFunction = function (...) {...} | ||
// s.myFunction() | ||
exports.extension = Sprinkler.prototype; | ||
exports.samplePoisson = function (rate) { | ||
// Purpose: number of images to drop in each interval. | ||
// Take a sample from poisson distribution. | ||
// https://en.wikipedia.org/wiki/Poisson_distribution#Generating_Poisson-distributed_random_variables | ||
var L, k, p, u; | ||
L = Math.exp(-rate); | ||
k = 0; | ||
p = 1; | ||
do { | ||
k += 1; | ||
u = Math.random(); | ||
p *= u; | ||
} while (p > L); | ||
return k - 1; | ||
}; | ||
// ******* | ||
// Version | ||
// ******* | ||
exports.version = '0.4.1'; | ||
})); | ||
},{}]},{},[3])(3) | ||
}); |
@@ -1,2 +0,13 @@ | ||
!function(t,n){"use strict";"function"==typeof define&&define.amd?define(["exports"],n):n("object"==typeof exports?exports:t.Sprinkler={})}(this,function(t){"use strict";var n=function(t,n){var i,d,a,r,e,h;for(a=t.length,h=!1,d=[],e=0,r=function(){if(!h){e+=1;var t=e===a;t&&n(null,d)}},onerror=function(t){return h=!0,n(t,null),!0},i=0;i<t.length;i+=1)d.push(new Image),d[i].onload=r,d[i].onerror=onerror,d[i].src=t[i]},i=function(t,n){var i=n-t;return t+i*Math.random()},d=function(t){var n=0,d=t.length,a=i(n,d),r=Math.floor(a),e=r;return t[e]},a=function(t){var n,i,d,a;n=Math.exp(-t),i=0,d=1;do i+=1,a=Math.random(),d*=a;while(d>n);return i-1},r=function(t,n){var i;for(i in t)t.hasOwnProperty(i)&&n.hasOwnProperty(i)&&typeof t[i]==typeof n[i]&&(n[i]=t[i])},e=function(t){var n=function(){t.width=window.innerWidth,t.height=window.innerHeight};window.addEventListener("resize",n,!1),n()},h=function(t,n,i,d,a,r,e,h,o,s,M,f,x,u,c,l,g,y){this.x=t,this.y=n,this.z=i,this.r=d,this.a=a,this.dx=r,this.dy=e,this.dz=h,this.dr=o,this.da=s,this.ddx=M,this.ddy=f,this.ddz=x,this.ddr=u,this.dda=c,this.img=l,this.w=g,this.h=y};h.prototype.tick=function(t){this.x+=this.dx*t,this.y+=this.dy*t,this.z+=this.dz*t,this.r+=this.dr*t,this.a=Math.min(1,Math.max(0,this.a+this.da*t)),this.dx+=this.ddx*t,this.dy+=this.ddy*t,this.dz+=this.ddz*t,this.dr+=this.ddr*t,this.da+=this.dda*t};var o=function(t){var o={},s=[],M=!1,f=null,x=t.getContext("2d");e(t);var u=function(n){var a,r,e;return a=t.width,r=t.height,e=d(n.selectImages),new h(i(0,a),-n.zMax*Math.max(e.width,e.height)/2,i(n.zMin,n.zMax),i(n.rMin,n.rMax),i(n.aMin,n.aMax),i(n.dxMin,n.dxMax),i(n.dyMin,n.dyMax),i(n.dzMin,n.dzMax),i(n.drMin,n.drMax),i(n.daMin,n.daMax),i(n.ddxMin,n.ddxMax),i(n.ddyMin,n.ddyMax),i(n.ddzMin,n.ddzMax),i(n.ddrMin,n.ddrMax),i(n.ddaMin,n.ddaMax),e,e.width,e.height)},c=function(t,n){var i,d=t.imagesInSecond,r=n*d,e=a(r);for(i=0;e>i;i+=1)s.push(u(t))},l=function(n){var i,d,a,r,e,h,M,f,x,u,l;if(.5>n){for(i=0;i<s.length;i+=1)s[i].tick(n);for(d in o)if(o.hasOwnProperty(d)){r=o[d];for(a in r)r.hasOwnProperty(a)&&(e=r[a],c(e,n))}}for(h=t.height,M=[],i=0;i<s.length;i+=1)x=s[i].w,u=s[i].h,l=s[i].z*Math.max(x,u)/2,f=s[i].y<h+l,f&&M.push(s[i]);s=M},g=function(){var n,i,d;for(x.clearRect(0,0,t.width,t.height),n=0;n<s.length;n+=1)x.globalAlpha=s[n].a,i=s[n].z*s[n].w,d=s[n].z*s[n].h,x.translate(s[n].x,s[n].y),x.rotate(s[n].r),x.drawImage(s[n].img,-Math.floor(i/2),-Math.floor(d/2),i,d),x.setTransform(1,0,0,1,0,0),x.globalAlpha=1},y=function w(){var t,n;t=Date.now(),n=null===f?0:t-f,f=t,l(n/1e3),g(),M&&window.requestAnimationFrame(w)},p=function(){M||(M=!0,y())};this.load=function(t,i){n(t,function(t,n){t&&i(t,null);var d=Math.random().toString();o[d]={},o[d].images=n;var a=function(t){var i,a;if("undefined"==typeof t&&(t={}),a={type:"default",selectImages:n,zMin:.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:1/0,onStop:function(){}},t.hasOwnProperty("selectImages"))for(i=0;i<t.selectImages.length;i+=1)t.selectImages[i]=n[t.selectImages[i]];r(t,a),t=a;var e=Math.random().toString();return o[d][e]=t,p(),function(){delete o[d][e]}};i(null,a)})}};t.create=function(t,n){return new o(t,n)},t.extension=o.prototype,t.version="0.4.1"}); | ||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Sprinkler=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
module.exports=function(n,r){var o,e,l,u,t,f,a;for(l=n.length,a=!1,f=!1,e=[],t=0,u=function(){if(!f){t+=1;var n=t===l;n&&(a=!0,r(null,e))}},onerror=function(n){return a||(f=!0,r(n,null)),!0},o=0;o<n.length;o+=1)e.push(new Image),e[o].onload=u,e[o].onerror=onerror,e[o].src=n[o]}; | ||
},{}],2:[function(require,module,exports){ | ||
var Particle=function(t,i,h,s,d,a,r,x,y,c,z,e,n,o,l,P,m,p){this.x=t,this.y=i,this.z=h,this.r=s,this.a=d,this.dx=a,this.dy=r,this.dz=x,this.dr=y,this.da=c,this.ddx=z,this.ddy=e,this.ddz=n,this.ddr=o,this.dda=l,this.img=P,this.w=m,this.h=p};Particle.prototype.tick=function(t){this.x+=this.dx*t,this.y+=this.dy*t,this.z+=this.dz*t,this.r+=this.dr*t,this.a=Math.min(1,Math.max(0,this.a+this.da*t)),this.dx+=this.ddx*t,this.dy+=this.ddy*t,this.dz+=this.ddz*t,this.dr+=this.ddr*t,this.da+=this.dda*t},exports.Particle=Particle; | ||
},{}],3:[function(require,module,exports){ | ||
var loadImages=require("./loadimages"),Particle=require("./particle").Particle,stat=require("./stat"),randomIn=stat.randomIn,randomPick=stat.randomPick,samplePoisson=stat.samplePoisson,extendValid=function(n,a){var r;for(r in n)n.hasOwnProperty(r)&&a.hasOwnProperty(r)&&typeof n[r]==typeof a[r]&&(a[r]=n[r])},makeCanvasAutoFullwindow=function(n){var a=function(){n.width=window.innerWidth,n.height=window.innerHeight};window.addEventListener("resize",a,!1),a()},Sprinkler=function(n){var a={},r=[],t=!1,d=null,e=n.getContext("2d");makeCanvasAutoFullwindow(n);var i=function(a){var r,t,d;return r=n.width,t=n.height,d=randomPick(a.selectImages),new Particle(randomIn(0,r),-a.zMax*Math.max(d.width,d.height)/2,randomIn(a.zMin,a.zMax),randomIn(a.rMin,a.rMax),randomIn(a.aMin,a.aMax),randomIn(a.dxMin,a.dxMax),randomIn(a.dyMin,a.dyMax),randomIn(a.dzMin,a.dzMax),randomIn(a.drMin,a.drMax),randomIn(a.daMin,a.daMax),randomIn(a.ddxMin,a.ddxMax),randomIn(a.ddyMin,a.ddyMax),randomIn(a.ddzMin,a.ddzMax),randomIn(a.ddrMin,a.ddrMax),randomIn(a.ddaMin,a.ddaMax),d,d.width,d.height)},o=function(n,a){var t,d=n.imagesInSecond,e=a*d,o=samplePoisson(e);for(t=0;o>t;t+=1)r.push(i(n))},M=function(t){var d,e,i,M,s,l,x,m,h,c,f;if(.5>t){for(d=0;d<r.length;d+=1)r[d].tick(t);for(e in a)if(a.hasOwnProperty(e)){M=a[e];for(i in M)M.hasOwnProperty(i)&&(s=M[i],o(s,t))}}for(l=n.height,x=[],d=0;d<r.length;d+=1)h=r[d].w,c=r[d].h,f=r[d].z*Math.max(h,c)/2,m=r[d].y<l+f,m&&x.push(r[d]);r=x},s=function(){var a,t,d;for(e.clearRect(0,0,n.width,n.height),a=0;a<r.length;a+=1)e.globalAlpha=r[a].a,t=r[a].z*r[a].w,d=r[a].z*r[a].h,e.translate(r[a].x,r[a].y),e.rotate(r[a].r),e.drawImage(r[a].img,-Math.floor(t/2),-Math.floor(d/2),t,d),e.setTransform(1,0,0,1,0,0),e.globalAlpha=1},l=function m(){var n,a;n=Date.now(),a=null===d?0:n-d,d=n,M(a/1e3),s(),t&&window.requestAnimationFrame(m)},x=function(){t||(t=!0,l())};this.load=function(n,r){loadImages(n,function(n,t){if(n)return void r(n,null);var d=Math.random().toString();a[d]={};var e=function(n){var r,e;if("undefined"==typeof n&&(n={}),"[object Object]"!==Object.prototype.toString.call(n))throw"InvalidOptionsError";if(e={type:"default",selectImages:t,zMin:.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:1/0,onStop:function(){}},n.hasOwnProperty("selectImages"))for(r=0;r<n.selectImages.length;r+=1)n.selectImages[r]=t[n.selectImages[r]];extendValid(n,e),n=e;var i=Math.random().toString();return a[d][i]=n,x(),function(){delete a[d][i]}};r(null,e)})}};exports.create=function(n,a){return new Sprinkler(n,a)},exports.extension=Sprinkler.prototype,exports.version="0.4.2"; | ||
},{"./loadimages":1,"./particle":2,"./stat":4}],4:[function(require,module,exports){ | ||
exports.randomIn=function(r,n){var o=n-r;return r+o*Math.random()},exports.randomPick=function(r){var n=0,o=r.length,t=exports.randomIn(n,o),a=Math.floor(t),e=a;return r[e]},exports.samplePoisson=function(r){var n,o,t,a;n=Math.exp(-r),o=0,t=1;do o+=1,a=Math.random(),t*=a;while(t>n);return o-1}; | ||
},{}]},{},[3])(3) | ||
}); | ||
//# sourceMappingURL=sprinkler.min.js.map |
@@ -1,279 +0,151 @@ | ||
// ***************************** | ||
// UMD pattern commonjsStrict.js | ||
// https://github.com/umdjs/umd | ||
// ***************************** | ||
(function (root, factory) { | ||
'use strict'; | ||
if (typeof define === 'function' && define.amd) { | ||
// AMD. Register as an anonymous module. | ||
define(['exports'], factory); | ||
} else if (typeof exports === 'object') { | ||
// CommonJS & Node | ||
factory(exports); | ||
} else { | ||
// Browser globals | ||
factory((root.Sprinkler = {})); | ||
} | ||
}(this, function (exports) { | ||
'use strict'; | ||
// **************** | ||
// Helper functions | ||
// **************** | ||
var loadImages = require('./loadimages'); | ||
var Particle = require('./particle').Particle; | ||
// **************** | ||
// Helper functions | ||
// **************** | ||
var stat = require('./stat'); | ||
var randomIn = stat.randomIn; | ||
var randomPick = stat.randomPick; | ||
var samplePoisson = stat.samplePoisson; | ||
var loadImages = function (imgSrcs, then) { | ||
// then(err, imgElements) | ||
// Calls then after all the images were loaded. | ||
var i, imgs, numberOfImages, onload, onloadsCalled, thereWasError; | ||
numberOfImages = imgSrcs.length; | ||
thereWasError = false; | ||
imgs = []; | ||
onloadsCalled = 0; | ||
onload = function () { | ||
// Note: | ||
// this = Image | ||
if (!thereWasError) { | ||
onloadsCalled += 1; | ||
var isFinalImage = (onloadsCalled === numberOfImages); | ||
if (isFinalImage) { | ||
then(null, imgs); | ||
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]; | ||
} | ||
} | ||
}; | ||
onerror = function (errMsg) { | ||
// Note: | ||
// this = Image | ||
thereWasError = true; | ||
then(errMsg, null); | ||
// Prevent firing the default event handler | ||
// https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.onerror#Parameters | ||
return true; | ||
}; | ||
for (i = 0; i < imgSrcs.length; i += 1) { | ||
imgs.push(new Image()); | ||
imgs[i].onload = onload; | ||
imgs[i].onerror = onerror; | ||
imgs[i].src = imgSrcs[i]; | ||
} | ||
}; | ||
} | ||
}; | ||
var randomIn = function (min, max) { | ||
// Continuous uniform distribution. | ||
// Return x: min <= x < max | ||
var d = max - min; | ||
return min + d * Math.random(); | ||
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(); | ||
}; | ||
var randomPick = function (array) { | ||
// Return one randomly picked element. | ||
// Discrete uniform distribution. | ||
var min = 0; | ||
var max = array.length; | ||
var continuousIndex = randomIn(min, max); | ||
var discreteIndex = Math.floor(continuousIndex); | ||
var i = discreteIndex; | ||
return array[i]; | ||
}; | ||
var samplePoisson = function (rate) { | ||
// Purpose: number of images to drop in each interval. | ||
// Take a sample from poisson distribution. | ||
// https://en.wikipedia.org/wiki/Poisson_distribution#Generating_Poisson-distributed_random_variables | ||
var L, k, p, u; | ||
L = Math.exp(-rate); | ||
k = 0; | ||
p = 1; | ||
do { | ||
k += 1; | ||
u = Math.random(); | ||
p *= u; | ||
} while (p > L); | ||
return k - 1; | ||
}; | ||
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]; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
// ********** | ||
// Exceptions | ||
// ********** | ||
//... | ||
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(); | ||
}; | ||
// TODO Remove useless parameters | ||
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 | ||
}; | ||
Particle.prototype.tick = function (dt) { | ||
// Parameter | ||
// 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; | ||
}; | ||
// *********** | ||
// Constructor | ||
// *********** | ||
var Sprinkler = function (canvas) { | ||
// All the loaded images are stored here | ||
var sourceImages = []; | ||
// ********** | ||
// Exceptions | ||
// ********** | ||
//... | ||
// 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 = {}; | ||
// Images are modeled as particles and stored here | ||
var particles = []; | ||
// To pause animation loop | ||
var running = false; | ||
// *********** | ||
// Constructor | ||
// *********** | ||
// number, unix timestamp milliseconds of most recent frame. | ||
var past = null; | ||
var Sprinkler = function (canvas) { | ||
// Everything is drawn on canvas. | ||
var ctx = canvas.getContext('2d'); | ||
// All the loaded images are stored here | ||
var sourceImages = []; | ||
// Make canvas resize automatically to full window area | ||
makeCanvasAutoFullwindow(canvas); | ||
// 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 = {}; | ||
// We use this to add particles in to the model. | ||
var createParticle = function (options) { | ||
// Turn images to particles | ||
var p, w, h, image; | ||
w = canvas.width; | ||
h = canvas.height; | ||
// Images are modeled as particles and stored here | ||
var particles = []; | ||
image = randomPick(options.selectImages); | ||
// To pause animation loop | ||
var running = false; | ||
return new Particle( | ||
randomIn(0, w), // x, randomize start point | ||
-options.zMax * Math.max(image.width, image.height) / 2, // y, maxRadius above canvas top | ||
randomIn(options.zMin, options.zMax), // z, scale | ||
randomIn(options.rMin, options.rMax), // rotation | ||
randomIn(options.aMin, options.aMax), // a, alpha, opacity | ||
randomIn(options.dxMin, options.dxMax), // dx, horizontal movement | ||
randomIn(options.dyMin, options.dyMax), // dy, falling speed | ||
randomIn(options.dzMin, options.dzMax), // dz | ||
randomIn(options.drMin, options.drMax), // dr, rotation speed, rads/sec | ||
randomIn(options.daMin, options.daMax), // da | ||
randomIn(options.ddxMin, options.ddxMax), // ddx | ||
randomIn(options.ddyMin, options.ddyMax), // ddy | ||
randomIn(options.ddzMin, options.ddzMax), // ddz | ||
randomIn(options.ddrMin, options.ddrMax), // ddr | ||
randomIn(options.ddaMin, options.ddaMax), // dda | ||
image, | ||
image.width, image.height | ||
); | ||
}; | ||
// number, unix timestamp milliseconds of most recent frame. | ||
var past = null; | ||
var createParticles = function (options, dt) { | ||
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)); | ||
} | ||
}; | ||
// Everything is drawn on canvas. | ||
var ctx = canvas.getContext('2d'); | ||
// Model is simulated forward every frame | ||
var tickModel = function (dt) { | ||
// Parameter | ||
// dt | ||
// simulation time, seconds | ||
var i, k, l, load, startOptions, h, | ||
bufferParticles, visible, pw, ph, maxRadius; | ||
// Make canvas resize automatically to full window area | ||
makeCanvasAutoFullwindow(canvas); | ||
// We use this to add particles in to the model. | ||
var createParticle = function (options) { | ||
// Turn images to particles | ||
var p, w, h, image; | ||
w = canvas.width; | ||
h = canvas.height; | ||
image = randomPick(options.selectImages); | ||
return new Particle( | ||
randomIn(0, w), // x, randomize start point | ||
-options.zMax * Math.max(image.width, image.height) / 2, // y, maxRadius above canvas top | ||
randomIn(options.zMin, options.zMax), // z, scale | ||
randomIn(options.rMin, options.rMax), // rotation | ||
randomIn(options.aMin, options.aMax), // a, alpha, opacity | ||
randomIn(options.dxMin, options.dxMax), // dx, horizontal movement | ||
randomIn(options.dyMin, options.dyMax), // dy, falling speed | ||
randomIn(options.dzMin, options.dzMax), // dz | ||
randomIn(options.drMin, options.drMax), // dr, rotation speed, rads/sec | ||
randomIn(options.daMin, options.daMax), // da | ||
randomIn(options.ddxMin, options.ddxMax), // ddx | ||
randomIn(options.ddyMin, options.ddyMax), // ddy | ||
randomIn(options.ddzMin, options.ddzMax), // ddz | ||
randomIn(options.ddrMin, options.ddrMax), // ddr | ||
randomIn(options.ddaMin, options.ddaMax), // dda | ||
image, | ||
image.width, image.height | ||
); | ||
}; | ||
var createParticles = function (options, dt) { | ||
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)); | ||
// To avoid huge wave of particles, they are created only | ||
// if dt is close to given framerate. | ||
if (dt < 0.5) { | ||
// Simulate each particle | ||
for (i = 0; i < particles.length; i += 1) { | ||
particles[i].tick(dt); | ||
} | ||
}; | ||
// Model is simulated forward every frame | ||
var tickModel = function (dt) { | ||
// Parameter | ||
// dt | ||
// simulation time, seconds | ||
var i, k, l, load, startOptions, h, | ||
bufferParticles, visible, pw, ph, maxRadius; | ||
// To avoid huge wave of particles, they are created only | ||
// if dt is close to given framerate. | ||
if (dt < 0.5) { | ||
// Simulate each particle | ||
for (i = 0; i < particles.length; i += 1) { | ||
particles[i].tick(dt); | ||
} | ||
// Create particles. Each start call has its own configuration. | ||
for (k in loads) { | ||
if (loads.hasOwnProperty(k)) { | ||
load = loads[k]; | ||
for (l in load) { | ||
if (load.hasOwnProperty(l)) { | ||
startOptions = load[l]; | ||
createParticles(startOptions, dt); | ||
} | ||
// Create particles. Each start call has its own configuration. | ||
for (k in loads) { | ||
if (loads.hasOwnProperty(k)) { | ||
load = loads[k]; | ||
for (l in load) { | ||
if (load.hasOwnProperty(l)) { | ||
startOptions = load[l]; | ||
createParticles(startOptions, dt); | ||
} | ||
@@ -283,186 +155,171 @@ } | ||
} | ||
} | ||
// Clean up. | ||
// Remove particles that are out of screen | ||
// by replacing particles array. | ||
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); | ||
if (visible) { | ||
bufferParticles.push(particles[i]); | ||
} | ||
// Clean up. | ||
// Remove particles that are out of screen | ||
// by replacing particles array. | ||
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); | ||
if (visible) { | ||
bufferParticles.push(particles[i]); | ||
} | ||
particles = bufferParticles; | ||
}; | ||
} | ||
particles = bufferParticles; | ||
}; | ||
// View is rendered each frame | ||
var tickView = function () { | ||
// Draw; View current model | ||
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.drawImage( | ||
particles[i].img, | ||
-Math.floor(imgW / 2), // gravity to image center | ||
-Math.floor(imgH / 2), | ||
imgW, imgH | ||
); | ||
ctx.setTransform(1, 0, 0, 1, 0, 0); // resetTransform | ||
ctx.globalAlpha = 1; // reset alpha | ||
} | ||
}; | ||
// View is rendered each frame | ||
var tickView = function () { | ||
// Draw; View current model | ||
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.drawImage( | ||
particles[i].img, | ||
-Math.floor(imgW / 2), // gravity to image center | ||
-Math.floor(imgH / 2), | ||
imgW, imgH | ||
); | ||
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; | ||
// Time difference from previous frame in milliseconds | ||
present = Date.now(); | ||
dt = (past === null) ? 0 : present - past; | ||
past = present; | ||
// Update Model | ||
tickModel(dt / 1000); // secs | ||
// Update Model | ||
tickModel(dt / 1000); // secs | ||
// Draw; View current model | ||
tickView(); | ||
// Draw; View current model | ||
tickView(); | ||
// Recursion | ||
// Allow only one viewLoop recursion at a time. | ||
if (running) { | ||
window.requestAnimationFrame(loopFn); | ||
} | ||
}; | ||
// Recursion | ||
// Allow only one viewLoop recursion at a time. | ||
if (running) { | ||
window.requestAnimationFrame(loopFn); | ||
} | ||
}; | ||
var startAnimation = function () { | ||
if (!running) { | ||
running = true; | ||
startAnimationLoop(); | ||
} | ||
}; | ||
var stopAnimation = function () { | ||
running = false; | ||
}; | ||
/*var loads = { | ||
loadId: { | ||
startId: {opt} | ||
} | ||
var startAnimation = function () { | ||
if (!running) { | ||
running = true; | ||
startAnimationLoop(); | ||
} | ||
[{opt1}, {opt2}], | ||
[{opt1}, {opt3}] | ||
];*/ | ||
}; | ||
var stopAnimation = function () { | ||
running = false; | ||
}; | ||
this.load = function (imagePaths, callback) { | ||
// Parameter | ||
// imagePaths | ||
// array | ||
// callback | ||
// function (err, start) | ||
// | ||
// Throw | ||
// 'InvalidOptionsError' | ||
loadImages(imagePaths, function then(err, imageElements) { | ||
if (err) { callback(err, null); return; } | ||
this.load = function (imagePaths, callback) { | ||
// Parameter | ||
// imagePaths | ||
// array | ||
// callback | ||
// function (err, start) | ||
loadImages(imagePaths, function then(err, imageElements) { | ||
if (err) { callback(err, null) } | ||
// 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 i, defaultOptions; | ||
loads[loadId].images = imageElements; | ||
// Default parameter | ||
if (typeof options === 'undefined') { | ||
options = {}; | ||
} | ||
var start = function start(options) { | ||
var i, defaultOptions; | ||
if (typeof options === 'undefined') options = {}; | ||
// Invalid parameter | ||
if (Object.prototype.toString.call(options) !== '[object Object]') { | ||
throw 'InvalidOptionsError'; | ||
} | ||
// Various start options | ||
defaultOptions = { | ||
type: 'default', | ||
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, | ||
imagesInSecond: 7, | ||
stopAfter: Infinity, | ||
onStop: function noop() {} | ||
}; | ||
// Various start options | ||
defaultOptions = { | ||
type: 'default', | ||
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, | ||
imagesInSecond: 7, | ||
stopAfter: Infinity, | ||
onStop: function noop() {} | ||
}; | ||
// Map image indices to actual image objects. | ||
if (options.hasOwnProperty('selectImages')) { | ||
for (i = 0; i < options.selectImages.length; i += 1) { | ||
options.selectImages[i] = imageElements[options.selectImages[i]]; | ||
} | ||
// Map image indices to actual image objects. | ||
if (options.hasOwnProperty('selectImages')) { | ||
for (i = 0; i < options.selectImages.length; i += 1) { | ||
options.selectImages[i] = imageElements[options.selectImages[i]]; | ||
} | ||
} | ||
// Push all valid options to defaultOptions. | ||
extendValid(options, defaultOptions); | ||
options = defaultOptions; | ||
// Push all valid options to defaultOptions. | ||
extendValid(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); | ||
}; | ||
exports.create = function (canvas, options) { | ||
return new Sprinkler(canvas, options); | ||
}; | ||
// **************** | ||
// Instance methods | ||
// **************** | ||
// ... | ||
// ************* | ||
// Extendability | ||
// ************* | ||
// Usage | ||
// var s = Sprinkler.create(...) | ||
// Sprinkler.extension.myFunction = function (...) {...} | ||
// s.myFunction() | ||
exports.extension = Sprinkler.prototype; | ||
// ************** | ||
// Module methods | ||
// ************** | ||
// exports.someMethod = ... | ||
// ************* | ||
// Extendability | ||
// ************* | ||
// Usage | ||
// var s = Sprinkler.create(...) | ||
// Sprinkler.extension.myFunction = function (...) {...} | ||
// s.myFunction() | ||
exports.extension = Sprinkler.prototype; | ||
// ******* | ||
// Version | ||
// ******* | ||
exports.version = '0.4.1'; | ||
})); | ||
// ******* | ||
// Version | ||
// ******* | ||
exports.version = '0.4.2'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
177544
31
11
867
2
4