mirror of
https://github.com/wassname/cardsforscience.git
synced 2026-06-27 17:29:55 +08:00
221 lines
6.6 KiB
JavaScript
221 lines
6.6 KiB
JavaScript
|
|
/**
|
|
* @name Flame
|
|
* @description jquery plugin to generate flame on a canvas element..
|
|
* Based on http://codepen.io/jackrugile/pen/Jbnpv
|
|
* @copyright (c) 2015 wassname
|
|
* @license: MIT
|
|
*/
|
|
// TODO recenter on canvas/window resize
|
|
;(function ( $, window, document, undefined ) {
|
|
var pluginName = "flame";
|
|
|
|
var defaults = {
|
|
hueRange: 50,
|
|
};
|
|
|
|
var defaultState = {
|
|
parts: [],
|
|
partCount: 200,
|
|
partsFull: false,
|
|
on: true,
|
|
rendering: false,
|
|
globalTick: 0,
|
|
width: null,
|
|
height: null,
|
|
}
|
|
|
|
var Part = function(flame){
|
|
this.flame=flame;
|
|
this.ctx=this.flame.ctx;
|
|
this.reset();
|
|
};
|
|
|
|
|
|
Part.prototype.reset = function(){
|
|
this.startRadius = this.rand(1, 25);
|
|
this.radius = this.startRadius;
|
|
this.width = this.flame.state.width;
|
|
this.height = this.flame.state.height;
|
|
this.x = this.width/2 + (this.rand(0, 6) - 3);
|
|
this.y = 250;
|
|
this.vx = 0;
|
|
this.vy = 0;
|
|
this.hue = this.rand(this.flame.state.globalTick - this.flame.options.hueRange, this.flame.state.globalTick + this.flame.options.hueRange);
|
|
this.saturation = this.rand(50, 100);
|
|
this.lightness = this.rand(20, 70);
|
|
this.startAlpha = this.rand(1, 10) / 100;
|
|
this.alpha = this.startAlpha;
|
|
this.decayRate = 0.1;
|
|
this.startLife = 7;
|
|
this.life = this.startLife;
|
|
this.lineWidth = this.rand(1, 3);
|
|
}
|
|
|
|
Part.prototype.update = function(){
|
|
this.vx += (this.rand(0, 200) - 100) / 1500;
|
|
this.vy -= this.life/50;
|
|
this.x += this.vx;
|
|
this.y += this.vy;
|
|
this.alpha = this.startAlpha * (this.life / this.startLife);
|
|
this.radius = this.startRadius * (this.life / this.startLife);
|
|
this.life -= this.decayRate;
|
|
if(
|
|
this.x > this.width + this.radius ||
|
|
this.x < -this.radius ||
|
|
this.y > this.height + this.radius ||
|
|
this.y < -this.radius ||
|
|
this.life <= this.decayRate
|
|
){
|
|
this.reset();
|
|
}
|
|
};
|
|
|
|
Part.prototype.render = function(){
|
|
this.ctx.beginPath();
|
|
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
|
|
this.ctx.fillStyle = this.ctx.strokeStyle = 'hsla('+this.hue+', '+this.saturation+'%, '+this.lightness+'%, '+this.alpha+')';
|
|
this.ctx.lineWidth = this.lineWidth;
|
|
this.ctx.fill();
|
|
this.ctx.stroke();
|
|
};
|
|
|
|
Part.prototype.rand = function(min, max){
|
|
return Math.floor( (Math.random() * (max - min + 1) ) + min);
|
|
};
|
|
|
|
var Flame = function(element, options){
|
|
this.element = element;
|
|
this.options = $.extend( {}, defaults, options) ;
|
|
this._defaults = defaults;
|
|
this.init();
|
|
};
|
|
|
|
Flame.prototype.init = function (arguments) {
|
|
if(this.element.getContext) {
|
|
this.ctx = this.element.getContext("2d");
|
|
} else {
|
|
return;
|
|
}
|
|
if (this.state) this.stop();
|
|
this.state = $.extend( {parts: [],partsFull: false,globalTick: 0,}, defaultState, this.state);
|
|
// this.state = {
|
|
// parts: [],
|
|
// partCount: 200,
|
|
// partsFull: false,
|
|
// on: true,
|
|
// rendering: false,
|
|
// globalTick: 0,
|
|
// width: null,
|
|
// height: null,
|
|
// }
|
|
this.state.width = $(this.element).outerWidth();
|
|
this.state.height = $(this.element).outerWidth();
|
|
this.start();
|
|
}
|
|
|
|
/** If needed: $(window).on('resize',this.onResize.bind(this) **/
|
|
Flame.prototype.onResize = function (arguments) {
|
|
this.init();
|
|
}
|
|
|
|
Flame.prototype.createParts = function(){
|
|
if(this.state.parts.length > this.state.partCount){
|
|
this.state.partsFull = true;
|
|
} else {
|
|
this.state.parts.push(new Part(this));
|
|
}
|
|
};
|
|
|
|
Flame.prototype.updateParts = function(){
|
|
var i = this.state.parts.length;
|
|
while(i--){
|
|
this.state.parts[i].update();
|
|
}
|
|
};
|
|
|
|
Flame.prototype.renderParts = function(){
|
|
var i = this.state.parts.length;
|
|
while(i--){
|
|
this.state.parts[i].render();
|
|
}
|
|
};
|
|
|
|
Flame.prototype.clear = function (arguments) {
|
|
this.ctx.globalAlpha = 1;
|
|
this.ctx.fillStyle = 'hsla(0, 0%, 0%, .0)';
|
|
this.ctx.clearRect(0,0,this.state.width, this.state.height);
|
|
}
|
|
|
|
/** Fades the previous flames into opacity to product a blur **/
|
|
Flame.prototype.fade = function(){
|
|
this.ctx.globalCompositeOperation = 'destination-out';
|
|
this.ctx.fillStyle = 'hsla(0, 0%, 0%, .3)';
|
|
this.ctx.fillRect(0, 0, this.state.width, this.state.height);
|
|
this.ctx.globalCompositeOperation = 'lighter';
|
|
};
|
|
|
|
Flame.prototype.draw = function (arguments) {
|
|
this.fade();
|
|
if (this.state.on){
|
|
this.createParts();
|
|
} else if (this.state.parts.length>1){
|
|
this.state.parts.pop();
|
|
}
|
|
this.updateParts();
|
|
this.renderParts();
|
|
}
|
|
|
|
Flame.prototype.start = function (arguments) {
|
|
if (!this.state.rendering){
|
|
this.state.rendering=true
|
|
this.animate();
|
|
return this
|
|
} else {return;}
|
|
}
|
|
|
|
Flame.prototype.stop = function (arguments) {
|
|
this.state.rendering=false;
|
|
this.clear();
|
|
return this;
|
|
}
|
|
|
|
/** Toggle fuel and the flame will burn down or up again **/
|
|
Flame.prototype.toggleFuel = function (state) {
|
|
if (state===undefined)
|
|
detector.flame.state.on=!detector.flame.state.on;
|
|
else
|
|
detector.flame.state.on=state;
|
|
return detector.flame.state.on;
|
|
}
|
|
|
|
Flame.prototype.animate = function(){
|
|
window.requestAnimFrame(this.animate.bind(this),this.element);
|
|
this.state.globalTick++;
|
|
if (this.state.rendering) this.draw();
|
|
};
|
|
|
|
$.fn[pluginName] = function ( options ) {
|
|
return this.each(function () {
|
|
if (!$.data(this, 'plugin_' + pluginName)) {
|
|
$.data(this, 'plugin_' + pluginName,
|
|
new Flame( this, options ));
|
|
}
|
|
});
|
|
}
|
|
|
|
// shim for requestAnimFrame
|
|
window.requestAnimFrame = (function(){
|
|
return window.requestAnimationFrame ||
|
|
window.webkitRequestAnimationFrame ||
|
|
window.mozRequestAnimationFrame ||
|
|
window.oRequestAnimationFrame ||
|
|
window.msRequestAnimationFrame ||
|
|
function(/* function */ callback, /* DOMElement */ element){
|
|
window.setTimeout(callback, 1000 / 60);
|
|
};
|
|
})();
|
|
|
|
|
|
})( jQuery, window, document );
|