2012-10-10 07:59:04 +02:00
|
|
|
/*
|
|
|
|
----------------------------------------------------
|
2012-11-21 10:30:04 +01:00
|
|
|
Loader.js : 0.4.2 : 2012/11/09
|
2012-10-10 07:59:04 +02:00
|
|
|
----------------------------------------------------
|
|
|
|
https://github.com/mudcube/Loader.js
|
|
|
|
----------------------------------------------------
|
2012-11-21 10:30:04 +01:00
|
|
|
/// Simple setup.
|
|
|
|
var loader = new widgets.Loader;
|
|
|
|
|
|
|
|
/// More complex setup.
|
2012-10-10 07:59:04 +02:00
|
|
|
var loader = new widgets.Loader({
|
|
|
|
id: "loader",
|
|
|
|
bars: 12,
|
|
|
|
radius: 0,
|
|
|
|
lineWidth: 20,
|
|
|
|
lineHeight: 70,
|
2012-11-21 10:30:04 +01:00
|
|
|
timeout: 30, // maximum timeout in seconds.
|
2012-10-10 07:59:04 +02:00
|
|
|
background: "rgba(0,0,0,0.5)",
|
2012-11-21 10:30:04 +01:00
|
|
|
container: document.body,
|
|
|
|
oncomplete: function() {
|
|
|
|
// call function once loader has completed
|
|
|
|
},
|
|
|
|
onstart: function() {
|
2012-10-10 07:59:04 +02:00
|
|
|
// call function once loader has started
|
|
|
|
}
|
|
|
|
});
|
2012-11-21 10:30:04 +01:00
|
|
|
|
|
|
|
/// Add a new message to the queue.
|
|
|
|
var loaderId = loader.add({
|
|
|
|
message: "test",
|
|
|
|
getProgress: function() { // sends progress to loader.js
|
|
|
|
return progress; // value between 1-100
|
|
|
|
}
|
2012-10-10 07:59:04 +02:00
|
|
|
});
|
2012-11-21 10:30:04 +01:00
|
|
|
|
|
|
|
/// Remove a specific loader message.
|
|
|
|
loader.remove(loaderId);
|
|
|
|
|
|
|
|
/// Recenter the loader within container (run onresize)
|
|
|
|
loader.center();
|
|
|
|
|
|
|
|
/// Stop all loader instances.
|
|
|
|
loader.stop();
|
2012-10-10 07:59:04 +02:00
|
|
|
*/
|
|
|
|
|
2012-11-21 10:30:04 +01:00
|
|
|
if (typeof (widgets) === "undefined") var widgets = {};
|
2012-10-10 07:59:04 +02:00
|
|
|
|
2012-11-21 10:30:04 +01:00
|
|
|
(function() { "use strict";
|
2012-10-10 07:59:04 +02:00
|
|
|
|
|
|
|
var PI = Math.PI;
|
2012-11-21 10:30:04 +01:00
|
|
|
var noCanvas = !document.createElement("canvas").getContext;
|
|
|
|
var fadeOutSpeed = 400;
|
|
|
|
var defaultConfig = {
|
2012-10-10 07:59:04 +02:00
|
|
|
id: "loader",
|
|
|
|
bars: 12,
|
|
|
|
radius: 0,
|
|
|
|
lineWidth: 20,
|
|
|
|
lineHeight: 70,
|
2012-11-21 10:30:04 +01:00
|
|
|
timeout: 0,
|
2012-10-10 07:59:04 +02:00
|
|
|
display: true
|
|
|
|
};
|
|
|
|
|
2012-11-21 10:30:04 +01:00
|
|
|
widgets.Loader = function (configure) {
|
|
|
|
if (noCanvas) return;
|
2012-10-10 07:59:04 +02:00
|
|
|
var that = this;
|
2012-11-21 10:30:04 +01:00
|
|
|
if (typeof (configure) === "string") configure = { message: configure };
|
|
|
|
if (typeof (configure) === "boolean") configure = { display: false };
|
|
|
|
if (typeof (configure) === "undefined") configure = {};
|
|
|
|
configure.container = configure.container || document.body;
|
|
|
|
if (!configure.container) return;
|
|
|
|
|
|
|
|
/// Mixin the default configurations.
|
2012-10-10 07:59:04 +02:00
|
|
|
for (var key in defaultConfig) {
|
2012-11-21 10:30:04 +01:00
|
|
|
if (typeof (configure[key]) === "undefined") {
|
|
|
|
configure[key] = defaultConfig[key];
|
2012-10-10 07:59:04 +02:00
|
|
|
}
|
|
|
|
}
|
2012-11-21 10:30:04 +01:00
|
|
|
|
|
|
|
/// Setup element
|
|
|
|
var canvas = document.getElementById(configure.id);
|
2012-10-10 07:59:04 +02:00
|
|
|
if (!canvas) {
|
|
|
|
var div = document.createElement("div");
|
|
|
|
var span = document.createElement("span");
|
2012-11-21 10:30:04 +01:00
|
|
|
span.className = "message";
|
2012-10-10 07:59:04 +02:00
|
|
|
div.appendChild(span);
|
2012-11-06 22:06:08 +01:00
|
|
|
div.className = defaultConfig.id;
|
2012-11-21 10:30:04 +01:00
|
|
|
div.style.cssText = transitionCSS("opacity", fadeOutSpeed);
|
|
|
|
this.span = span;
|
|
|
|
this.div = div;
|
2012-10-10 07:59:04 +02:00
|
|
|
var canvas = document.createElement("canvas");
|
|
|
|
document.body.appendChild(canvas);
|
2012-11-21 10:30:04 +01:00
|
|
|
canvas.id = configure.id;
|
2012-10-10 07:59:04 +02:00
|
|
|
canvas.style.cssText = "opacity: 1; position: absolute; z-index: 10000;";
|
|
|
|
div.appendChild(canvas);
|
2012-11-21 10:30:04 +01:00
|
|
|
configure.container.appendChild(div);
|
2012-10-10 07:59:04 +02:00
|
|
|
} else {
|
2012-11-21 10:30:04 +01:00
|
|
|
this.span = canvas.parentNode.getElementsByTagName("span")[0];
|
2012-10-10 07:59:04 +02:00
|
|
|
}
|
2012-11-21 10:30:04 +01:00
|
|
|
|
|
|
|
/// Configure
|
|
|
|
var delay = configure.delay;
|
|
|
|
var bars = configure.bars;
|
|
|
|
var radius = configure.radius;
|
|
|
|
var max = configure.lineHeight + 20;
|
|
|
|
var size = max * 2 + configure.radius * 2;
|
|
|
|
var windowSize = getWindowSize(configure.container);
|
2012-10-10 07:59:04 +02:00
|
|
|
var width = windowSize.width - size;
|
|
|
|
var height = windowSize.height - size;
|
2012-11-21 10:30:04 +01:00
|
|
|
var deviceRatio = window.devicePixelRatio || 1;
|
2012-10-10 07:59:04 +02:00
|
|
|
///
|
2012-11-21 10:30:04 +01:00
|
|
|
canvas.width = size * deviceRatio;
|
|
|
|
canvas.height = size * deviceRatio;
|
2012-10-10 07:59:04 +02:00
|
|
|
///
|
2012-11-21 10:30:04 +01:00
|
|
|
var iteration = 0;
|
|
|
|
var ctx = canvas.getContext("2d");
|
2012-10-10 07:59:04 +02:00
|
|
|
ctx.globalCompositeOperation = "lighter";
|
|
|
|
ctx.shadowOffsetX = 1;
|
|
|
|
ctx.shadowOffsetY = 1;
|
|
|
|
ctx.shadowBlur = 1;
|
2012-11-21 10:30:04 +01:00
|
|
|
ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
|
|
|
|
|
|
|
|
/// Public functions.
|
|
|
|
this.messages = {};
|
|
|
|
this.message = function (message, onstart) {
|
|
|
|
if (!this.interval) return this.start(onstart, message);
|
2013-01-12 03:05:42 +01:00
|
|
|
return this.add({
|
2012-11-21 10:30:04 +01:00
|
|
|
message: message,
|
|
|
|
onstart: onstart
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
this.update = function(id, message, percent) {
|
2013-01-12 03:05:42 +01:00
|
|
|
if (!id) for (var id in this.messages);
|
2012-11-21 10:30:04 +01:00
|
|
|
var item = this.messages[id];
|
|
|
|
item.message = message;
|
|
|
|
if (typeof(percent) === "number") item.span.innerHTML = percent + "%";
|
|
|
|
if (message.substr(-3) === "...") { // animated dots
|
|
|
|
item._message = message.substr(0, message.length - 3);
|
|
|
|
item.messageAnimate = [". ", ".. ", "..."].reverse();
|
|
|
|
} else { // normal
|
|
|
|
item._message = message;
|
|
|
|
item.messageAnimate = false;
|
|
|
|
}
|
|
|
|
///
|
|
|
|
item.element.innerHTML = message;
|
|
|
|
};
|
|
|
|
|
|
|
|
this.add = function (conf) {
|
|
|
|
if (typeof(conf) === "string") conf = { message: conf };
|
|
|
|
var background = configure.background ? configure.background : "rgba(0,0,0,0.65)";
|
|
|
|
this.span.style.cssText = "background: " + background + ";";
|
|
|
|
this.div.style.cssText = transitionCSS("opacity", fadeOutSpeed);
|
|
|
|
if (this.stopPropagation) {
|
|
|
|
this.div.style.cssText += "background: rgba(0,0,0,0.25);";
|
|
|
|
} else {
|
|
|
|
this.div.style.cssText += "pointer-events: none;";
|
|
|
|
}
|
|
|
|
///
|
|
|
|
canvas.parentNode.style.opacity = 1;
|
|
|
|
canvas.parentNode.style.display = "block";
|
|
|
|
if (configure.background) this.div.style.background = configure.backgrond;
|
|
|
|
///
|
|
|
|
var timestamp = (new Date()).getTime();
|
|
|
|
var seed = Math.abs(timestamp * Math.random() >> 0);
|
|
|
|
var message = conf.message;
|
|
|
|
///
|
|
|
|
var container = document.createElement("div");
|
|
|
|
container.style.cssText = transitionCSS("opacity", 500);
|
|
|
|
var span = document.createElement("span");
|
|
|
|
span.style.cssText = "float: right; width: 50px;";
|
|
|
|
var node = document.createElement("span");
|
|
|
|
node.innerHTML = message;
|
|
|
|
///
|
|
|
|
container.appendChild(node);
|
|
|
|
container.appendChild(span);
|
|
|
|
///
|
|
|
|
var item = this.messages[seed] = {
|
|
|
|
seed: seed,
|
|
|
|
container: container,
|
|
|
|
element: node,
|
|
|
|
span: span,
|
|
|
|
message: message,
|
|
|
|
timeout: (conf.timeout || configure.timeout) * 1000,
|
|
|
|
timestamp: timestamp,
|
|
|
|
getProgress: conf.getProgress
|
|
|
|
};
|
|
|
|
this.span.appendChild(container);
|
|
|
|
this.span.style.display = "block";
|
|
|
|
this.update(item.seed, message);
|
|
|
|
/// Escape event loop.
|
|
|
|
if (conf.onstart) {
|
|
|
|
window.setTimeout(conf.onstart, 50);
|
|
|
|
}
|
|
|
|
///
|
|
|
|
this.center();
|
|
|
|
///
|
|
|
|
if (!this.interval) {
|
|
|
|
if (!conf.delay) renderAnimation();
|
|
|
|
window.clearInterval(this.interval);
|
|
|
|
this.interval = window.setInterval(renderAnimation, 30);
|
|
|
|
}
|
|
|
|
/// Return identifier.
|
|
|
|
return seed;
|
|
|
|
};
|
|
|
|
|
|
|
|
this.remove = function (seed) {
|
|
|
|
iteration += 0.07;
|
|
|
|
var timestamp = (new Date()).getTime();
|
|
|
|
if (typeof(seed) === "object") seed = seed.join(":");
|
|
|
|
if (seed) seed = ":" + seed + ":";
|
|
|
|
/// Remove element.
|
|
|
|
for (var key in this.messages) {
|
|
|
|
var item = this.messages[key];
|
|
|
|
if (!seed || seed.indexOf(":" + item.seed + ":") !== -1) {
|
|
|
|
delete this.messages[item.seed];
|
|
|
|
item.container.style.color = "#99ff88";
|
|
|
|
removeChild(item);
|
|
|
|
if (item.getProgress) item.span.innerHTML = "100%";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
this.start = function (onstart, message) {
|
|
|
|
if (!(message || configure.message)) return;
|
2013-01-12 03:05:42 +01:00
|
|
|
return this.add({
|
2012-11-21 10:30:04 +01:00
|
|
|
message: message || configure.message,
|
|
|
|
onstart: onstart
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
this.stop = function () {
|
|
|
|
this.remove();
|
|
|
|
window.clearInterval(this.interval);
|
|
|
|
delete this.interval;
|
|
|
|
if (configure.oncomplete) configure.oncomplete();
|
|
|
|
if (canvas && canvas.style) {
|
|
|
|
div.style.cssText += "pointer-events: none;";
|
|
|
|
window.setTimeout(function() {
|
|
|
|
that.div.style.opacity = 0;
|
|
|
|
}, 1);
|
|
|
|
window.setTimeout(function () {
|
|
|
|
if (that.interval) return;
|
|
|
|
that.stopPropagation = false;
|
|
|
|
canvas.parentNode.style.display = "none";
|
|
|
|
ctx.clearRect(0, 0, size, size);
|
|
|
|
}, fadeOutSpeed * 1000);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
this.center = function() {
|
|
|
|
var windowSize = getWindowSize(configure.container);
|
2012-10-10 07:59:04 +02:00
|
|
|
var width = windowSize.width - size;
|
|
|
|
var height = windowSize.height - size;
|
2012-11-21 10:30:04 +01:00
|
|
|
/// Center the animation within the content.
|
2012-10-10 07:59:04 +02:00
|
|
|
canvas.style.left = (width / 2) + "px";
|
|
|
|
canvas.style.top = (height / 2) + "px";
|
2012-11-21 10:30:04 +01:00
|
|
|
canvas.style.width = (size) + "px";
|
|
|
|
canvas.style.height = (size) + "px";
|
|
|
|
that.span.style.top = (height / 2 + size - 10) + "px";
|
|
|
|
};
|
|
|
|
|
|
|
|
var style = document.createElement("style");
|
|
|
|
style.innerHTML = '\
|
|
|
|
.loader { color: #fff; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 100000; opacity: 0; display: none; }\
|
2013-01-12 03:05:42 +01:00
|
|
|
.loader span.message { line-height: 1.5em; font-family: monospace; font-size: 14px; margin: auto; opacity: 1; display: none; border-radius: 10px; padding: 0px; width: 300px; text-align: center; position: absolute; z-index: 10000; left: 0; right: 0; }\
|
2012-11-21 10:30:04 +01:00
|
|
|
.loader span.message div { border-bottom: 1px solid #222; padding: 5px 10px; clear: both; text-align: left; opacity: 1; }\
|
|
|
|
.loader span.message div:last-child { border-bottom: none; }\
|
|
|
|
';
|
|
|
|
document.head.appendChild(style);
|
|
|
|
/// Private functions.
|
|
|
|
var removeChild = function(item) {
|
|
|
|
window.setTimeout(function() { // timeout in case within same event loop.
|
|
|
|
item.container.style.opacity = 0;
|
|
|
|
}, 1);
|
|
|
|
window.setTimeout(function() { // wait for opacity=0 before removing the element.
|
|
|
|
item.container.parentNode.removeChild(item.container);
|
2013-01-12 03:05:42 +01:00
|
|
|
}, 250);
|
2012-11-21 10:30:04 +01:00
|
|
|
};
|
|
|
|
var renderAnimation = function () {
|
|
|
|
var timestamp = (new Date()).getTime();
|
|
|
|
for (var key in that.messages) {
|
|
|
|
var item = that.messages[key];
|
|
|
|
var nid = iteration / 0.07 >> 0;
|
|
|
|
if (nid % 5 === 0 && item.getProgress) {
|
|
|
|
if (item.timeout && item.timestamp && timestamp - item.timestamp > item.timeout) {
|
|
|
|
that.remove(item.seed);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var progress = item.getProgress();
|
|
|
|
if (progress >= 100) {
|
|
|
|
that.remove(item.seed);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
item.span.innerHTML = (progress >> 0) + "%";
|
|
|
|
}
|
|
|
|
if (nid % 10 === 0) {
|
|
|
|
if (item.messageAnimate) {
|
|
|
|
var length = item.messageAnimate.length;
|
|
|
|
var n = nid / 10 % length;
|
|
|
|
var text = item._message + item.messageAnimate[n];
|
|
|
|
item.element.innerHTML = text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!key) {
|
|
|
|
that.stop();
|
|
|
|
}
|
2012-10-10 07:59:04 +02:00
|
|
|
//
|
|
|
|
ctx.save();
|
2012-11-21 10:30:04 +01:00
|
|
|
ctx.clearRect(0, 0, size * deviceRatio, size * deviceRatio);
|
|
|
|
ctx.scale(deviceRatio, deviceRatio);
|
2012-10-10 07:59:04 +02:00
|
|
|
ctx.translate(size / 2, size / 2);
|
|
|
|
var hues = 360 - 360 / bars;
|
|
|
|
for (var i = 0; i < bars; i++) {
|
2012-11-21 10:30:04 +01:00
|
|
|
var angle = (i / bars * 2 * PI) + iteration;
|
2012-10-10 07:59:04 +02:00
|
|
|
ctx.save();
|
|
|
|
ctx.translate(radius * Math.sin(-angle), radius * Math.cos(-angle));
|
|
|
|
ctx.rotate(angle);
|
|
|
|
// round-rect properties
|
2012-11-21 10:30:04 +01:00
|
|
|
var x = -configure.lineWidth / 2;
|
2012-10-10 07:59:04 +02:00
|
|
|
var y = 0;
|
2012-11-21 10:30:04 +01:00
|
|
|
var width = configure.lineWidth;
|
|
|
|
var height = configure.lineHeight;
|
2012-10-10 07:59:04 +02:00
|
|
|
var curve = width / 2;
|
|
|
|
// round-rect path
|
|
|
|
ctx.beginPath();
|
|
|
|
ctx.moveTo(x + curve, y);
|
|
|
|
ctx.lineTo(x + width - curve, y);
|
|
|
|
ctx.quadraticCurveTo(x + width, y, x + width, y + curve);
|
|
|
|
ctx.lineTo(x + width, y + height - curve);
|
|
|
|
ctx.quadraticCurveTo(x + width, y + height, x + width - curve, y + height);
|
|
|
|
ctx.lineTo(x + curve, y + height);
|
|
|
|
ctx.quadraticCurveTo(x, y + height, x, y + height - curve);
|
|
|
|
ctx.lineTo(x, y + curve);
|
|
|
|
ctx.quadraticCurveTo(x, y, x + curve, y);
|
|
|
|
// round-rect fill
|
|
|
|
var hue = ((i / (bars - 1)) * hues);
|
|
|
|
ctx.fillStyle = "hsla(" + hue + ", 100%, 50%, 0.85)";
|
|
|
|
ctx.fill();
|
|
|
|
ctx.restore();
|
|
|
|
}
|
|
|
|
ctx.restore();
|
2012-11-21 10:30:04 +01:00
|
|
|
iteration += 0.07;
|
2012-10-10 07:59:04 +02:00
|
|
|
};
|
|
|
|
//
|
2012-11-21 10:30:04 +01:00
|
|
|
if (configure.display === false) return this;
|
2012-10-10 07:59:04 +02:00
|
|
|
//
|
|
|
|
this.start();
|
|
|
|
//
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2012-11-21 10:30:04 +01:00
|
|
|
////
|
|
|
|
|
|
|
|
var transitionCSS = function(type, ms) {
|
|
|
|
return '\
|
|
|
|
-webkit-transition-property: '+type+';\
|
|
|
|
-webkit-transition-duration: '+ms+'ms;\
|
|
|
|
-moz-transition-property: '+type+';\
|
|
|
|
-moz-transition-duration: '+ms+'ms;\
|
|
|
|
-o-transition-property: '+type+';\
|
|
|
|
-o-transition-duration: '+ms+'ms;\
|
|
|
|
-ms-transition-property: '+type+';\
|
|
|
|
-ms-transition-duration: '+ms+'ms;';
|
|
|
|
};
|
|
|
|
|
|
|
|
var getWindowSize = function (element) {
|
|
|
|
if (window.innerWidth && window.innerHeight) {
|
|
|
|
var width = window.innerWidth;
|
|
|
|
var height = window.innerHeight;
|
|
|
|
} else if (document.compatMode === "CSS1Compat" && document.documentElement && document.documentElement.offsetWidth) {
|
|
|
|
var width = document.documentElement.offsetWidth;
|
|
|
|
var height = document.documentElement.offsetHeight;
|
|
|
|
} else if (document.body && document.body.offsetWidth) {
|
|
|
|
var width = document.body.offsetWidth;
|
|
|
|
var height = document.body.offsetHeight;
|
|
|
|
}
|
|
|
|
if (element) {
|
|
|
|
var width = element.offsetWidth;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
width: width,
|
|
|
|
height: height
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
})();
|