spin.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. var __assign = (this && this.__assign) || function () {
  2. __assign = Object.assign || function(t) {
  3. for (var s, i = 1, n = arguments.length; i < n; i++) {
  4. s = arguments[i];
  5. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  6. t[p] = s[p];
  7. }
  8. return t;
  9. };
  10. return __assign.apply(this, arguments);
  11. };
  12. var defaults = {
  13. lines: 12,
  14. length: 7,
  15. width: 5,
  16. radius: 10,
  17. scale: 1.0,
  18. corners: 1,
  19. color: '#000',
  20. fadeColor: 'transparent',
  21. animation: 'spinner-line-fade-default',
  22. rotate: 0,
  23. direction: 1,
  24. speed: 1,
  25. zIndex: 2e9,
  26. className: 'spinner',
  27. top: '50%',
  28. left: '50%',
  29. shadow: '0 0 1px transparent',
  30. position: 'absolute',
  31. };
  32. var Spinner = /** @class */ (function () {
  33. function Spinner(opts) {
  34. if (opts === void 0) { opts = {}; }
  35. this.opts = __assign(__assign({}, defaults), opts);
  36. }
  37. /**
  38. * Adds the spinner to the given target element. If this instance is already
  39. * spinning, it is automatically removed from its previous target by calling
  40. * stop() internally.
  41. */
  42. Spinner.prototype.spin = function (target) {
  43. this.stop();
  44. this.el = document.createElement('div');
  45. this.el.className = this.opts.className;
  46. this.el.setAttribute('role', 'progressbar');
  47. css(this.el, {
  48. position: this.opts.position,
  49. width: 0,
  50. zIndex: this.opts.zIndex,
  51. left: this.opts.left,
  52. top: this.opts.top,
  53. transform: "scale(" + this.opts.scale + ")",
  54. });
  55. if (target) {
  56. target.insertBefore(this.el, target.firstChild || null);
  57. }
  58. drawLines(this.el, this.opts);
  59. return this;
  60. };
  61. /**
  62. * Stops and removes the Spinner.
  63. * Stopped spinners may be reused by calling spin() again.
  64. */
  65. Spinner.prototype.stop = function () {
  66. if (this.el) {
  67. if (typeof requestAnimationFrame !== 'undefined') {
  68. cancelAnimationFrame(this.animateId);
  69. }
  70. else {
  71. clearTimeout(this.animateId);
  72. }
  73. if (this.el.parentNode) {
  74. this.el.parentNode.removeChild(this.el);
  75. }
  76. this.el = undefined;
  77. }
  78. return this;
  79. };
  80. return Spinner;
  81. }());
  82. export { Spinner };
  83. /**
  84. * Sets multiple style properties at once.
  85. */
  86. function css(el, props) {
  87. for (var prop in props) {
  88. el.style[prop] = props[prop];
  89. }
  90. return el;
  91. }
  92. /**
  93. * Returns the line color from the given string or array.
  94. */
  95. function getColor(color, idx) {
  96. return typeof color == 'string' ? color : color[idx % color.length];
  97. }
  98. /**
  99. * Internal method that draws the individual lines.
  100. */
  101. function drawLines(el, opts) {
  102. var borderRadius = (Math.round(opts.corners * opts.width * 500) / 1000) + 'px';
  103. var shadow = 'none';
  104. if (opts.shadow === true) {
  105. shadow = '0 2px 4px #000'; // default shadow
  106. }
  107. else if (typeof opts.shadow === 'string') {
  108. shadow = opts.shadow;
  109. }
  110. var shadows = parseBoxShadow(shadow);
  111. for (var i = 0; i < opts.lines; i++) {
  112. var degrees = ~~(360 / opts.lines * i + opts.rotate);
  113. var backgroundLine = css(document.createElement('div'), {
  114. position: 'absolute',
  115. top: -opts.width / 2 + "px",
  116. width: (opts.length + opts.width) + 'px',
  117. height: opts.width + 'px',
  118. background: getColor(opts.fadeColor, i),
  119. borderRadius: borderRadius,
  120. transformOrigin: 'left',
  121. transform: "rotate(" + degrees + "deg) translateX(" + opts.radius + "px)",
  122. });
  123. var delay = i * opts.direction / opts.lines / opts.speed;
  124. delay -= 1 / opts.speed; // so initial animation state will include trail
  125. var line = css(document.createElement('div'), {
  126. width: '100%',
  127. height: '100%',
  128. background: getColor(opts.color, i),
  129. borderRadius: borderRadius,
  130. boxShadow: normalizeShadow(shadows, degrees),
  131. animation: 1 / opts.speed + "s linear " + delay + "s infinite " + opts.animation,
  132. });
  133. backgroundLine.appendChild(line);
  134. el.appendChild(backgroundLine);
  135. }
  136. }
  137. function parseBoxShadow(boxShadow) {
  138. var regex = /^\s*([a-zA-Z]+\s+)?(-?\d+(\.\d+)?)([a-zA-Z]*)\s+(-?\d+(\.\d+)?)([a-zA-Z]*)(.*)$/;
  139. var shadows = [];
  140. for (var _i = 0, _a = boxShadow.split(','); _i < _a.length; _i++) {
  141. var shadow = _a[_i];
  142. var matches = shadow.match(regex);
  143. if (matches === null) {
  144. continue; // invalid syntax
  145. }
  146. var x = +matches[2];
  147. var y = +matches[5];
  148. var xUnits = matches[4];
  149. var yUnits = matches[7];
  150. if (x === 0 && !xUnits) {
  151. xUnits = yUnits;
  152. }
  153. if (y === 0 && !yUnits) {
  154. yUnits = xUnits;
  155. }
  156. if (xUnits !== yUnits) {
  157. continue; // units must match to use as coordinates
  158. }
  159. shadows.push({
  160. prefix: matches[1] || '',
  161. x: x,
  162. y: y,
  163. xUnits: xUnits,
  164. yUnits: yUnits,
  165. end: matches[8],
  166. });
  167. }
  168. return shadows;
  169. }
  170. /**
  171. * Modify box-shadow x/y offsets to counteract rotation
  172. */
  173. function normalizeShadow(shadows, degrees) {
  174. var normalized = [];
  175. for (var _i = 0, shadows_1 = shadows; _i < shadows_1.length; _i++) {
  176. var shadow = shadows_1[_i];
  177. var xy = convertOffset(shadow.x, shadow.y, degrees);
  178. normalized.push(shadow.prefix + xy[0] + shadow.xUnits + ' ' + xy[1] + shadow.yUnits + shadow.end);
  179. }
  180. return normalized.join(', ');
  181. }
  182. function convertOffset(x, y, degrees) {
  183. var radians = degrees * Math.PI / 180;
  184. var sin = Math.sin(radians);
  185. var cos = Math.cos(radians);
  186. return [
  187. Math.round((x * cos + y * sin) * 1000) / 1000,
  188. Math.round((-x * sin + y * cos) * 1000) / 1000,
  189. ];
  190. }