/*
* Copyright (c) 2011 RĂ³bert Pataki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* ----------------------------------------------------------------------------------------
*
* Check out my GitHub: http://github.com/heartcode/
* Send me an email: heartcode@robertpataki.com
* Follow me on Twitter: http://twitter.com/#iHeartcode
* Blog: http://heartcode.robertpataki.com
*/
/**
* CanvasLoader uses the HTML5 canvas element in modern browsers and VML in IE6/7/8 to create and animate the most popular preloader shapes (oval, spiral, rectangle, square and rounded rectangle).
* It is important to note that CanvasLoader doesn't show up and starts rendering automatically on instantiation. To start rendering and display the loader use the show()
method.
* @module CanvasLoader
**/
(function (window) {
"use strict";
/**
* CanvasLoader is a JavaScript UI library that draws and animates circular preloaders using the Canvas HTML object.
* A CanvasLoader instance creates two canvas elements which are placed into a placeholder div (the id of the div has to be passed in the constructor). The second canvas is invisible and used for caching purposes only.
* If no id is passed in the constructor, the canvas objects are paced in the document directly.
* @class CanvasLoader
* @constructor
* @param id {String} The id of the placeholder div
* @param opt {Object} Optional parameters
* Possible values of optional parameters:
*
setFPS
and the setSpeed
methods allows the users to optimize the CPU usage of the loader whilst keeping the animation on a visually pleasing level.
* @method setSpeed
* @public
* @param speed {Number} The default value is 2
**/
p.setSpeed = function (speed) { this.speed = Math.round(Math.abs(speed)); };
/**
* Returns the speed of the loader animation
* @method getSpeed
* @public
* @return {Number}
**/
p.getSpeed = function () { return this.speed; };
/**
* The FPS value of the loader animation rendering
* @property fps
* @protected
* @type Number
**/
p.fps = 24;
/**
* Sets the rendering frequency.setSpeed
and the setFPS
methods allows the users to optimize the CPU usage of the loader whilst keeping the animation on a visually pleasing level.
* @method setFPS
* @public
* @param fps {Number} The default value is 24
**/
p.setFPS = function (fps) { this.fps = Math.round(Math.abs(fps)); this.reset(); };
/**
* Returns the fps of the loader
* @method getFPS
* @public
* @return {Number}
**/
p.getFPS = function () { return this.fps; };
// End of Property declarations
/////////////////////////////////////////////////////////////////////////////////////////////
/**
* Return the RGB values of the passed color
* @method getRGB
* @protected
* @param color {String} The HEX color value to be converted to RGB
*/
p.getRGB = function (c) {
c = c.charAt(0) === "#" ? c.substring(1, 7) : c;
return {r: parseInt(c.substring(0, 2), 16), g: parseInt(c.substring(2, 4), 16), b: parseInt(c.substring(4, 6), 16) };
};
/**
* Draw the shapes on the canvas
* @method draw
* @protected
*/
p.draw = function () {
var i = 0, size, w, h, x, y, ang, rads, rad, de = this.density, animBits = Math.round(de * this.range), bitMod, minBitMod = 0, s, g, sh, f, d = 1000, arc = 0, c = this.cCon, di = this.diameter, e = 0.47;
if (engine === engines[0]) {
c.clearRect(0, 0, d, d);
setAttr(this.can, {width: di, height: di});
setAttr(this.cCan, {width: di, height: di});
while (i < de) {
bitMod = i <= animBits ? 1 - ((1 - minBitMod) / animBits * i) : bitMod = minBitMod;
ang = 270 - 360 / de * i;
rads = ang / 180 * Math.PI;
c.fillStyle = "rgba(" + this.cRGB.r + "," + this.cRGB.g + "," + this.cRGB.b + "," + bitMod.toString() + ")";
switch (this.shape) {
case shapes[0]:
case shapes[1]:
size = di * 0.07;
x = di * e + Math.cos(rads) * (di * e - size) - di * e;
y = di * e + Math.sin(rads) * (di * e - size) - di * e;
c.beginPath();
if (this.shape === shapes[1]) { c.arc(di * 0.5 + x, di * 0.5 + y, size * bitMod, 0, Math.PI * 2, false); } else { c.arc(di * 0.5 + x, di * 0.5 + y, size, 0, Math.PI * 2, false); }
break;
case shapes[2]:
size = di * 0.12;
x = Math.cos(rads) * (di * e - size) + di * 0.5;
y = Math.sin(rads) * (di * e - size) + di * 0.5;
transCon(c, x, y, rads);
c.fillRect(x, y - size * 0.5, size, size);
break;
case shapes[3]:
case shapes[4]:
w = di * 0.3;
h = w * 0.27;
x = Math.cos(rads) * (h + (di - h) * 0.13) + di * 0.5;
y = Math.sin(rads) * (h + (di - h) * 0.13) + di * 0.5;
transCon(c, x, y, rads);
if(this.shape === shapes[3]) {
c.fillRect(x, y - h * 0.5, w, h);
} else {
rad = h * 0.55;
c.moveTo(x + rad, y - h * 0.5);
c.lineTo(x + w - rad, y - h * 0.5);
c.quadraticCurveTo(x + w, y - h * 0.5, x + w, y - h * 0.5 + rad);
c.lineTo(x + w, y - h * 0.5 + h - rad);
c.quadraticCurveTo(x + w, y - h * 0.5 + h, x + w - rad, y - h * 0.5 + h);
c.lineTo(x + rad, y - h * 0.5 + h);
c.quadraticCurveTo(x, y - h * 0.5 + h, x, y - h * 0.5 + h - rad);
c.lineTo(x, y - h * 0.5 + rad);
c.quadraticCurveTo(x, y - h * 0.5, x + rad, y - h * 0.5);
}
break;
}
c.closePath();
c.fill();
c.restore();
++i;
}
} else {
}
this.tick(true);
};
/**
* Cleans the canvas
* @method clean
* @protected
*/
p.clean = function () {
if (engine === engines[0]) {
this.con.clearRect(0, 0, 1000, 1000);
} else {
}
};
/**
* Redraws the canvas
* @method redraw
* @protected
*/
p.redraw = function () {
this.clean();
this.draw();
};
/**
* Resets the timer
* @method reset
* @protected
*/
p.reset = function () {
if (typeof (this.timer) === "number") {
this.hide();
this.show();
}
};
/**
* Renders the loader animation
* @method tick
* @protected
*/
p.tick = function (init) {
var c = this.con, di = this.diameter;
if (!init) { this.activeId += 360 / this.density * this.speed; }
if (engine === engines[0]) {
c.clearRect(0, 0, di, di);
transCon(c, di * 0.5, di * 0.5, this.activeId / 180 * Math.PI);
c.drawImage(this.cCan, 0, 0, di, di);
c.restore();
} else {
}
};
/**
* Shows the rendering of the loader animation
* @method show
* @public
*/
p.show = function () {
if (typeof (this.timer) !== "number") {
var t = this;
this.timer = self.setInterval(function () { t.tick(); }, Math.round(1000 / this.fps));
setCSS(this.cont, {display: "block"});
}
};
/**
* Stops the rendering of the loader animation and hides the loader
* @method hide
* @public
*/
p.hide = function () {
if (typeof (this.timer) === "number") {
clearInterval(this.timer);
delete this.timer;
setCSS(this.cont, {display: "none"});
}
};
/**
* Removes the CanvasLoader instance and all its references
* @method kill
* @public
*/
p.kill = function () {
var c = this.cont;
if (typeof (this.timer) === "number") { this.hide(); }
if (engine === engines[0]) {
c.removeChild(this.can);
c.removeChild(this.cCan);
} else {
}
var n;
for (n in this) { delete this[n]; }
};
window.CanvasLoader = CanvasLoader;
}(window));