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