UNPKG

16.7 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) :
3 typeof define === 'function' && define.amd ? define(['exports', '@angular/core'], factory) :
4 (factory((global.md = global.md || {}, global.md.progressCircle = global.md.progressCircle || {}),global.ng.core));
5}(this, (function (exports,_angular_core) { 'use strict';
6
7var __extends = (window && window.__extends) || function (d, b) {
8 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
9 function __() { this.constructor = d; }
10 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
11};
12var __decorate = (window && window.__decorate) || function (decorators, target, key, desc) {
13 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
15 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
16 return c > 3 && r && Object.defineProperty(target, key, r), r;
17};
18var __metadata = (window && window.__metadata) || function (k, v) {
19 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
20};
21// TODO(josephperrott): Benchpress tests.
22/** A single degree in radians. */
23var DEGREE_IN_RADIANS = Math.PI / 180;
24/** Duration of the indeterminate animation. */
25var DURATION_INDETERMINATE = 667;
26/** Duration of the indeterminate animation. */
27var DURATION_DETERMINATE = 225;
28/** Start animation value of the indeterminate animation */
29var startIndeterminate = 3;
30/** End animation value of the indeterminate animation */
31var endIndeterminate = 80;
32/**
33 * <md-progress-circle> component.
34 */
35var MdProgressCircle = (function () {
36 function MdProgressCircle(_changeDetectorRef) {
37 this._changeDetectorRef = _changeDetectorRef;
38 /** The id of the last requested animation. */
39 this._lastAnimationId = 0;
40 this._mode = 'determinate';
41 }
42 Object.defineProperty(MdProgressCircle.prototype, "_ariaValueMin", {
43 /**
44 * Values for aria max and min are only defined as numbers when in a determinate mode. We do this
45 * because voiceover does not report the progress indicator as indeterminate if the aria min
46 * and/or max value are number values.
47 */
48 get: function () {
49 return this.mode == 'determinate' ? 0 : null;
50 },
51 enumerable: true,
52 configurable: true
53 });
54 Object.defineProperty(MdProgressCircle.prototype, "_ariaValueMax", {
55 get: function () {
56 return this.mode == 'determinate' ? 100 : null;
57 },
58 enumerable: true,
59 configurable: true
60 });
61 Object.defineProperty(MdProgressCircle.prototype, "interdeterminateInterval", {
62 /** TODO: internal */
63 get: function () {
64 return this._interdeterminateInterval;
65 },
66 /** TODO: internal */
67 set: function (interval) {
68 clearInterval(this._interdeterminateInterval);
69 this._interdeterminateInterval = interval;
70 },
71 enumerable: true,
72 configurable: true
73 });
74 Object.defineProperty(MdProgressCircle.prototype, "currentPath", {
75 /** TODO: internal */
76 get: function () {
77 return this._currentPath;
78 },
79 set: function (path) {
80 this._currentPath = path;
81 // Mark for check as our ChangeDetectionStrategy is OnPush, when changes come from within the
82 // component, change detection must be called for.
83 this._changeDetectorRef.markForCheck();
84 },
85 enumerable: true,
86 configurable: true
87 });
88 /** Clean up any animations that were running. */
89 MdProgressCircle.prototype.ngOnDestroy = function () {
90 this._cleanupIndeterminateAnimation();
91 };
92 Object.defineProperty(MdProgressCircle.prototype, "value", {
93 get: function () {
94 if (this.mode == 'determinate') {
95 return this._value;
96 }
97 },
98 set: function (v) {
99 if (v && this.mode == 'determinate') {
100 var newValue = clamp(v);
101 this._animateCircle((this.value || 0), newValue, linearEase, DURATION_DETERMINATE, 0);
102 this._value = newValue;
103 }
104 },
105 enumerable: true,
106 configurable: true
107 });
108 Object.defineProperty(MdProgressCircle.prototype, "mode", {
109 /**
110 * Mode of the progress circle
111 *
112 * Input must be one of the values from ProgressMode, defaults to 'determinate'.
113 * mode is bound to the host as the attribute host.
114 */
115 get: function () {
116 return this._mode;
117 },
118 set: function (m) {
119 if (m == 'indeterminate') {
120 this._startIndeterminateAnimation();
121 }
122 else {
123 this._cleanupIndeterminateAnimation();
124 }
125 this._mode = m;
126 },
127 enumerable: true,
128 configurable: true
129 });
130 /**
131 * Animates the circle from one percentage value to another.
132 *
133 * @param animateFrom The percentage of the circle filled starting the animation.
134 * @param animateTo The percentage of the circle filled ending the animation.
135 * @param ease The easing function to manage the pace of change in the animation.
136 * @param duration The length of time to show the animation, in milliseconds.
137 * @param rotation The starting angle of the circle fill, with 0° represented at the top center
138 * of the circle.
139 */
140 MdProgressCircle.prototype._animateCircle = function (animateFrom, animateTo, ease, duration, rotation) {
141 var _this = this;
142 var id = ++this._lastAnimationId;
143 var startTime = Date.now();
144 var changeInValue = animateTo - animateFrom;
145 // No need to animate it if the values are the same
146 if (animateTo === animateFrom) {
147 this.currentPath = getSvgArc(animateTo, rotation);
148 }
149 else {
150 var animation_1 = function () {
151 var elapsedTime = Math.max(0, Math.min(Date.now() - startTime, duration));
152 _this.currentPath = getSvgArc(ease(elapsedTime, animateFrom, changeInValue, duration), rotation);
153 // Prevent overlapping animations by checking if a new animation has been called for and
154 // if the animation has lasted long than the animation duration.
155 if (id === _this._lastAnimationId && elapsedTime < duration) {
156 requestAnimationFrame(animation_1);
157 }
158 };
159 requestAnimationFrame(animation_1);
160 }
161 };
162 /**
163 * Starts the indeterminate animation interval, if it is not already running.
164 */
165 MdProgressCircle.prototype._startIndeterminateAnimation = function () {
166 var _this = this;
167 var rotationStartPoint = 0;
168 var start = startIndeterminate;
169 var end = endIndeterminate;
170 var duration = DURATION_INDETERMINATE;
171 var animate = function () {
172 _this._animateCircle(start, end, materialEase, duration, rotationStartPoint);
173 // Prevent rotation from reaching Number.MAX_SAFE_INTEGER.
174 rotationStartPoint = (rotationStartPoint + end) % 100;
175 var temp = start;
176 start = -end;
177 end = -temp;
178 };
179 if (!this.interdeterminateInterval) {
180 this.interdeterminateInterval = setInterval(animate, duration + 50, 0, false);
181 animate();
182 }
183 };
184 /**
185 * Removes interval, ending the animation.
186 */
187 MdProgressCircle.prototype._cleanupIndeterminateAnimation = function () {
188 this.interdeterminateInterval = null;
189 };
190 __decorate([
191 _angular_core.Input(),
192 _angular_core.HostBinding('attr.aria-valuenow'),
193 __metadata('design:type', Object)
194 ], MdProgressCircle.prototype, "value", null);
195 __decorate([
196 _angular_core.HostBinding('attr.mode'),
197 _angular_core.Input(),
198 __metadata('design:type', Object)
199 ], MdProgressCircle.prototype, "mode", null);
200 MdProgressCircle = __decorate([
201 _angular_core.Component({selector: 'md-progress-circle',
202 host: {
203 'role': 'progressbar',
204 '[attr.aria-valuemin]': '_ariaValueMin',
205 '[attr.aria-valuemax]': '_ariaValueMax',
206 },
207 template: "<!-- preserveAspectRatio of xMidYMid meet as the center of the viewport is the circle's center. The center of the circle with remain at the center of the md-progress-circle element containing the SVG. --> <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid meet\"> <path [attr.d]=\"currentPath\"></path> </svg> ",
208 styles: ["/* Animation Durations */ /** Component sizing */ :host { display: block; /** Height and width are provided for md-progress-circle to act as a default. The height and width are expected to be overwritten by application css. */ height: 100px; width: 100px; /** SVG's viewBox is defined as 0 0 100 100, this means that all SVG children will placed based on a 100px by 100px box. Additionally all SVG sizes and locations are in reference to this viewBox. */ } :host svg { height: 100%; width: 100%; transform-origin: center; } :host path { fill: transparent; stroke: #00897b; /** Stroke width of 10px defines stroke as 10% of the viewBox */ stroke-width: 10px; } :host[color='accent'] path { stroke: #8e24aa; } :host[color='warn'] path { stroke: #e53935; } :host[mode='indeterminate'] { animation-duration: 5250ms, 2887.5ms; animation-name: md-progress-circle-sporadic-rotate, md-progress-circle-linear-rotate; animation-timing-function: cubic-bezier(0.35, 0, 0.25, 1), linear; animation-iteration-count: infinite; transition: none; } /** Animations for indeterminate mode */ @keyframes md-progress-circle-linear-rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes md-progress-circle-sporadic-rotate { 12.5% { transform: rotate(135deg); } 25% { transform: rotate(270deg); } 37.5% { transform: rotate(405deg); } 50% { transform: rotate(540deg); } 62.5% { transform: rotate(675deg); } 75% { transform: rotate(810deg); } 87.5% { transform: rotate(945deg); } 100% { transform: rotate(1080deg); } } /*# sourceMappingURL=progress-circle.css.map */ "],
209 changeDetection: _angular_core.ChangeDetectionStrategy.OnPush,
210 }),
211 __metadata('design:paramtypes', [_angular_core.ChangeDetectorRef])
212 ], MdProgressCircle);
213 return MdProgressCircle;
214}());
215/**
216 * <md-spinner> component.
217 *
218 * This is a component definition to be used as a convenience reference to create an
219 * indeterminate <md-progress-circle> instance.
220 */
221var MdSpinner = (function (_super) {
222 __extends(MdSpinner, _super);
223 function MdSpinner(changeDetectorRef) {
224 _super.call(this, changeDetectorRef);
225 this.mode = 'indeterminate';
226 }
227 MdSpinner = __decorate([
228 _angular_core.Component({selector: 'md-spinner',
229 host: {
230 'role': 'progressbar',
231 'mode': 'indeterminate',
232 },
233 template: "<!-- preserveAspectRatio of xMidYMid meet as the center of the viewport is the circle's center. The center of the circle with remain at the center of the md-progress-circle element containing the SVG. --> <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid meet\"> <path [attr.d]=\"currentPath\"></path> </svg> ",
234 styles: ["/* Animation Durations */ /** Component sizing */ :host { display: block; /** Height and width are provided for md-progress-circle to act as a default. The height and width are expected to be overwritten by application css. */ height: 100px; width: 100px; /** SVG's viewBox is defined as 0 0 100 100, this means that all SVG children will placed based on a 100px by 100px box. Additionally all SVG sizes and locations are in reference to this viewBox. */ } :host svg { height: 100%; width: 100%; transform-origin: center; } :host path { fill: transparent; stroke: #00897b; /** Stroke width of 10px defines stroke as 10% of the viewBox */ stroke-width: 10px; } :host[color='accent'] path { stroke: #8e24aa; } :host[color='warn'] path { stroke: #e53935; } :host[mode='indeterminate'] { animation-duration: 5250ms, 2887.5ms; animation-name: md-progress-circle-sporadic-rotate, md-progress-circle-linear-rotate; animation-timing-function: cubic-bezier(0.35, 0, 0.25, 1), linear; animation-iteration-count: infinite; transition: none; } /** Animations for indeterminate mode */ @keyframes md-progress-circle-linear-rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes md-progress-circle-sporadic-rotate { 12.5% { transform: rotate(135deg); } 25% { transform: rotate(270deg); } 37.5% { transform: rotate(405deg); } 50% { transform: rotate(540deg); } 62.5% { transform: rotate(675deg); } 75% { transform: rotate(810deg); } 87.5% { transform: rotate(945deg); } 100% { transform: rotate(1080deg); } } /*# sourceMappingURL=progress-circle.css.map */ "],
235 }),
236 __metadata('design:paramtypes', [_angular_core.ChangeDetectorRef])
237 ], MdSpinner);
238 return MdSpinner;
239}(MdProgressCircle));
240/**
241 * Module functions.
242 */
243/** Clamps a value to be between 0 and 100. */
244function clamp(v) {
245 return Math.max(0, Math.min(100, v));
246}
247/**
248 * Converts Polar coordinates to Cartesian.
249 */
250function polarToCartesian(radius, pathRadius, angleInDegrees) {
251 var angleInRadians = (angleInDegrees - 90) * DEGREE_IN_RADIANS;
252 return (radius + (pathRadius * Math.cos(angleInRadians))) +
253 ',' + (radius + (pathRadius * Math.sin(angleInRadians)));
254}
255/**
256 * Easing function for linear animation.
257 */
258function linearEase(currentTime, startValue, changeInValue, duration) {
259 return changeInValue * currentTime / duration + startValue;
260}
261/**
262 * Easing function to match material design indeterminate animation.
263 */
264function materialEase(currentTime, startValue, changeInValue, duration) {
265 var time = currentTime / duration;
266 var timeCubed = Math.pow(time, 3);
267 var timeQuad = Math.pow(time, 4);
268 var timeQuint = Math.pow(time, 5);
269 return startValue + changeInValue * ((6 * timeQuint) + (-15 * timeQuad) + (10 * timeCubed));
270}
271/**
272 * Determines the path value to define the arc. Converting percentage values to to polar
273 * coordinates on the circle, and then to cartesian coordinates in the viewport.
274 *
275 * @param currentValue The current percentage value of the progress circle, the percentage of the
276 * circle to fill.
277 * @param rotation The starting point of the circle with 0 being the 0 degree point.
278 * @return A string for an SVG path representing a circle filled from the starting point to the
279 * percentage value provided.
280 */
281function getSvgArc(currentValue, rotation) {
282 // The angle can't be exactly 360, because the arc becomes hidden.
283 var maximumAngle = 359.99 / 100;
284 var startPoint = rotation || 0;
285 var radius = 50;
286 var pathRadius = 40;
287 var startAngle = startPoint * maximumAngle;
288 var endAngle = currentValue * maximumAngle;
289 var start = polarToCartesian(radius, pathRadius, startAngle);
290 var end = polarToCartesian(radius, pathRadius, endAngle + startAngle);
291 var arcSweep = endAngle < 0 ? 0 : 1;
292 var largeArcFlag;
293 if (endAngle < 0) {
294 largeArcFlag = endAngle >= -180 ? 0 : 1;
295 }
296 else {
297 largeArcFlag = endAngle <= 180 ? 0 : 1;
298 }
299 return "M" + start + "A" + pathRadius + "," + pathRadius + " 0 " + largeArcFlag + "," + arcSweep + " " + end;
300}
301var MdProgressCircleModule = (function () {
302 function MdProgressCircleModule() {
303 }
304 MdProgressCircleModule.forRoot = function () {
305 return {
306 ngModule: MdProgressCircleModule,
307 providers: []
308 };
309 };
310 MdProgressCircleModule = __decorate([
311 _angular_core.NgModule({
312 exports: [MdProgressCircle, MdSpinner],
313 declarations: [MdProgressCircle, MdSpinner],
314 }),
315 __metadata('design:paramtypes', [])
316 ], MdProgressCircleModule);
317 return MdProgressCircleModule;
318}());
319
320exports.MdProgressCircle = MdProgressCircle;
321exports.MdSpinner = MdSpinner;
322exports.MdProgressCircleModule = MdProgressCircleModule;
323
324Object.defineProperty(exports, '__esModule', { value: true });
325
326})));
\No newline at end of file