diff options
Diffstat (limited to 'view/js/spin.js')
-rw-r--r-- | view/js/spin.js | 290 |
1 files changed, 159 insertions, 131 deletions
diff --git a/view/js/spin.js b/view/js/spin.js index c66c607a7..145ce1baf 100644 --- a/view/js/spin.js +++ b/view/js/spin.js @@ -1,65 +1,82 @@ -//fgnass.github.com/spin.js#v1.3 - /** - * Copyright (c) 2011-2013 Felix Gnass + * Copyright (c) 2011-2014 Felix Gnass * Licensed under the MIT license + * http://spin.js.org/ + * + * Example: + var opts = { + lines: 12, // The number of lines to draw + , length: 7, // The length of each line + , width: 5, // The line thickness + , radius: 10 // The radius of the inner circle + , scale: 1.0 // Scales overall size of the spinner + , corners: 1 // Roundness (0..1) + , color: '#000' // #rgb or #rrggbb + , opacity: 1/4 // Opacity of the lines + , rotate: 0 // Rotation offset + , direction: 1 // 1: clockwise, -1: counterclockwise + , speed: 1 // Rounds per second + , trail: 100 // Afterglow percentage + , fps: 20 // Frames per second when using setTimeout() + , zIndex: 2e9 // Use a high z-index by default + , className: 'spinner' // CSS class to assign to the element + , top: '50%' // center vertically + , left: '50%' // center horizontally + , shadow: false // Whether to render a shadow + , hwaccel: false // Whether to use hardware acceleration (might be buggy) + , position: 'absolute' // Element positioning + } + var target = document.getElementById('foo') + var spinner = new Spinner(opts).spin(target) */ -(function(root, factory) { +;(function (root, factory) { /* CommonJS */ - if (typeof exports == 'object') module.exports = factory() + if (typeof exports == 'object') module.exports = factory() /* AMD module */ else if (typeof define == 'function' && define.amd) define(factory) /* Browser global */ else root.Spinner = factory() -} -(this, function() { - "use strict"; +}(this, function () { + "use strict" var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */ , animations = {} /* Animation rules keyed by their name */ , useCssAnimations /* Whether to use CSS animations or setTimeout */ + , sheet /* A stylesheet to hold the @keyframe or VML rules. */ /** * Utility function to create elements. If no tag name is given, * a DIV is created. Optionally properties can be passed. */ - function createEl(tag, prop) { + function createEl (tag, prop) { var el = document.createElement(tag || 'div') , n - for(n in prop) el[n] = prop[n] + for (n in prop) el[n] = prop[n] return el } /** * Appends children and returns the parent. */ - function ins(parent /* child1, child2, ...*/) { - for (var i=1, n=arguments.length; i<n; i++) + function ins (parent /* child1, child2, ...*/) { + for (var i = 1, n = arguments.length; i < n; i++) { parent.appendChild(arguments[i]) + } return parent } /** - * Insert a new stylesheet to hold the @keyframe or VML rules. - */ - var sheet = (function() { - var el = createEl('style', {type : 'text/css'}) - ins(document.getElementsByTagName('head')[0], el) - return el.sheet || el.styleSheet - }()) - - /** * Creates an opacity keyframe animation rule and returns its name. * Since most mobile Webkits have timing issues with animation-delay, * we create separate rules for each line/segment. */ - function addAnimation(alpha, trail, i, lines) { - var name = ['opacity', trail, ~~(alpha*100), i, lines].join('-') + function addAnimation (alpha, trail, i, lines) { + var name = ['opacity', trail, ~~(alpha * 100), i, lines].join('-') , start = 0.01 + i/lines * 100 , z = Math.max(1 - (1-alpha) / trail * (100-start), alpha) , prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase() @@ -84,25 +101,26 @@ /** * Tries various vendor prefixes and returns the first supported property. */ - function vendor(el, prop) { + function vendor (el, prop) { var s = el.style , pp , i - if(s[prop] !== undefined) return prop prop = prop.charAt(0).toUpperCase() + prop.slice(1) - for(i=0; i<prefixes.length; i++) { + if (s[prop] !== undefined) return prop + for (i = 0; i < prefixes.length; i++) { pp = prefixes[i]+prop - if(s[pp] !== undefined) return pp + if (s[pp] !== undefined) return pp } } /** * Sets multiple style properties at once. */ - function css(el, prop) { - for (var n in prop) - el.style[vendor(el, n)||n] = prop[n] + function css (el, prop) { + for (var n in prop) { + el.style[vendor(el, n) || n] = prop[n] + } return el } @@ -110,51 +128,50 @@ /** * Fills in default values. */ - function merge(obj) { - for (var i=1; i < arguments.length; i++) { + function merge (obj) { + for (var i = 1; i < arguments.length; i++) { var def = arguments[i] - for (var n in def) + for (var n in def) { if (obj[n] === undefined) obj[n] = def[n] + } } return obj } /** - * Returns the absolute page-offset of the given element. + * Returns the line color from the given string or array. */ - function pos(el) { - var o = { x:el.offsetLeft, y:el.offsetTop } - while((el = el.offsetParent)) - o.x+=el.offsetLeft, o.y+=el.offsetTop - - return o + function getColor (color, idx) { + return typeof color == 'string' ? color : color[idx % color.length] } // Built-in defaults var defaults = { - lines: 12, // The number of lines to draw - length: 7, // The length of each line - width: 5, // The line thickness - radius: 10, // The radius of the inner circle - rotate: 0, // Rotation offset - corners: 1, // Roundness (0..1) - color: '#000', // #rgb or #rrggbb - direction: 1, // 1: clockwise, -1: counterclockwise - speed: 1, // Rounds per second - trail: 100, // Afterglow percentage - opacity: 1/4, // Opacity of the lines - fps: 20, // Frames per second when using setTimeout() - zIndex: 2e9, // Use a high z-index by default - className: 'spinner', // CSS class to assign to the element - top: 'auto', // center vertically - left: 'auto', // center horizontally - position: 'relative' // element position + lines: 12 // The number of lines to draw + , length: 7 // The length of each line + , width: 5 // The line thickness + , radius: 10 // The radius of the inner circle + , scale: 1.0 // Scales overall size of the spinner + , corners: 1 // Roundness (0..1) + , color: '#000' // #rgb or #rrggbb + , opacity: 1/4 // Opacity of the lines + , rotate: 0 // Rotation offset + , direction: 1 // 1: clockwise, -1: counterclockwise + , speed: 1 // Rounds per second + , trail: 100 // Afterglow percentage + , fps: 20 // Frames per second when using setTimeout() + , zIndex: 2e9 // Use a high z-index by default + , className: 'spinner' // CSS class to assign to the element + , top: '50%' // center vertically + , left: '50%' // center horizontally + , shadow: false // Whether to render a shadow + , hwaccel: false // Whether to use hardware acceleration (might be buggy) + , position: 'absolute' // Element positioning } /** The constructor */ - function Spinner(o) { - if (typeof this == 'undefined') return new Spinner(o) + function Spinner (o) { this.opts = merge(o || {}, Spinner.defaults, defaults) } @@ -162,30 +179,28 @@ Spinner.defaults = {} merge(Spinner.prototype, { - /** * Adds the spinner to the given target element. If this instance is already * spinning, it is automatically removed from its previous target b calling * stop() internally. */ - spin: function(target) { + spin: function (target) { this.stop() var self = this , o = self.opts - , el = self.el = css(createEl(0, {className: o.className}), {position: o.position, width: 0, zIndex: o.zIndex}) - , mid = o.radius+o.length+o.width - , ep // element position - , tp // target position + , el = self.el = createEl(null, {className: o.className}) + + css(el, { + position: o.position + , width: 0 + , zIndex: o.zIndex + , left: o.left + , top: o.top + }) if (target) { - target.insertBefore(el, target.firstChild||null) - tp = pos(target) - ep = pos(el) - css(el, { - left: (o.left == 'auto' ? tp.x-ep.x + (target.offsetWidth >> 1) : parseInt(o.left, 10) + mid) + 'px', - top: (o.top == 'auto' ? tp.y-ep.y + (target.offsetHeight >> 1) : parseInt(o.top, 10) + mid) + 'px' - }) + target.insertBefore(el, target.firstChild || null) } el.setAttribute('role', 'progressbar') @@ -197,27 +212,27 @@ , start = (o.lines - 1) * (1 - o.direction) / 2 , alpha , fps = o.fps - , f = fps/o.speed - , ostep = (1-o.opacity) / (f*o.trail / 100) - , astep = f/o.lines + , f = fps / o.speed + , ostep = (1 - o.opacity) / (f * o.trail / 100) + , astep = f / o.lines - ;(function anim() { - i++; + ;(function anim () { + i++ for (var j = 0; j < o.lines; j++) { alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity) self.opacity(el, j * o.direction + start, alpha, o) } - self.timeout = self.el && setTimeout(anim, ~~(1000/fps)) + self.timeout = self.el && setTimeout(anim, ~~(1000 / fps)) })() } return self - }, + } /** * Stops and removes the Spinner. */ - stop: function() { + , stop: function () { var el = this.el if (el) { clearTimeout(this.timeout) @@ -225,124 +240,137 @@ this.el = undefined } return this - }, + } /** * Internal method that draws the individual lines. Will be overwritten * in VML fallback mode below. */ - lines: function(el, o) { + , lines: function (el, o) { var i = 0 , start = (o.lines - 1) * (1 - o.direction) / 2 , seg - function fill(color, shadow) { + function fill (color, shadow) { return css(createEl(), { - position: 'absolute', - width: (o.length+o.width) + 'px', - height: o.width + 'px', - background: color, - boxShadow: shadow, - transformOrigin: 'left', - transform: 'rotate(' + ~~(360/o.lines*i+o.rotate) + 'deg) translate(' + o.radius+'px' +',0)', - borderRadius: (o.corners * o.width>>1) + 'px' + position: 'absolute' + , width: o.scale * (o.length + o.width) + 'px' + , height: o.scale * o.width + 'px' + , background: color + , boxShadow: shadow + , transformOrigin: 'left' + , transform: 'rotate(' + ~~(360/o.lines*i + o.rotate) + 'deg) translate(' + o.scale*o.radius + 'px' + ',0)' + , borderRadius: (o.corners * o.scale * o.width >> 1) + 'px' }) } for (; i < o.lines; i++) { seg = css(createEl(), { - position: 'absolute', - top: 1+~(o.width/2) + 'px', - transform: o.hwaccel ? 'translate3d(0,0,0)' : '', - opacity: o.opacity, - animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1/o.speed + 's linear infinite' + position: 'absolute' + , top: 1 + ~(o.scale * o.width / 2) + 'px' + , transform: o.hwaccel ? 'translate3d(0,0,0)' : '' + , opacity: o.opacity + , animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1 / o.speed + 's linear infinite' }) - if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'})) - - ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)'))) + if (o.shadow) ins(seg, css(fill('#000', '0 0 4px #000'), {top: '2px'})) + ins(el, ins(seg, fill(getColor(o.color, i), '0 0 1px rgba(0,0,0,.1)'))) } return el - }, + } /** * Internal method that adjusts the opacity of a single line. * Will be overwritten in VML fallback mode below. */ - opacity: function(el, i, val) { + , opacity: function (el, i, val) { if (i < el.childNodes.length) el.childNodes[i].style.opacity = val } }) - function initVML() { + function initVML () { /* Utility function to create a VML tag */ - function vml(tag, attr) { + function vml (tag, attr) { return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr) } // No CSS transforms but VML support, add a CSS rule for VML elements: sheet.addRule('.spin-vml', 'behavior:url(#default#VML)') - Spinner.prototype.lines = function(el, o) { - var r = o.length+o.width - , s = 2*r + Spinner.prototype.lines = function (el, o) { + var r = o.scale * (o.length + o.width) + , s = o.scale * 2 * r - function grp() { + function grp () { return css( vml('group', { - coordsize: s + ' ' + s, - coordorigin: -r + ' ' + -r - }), - { width: s, height: s } + coordsize: s + ' ' + s + , coordorigin: -r + ' ' + -r + }) + , { width: s, height: s } ) } - var margin = -(o.width+o.length)*2 + 'px' + var margin = -(o.width + o.length) * o.scale * 2 + 'px' , g = css(grp(), {position: 'absolute', top: margin, left: margin}) , i - function seg(i, dx, filter) { - ins(g, - ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}), - ins(css(vml('roundrect', {arcsize: o.corners}), { - width: r, - height: o.width, - left: o.radius, - top: -o.width>>1, - filter: filter - }), - vml('fill', {color: o.color, opacity: o.opacity}), - vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change + function seg (i, dx, filter) { + ins( + g + , ins( + css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}) + , ins( + css( + vml('roundrect', {arcsize: o.corners}) + , { width: r + , height: o.scale * o.width + , left: o.scale * o.radius + , top: -o.scale * o.width >> 1 + , filter: filter + } + ) + , vml('fill', {color: getColor(o.color, i), opacity: o.opacity}) + , vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change ) ) ) } if (o.shadow) - for (i = 1; i <= o.lines; i++) + for (i = 1; i <= o.lines; i++) { seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)') + } for (i = 1; i <= o.lines; i++) seg(i) return ins(el, g) } - Spinner.prototype.opacity = function(el, i, val, o) { + Spinner.prototype.opacity = function (el, i, val, o) { var c = el.firstChild o = o.shadow && o.lines || 0 - if (c && i+o < c.childNodes.length) { - c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild + if (c && i + o < c.childNodes.length) { + c = c.childNodes[i + o]; c = c && c.firstChild; c = c && c.firstChild if (c) c.opacity = val } } } - var probe = css(createEl('group'), {behavior: 'url(#default#VML)'}) + if (typeof document !== 'undefined') { + sheet = (function () { + var el = createEl('style', {type : 'text/css'}) + ins(document.getElementsByTagName('head')[0], el) + return el.sheet || el.styleSheet + }()) - if (!vendor(probe, 'transform') && probe.adj) initVML() - else useCssAnimations = vendor(probe, 'animation') + var probe = css(createEl('group'), {behavior: 'url(#default#VML)'}) + + if (!vendor(probe, 'transform') && probe.adj) initVML() + else useCssAnimations = vendor(probe, 'animation') + } return Spinner |