var app = angular.module('spinnerApp', ['angularSpinner']);

app.controller('MainCtrl', function($scope, usSpinnerService) {
  $scope.name = 'Adam';
  $scope.startSpin = function (){
    usSpinnerService.spin('spinner-1');
  }
  $scope.stopSpin = function (){
    usSpinnerService.stop('spinner-1');
  }
  $scope.startOuterSpin = function (){
    usSpinnerService.spin('spinner-2');
  }
  $scope.stopOuterSpin = function (){
    usSpinnerService.stop('spinner-2');
  }
  console.log('done!')
});
<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8" />
    <title></title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angularjs@1.6.1" data-semver="1.6.1" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
    <script src="angular-spinner.js"></script>
    <script src="app.js"></script>
  </head>

  <body>
    <div ng-app="spinnerApp"> 
      <div ng-controller="MainCtrl">
        <span us-spinner="{radius:30, width:8, length: 16}" spinner-key="spinner-2"></span>
        <div class="big-square">
          <p>Hello {{name}}!</p>
          <button ng-click="startSpin()">Start spinner</button>
          <button ng-click="stopSpin()">Stop spinner</button><br/>
          <button ng-click="startOuterSpin()">Start outer spinner</button>
          <button ng-click="stopOuterSpin()">Stop outer spinner</button>
          <span us-spinner="{radius:12, width:6, length: 12}" spinner-key="spinner-1"></span>
        </div>
      </div>
    </div>
  </body>

</html>
/* Put your css in here */
.big-square {
  position: absolute;
  left: 100px;
  top: 15px;
  width: 400px;
  height: 200px;
  border-width:2px;
  border-style:solid;
  border-color:black;
  padding:10px;
  background: lightblue;
}
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var defaults = {
    lines: 12,
    length: 7,
    width: 5,
    radius: 10,
    scale: 1.0,
    corners: 1,
    color: '#000',
    fadeColor: 'transparent',
    animation: 'spinner-line-fade-default',
    rotate: 0,
    direction: 1,
    speed: 1,
    zIndex: 2e9,
    className: 'spinner',
    top: '50%',
    left: '50%',
    shadow: '0 0 1px transparent',
    position: 'absolute',
};
var Spinner = /** @class */ (function () {
    function Spinner(opts) {
        if (opts === void 0) { opts = {}; }
        this.opts = __assign({}, defaults, opts);
    }
    /**
     * Adds the spinner to the given target element. If this instance is already
     * spinning, it is automatically removed from its previous target by calling
     * stop() internally.
     */
    Spinner.prototype.spin = function (target) {
        this.stop();
        this.el = document.createElement('div');
        this.el.className = this.opts.className;
        this.el.setAttribute('role', 'progressbar');
        css(this.el, {
            position: this.opts.position,
            width: 0,
            zIndex: this.opts.zIndex,
            left: this.opts.left,
            top: this.opts.top,
            transform: "scale(" + this.opts.scale + ")",
        });
        if (target) {
            target.insertBefore(this.el, target.firstChild || null);
        }
        drawLines(this.el, this.opts);
        return this;
    };
    /**
     * Stops and removes the Spinner.
     * Stopped spinners may be reused by calling spin() again.
     */
    Spinner.prototype.stop = function () {
        if (this.el) {
            if (typeof requestAnimationFrame !== 'undefined') {
                cancelAnimationFrame(this.animateId);
            }
            else {
                clearTimeout(this.animateId);
            }
            if (this.el.parentNode) {
                this.el.parentNode.removeChild(this.el);
            }
            this.el = undefined;
        }
        return this;
    };
    return Spinner;
}());
export { Spinner };
/**
 * Sets multiple style properties at once.
 */
function css(el, props) {
    for (var prop in props) {
        el.style[prop] = props[prop];
    }
    return el;
}
/**
 * Returns the line color from the given string or array.
 */
function getColor(color, idx) {
    return typeof color == 'string' ? color : color[idx % color.length];
}
/**
 * Internal method that draws the individual lines.
 */
function drawLines(el, opts) {
    var borderRadius = (Math.round(opts.corners * opts.width * 500) / 1000) + 'px';
    var shadow = 'none';
    if (opts.shadow === true) {
        shadow = '0 2px 4px #000'; // default shadow
    }
    else if (typeof opts.shadow === 'string') {
        shadow = opts.shadow;
    }
    var shadows = parseBoxShadow(shadow);
    for (var i = 0; i < opts.lines; i++) {
        var degrees = ~~(360 / opts.lines * i + opts.rotate);
        var backgroundLine = css(document.createElement('div'), {
            position: 'absolute',
            top: -opts.width / 2 + "px",
            width: (opts.length + opts.width) + 'px',
            height: opts.width + 'px',
            background: getColor(opts.fadeColor, i),
            borderRadius: borderRadius,
            transformOrigin: 'left',
            transform: "rotate(" + degrees + "deg) translateX(" + opts.radius + "px)",
        });
        var delay = i * opts.direction / opts.lines / opts.speed;
        delay -= 1 / opts.speed; // so initial animation state will include trail
        var line = css(document.createElement('div'), {
            width: '100%',
            height: '100%',
            background: getColor(opts.color, i),
            borderRadius: borderRadius,
            boxShadow: normalizeShadow(shadows, degrees),
            animation: 1 / opts.speed + "s linear " + delay + "s infinite " + opts.animation,
        });
        backgroundLine.appendChild(line);
        el.appendChild(backgroundLine);
    }
}
function parseBoxShadow(boxShadow) {
    var regex = /^\s*([a-zA-Z]+\s+)?(-?\d+(\.\d+)?)([a-zA-Z]*)\s+(-?\d+(\.\d+)?)([a-zA-Z]*)(.*)$/;
    var shadows = [];
    for (var _i = 0, _a = boxShadow.split(','); _i < _a.length; _i++) {
        var shadow = _a[_i];
        var matches = shadow.match(regex);
        if (matches === null) {
            continue; // invalid syntax
        }
        var x = +matches[2];
        var y = +matches[5];
        var xUnits = matches[4];
        var yUnits = matches[7];
        if (x === 0 && !xUnits) {
            xUnits = yUnits;
        }
        if (y === 0 && !yUnits) {
            yUnits = xUnits;
        }
        if (xUnits !== yUnits) {
            continue; // units must match to use as coordinates
        }
        shadows.push({
            prefix: matches[1] || '',
            x: x,
            y: y,
            xUnits: xUnits,
            yUnits: yUnits,
            end: matches[8],
        });
    }
    return shadows;
}
/**
 * Modify box-shadow x/y offsets to counteract rotation
 */
function normalizeShadow(shadows, degrees) {
    var normalized = [];
    for (var _i = 0, shadows_1 = shadows; _i < shadows_1.length; _i++) {
        var shadow = shadows_1[_i];
        var xy = convertOffset(shadow.x, shadow.y, degrees);
        normalized.push(shadow.prefix + xy[0] + shadow.xUnits + ' ' + xy[1] + shadow.yUnits + shadow.end);
    }
    return normalized.join(', ');
}
function convertOffset(x, y, degrees) {
    var radians = degrees * Math.PI / 180;
    var sin = Math.sin(radians);
    var cos = Math.cos(radians);
    return [
        Math.round((x * cos + y * sin) * 1000) / 1000,
        Math.round((-x * sin + y * cos) * 1000) / 1000,
    ];
}
!function(t,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n(require("angular"));else if("function"==typeof define&&define.amd)define(["angular"],n);else{var e=n("object"==typeof exports?require("angular"):t.angular);for(var i in e)("object"==typeof exports?exports:t)[i]=e[i]}}(this,function(t){return function(t){function n(i){if(e[i])return e[i].exports;var o=e[i]={exports:{},id:i,loaded:!1};return t[i].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var e={};return n.m=t,n.c=e,n.p="",n(0)}([function(t,n,e){"use strict";var i=e(4),o=e(6),r=e(5),s=e(3),p=e(1);n.angularSpinner=p.module("angularSpinner",[]).provider("usSpinnerConfig",s.UsSpinnerConfig).constant("SpinJSSpinner",i.SpinJSSpinner).service("usSpinnerService",o.UsSpinnerService).directive("usSpinner",r.usSpinner)},function(n,e){n.exports=t},function(t,n,e){var i,o;!function(r,s){"object"==typeof t&&t.exports?t.exports=s():(i=s,o="function"==typeof i?i.call(n,e,n,t):i,!(void 0!==o&&(t.exports=o)))}(this,function(){"use strict";function t(t,n){var e,i=document.createElement(t||"div");for(e in n)i[e]=n[e];return i}function n(t){for(var n=1,e=arguments.length;n<e;n++)t.appendChild(arguments[n]);return t}function e(t,n,e,i){var o=["opacity",n,~~(100*t),e,i].join("-"),r=.01+e/i*100,s=Math.max(1-(1-t)/n*(100-r),t),p=a.substring(0,a.indexOf("Animation")).toLowerCase(),c=p&&"-"+p+"-"||"";return f[o]||(u.insertRule("@"+c+"keyframes "+o+"{0%{opacity:"+s+"}"+r+"%{opacity:"+t+"}"+(r+.01)+"%{opacity:1}"+(r+n)%100+"%{opacity:"+t+"}100%{opacity:"+s+"}}",u.cssRules.length),f[o]=1),o}function i(t,n){var e,i,o=t.style;if(n=n.charAt(0).toUpperCase()+n.slice(1),void 0!==o[n])return n;for(i=0;i<l.length;i++)if(e=l[i]+n,void 0!==o[e])return e}function o(t,n){for(var e in n)t.style[i(t,e)||e]=n[e];return t}function r(t){for(var n=1;n<arguments.length;n++){var e=arguments[n];for(var i in e)void 0===t[i]&&(t[i]=e[i])}return t}function s(t,n){return"string"==typeof t?t:t[n%t.length]}function p(t){this.opts=r(t||{},p.defaults,d)}function c(){function e(n,e){return t("<"+n+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',e)}u.addRule(".spin-vml","behavior:url(#default#VML)"),p.prototype.lines=function(t,i){function r(){return o(e("group",{coordsize:u+" "+u,coordorigin:-a+" "+-a}),{width:u,height:u})}function p(t,p,c){n(f,n(o(r(),{rotation:360/i.lines*t+"deg",left:~~p}),n(o(e("roundrect",{arcsize:i.corners}),{width:a,height:i.scale*i.width,left:i.scale*i.radius,top:-i.scale*i.width>>1,filter:c}),e("fill",{color:s(i.color,t),opacity:i.opacity}),e("stroke",{opacity:0}))))}var c,a=i.scale*(i.length+i.width),u=2*i.scale*a,l=-(i.width+i.length)*i.scale*2+"px",f=o(r(),{position:"absolute",top:l,left:l});if(i.shadow)for(c=1;c<=i.lines;c++)p(c,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(c=1;c<=i.lines;c++)p(c);return n(t,f)},p.prototype.opacity=function(t,n,e,i){var o=t.firstChild;i=i.shadow&&i.lines||0,o&&n+i<o.childNodes.length&&(o=o.childNodes[n+i],o=o&&o.firstChild,o=o&&o.firstChild,o&&(o.opacity=e))}}var a,u,l=["webkit","Moz","ms","O"],f={},d={lines:12,length:7,width:5,radius:10,scale:1,corners:1,color:"#000",opacity:.25,rotate:0,direction:1,speed:1,trail:100,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",shadow:!1,hwaccel:!1,position:"absolute"};if(p.defaults={},r(p.prototype,{spin:function(n){this.stop();var e=this,i=e.opts,r=e.el=t(null,{className:i.className});if(o(r,{position:i.position,width:0,zIndex:i.zIndex,left:i.left,top:i.top}),n&&n.insertBefore(r,n.firstChild||null),r.setAttribute("role","progressbar"),e.lines(r,e.opts),!a){var s,p=0,c=(i.lines-1)*(1-i.direction)/2,u=i.fps,l=u/i.speed,f=(1-i.opacity)/(l*i.trail/100),d=l/i.lines;!function t(){p++;for(var n=0;n<i.lines;n++)s=Math.max(1-(p+(i.lines-n)*d)%l*f,i.opacity),e.opacity(r,n*i.direction+c,s,i);e.timeout=e.el&&setTimeout(t,~~(1e3/u))}()}return e},stop:function(){var t=this.el;return t&&(clearTimeout(this.timeout),t.parentNode&&t.parentNode.removeChild(t),this.el=void 0),this},lines:function(i,r){function p(n,e){return o(t(),{position:"absolute",width:r.scale*(r.length+r.width)+"px",height:r.scale*r.width+"px",background:n,boxShadow:e,transformOrigin:"left",transform:"rotate("+~~(360/r.lines*u+r.rotate)+"deg) translate("+r.scale*r.radius+"px,0)",borderRadius:(r.corners*r.scale*r.width>>1)+"px"})}for(var c,u=0,l=(r.lines-1)*(1-r.direction)/2;u<r.lines;u++)c=o(t(),{position:"absolute",top:1+~(r.scale*r.width/2)+"px",transform:r.hwaccel?"translate3d(0,0,0)":"",opacity:r.opacity,animation:a&&e(r.opacity,r.trail,l+u*r.direction,r.lines)+" "+1/r.speed+"s linear infinite"}),r.shadow&&n(c,o(p("#000","0 0 4px #000"),{top:"2px"})),n(i,n(c,p(s(r.color,u),"0 0 1px rgba(0,0,0,.1)")));return i},opacity:function(t,n,e){n<t.childNodes.length&&(t.childNodes[n].style.opacity=e)}}),"undefined"!=typeof document){u=function(){var e=t("style",{type:"text/css"});return n(document.getElementsByTagName("head")[0],e),e.sheet||e.styleSheet}();var h=o(t("group"),{behavior:"url(#default#VML)"});!i(h,"transform")&&h.adj?c():a=i(h,"animation")}return p})},function(t,n){"use strict";var e=function(){function t(){this.config={},this.themes={}}return t.prototype.setDefaults=function(t){this.config=t||this.config},t.prototype.setTheme=function(t,n){this.themes[t]=n},t.prototype.$get=function(){var t=this,n=t.config,e=t.themes;return{config:n,themes:e}},t}();n.UsSpinnerConfig=e},function(t,n,e){"use strict";var i=e(2);n.SpinJSSpinner=i},function(t,n,e){"use strict";var i=e(1);n.usSpinner=function(t,n){return{scope:!0,link:function(e,o,r){function s(){e.spinner&&e.spinner.stop()}e.spinner=null,e.key=!!i.isDefined(r.spinnerKey)&&r.spinnerKey,e.startActive=r.spinnerStartActive?e.$eval(r.spinnerStartActive):!e.key,e.spin=function(){e.spinner&&e.spinner.spin(o[0])},e.stop=function(){e.startActive=!1,s()},e.$watch(r.usSpinner,function(p){s(),p=i.extend({},n.config,r.spinnerTheme?n.themes[r.spinnerTheme]:void 0,p),e.spinner=new t(p),e.key&&!e.startActive||r.spinnerOn||e.spinner.spin(o[0])},!0),r.spinnerOn&&e.$watch(r.spinnerOn,function(t){t?e.spin():e.stop()}),e.$on("us-spinner:spin",function(t,n){n&&n!==e.key||e.spin()}),e.$on("us-spinner:stop",function(t,n){n&&n!==e.key||e.stop()}),e.$on("$destroy",function(){e.stop(),e.spinner=null})}}},n.usSpinner.$inject=["SpinJSSpinner","usSpinnerConfig"]},function(t,n){"use strict";var e=function(){function t(t){this.$rootScope=t}return t.prototype.spin=function(t){this.$rootScope.$broadcast("us-spinner:spin",t)},t.prototype.stop=function(t){this.$rootScope.$broadcast("us-spinner:stop",t)},t}();e.$inject=["$rootScope"],n.UsSpinnerService=e}])});
# Angular-Spinner Example
This plunker is to remind you how to use the spinner. The position is dependent
on the position of the parent, however if the position of the parent is not
absolute then it centers on the page.