Path: blob/master/sites/icloud/activity-indicator.js
777 views
/*!1* NETEYE Activity Indicator jQuery Plugin2*3* Copyright (c) 2010 NETEYE GmbH4* Licensed under the MIT license5*6* Author: Felix Gnass [fgnass at neteye dot de]7* Version: @{VERSION}8*/910/**11* Plugin that renders a customisable activity indicator (spinner) using SVG or VML.12*/13(function($) {1415$.fn.activity = function(opts) {16this.each(function() {17var $this = $(this);18var el = $this.data('activity');19if (el) {20clearInterval(el.data('interval'));21el.remove();22$this.removeData('activity');23}24if (opts !== false) {25opts = $.extend({color: $this.css('color')}, $.fn.activity.defaults, opts);2627el = render($this, opts).css('position', 'absolute').prependTo(opts.outside ? 'body' : $this);28var h = $this.outerHeight() - el.height();29var w = $this.outerWidth() - el.width();30var margin = {31top: opts.valign == 'top' ? opts.padding : opts.valign == 'bottom' ? h - opts.padding : Math.floor(h / 2),32left: opts.align == 'left' ? opts.padding : opts.align == 'right' ? w - opts.padding : Math.floor(w / 2)33};34var offset = $this.offset();35if (opts.outside) {36el.css({top: offset.top + 'px', left: offset.left + 'px'});37}38else {39margin.top -= el.offset().top - offset.top;40margin.left -= el.offset().left - offset.left;41}42el.css({marginTop: margin.top + 'px', marginLeft: margin.left + 'px'});43animate(el, opts.segments, Math.round(10 / opts.speed) / 10);44$this.data('activity', el);45}46});47return this;48};4950$.fn.activity.defaults = {51segments: 12,52space: 3,53length: 7,54width: 4,55speed: 1.2,56align: 'center',57valign: 'center',58padding: 459};6061$.fn.activity.getOpacity = function(opts, i) {62var steps = opts.steps || opts.segments-1;63var end = opts.opacity !== undefined ? opts.opacity : 1/steps;64return 1 - Math.min(i, steps) * (1 - end) / steps;65};6667/**68* Default rendering strategy. If neither SVG nor VML is available, a div with class-name 'busy'69* is inserted, that can be styled with CSS to display an animated gif as fallback.70*/71var render = function() {72return $('<div>').addClass('busy');73};7475/**76* The default animation strategy does nothing as we expect an animated gif as fallback.77*/78var animate = function() {79};8081/**82* Utility function to create elements in the SVG namespace.83*/84function svg(tag, attr) {85var el = document.createElementNS("http://www.w3.org/2000/svg", tag || 'svg');86if (attr) {87$.each(attr, function(k, v) {88el.setAttributeNS(null, k, v);89});90}91return $(el);92}9394if (document.createElementNS && document.createElementNS( "http://www.w3.org/2000/svg", "svg").createSVGRect) {9596// =======================================================================================97// SVG Rendering98// =======================================================================================99100/**101* Rendering strategy that creates a SVG tree.102*/103render = function(target, d) {104var innerRadius = d.width*2 + d.space;105var r = (innerRadius + d.length + Math.ceil(d.width / 2) + 1);106107var el = svg().width(r*2).height(r*2);108109var g = svg('g', {110'stroke-width': d.width,111'stroke-linecap': 'round',112stroke: d.color113}).appendTo(svg('g', {transform: 'translate('+ r +','+ r +')'}).appendTo(el));114115for (var i = 0; i < d.segments; i++) {116g.append(svg('line', {117x1: 0,118y1: innerRadius,119x2: 0,120y2: innerRadius + d.length,121transform: 'rotate(' + (360 / d.segments * i) + ', 0, 0)',122opacity: $.fn.activity.getOpacity(d, i)123}));124}125return $('<div>').append(el).width(2*r).height(2*r);126};127128// Check if Webkit CSS animations are available, as they work much better on the iPad129// than setTimeout() based animations.130131if (document.createElement('div').style.WebkitAnimationName !== undefined) {132133var animations = {};134135/**136* Animation strategy that uses dynamically created CSS animation rules.137*/138animate = function(el, steps, duration) {139if (!animations[steps]) {140var name = 'spin' + steps;141var rule = '@-webkit-keyframes '+ name +' {';142for (var i=0; i < steps; i++) {143var p1 = Math.round(100000 / steps * i) / 1000;144var p2 = Math.round(100000 / steps * (i+1) - 1) / 1000;145var value = '% { -webkit-transform:rotate(' + Math.round(360 / steps * i) + 'deg); }\n';146rule += p1 + value + p2 + value;147}148rule += '100% { -webkit-transform:rotate(100deg); }\n}';149document.styleSheets[0].insertRule(rule);150animations[steps] = name;151}152el.css('-webkit-animation', animations[steps] + ' ' + duration +'s linear infinite');153};154}155else {156157/**158* Animation strategy that transforms a SVG element using setInterval().159*/160animate = function(el, steps, duration) {161var rotation = 0;162var g = el.find('g g').get(0);163el.data('interval', setInterval(function() {164g.setAttributeNS(null, 'transform', 'rotate(' + (++rotation % steps * (360 / steps)) + ')');165}, duration * 1000 / steps));166};167}168169}170else {171172// =======================================================================================173// VML Rendering174// =======================================================================================175176var s = $('<shape>').css('behavior', 'url(#default#VML)');177178$('body').append(s);179180if (s.get(0).adj) {181182// VML support detected. Insert CSS rules for group, shape and stroke.183var sheet = document.createStyleSheet();184$.each(['group', 'shape', 'stroke'], function() {185sheet.addRule(this, "behavior:url(#default#VML);");186});187188/**189* Rendering strategy that creates a VML tree.190*/191render = function(target, d) {192193var innerRadius = d.width*2 + d.space;194var r = (innerRadius + d.length + Math.ceil(d.width / 2) + 1);195var s = r*2;196var o = -Math.ceil(s/2);197198var el = $('<group>', {coordsize: s + ' ' + s, coordorigin: o + ' ' + o}).css({top: o, left: o, width: s, height: s});199for (var i = 0; i < d.segments; i++) {200el.append($('<shape>', {path: 'm ' + innerRadius + ',0 l ' + (innerRadius + d.length) + ',0'}).css({201width: s,202height: s,203rotation: (360 / d.segments * i) + 'deg'204}).append($('<stroke>', {color: d.color, weight: d.width + 'px', endcap: 'round', opacity: $.fn.activity.getOpacity(d, i)})));205}206return $('<group>', {coordsize: s + ' ' + s}).css({width: s, height: s, overflow: 'hidden'}).append(el);207};208209/**210* Animation strategy that modifies the VML rotation property using setInterval().211*/212animate = function(el, steps, duration) {213var rotation = 0;214var g = el.get(0);215el.data('interval', setInterval(function() {216g.style.rotation = ++rotation % steps * (360 / steps);217}, duration * 1000 / steps));218};219}220$(s).remove();221}222223})(jQuery);224225