1 | /*!
|
---|
2 | * AngularJS Material Design
|
---|
3 | * https://github.com/angular/material
|
---|
4 | * @license MIT
|
---|
5 | * v1.2.3
|
---|
6 | */
|
---|
7 | (function( window, angular, undefined ){
|
---|
8 | "use strict";
|
---|
9 |
|
---|
10 | /**
|
---|
11 | * @ngdoc module
|
---|
12 | * @name material.components.progressCircular
|
---|
13 | * @description Module for a circular progressbar
|
---|
14 | */
|
---|
15 |
|
---|
16 | angular.module('material.components.progressCircular', ['material.core']);
|
---|
17 |
|
---|
18 | /**
|
---|
19 | * @ngdoc directive
|
---|
20 | * @name mdProgressCircular
|
---|
21 | * @module material.components.progressCircular
|
---|
22 | * @restrict E
|
---|
23 | *
|
---|
24 | * @description
|
---|
25 | * The circular progress directive is used to make loading content in your app as delightful and
|
---|
26 | * painless as possible by minimizing the amount of visual change a user sees before they can view
|
---|
27 | * and interact with content.
|
---|
28 | *
|
---|
29 | * For operations where the percentage of the operation completed can be determined, use a
|
---|
30 | * determinate indicator. They give users a quick sense of how long an operation will take.
|
---|
31 | *
|
---|
32 | * For operations where the user is asked to wait a moment while something finishes up, and it’s
|
---|
33 | * not necessary to expose what's happening behind the scenes and how long it will take, use an
|
---|
34 | * indeterminate indicator.
|
---|
35 | *
|
---|
36 | * @param {string} md-mode Select from one of two modes: **'determinate'** and **'indeterminate'**.
|
---|
37 | *
|
---|
38 | * Note: if the `md-mode` value is set as undefined or specified as not 1 of the two (2) valid modes, then **'indeterminate'**
|
---|
39 | * will be auto-applied as the mode.
|
---|
40 | *
|
---|
41 | * Note: if not configured, the `md-mode="indeterminate"` will be auto injected as an attribute.
|
---|
42 | * If `value=""` is also specified, however, then `md-mode="determinate"` would be auto-injected instead.
|
---|
43 | * @param {number=} value In determinate mode, this number represents the percentage of the
|
---|
44 | * circular progress. Default: 0
|
---|
45 | * @param {number=} md-diameter This specifies the diameter of the circular progress. The value
|
---|
46 | * should be a pixel-size value (eg '100'). If this attribute is
|
---|
47 | * not present then a default value of '50px' is assumed.
|
---|
48 | *
|
---|
49 | * @param {boolean=} ng-disabled Determines whether to disable the progress element.
|
---|
50 | *
|
---|
51 | * @usage
|
---|
52 | * <hljs lang="html">
|
---|
53 | * <md-progress-circular md-mode="determinate" value="..."></md-progress-circular>
|
---|
54 | *
|
---|
55 | * <md-progress-circular md-mode="determinate" ng-value="..."></md-progress-circular>
|
---|
56 | *
|
---|
57 | * <md-progress-circular md-mode="determinate" value="..." md-diameter="100"></md-progress-circular>
|
---|
58 | *
|
---|
59 | * <md-progress-circular md-mode="indeterminate"></md-progress-circular>
|
---|
60 | * </hljs>
|
---|
61 | */
|
---|
62 |
|
---|
63 | MdProgressCircularDirective['$inject'] = ["$window", "$mdProgressCircular", "$mdTheming", "$mdUtil", "$interval", "$log"];
|
---|
64 | angular
|
---|
65 | .module('material.components.progressCircular')
|
---|
66 | .directive('mdProgressCircular', MdProgressCircularDirective);
|
---|
67 |
|
---|
68 | /* ngInject */
|
---|
69 | function MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,
|
---|
70 | $mdUtil, $interval, $log) {
|
---|
71 |
|
---|
72 | // Note that this shouldn't use use $$rAF, because it can cause an infinite loop
|
---|
73 | // in any tests that call $animate.flush.
|
---|
74 | var rAF = $window.requestAnimationFrame ||
|
---|
75 | $window.webkitRequestAnimationFrame ||
|
---|
76 | angular.noop;
|
---|
77 |
|
---|
78 | var cAF = $window.cancelAnimationFrame ||
|
---|
79 | $window.webkitCancelAnimationFrame ||
|
---|
80 | $window.webkitCancelRequestAnimationFrame ||
|
---|
81 | angular.noop;
|
---|
82 |
|
---|
83 | var MODE_DETERMINATE = 'determinate';
|
---|
84 | var MODE_INDETERMINATE = 'indeterminate';
|
---|
85 | var DISABLED_CLASS = '_md-progress-circular-disabled';
|
---|
86 | var INDETERMINATE_CLASS = 'md-mode-indeterminate';
|
---|
87 |
|
---|
88 | return {
|
---|
89 | restrict: 'E',
|
---|
90 | scope: {
|
---|
91 | value: '@',
|
---|
92 | mdDiameter: '@',
|
---|
93 | mdMode: '@'
|
---|
94 | },
|
---|
95 | template:
|
---|
96 | '<svg xmlns="http://www.w3.org/2000/svg">' +
|
---|
97 | '<path fill="none"/>' +
|
---|
98 | '</svg>',
|
---|
99 | compile: function(element, attrs) {
|
---|
100 | element.attr({
|
---|
101 | 'aria-valuemin': 0,
|
---|
102 | 'aria-valuemax': 100,
|
---|
103 | 'role': 'progressbar'
|
---|
104 | });
|
---|
105 |
|
---|
106 | if (angular.isUndefined(attrs.mdMode)) {
|
---|
107 | var mode = attrs.hasOwnProperty('value') ? MODE_DETERMINATE : MODE_INDETERMINATE;
|
---|
108 | attrs.$set('mdMode', mode);
|
---|
109 | } else {
|
---|
110 | attrs.$set('mdMode', attrs.mdMode.trim());
|
---|
111 | }
|
---|
112 |
|
---|
113 | return MdProgressCircularLink;
|
---|
114 | }
|
---|
115 | };
|
---|
116 |
|
---|
117 | function MdProgressCircularLink(scope, element, attrs) {
|
---|
118 | var node = element[0];
|
---|
119 | var svg = angular.element(node.querySelector('svg'));
|
---|
120 | var path = angular.element(node.querySelector('path'));
|
---|
121 | var startIndeterminate = $mdProgressCircular.startIndeterminate;
|
---|
122 | var endIndeterminate = $mdProgressCircular.endIndeterminate;
|
---|
123 | var iterationCount = 0;
|
---|
124 | var lastAnimationId = 0;
|
---|
125 | var lastDrawFrame;
|
---|
126 | var interval;
|
---|
127 |
|
---|
128 | $mdTheming(element);
|
---|
129 | element.toggleClass(DISABLED_CLASS, attrs.hasOwnProperty('disabled'));
|
---|
130 |
|
---|
131 | // If the mode is indeterminate, it doesn't need to
|
---|
132 | // wait for the next digest. It can start right away.
|
---|
133 | if (scope.mdMode === MODE_INDETERMINATE){
|
---|
134 | startIndeterminateAnimation();
|
---|
135 | }
|
---|
136 |
|
---|
137 | scope.$on('$destroy', function(){
|
---|
138 | cleanupIndeterminateAnimation();
|
---|
139 |
|
---|
140 | if (lastDrawFrame) {
|
---|
141 | cAF(lastDrawFrame);
|
---|
142 | }
|
---|
143 | });
|
---|
144 |
|
---|
145 | scope.$watchGroup(['value', 'mdMode', function() {
|
---|
146 | var isDisabled = node.disabled;
|
---|
147 |
|
---|
148 | // Sometimes the browser doesn't return a boolean, in
|
---|
149 | // which case we should check whether the attribute is
|
---|
150 | // present.
|
---|
151 | if (isDisabled === true || isDisabled === false){
|
---|
152 | return isDisabled;
|
---|
153 | }
|
---|
154 |
|
---|
155 | return angular.isDefined(element.attr('disabled'));
|
---|
156 | }], function(newValues, oldValues) {
|
---|
157 | var mode = newValues[1];
|
---|
158 | var isDisabled = newValues[2];
|
---|
159 | var wasDisabled = oldValues[2];
|
---|
160 | var diameter = 0;
|
---|
161 | var strokeWidth = 0;
|
---|
162 |
|
---|
163 | if (isDisabled !== wasDisabled) {
|
---|
164 | element.toggleClass(DISABLED_CLASS, !!isDisabled);
|
---|
165 | }
|
---|
166 |
|
---|
167 | if (isDisabled) {
|
---|
168 | cleanupIndeterminateAnimation();
|
---|
169 | } else {
|
---|
170 | if (mode !== MODE_DETERMINATE && mode !== MODE_INDETERMINATE) {
|
---|
171 | mode = MODE_INDETERMINATE;
|
---|
172 | attrs.$set('mdMode', mode);
|
---|
173 | }
|
---|
174 |
|
---|
175 | if (mode === MODE_INDETERMINATE) {
|
---|
176 | if (oldValues[1] === MODE_DETERMINATE) {
|
---|
177 | diameter = getSize(scope.mdDiameter);
|
---|
178 | strokeWidth = getStroke(diameter);
|
---|
179 | path.attr('d', getSvgArc(diameter, strokeWidth, true));
|
---|
180 | path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 75));
|
---|
181 | }
|
---|
182 | startIndeterminateAnimation();
|
---|
183 | } else {
|
---|
184 | var newValue = clamp(newValues[0]);
|
---|
185 | var oldValue = clamp(oldValues[0]);
|
---|
186 |
|
---|
187 | cleanupIndeterminateAnimation();
|
---|
188 |
|
---|
189 | if (oldValues[1] === MODE_INDETERMINATE) {
|
---|
190 | diameter = getSize(scope.mdDiameter);
|
---|
191 | strokeWidth = getStroke(diameter);
|
---|
192 | path.attr('d', getSvgArc(diameter, strokeWidth, false));
|
---|
193 | path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 100));
|
---|
194 | }
|
---|
195 |
|
---|
196 | element.attr('aria-valuenow', newValue);
|
---|
197 | renderCircle(oldValue, newValue);
|
---|
198 | }
|
---|
199 | }
|
---|
200 |
|
---|
201 | });
|
---|
202 |
|
---|
203 | // This is in a separate watch in order to avoid layout, unless
|
---|
204 | // the value has actually changed.
|
---|
205 | scope.$watch('mdDiameter', function(newValue) {
|
---|
206 | var diameter = getSize(newValue);
|
---|
207 | var strokeWidth = getStroke(diameter);
|
---|
208 | var value = clamp(scope.value);
|
---|
209 | var transformOrigin = (diameter / 2) + 'px';
|
---|
210 | var dimensions = {
|
---|
211 | width: diameter + 'px',
|
---|
212 | height: diameter + 'px'
|
---|
213 | };
|
---|
214 |
|
---|
215 | // The viewBox has to be applied via setAttribute, because it is
|
---|
216 | // case-sensitive. If jQuery is included in the page, `.attr` lowercases
|
---|
217 | // all attribute names.
|
---|
218 | svg[0].setAttribute('viewBox', '0 0 ' + diameter + ' ' + diameter);
|
---|
219 |
|
---|
220 | // Usually viewBox sets the dimensions for the SVG, however that doesn't
|
---|
221 | // seem to be the case on IE10.
|
---|
222 | // Important! The transform origin has to be set from here and it has to
|
---|
223 | // be in the format of "Ypx Ypx Ypx", otherwise the rotation wobbles in
|
---|
224 | // IE and Edge, because they don't account for the stroke width when
|
---|
225 | // rotating. Also "center" doesn't help in this case, it has to be a
|
---|
226 | // precise value.
|
---|
227 | svg
|
---|
228 | .css(dimensions)
|
---|
229 | .css('transform-origin', transformOrigin + ' ' + transformOrigin + ' ' + transformOrigin);
|
---|
230 |
|
---|
231 | element.css(dimensions);
|
---|
232 |
|
---|
233 | path.attr('stroke-width', strokeWidth);
|
---|
234 | path.attr('stroke-linecap', 'square');
|
---|
235 | if (scope.mdMode == MODE_INDETERMINATE) {
|
---|
236 | path.attr('d', getSvgArc(diameter, strokeWidth, true));
|
---|
237 | path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 75));
|
---|
238 | path.attr('stroke-dashoffset', getDashOffset(diameter, strokeWidth, 1, 75));
|
---|
239 | } else {
|
---|
240 | path.attr('d', getSvgArc(diameter, strokeWidth, false));
|
---|
241 | path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 100));
|
---|
242 | path.attr('stroke-dashoffset', getDashOffset(diameter, strokeWidth, 0, 100));
|
---|
243 | renderCircle(value, value);
|
---|
244 | }
|
---|
245 |
|
---|
246 | });
|
---|
247 |
|
---|
248 | function renderCircle(animateFrom, animateTo, easing, duration, iterationCount, maxValue) {
|
---|
249 | var id = ++lastAnimationId;
|
---|
250 | var startTime = $mdUtil.now();
|
---|
251 | var changeInValue = animateTo - animateFrom;
|
---|
252 | var diameter = getSize(scope.mdDiameter);
|
---|
253 | var strokeWidth = getStroke(diameter);
|
---|
254 | var ease = easing || $mdProgressCircular.easeFn;
|
---|
255 | var animationDuration = duration || $mdProgressCircular.duration;
|
---|
256 | var rotation = -90 * (iterationCount || 0);
|
---|
257 | var dashLimit = maxValue || 100;
|
---|
258 |
|
---|
259 | // No need to animate it if the values are the same
|
---|
260 | if (animateTo === animateFrom) {
|
---|
261 | renderFrame(animateTo);
|
---|
262 | } else {
|
---|
263 | lastDrawFrame = rAF(function animation() {
|
---|
264 | var currentTime = $window.Math.max(0, $window.Math.min($mdUtil.now() - startTime, animationDuration));
|
---|
265 |
|
---|
266 | renderFrame(ease(currentTime, animateFrom, changeInValue, animationDuration));
|
---|
267 |
|
---|
268 | // Do not allow overlapping animations
|
---|
269 | if (id === lastAnimationId && currentTime < animationDuration) {
|
---|
270 | lastDrawFrame = rAF(animation);
|
---|
271 | }
|
---|
272 | });
|
---|
273 | }
|
---|
274 |
|
---|
275 | function renderFrame(value) {
|
---|
276 | path.attr('stroke-dashoffset', getDashOffset(diameter, strokeWidth, value, dashLimit));
|
---|
277 | path.attr('transform','rotate(' + (rotation) + ' ' + diameter/2 + ' ' + diameter/2 + ')');
|
---|
278 | }
|
---|
279 | }
|
---|
280 |
|
---|
281 | function animateIndeterminate() {
|
---|
282 | renderCircle(
|
---|
283 | startIndeterminate,
|
---|
284 | endIndeterminate,
|
---|
285 | $mdProgressCircular.easeFnIndeterminate,
|
---|
286 | $mdProgressCircular.durationIndeterminate,
|
---|
287 | iterationCount,
|
---|
288 | 75
|
---|
289 | );
|
---|
290 |
|
---|
291 | // The %4 technically isn't necessary, but it keeps the rotation
|
---|
292 | // under 360, instead of becoming a crazy large number.
|
---|
293 | iterationCount = ++iterationCount % 4;
|
---|
294 |
|
---|
295 | }
|
---|
296 |
|
---|
297 | function startIndeterminateAnimation() {
|
---|
298 | if (!interval) {
|
---|
299 | // Note that this interval isn't supposed to trigger a digest.
|
---|
300 | interval = $interval(
|
---|
301 | animateIndeterminate,
|
---|
302 | $mdProgressCircular.durationIndeterminate,
|
---|
303 | 0,
|
---|
304 | false
|
---|
305 | );
|
---|
306 |
|
---|
307 | animateIndeterminate();
|
---|
308 |
|
---|
309 | element
|
---|
310 | .addClass(INDETERMINATE_CLASS)
|
---|
311 | .removeAttr('aria-valuenow');
|
---|
312 | }
|
---|
313 | }
|
---|
314 |
|
---|
315 | function cleanupIndeterminateAnimation() {
|
---|
316 | if (interval) {
|
---|
317 | $interval.cancel(interval);
|
---|
318 | interval = null;
|
---|
319 | element.removeClass(INDETERMINATE_CLASS);
|
---|
320 | }
|
---|
321 | }
|
---|
322 | }
|
---|
323 |
|
---|
324 | /**
|
---|
325 | * Returns SVG path data for progress circle
|
---|
326 | * Syntax spec: https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
---|
327 | *
|
---|
328 | * @param {number} diameter Diameter of the container.
|
---|
329 | * @param {number} strokeWidth Stroke width to be used when drawing circle
|
---|
330 | * @param {boolean} indeterminate Use if progress circle will be used for indeterminate
|
---|
331 | *
|
---|
332 | * @returns {string} String representation of an SVG arc.
|
---|
333 | */
|
---|
334 | function getSvgArc(diameter, strokeWidth, indeterminate) {
|
---|
335 | var radius = diameter / 2;
|
---|
336 | var offset = strokeWidth / 2;
|
---|
337 | var start = radius + ',' + offset; // ie: (25, 2.5) or 12 o'clock
|
---|
338 | var end = offset + ',' + radius; // ie: (2.5, 25) or 9 o'clock
|
---|
339 | var arcRadius = radius - offset;
|
---|
340 | return 'M' + start
|
---|
341 | + 'A' + arcRadius + ',' + arcRadius + ' 0 1 1 ' + end // 75% circle
|
---|
342 | + (indeterminate ? '' : 'A' + arcRadius + ',' + arcRadius + ' 0 0 1 ' + start); // loop to start
|
---|
343 | }
|
---|
344 |
|
---|
345 | /**
|
---|
346 | * Return stroke length for progress circle
|
---|
347 | *
|
---|
348 | * @param {number} diameter Diameter of the container.
|
---|
349 | * @param {number} strokeWidth Stroke width to be used when drawing circle
|
---|
350 | * @param {number} value Percentage of circle (between 0 and 100)
|
---|
351 | * @param {number} maxArcLength Maximum length of arc as a percentage of circle (between 0 and 100)
|
---|
352 | *
|
---|
353 | * @returns {number} Stroke length for progress circle
|
---|
354 | */
|
---|
355 | function getDashOffset(diameter, strokeWidth, value, maxArcLength) {
|
---|
356 | return getSpinnerCircumference(diameter, strokeWidth) * ((maxArcLength - value) / 100);
|
---|
357 | }
|
---|
358 |
|
---|
359 | /**
|
---|
360 | * Limits a value between 0 and 100.
|
---|
361 | */
|
---|
362 | function clamp(value) {
|
---|
363 | return $window.Math.max(0, $window.Math.min(value || 0, 100));
|
---|
364 | }
|
---|
365 |
|
---|
366 | /**
|
---|
367 | * Determines the size of a progress circle, based on the provided
|
---|
368 | * value in the following formats: `X`, `Ypx`, `Z%`.
|
---|
369 | */
|
---|
370 | function getSize(value) {
|
---|
371 | var defaultValue = $mdProgressCircular.progressSize;
|
---|
372 |
|
---|
373 | if (value) {
|
---|
374 | var parsed = parseFloat(value);
|
---|
375 |
|
---|
376 | if (value.lastIndexOf('%') === value.length - 1) {
|
---|
377 | parsed = (parsed / 100) * defaultValue;
|
---|
378 | }
|
---|
379 |
|
---|
380 | return parsed;
|
---|
381 | }
|
---|
382 |
|
---|
383 | return defaultValue;
|
---|
384 | }
|
---|
385 |
|
---|
386 | /**
|
---|
387 | * Determines the circle's stroke width, based on
|
---|
388 | * the provided diameter.
|
---|
389 | */
|
---|
390 | function getStroke(diameter) {
|
---|
391 | return $mdProgressCircular.strokeWidth / 100 * diameter;
|
---|
392 | }
|
---|
393 |
|
---|
394 | /**
|
---|
395 | * Return length of the dash
|
---|
396 | *
|
---|
397 | * @param {number} diameter Diameter of the container.
|
---|
398 | * @param {number} strokeWidth Stroke width to be used when drawing circle
|
---|
399 | * @param {number} value Percentage of circle (between 0 and 100)
|
---|
400 | *
|
---|
401 | * @returns {number} Length of the dash
|
---|
402 | */
|
---|
403 | function getDashLength(diameter, strokeWidth, value) {
|
---|
404 | return getSpinnerCircumference(diameter, strokeWidth) * (value / 100);
|
---|
405 | }
|
---|
406 |
|
---|
407 | /**
|
---|
408 | * Return circumference of the spinner
|
---|
409 | *
|
---|
410 | * @param {number} diameter Diameter of the container.
|
---|
411 | * @param {number} strokeWidth Stroke width to be used when drawing circle
|
---|
412 | *
|
---|
413 | * @returns {number} Circumference of the spinner
|
---|
414 | */
|
---|
415 | function getSpinnerCircumference(diameter, strokeWidth) {
|
---|
416 | return ((diameter - strokeWidth) * $window.Math.PI);
|
---|
417 | }
|
---|
418 |
|
---|
419 | }
|
---|
420 |
|
---|
421 | /**
|
---|
422 | * @ngdoc service
|
---|
423 | * @name $mdProgressCircular
|
---|
424 | * @module material.components.progressCircular
|
---|
425 | *
|
---|
426 | * @description
|
---|
427 | * Allows the user to specify the default options for the `progressCircular` directive.
|
---|
428 | *
|
---|
429 | * @property {number} progressSize Diameter of the progress circle in pixels.
|
---|
430 | * @property {number} strokeWidth Width of the circle's stroke as a percentage of the circle's size.
|
---|
431 | * @property {number} duration Length of the circle animation in milliseconds.
|
---|
432 | * @property {function} easeFn Default easing animation function.
|
---|
433 | * @property {object} easingPresets Collection of pre-defined easing functions.
|
---|
434 | *
|
---|
435 | * @property {number} durationIndeterminate Duration of the indeterminate animation.
|
---|
436 | * @property {number} startIndeterminate Indeterminate animation start point.
|
---|
437 | * @property {number} endIndeterminate Indeterminate animation end point.
|
---|
438 | * @property {function} easeFnIndeterminate Easing function to be used when animating
|
---|
439 | * between the indeterminate values.
|
---|
440 | *
|
---|
441 | * @property {(function(object): object)} configure Used to modify the default options.
|
---|
442 | *
|
---|
443 | * @usage
|
---|
444 | * <hljs lang="js">
|
---|
445 | * myAppModule.config(function($mdProgressCircularProvider) {
|
---|
446 | *
|
---|
447 | * // Example of changing the default progress options.
|
---|
448 | * $mdProgressCircularProvider.configure({
|
---|
449 | * progressSize: 100,
|
---|
450 | * strokeWidth: 20,
|
---|
451 | * duration: 800
|
---|
452 | * });
|
---|
453 | * });
|
---|
454 | * </hljs>
|
---|
455 | *
|
---|
456 | */
|
---|
457 |
|
---|
458 | angular
|
---|
459 | .module('material.components.progressCircular')
|
---|
460 | .provider("$mdProgressCircular", MdProgressCircularProvider);
|
---|
461 |
|
---|
462 | function MdProgressCircularProvider() {
|
---|
463 | var progressConfig = {
|
---|
464 | progressSize: 50,
|
---|
465 | strokeWidth: 10,
|
---|
466 | duration: 100,
|
---|
467 | easeFn: linearEase,
|
---|
468 |
|
---|
469 | durationIndeterminate: 1333,
|
---|
470 | startIndeterminate: 1,
|
---|
471 | endIndeterminate: 149,
|
---|
472 | easeFnIndeterminate: materialEase,
|
---|
473 |
|
---|
474 | easingPresets: {
|
---|
475 | linearEase: linearEase,
|
---|
476 | materialEase: materialEase
|
---|
477 | }
|
---|
478 | };
|
---|
479 |
|
---|
480 | return {
|
---|
481 | configure: function(options) {
|
---|
482 | progressConfig = angular.extend(progressConfig, options || {});
|
---|
483 | return progressConfig;
|
---|
484 | },
|
---|
485 | $get: function() { return progressConfig; }
|
---|
486 | };
|
---|
487 |
|
---|
488 | function linearEase(t, b, c, d) {
|
---|
489 | return c * t / d + b;
|
---|
490 | }
|
---|
491 |
|
---|
492 | function materialEase(t, b, c, d) {
|
---|
493 | // via http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm
|
---|
494 | // with settings of [0, 0, 1, 1]
|
---|
495 | var ts = (t /= d) * t;
|
---|
496 | var tc = ts * t;
|
---|
497 | return b + c * (6 * tc * ts + -15 * ts * ts + 10 * tc);
|
---|
498 | }
|
---|
499 | }
|
---|
500 |
|
---|
501 | })(window, window.angular); |
---|