arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/www/bower_components/angular-material/modules/js/progressCircular/progressCircular.js
www/bower_components/angular-material/modules/js/progressCircular/progressCircular.jsRaw
  1/*!
  2 * Angular Material Design
  3 * https://github.com/angular/material
  4 * @license MIT
  5 * v1.1.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
 16angular.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
 63MdProgressCircularDirective['$inject'] = ["$window", "$mdProgressCircular", "$mdTheming", "$mdUtil", "$interval", "$log"];
 64angular
 65  .module('material.components.progressCircular')
 66  .directive('mdProgressCircular', MdProgressCircularDirective);
 67
 68/* ngInject */
 69function 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
161      if (isDisabled !== wasDisabled) {
162        element.toggleClass(DISABLED_CLASS, !!isDisabled);
163      }
164
165      if (isDisabled) {
166        cleanupIndeterminateAnimation();
167      } else {
168        if (mode !== MODE_DETERMINATE && mode !== MODE_INDETERMINATE) {
169          mode = MODE_INDETERMINATE;
170          attrs.$set('mdMode', mode);
171        }
172
173        if (mode === MODE_INDETERMINATE) {
174          startIndeterminateAnimation();
175        } else {
176          var newValue = clamp(newValues[0]);
177
178          cleanupIndeterminateAnimation();
179
180          element.attr('aria-valuenow', newValue);
181          renderCircle(clamp(oldValues[0]), newValue);
182        }
183      }
184
185    });
186
187    // This is in a separate watch in order to avoid layout, unless
188    // the value has actually changed.
189    scope.$watch('mdDiameter', function(newValue) {
190      var diameter = getSize(newValue);
191      var strokeWidth = getStroke(diameter);
192      var value = clamp(scope.value);
193      var transformOrigin = (diameter / 2) + 'px';
194      var dimensions = {
195        width: diameter + 'px',
196        height: diameter + 'px'
197      };
198
199      // The viewBox has to be applied via setAttribute, because it is
200      // case-sensitive. If jQuery is included in the page, `.attr` lowercases
201      // all attribute names.
202      svg[0].setAttribute('viewBox', '0 0 ' + diameter + ' ' + diameter);
203
204      // Usually viewBox sets the dimensions for the SVG, however that doesn't
205      // seem to be the case on IE10.
206      // Important! The transform origin has to be set from here and it has to
207      // be in the format of "Ypx Ypx Ypx", otherwise the rotation wobbles in
208      // IE and Edge, because they don't account for the stroke width when
209      // rotating. Also "center" doesn't help in this case, it has to be a
210      // precise value.
211      svg
212        .css(dimensions)
213        .css('transform-origin', transformOrigin + ' ' + transformOrigin + ' ' + transformOrigin);
214
215      element.css(dimensions);
216
217      path.attr('stroke-width', strokeWidth);
218      path.attr('stroke-linecap', 'square');
219      if (scope.mdMode == MODE_INDETERMINATE) {
220        path.attr('d', getSvgArc(diameter, strokeWidth, true));
221        path.attr('stroke-dasharray', (diameter - strokeWidth) * $window.Math.PI * 0.75);
222        path.attr('stroke-dashoffset', getDashLength(diameter, strokeWidth, 1, 75));
223      } else {
224        path.attr('d', getSvgArc(diameter, strokeWidth, false));
225        path.attr('stroke-dasharray', (diameter - strokeWidth) * $window.Math.PI);
226        path.attr('stroke-dashoffset', getDashLength(diameter, strokeWidth, 0, 100));
227        renderCircle(value, value);
228      }
229
230    });
231
232    function renderCircle(animateFrom, animateTo, easing, duration, iterationCount, maxValue) {
233      var id = ++lastAnimationId;
234      var startTime = $mdUtil.now();
235      var changeInValue = animateTo - animateFrom;
236      var diameter = getSize(scope.mdDiameter);
237      var strokeWidth = getStroke(diameter);
238      var ease = easing || $mdProgressCircular.easeFn;
239      var animationDuration = duration || $mdProgressCircular.duration;
240      var rotation = -90 * (iterationCount || 0);
241      var dashLimit = maxValue || 100;
242
243      // No need to animate it if the values are the same
244      if (animateTo === animateFrom) {
245        renderFrame(animateTo);
246      } else {
247        lastDrawFrame = rAF(function animation() {
248          var currentTime = $window.Math.max(0, $window.Math.min($mdUtil.now() - startTime, animationDuration));
249
250          renderFrame(ease(currentTime, animateFrom, changeInValue, animationDuration));
251
252          // Do not allow overlapping animations
253          if (id === lastAnimationId && currentTime < animationDuration) {
254            lastDrawFrame = rAF(animation);
255          }
256        });
257      }
258
259      function renderFrame(value) {
260        path.attr('stroke-dashoffset', getDashLength(diameter, strokeWidth, value, dashLimit));
261        path.attr('transform','rotate(' + (rotation) + ' ' + diameter/2 + ' ' + diameter/2 + ')');
262      }
263    }
264
265    function animateIndeterminate() {
266      renderCircle(
267        startIndeterminate,
268        endIndeterminate,
269        $mdProgressCircular.easeFnIndeterminate,
270        $mdProgressCircular.durationIndeterminate,
271        iterationCount,
272        75
273      );
274
275      // The %4 technically isn't necessary, but it keeps the rotation
276      // under 360, instead of becoming a crazy large number.
277      iterationCount = ++iterationCount % 4;
278
279    }
280
281    function startIndeterminateAnimation() {
282      if (!interval) {
283        // Note that this interval isn't supposed to trigger a digest.
284        interval = $interval(
285          animateIndeterminate,
286          $mdProgressCircular.durationIndeterminate,
287          0,
288          false
289        );
290
291        animateIndeterminate();
292
293        element
294          .addClass(INDETERMINATE_CLASS)
295          .removeAttr('aria-valuenow');
296      }
297    }
298
299    function cleanupIndeterminateAnimation() {
300      if (interval) {
301        $interval.cancel(interval);
302        interval = null;
303        element.removeClass(INDETERMINATE_CLASS);
304      }
305    }
306  }
307
308  /**
309   * Returns SVG path data for progress circle
310   * Syntax spec: https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
311   *
312   * @param {number} diameter Diameter of the container.
313   * @param {number} strokeWidth Stroke width to be used when drawing circle
314   * @param {boolean} indeterminate Use if progress circle will be used for indeterminate
315   *
316   * @returns {string} String representation of an SVG arc.
317   */
318  function getSvgArc(diameter, strokeWidth, indeterminate) {
319    var radius = diameter / 2;
320    var offset = strokeWidth / 2;
321    var start = radius + ',' + offset; // ie: (25, 2.5) or 12 o'clock
322    var end = offset + ',' + radius;   // ie: (2.5, 25) or  9 o'clock
323    var arcRadius = radius - offset;
324    return 'M' + start
325         + 'A' + arcRadius + ',' + arcRadius + ' 0 1 1 ' + end // 75% circle
326         + (indeterminate ? '' : 'A' + arcRadius + ',' + arcRadius + ' 0 0 1 ' + start); // loop to start
327  }
328
329  /**
330   * Return stroke length for progress circle
331   *
332   * @param {number} diameter Diameter of the container.
333   * @param {number} strokeWidth Stroke width to be used when drawing circle
334   * @param {number} value Percentage of circle (between 0 and 100)
335   * @param {number} limit Max percentage for circle
336   *
337   * @returns {number} Stroke length for progres circle
338   */
339  function getDashLength(diameter, strokeWidth, value, limit) {
340    return (diameter - strokeWidth) * $window.Math.PI * ( (3 * (limit || 100) / 100) - (value/100) );
341  }
342
343  /**
344   * Limits a value between 0 and 100.
345   */
346  function clamp(value) {
347    return $window.Math.max(0, $window.Math.min(value || 0, 100));
348  }
349
350  /**
351   * Determines the size of a progress circle, based on the provided
352   * value in the following formats: `X`, `Ypx`, `Z%`.
353   */
354  function getSize(value) {
355    var defaultValue = $mdProgressCircular.progressSize;
356
357    if (value) {
358      var parsed = parseFloat(value);
359
360      if (value.lastIndexOf('%') === value.length - 1) {
361        parsed = (parsed / 100) * defaultValue;
362      }
363
364      return parsed;
365    }
366
367    return defaultValue;
368  }
369
370  /**
371   * Determines the circle's stroke width, based on
372   * the provided diameter.
373   */
374  function getStroke(diameter) {
375    return $mdProgressCircular.strokeWidth / 100 * diameter;
376  }
377
378}
379
380/**
381 * @ngdoc service
382 * @name $mdProgressCircular
383 * @module material.components.progressCircular
384 *
385 * @description
386 * Allows the user to specify the default options for the `progressCircular` directive.
387 *
388 * @property {number} progressSize Diameter of the progress circle in pixels.
389 * @property {number} strokeWidth Width of the circle's stroke as a percentage of the circle's size.
390 * @property {number} duration Length of the circle animation in milliseconds.
391 * @property {function} easeFn Default easing animation function.
392 * @property {object} easingPresets Collection of pre-defined easing functions.
393 *
394 * @property {number} durationIndeterminate Duration of the indeterminate animation.
395 * @property {number} startIndeterminate Indeterminate animation start point.
396 * @property {number} endIndeterminate Indeterminate animation end point.
397 * @property {function} easeFnIndeterminate Easing function to be used when animating
398 * between the indeterminate values.
399 *
400 * @property {(function(object): object)} configure Used to modify the default options.
401 *
402 * @usage
403 * <hljs lang="js">
404 *   myAppModule.config(function($mdProgressCircularProvider) {
405 *
406 *     // Example of changing the default progress options.
407 *     $mdProgressCircularProvider.configure({
408 *       progressSize: 100,
409 *       strokeWidth: 20,
410 *       duration: 800
411 *     });
412 * });
413 * </hljs>
414 *
415 */
416
417angular
418  .module('material.components.progressCircular')
419  .provider("$mdProgressCircular", MdProgressCircularProvider);
420
421function MdProgressCircularProvider() {
422  var progressConfig = {
423    progressSize: 50,
424    strokeWidth: 10,
425    duration: 100,
426    easeFn: linearEase,
427
428    durationIndeterminate: 1333,
429    startIndeterminate: 1,
430    endIndeterminate: 149,
431    easeFnIndeterminate: materialEase,
432
433    easingPresets: {
434      linearEase: linearEase,
435      materialEase: materialEase
436    }
437  };
438
439  return {
440    configure: function(options) {
441      progressConfig = angular.extend(progressConfig, options || {});
442      return progressConfig;
443    },
444    $get: function() { return progressConfig; }
445  };
446
447  function linearEase(t, b, c, d) {
448    return c * t / d + b;
449  }
450
451  function materialEase(t, b, c, d) {
452    // via http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm
453    // with settings of [0, 0, 1, 1]
454    var ts = (t /= d) * t;
455    var tc = ts * t;
456    return b + c * (6 * tc * ts + -15 * ts * ts + 10 * tc);
457  }
458}
459
460})(window, window.angular);