From 50eb9cb6eb697514255ba9f19bcaf2709d32dd4d Mon Sep 17 00:00:00 2001 From: Michael Deal Date: Wed, 21 Nov 2012 01:30:04 -0800 Subject: [PATCH] add latest loader.js --- js/Widgets/Loader.js | 455 ++++++++++++++++++++++++++++--------------- 1 file changed, 297 insertions(+), 158 deletions(-) diff --git a/js/Widgets/Loader.js b/js/Widgets/Loader.js index 9b7810b..c654406 100644 --- a/js/Widgets/Loader.js +++ b/js/Widgets/Loader.js @@ -1,151 +1,329 @@ /* ---------------------------------------------------- - Loader.js : 0.3 : 2012/04/12 + Loader.js : 0.4.2 : 2012/11/09 ---------------------------------------------------- https://github.com/mudcube/Loader.js ---------------------------------------------------- - var loader = new widgets.Loader({ message: "loading: New loading message..." }); - ---------------------------------------------------- + /// Simple setup. + var loader = new widgets.Loader; + + /// More complex setup. var loader = new widgets.Loader({ id: "loader", bars: 12, radius: 0, lineWidth: 20, lineHeight: 70, + timeout: 30, // maximum timeout in seconds. background: "rgba(0,0,0,0.5)", - message: "loading...", - callback: function() { + container: document.body, + oncomplete: function() { + // call function once loader has completed + }, + onstart: function() { // call function once loader has started } }); - loader.stop(); - ---------------------------------------------------- - loader.message("loading: New loading message...", function() { - // call function once loader has started + + /// 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 + } }); + + /// Remove a specific loader message. + loader.remove(loaderId); + + /// Recenter the loader within container (run onresize) + loader.center(); + + /// Stop all loader instances. + loader.stop(); */ -if (typeof(widgets) === "undefined") var widgets = {}; +if (typeof (widgets) === "undefined") var widgets = {}; -widgets.Loader = (function(root) { "use strict"; +(function() { "use strict"; var PI = Math.PI; -var defaultConfig = { +var noCanvas = !document.createElement("canvas").getContext; +var fadeOutSpeed = 400; +var defaultConfig = { id: "loader", bars: 12, radius: 0, lineWidth: 20, lineHeight: 70, + timeout: 0, display: true }; -var getWindowSize = function() { - 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; - } - return { - width: width, - height: height - }; -}; +widgets.Loader = function (configure) { + if (noCanvas) return; + var that = this; + 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; -return function (conf) { - var that = this; - if (!document.createElement("canvas").getContext) return; - var that = this; - if (!document.body) return; - if (typeof(conf) === "string") conf = { message: conf }; - if (typeof(conf) === "undefined") conf = {}; - if (typeof(conf) === "boolean") conf = { display: false }; + /// Mixin the default configurations. for (var key in defaultConfig) { - if (typeof(conf[key]) === "undefined") { - conf[key] = defaultConfig[key]; + if (typeof (configure[key]) === "undefined") { + configure[key] = defaultConfig[key]; } } - // - function centerSpan() { - if (conf.message) { - var windowSize = getWindowSize(); - var width = windowSize.width - size; - var height = windowSize.height - size; - that.span.style.left = ((width + size) / 2 - that.span.offsetWidth/2) + "px"; - that.span.style.top = (height / 2 + size - 10) + "px"; - } - }; - /// - var canvas = document.getElementById(conf.id); - var timeout = 1; + + /// Setup element + var canvas = document.getElementById(configure.id); if (!canvas) { var div = document.createElement("div"); var span = document.createElement("span"); + span.className = "message"; div.appendChild(span); div.className = defaultConfig.id; - that.span = span; - that.div = div; + div.style.cssText = transitionCSS("opacity", fadeOutSpeed); + this.span = span; + this.div = div; var canvas = document.createElement("canvas"); document.body.appendChild(canvas); - canvas.id = conf.id; + canvas.id = configure.id; canvas.style.cssText = "opacity: 1; position: absolute; z-index: 10000;"; div.appendChild(canvas); - document.body.appendChild(div); + configure.container.appendChild(div); } else { - that.span = canvas.parentNode.getElementsByTagName("span")[0]; + this.span = canvas.parentNode.getElementsByTagName("span")[0]; } - // - var delay = conf.delay; - var bars = conf.bars; - var radius = conf.radius; - var max = conf.lineHeight + 20; - var size = max * 2 + conf.radius * 2; - var windowSize = getWindowSize(); + + /// 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); var width = windowSize.width - size; var height = windowSize.height - size; + var deviceRatio = window.devicePixelRatio || 1; /// - canvas.width = size; - canvas.height = size; - canvas.style.left = (width / 2) + "px"; - canvas.style.top = (height / 2) + "px"; + canvas.width = size * deviceRatio; + canvas.height = size * deviceRatio; /// - centerSpan(); - /// - var offset = 0; - var ctx = canvas.getContext('2d'); + var iteration = 0; + var ctx = canvas.getContext("2d"); ctx.globalCompositeOperation = "lighter"; ctx.shadowOffsetX = 1; ctx.shadowOffsetY = 1; ctx.shadowBlur = 1; - ctx.shadowColor = 'rgba(0, 0, 0, 0.5)'; - // - function animate() { - var windowSize = getWindowSize(); + ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; + + /// Public functions. + this.messageId; + this.messages = {}; + this.message = function (message, onstart) { + if (!this.interval) return this.start(onstart, message); + if (this.messageId) return this.update(this.messageId, message); + return this.messageId = this.add({ + message: message, + onstart: onstart + }); + }; + + this.update = function(id, message, percent) { + 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); + this.center(); + /// 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; + return this.messageId = this.add({ + 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); var width = windowSize.width - size; var height = windowSize.height - size; - // + /// Center the animation within the content. canvas.style.left = (width / 2) + "px"; canvas.style.top = (height / 2) + "px"; - centerSpan(); + canvas.style.width = (size) + "px"; + canvas.style.height = (size) + "px"; + that.span.style.left = ((width + size) / 2 - that.span.offsetWidth / 2) + "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; }\ +.loader span.message { font-family: monospace; font-size: 14px; opacity: 1; display: none; border-radius: 10px; padding: 0px; width: 300px; text-align: center; position: absolute; z-index: 10000; }\ +.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); + }, 10); + }; + 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(); + } // ctx.save(); - ctx.clearRect(0, 0, size, size); + ctx.clearRect(0, 0, size * deviceRatio, size * deviceRatio); + ctx.scale(deviceRatio, deviceRatio); ctx.translate(size / 2, size / 2); var hues = 360 - 360 / bars; for (var i = 0; i < bars; i++) { - var angle = (i / bars * 2 * PI) + offset; + var angle = (i / bars * 2 * PI) + iteration; ctx.save(); ctx.translate(radius * Math.sin(-angle), radius * Math.cos(-angle)); ctx.rotate(angle); // round-rect properties - var x = -conf.lineWidth / 2; + var x = -configure.lineWidth / 2; var y = 0; - var width = conf.lineWidth; - var height = conf.lineHeight; + var width = configure.lineWidth; + var height = configure.lineHeight; var curve = width / 2; // round-rect path ctx.beginPath(); @@ -165,87 +343,48 @@ return function (conf) { ctx.restore(); } ctx.restore(); - offset += 0.07; - // - if (conf.messageAnimate) { - var iteration = offset / 0.07 >> 0; - if (iteration % 10 === 0) { - var length = conf.messageAnimate.length; - var n = iteration / 10 % length; - that.span.innerHTML = conf.message + conf.messageAnimate[n]; - } - } - }; - this.css = function() { - var background = conf.background ? conf.background : "rgba(0,0,0,0.65)"; - span.style.cssText = "font-family: monospace; font-size: 14px; opacity: 1; display: none; background: "+background+"; border-radius: 10px; padding: 10px; width: 200px; text-align: center; position: absolute; z-index: 10000;"; - div.style.cssText = "color: #fff; -webkit-transition-property: opacity; -webkit-transition-duration: " + timeout + "s; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 100000; opacity: 0; display: none"; - if (this.stopPropagation) { - div.style.cssText += "background: rgba(0,0,0,0.25);"; - } else { - div.style.cssText += "pointer-events: none;"; - } - }; - this.stop = function () { - setTimeout(function() { - window.clearInterval(that.interval); - delete that.interval; - }, 50); - if (canvas && canvas.style) { - div.style.cssText += "pointer-events: none;"; - canvas.parentNode.style.opacity = 0; - window.setTimeout(function () { - that.stopPropagation = false; - canvas.parentNode.style.display = "none"; - ctx.clearRect(0, 0, size, size); - }, timeout * 1000); - } - }; - this.start = function (callback) { - this.css(); - var windowSize = getWindowSize(); - var width = windowSize.width - size; - var height = windowSize.height - size; - canvas.parentNode.style.opacity = 1; - canvas.parentNode.style.display = "block"; - that.span.style.display = conf.message ? "block" : "none"; - if (conf.background) that.div.style.background = conf.backgrond; - canvas.style.left = (width / 2) + "px"; - canvas.style.top = (height / 2) + "px"; - if (!conf.delay) animate(); - window.clearInterval(this.interval); - this.interval = window.setInterval(animate, 30); - if (conf.message) { - compileMessage(conf.message, callback); - } - }; - this.message = function(message, callback) { - conf.message = message; - if (!this.interval) return this.start(callback); - if (conf.background) that.span.style.background = conf.backgrond; - compileMessage(conf.message, callback); - that.span.style.display = conf.message ? "block" : "none"; - }; - var compileMessage = function(message, callback) { - if (message.substr(-3) === "...") { - conf.message = message.substr(0, message.length - 3); - conf.messageAnimate = [ ".  ",".. ","..." ].reverse(); - that.span.innerHTML = conf.message + conf.messageAnimate[0]; - } else { - conf.messageAnimate = false; - that.span.innerHTML = conf.message; - } - if (callback) { - setTimeout(callback, 50); - } + iteration += 0.07; }; // - if (conf.display === false) return this; + if (configure.display === false) return this; // - this.css(); this.start(); // return this; }; -})(widgets); \ No newline at end of file +//// + +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 + }; +}; + +})(); \ No newline at end of file