mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 13:01:01 +08:00
284 lines
6.1 KiB
TypeScript
284 lines
6.1 KiB
TypeScript
import {Component, Input} from 'angular2/core';
|
||
import {NgStyle} from 'angular2/common';
|
||
|
||
import {Config} from '../../config/config';
|
||
|
||
|
||
/**
|
||
* @name Spinner
|
||
* @description
|
||
* The `ion-spinner` component provides a variety of animated SVG spinners.
|
||
* Spinners enables you to give users feedback that the app is actively
|
||
* processing/thinking/waiting/chillin’ out, or whatever you’d like it to indicate.
|
||
* By default, the `ion-refresher` feature uses this spinner component while it's
|
||
* the refresher is in the `refreshing` state.
|
||
*
|
||
* Ionic offers a handful of spinners out of the box, and by default, it will use
|
||
* the appropriate spinner for the platform on which it’s running.
|
||
*
|
||
* <table class="table spinner-table">
|
||
* <tr>
|
||
* <th>
|
||
* <code>ios</code>
|
||
* </th>
|
||
* <td>
|
||
* <ion-spinner name="ios"></ion-spinner>
|
||
* </td>
|
||
* </tr>
|
||
* <tr>
|
||
* <th>
|
||
* <code>ios-small</code>
|
||
* </th>
|
||
* <td>
|
||
* <ion-spinner name="ios-small"></ion-spinner>
|
||
* </td>
|
||
* </tr>
|
||
* <tr>
|
||
* <th>
|
||
* <code>bubbles</code>
|
||
* </th>
|
||
* <td>
|
||
* <ion-spinner name="bubbles"></ion-spinner>
|
||
* </td>
|
||
* </tr>
|
||
* <tr>
|
||
* <th>
|
||
* <code>circles</code>
|
||
* </th>
|
||
* <td>
|
||
* <ion-spinner name="circles"></ion-spinner>
|
||
* </td>
|
||
* </tr>
|
||
* <tr>
|
||
* <th>
|
||
* <code>crescent</code>
|
||
* </th>
|
||
* <td>
|
||
* <ion-spinner name="crescent"></ion-spinner>
|
||
* </td>
|
||
* </tr>
|
||
* <tr>
|
||
* <th>
|
||
* <code>dots</code>
|
||
* </th>
|
||
* <td>
|
||
* <ion-spinner name="dots"></ion-spinner>
|
||
* </td>
|
||
* </tr>
|
||
* </table>
|
||
*
|
||
* @usage
|
||
* The following code would use the default spinner for the platform it's
|
||
* running from. If it's neither iOS or Android, it'll default to use `ios`.
|
||
*
|
||
* ```html
|
||
* <ion-spinner></ion-spinner>
|
||
* ```
|
||
*
|
||
* By setting the `name` property, you can specify which predefined spinner to
|
||
* use, no matter what the platform is.
|
||
*
|
||
* ```html
|
||
* <ion-spinner name="bubbles"></ion-spinner>
|
||
* ```
|
||
*
|
||
* ## Styling SVG with CSS
|
||
* One cool thing about SVG is its ability to be styled with CSS! One thing to note
|
||
* is that some of the CSS properties on an SVG element have different names. For
|
||
* example, SVG uses the term `stroke` instead of `border`, and `fill` instead
|
||
* of `background-color`.
|
||
*
|
||
* ```css
|
||
* ion-spinner svg {
|
||
* width: 28px;
|
||
* height: 28px;
|
||
* stroke: #444;
|
||
* fill: #222;
|
||
* }
|
||
* ```
|
||
*/
|
||
@Component({
|
||
selector: 'ion-spinner',
|
||
template:
|
||
'<svg viewBox="0 0 64 64" *ngFor="#i of _c" [ngStyle]="i.style">' +
|
||
'<circle [attr.r]="i.r" transform="translate(32,32)"></circle>' +
|
||
'</svg>' +
|
||
'<svg viewBox="0 0 64 64" *ngFor="#i of _l" [ngStyle]="i.style">' +
|
||
'<line [attr.y1]="i.y1" [attr.y2]="i.y2" transform="translate(32,32)"></line>' +
|
||
'</svg>',
|
||
directives: [NgStyle],
|
||
host: {
|
||
'[class]': '_applied',
|
||
'[class.spinner-paused]': 'paused'
|
||
}
|
||
})
|
||
export class Spinner {
|
||
private _c: any[];
|
||
private _l: any[];
|
||
private _name: string;
|
||
private _dur: number = null;
|
||
private _init: boolean;
|
||
private _applied: string;
|
||
|
||
/**
|
||
* @input {string} SVG spinner name.
|
||
*/
|
||
@Input()
|
||
get name(): string {
|
||
return this._name;
|
||
}
|
||
|
||
set name(val: string) {
|
||
this._name = val;
|
||
this.load();
|
||
}
|
||
|
||
/**
|
||
* @input {string} How long it takes it to do one loop.
|
||
*/
|
||
@Input()
|
||
get duration(): number {
|
||
return this._dur;
|
||
}
|
||
|
||
set duration(val: number) {
|
||
this._dur = val;
|
||
this.load();
|
||
}
|
||
|
||
/**
|
||
* @input {string} If the animation is paused or not. Defaults to `false`.
|
||
*/
|
||
@Input() paused: boolean = false;
|
||
|
||
constructor(private _config: Config) {}
|
||
|
||
ngOnInit() {
|
||
this._init = true;
|
||
this.load();
|
||
}
|
||
|
||
load() {
|
||
if (this._init) {
|
||
this._l = [];
|
||
this._c = [];
|
||
|
||
var name = this._name || this._config.get('spinner', 'ios');
|
||
|
||
const spinner = SPINNERS[name];
|
||
if (spinner) {
|
||
this._applied = 'spinner-' + name;
|
||
|
||
if (spinner.lines) {
|
||
for (var i = 0, l = spinner.lines; i < l; i++) {
|
||
this._l.push( this._loadEle(spinner, i, l) );
|
||
}
|
||
|
||
} else if (spinner.circles) {
|
||
for (var i = 0, l = spinner.circles; i < l; i++) {
|
||
this._c.push( this._loadEle(spinner, i, l) );
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
_loadEle(spinner: any, index: number, total: number) {
|
||
let duration = this._dur || spinner.dur
|
||
let data = spinner.fn(duration, index, total);
|
||
data.style.animationDuration = duration + 'ms';
|
||
return data;
|
||
}
|
||
|
||
}
|
||
|
||
const SPINNERS = {
|
||
|
||
ios: {
|
||
dur: 1000,
|
||
lines: 12,
|
||
fn: function(dur, index, total) {
|
||
return {
|
||
y1: 17,
|
||
y2: 29,
|
||
style: {
|
||
transform: 'rotate(' + (30 * index + (index < 6 ? 180 : -180)) + 'deg)',
|
||
animationDelay: -(dur - ((dur / total) * index)) + 'ms'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
'ios-small': {
|
||
dur: 1000,
|
||
lines: 12,
|
||
fn: function(dur, index, total) {
|
||
return {
|
||
y1: 12,
|
||
y2: 20,
|
||
style: {
|
||
transform: 'rotate(' + (30 * index + (index < 6 ? 180 : -180)) + 'deg)',
|
||
animationDelay: -(dur - ((dur / total) * index)) + 'ms'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
bubbles: {
|
||
dur: 1000,
|
||
circles: 9,
|
||
fn: function(dur, index, total) {
|
||
return {
|
||
r: 5,
|
||
style: {
|
||
top: 9 * Math.sin(2 * Math.PI * index / total),
|
||
left: 9 * Math.cos(2 * Math.PI * index / total),
|
||
animationDelay: -(dur - ((dur / total) * index)) + 'ms'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
circles: {
|
||
dur: 1000,
|
||
circles: 8,
|
||
fn: function(dur, index, total) {
|
||
return {
|
||
r: 5,
|
||
style: {
|
||
top: 9 * Math.sin(2 * Math.PI * index / total),
|
||
left: 9 * Math.cos(2 * Math.PI * index / total),
|
||
animationDelay: -(dur - ((dur / total) * index)) + 'ms'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
crescent: {
|
||
dur: 750,
|
||
circles: 1,
|
||
fn: function(dur) {
|
||
return {
|
||
r: 26,
|
||
style: {}
|
||
}
|
||
}
|
||
},
|
||
|
||
dots: {
|
||
dur: 750,
|
||
circles: 3,
|
||
fn: function(dur, index, total) {
|
||
return {
|
||
r: 6,
|
||
style: {
|
||
left: (9 - (9 * index)),
|
||
animationDelay: -(110 * index) + 'ms'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
};
|