123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. import { ChangeDetectionStrategy, Component, ElementRef, Input, Renderer, ViewEncapsulation } from '@angular/core';
  2. import { Config } from '../../config/config';
  3. import { Ion } from '../ion';
  4. import { isTrueProperty } from '../../util/util';
  5. /**
  6. * @name Spinner
  7. * @description
  8. * The `ion-spinner` component provides a variety of animated SVG spinners.
  9. * Spinners enables you to give users feedback that the app is actively
  10. * processing/thinking/waiting/chillin’ out, or whatever you’d like it to indicate.
  11. * By default, the `ion-refresher` feature uses this spinner component while it's
  12. * the refresher is in the `refreshing` state.
  13. *
  14. * Ionic offers a handful of spinners out of the box, and by default, it will use
  15. * the appropriate spinner for the platform on which it’s running.
  16. *
  17. * <table class="table spinner-table">
  18. * <tr>
  19. * <th>
  20. * <code>ios</code>
  21. * </th>
  22. * <td>
  23. * <ion-spinner name="ios"></ion-spinner>
  24. * </td>
  25. * </tr>
  26. * <tr>
  27. * <th>
  28. * <code>ios-small</code>
  29. * </th>
  30. * <td>
  31. * <ion-spinner name="ios-small"></ion-spinner>
  32. * </td>
  33. * </tr>
  34. * <tr>
  35. * <th>
  36. * <code>bubbles</code>
  37. * </th>
  38. * <td>
  39. * <ion-spinner name="bubbles"></ion-spinner>
  40. * </td>
  41. * </tr>
  42. * <tr>
  43. * <th>
  44. * <code>circles</code>
  45. * </th>
  46. * <td>
  47. * <ion-spinner name="circles"></ion-spinner>
  48. * </td>
  49. * </tr>
  50. * <tr>
  51. * <th>
  52. * <code>crescent</code>
  53. * </th>
  54. * <td>
  55. * <ion-spinner name="crescent"></ion-spinner>
  56. * </td>
  57. * </tr>
  58. * <tr>
  59. * <th>
  60. * <code>dots</code>
  61. * </th>
  62. * <td>
  63. * <ion-spinner name="dots"></ion-spinner>
  64. * </td>
  65. * </tr>
  66. * </table>
  67. *
  68. * @usage
  69. * The following code would use the default spinner for the platform it's
  70. * running from. If it's neither iOS or Android, it'll default to use `ios`.
  71. *
  72. * ```html
  73. * <ion-spinner></ion-spinner>
  74. * ```
  75. *
  76. * By setting the `name` property, you can specify which predefined spinner to
  77. * use, no matter what the platform is.
  78. *
  79. * ```html
  80. * <ion-spinner name="bubbles"></ion-spinner>
  81. * ```
  82. *
  83. * ## Styling SVG with CSS
  84. * One cool thing about SVG is its ability to be styled with CSS! One thing to note
  85. * is that some of the CSS properties on an SVG element have different names. For
  86. * example, SVG uses the term `stroke` instead of `border`, and `fill` instead
  87. * of `background-color`.
  88. *
  89. * ```css
  90. * ion-spinner * {
  91. * width: 28px;
  92. * height: 28px;
  93. * stroke: #444;
  94. * fill: #222;
  95. * }
  96. * ```
  97. */
  98. export class Spinner extends Ion {
  99. constructor(config, elementRef, renderer) {
  100. super(config, elementRef, renderer, 'spinner');
  101. this._dur = null;
  102. this._paused = false;
  103. }
  104. /**
  105. * @input {string} SVG spinner name.
  106. */
  107. get name() {
  108. return this._name;
  109. }
  110. set name(val) {
  111. this._name = val;
  112. this.load();
  113. }
  114. /**
  115. * @input {string} How long it takes it to do one loop.
  116. */
  117. get duration() {
  118. return this._dur;
  119. }
  120. set duration(val) {
  121. this._dur = val;
  122. this.load();
  123. }
  124. /**
  125. * @input {boolean} If true, pause the animation.
  126. */
  127. get paused() {
  128. return this._paused;
  129. }
  130. set paused(val) {
  131. this._paused = isTrueProperty(val);
  132. }
  133. /**
  134. * @hidden
  135. */
  136. ngOnInit() {
  137. this._init = true;
  138. this.load();
  139. }
  140. /**
  141. * @hidden
  142. */
  143. load() {
  144. if (this._init) {
  145. this._l = [];
  146. this._c = [];
  147. var name = this._name || this._config.get('spinner', 'ios');
  148. const spinner = SPINNERS[name];
  149. if (spinner) {
  150. if (spinner.lines) {
  151. for (let i = 0, l = spinner.lines; i < l; i++) {
  152. this._l.push(this._loadEle(spinner, i, l));
  153. }
  154. }
  155. else if (spinner.circles) {
  156. for (let i = 0, l = spinner.circles; i < l; i++) {
  157. this._c.push(this._loadEle(spinner, i, l));
  158. }
  159. }
  160. this.setElementClass(`spinner-${name}`, true);
  161. this.setElementClass(`spinner-${this._mode}-${name}`, true);
  162. }
  163. }
  164. }
  165. _loadEle(spinner, index, total) {
  166. let duration = this._dur || spinner.dur;
  167. let data = spinner.fn(duration, index, total);
  168. data.style.animationDuration = duration + 'ms';
  169. return data;
  170. }
  171. }
  172. Spinner.decorators = [
  173. { type: Component, args: [{
  174. selector: 'ion-spinner',
  175. template: '<svg viewBox="0 0 64 64" *ngFor="let i of _c" [ngStyle]="i.style">' +
  176. '<circle [attr.r]="i.r" transform="translate(32,32)"></circle>' +
  177. '</svg>' +
  178. '<svg viewBox="0 0 64 64" *ngFor="let i of _l" [ngStyle]="i.style">' +
  179. '<line [attr.y1]="i.y1" [attr.y2]="i.y2" transform="translate(32,32)"></line>' +
  180. '</svg>',
  181. host: {
  182. '[class.spinner-paused]': '_paused'
  183. },
  184. changeDetection: ChangeDetectionStrategy.OnPush,
  185. encapsulation: ViewEncapsulation.None,
  186. },] },
  187. ];
  188. /** @nocollapse */
  189. Spinner.ctorParameters = () => [
  190. { type: Config, },
  191. { type: ElementRef, },
  192. { type: Renderer, },
  193. ];
  194. Spinner.propDecorators = {
  195. 'name': [{ type: Input },],
  196. 'duration': [{ type: Input },],
  197. 'paused': [{ type: Input },],
  198. };
  199. const SPINNERS = {
  200. ios: {
  201. dur: 1000,
  202. lines: 12,
  203. fn: function (dur, index, total) {
  204. const transform = 'rotate(' + (30 * index + (index < 6 ? 180 : -180)) + 'deg)';
  205. const animationDelay = -(dur - ((dur / total) * index)) + 'ms';
  206. return {
  207. y1: 17,
  208. y2: 29,
  209. style: {
  210. transform: transform,
  211. webkitTransform: transform,
  212. animationDelay: animationDelay,
  213. webkitAnimationDelay: animationDelay
  214. }
  215. };
  216. }
  217. },
  218. 'ios-small': {
  219. dur: 1000,
  220. lines: 12,
  221. fn: function (dur, index, total) {
  222. const transform = 'rotate(' + (30 * index + (index < 6 ? 180 : -180)) + 'deg)';
  223. const animationDelay = -(dur - ((dur / total) * index)) + 'ms';
  224. return {
  225. y1: 12,
  226. y2: 20,
  227. style: {
  228. transform: transform,
  229. webkitTransform: transform,
  230. animationDelay: animationDelay,
  231. webkitAnimationDelay: animationDelay
  232. }
  233. };
  234. }
  235. },
  236. bubbles: {
  237. dur: 1000,
  238. circles: 9,
  239. fn: function (dur, index, total) {
  240. const animationDelay = -(dur - ((dur / total) * index)) + 'ms';
  241. return {
  242. r: 5,
  243. style: {
  244. top: (9 * Math.sin(2 * Math.PI * index / total)) + 'px',
  245. left: (9 * Math.cos(2 * Math.PI * index / total)) + 'px',
  246. animationDelay: animationDelay,
  247. webkitAnimationDelay: animationDelay
  248. }
  249. };
  250. }
  251. },
  252. circles: {
  253. dur: 1000,
  254. circles: 8,
  255. fn: function (dur, index, total) {
  256. const animationDelay = -(dur - ((dur / total) * index)) + 'ms';
  257. return {
  258. r: 5,
  259. style: {
  260. top: (9 * Math.sin(2 * Math.PI * index / total)) + 'px',
  261. left: (9 * Math.cos(2 * Math.PI * index / total)) + 'px',
  262. animationDelay: animationDelay,
  263. webkitAnimationDelay: animationDelay
  264. }
  265. };
  266. }
  267. },
  268. crescent: {
  269. dur: 750,
  270. circles: 1,
  271. fn: function () {
  272. return {
  273. r: 26,
  274. style: {}
  275. };
  276. }
  277. },
  278. dots: {
  279. dur: 750,
  280. circles: 3,
  281. fn: function (_dur, index) {
  282. const animationDelay = -(110 * index) + 'ms';
  283. return {
  284. r: 6,
  285. style: {
  286. left: (9 - (9 * index)) + 'px',
  287. animationDelay: animationDelay,
  288. webkitAnimationDelay: animationDelay
  289. }
  290. };
  291. }
  292. }
  293. };
  294. //# sourceMappingURL=spinner.js.map