@@ -62,7 +62,6 @@ function MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,
6262 $window . webkitCancelRequestAnimationFrame ||
6363 angular . noop ;
6464
65- var DEGREE_IN_RADIANS = $window . Math . PI / 180 ;
6665 var MODE_DETERMINATE = 'determinate' ;
6766 var MODE_INDETERMINATE = 'indeterminate' ;
6867 var DISABLED_CLASS = '_md-progress-circular-disabled' ;
@@ -103,7 +102,7 @@ function MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,
103102 var path = angular . element ( node . querySelector ( 'path' ) ) ;
104103 var startIndeterminate = $mdProgressCircular . startIndeterminate ;
105104 var endIndeterminate = $mdProgressCircular . endIndeterminate ;
106- var rotationIndeterminate = 0 ;
105+ var iterationCount = 0 ;
107106 var lastAnimationId = 0 ;
108107 var lastDrawFrame ;
109108 var interval ;
@@ -196,40 +195,52 @@ function MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,
196195 . css ( 'transform-origin' , transformOrigin + ' ' + transformOrigin + ' ' + transformOrigin ) ;
197196
198197 element . css ( dimensions ) ;
199- path . css ( 'stroke-width' , strokeWidth + 'px' ) ;
200198
201- renderCircle ( value , value ) ;
199+ path . attr ( 'stroke-width' , strokeWidth ) ;
200+ path . attr ( 'stroke-linecap' , 'square' ) ;
201+ if ( scope . mdMode == MODE_INDETERMINATE ) {
202+ path . attr ( 'd' , getSvgArc ( diameter , true ) ) ;
203+ path . attr ( 'stroke-dasharray' , diameter * $window . Math . PI * 0.75 ) ;
204+ path . attr ( 'stroke-dashoffset' , getDashLength ( diameter , 1 , 75 ) ) ;
205+ } else {
206+ path . attr ( 'd' , getSvgArc ( diameter , false ) ) ;
207+ path . attr ( 'stroke-dasharray' , diameter * $window . Math . PI ) ;
208+ path . attr ( 'stroke-dashoffset' , getDashLength ( diameter , 0 , 100 ) ) ;
209+ renderCircle ( value , value ) ;
210+ }
211+
202212 } ) ;
203213
204- function renderCircle ( animateFrom , animateTo , easing , duration , rotation ) {
214+ function renderCircle ( animateFrom , animateTo , easing , duration , iterationCount , maxValue ) {
205215 var id = ++ lastAnimationId ;
206216 var startTime = $mdUtil . now ( ) ;
207217 var changeInValue = animateTo - animateFrom ;
208218 var diameter = getSize ( scope . mdDiameter ) ;
209- var pathDiameter = diameter - getStroke ( diameter ) ;
210219 var ease = easing || $mdProgressCircular . easeFn ;
211220 var animationDuration = duration || $mdProgressCircular . duration ;
221+ var rotation = - 90 * ( iterationCount || 0 ) ;
222+ var dashLimit = maxValue || 100 ;
212223
213224 // No need to animate it if the values are the same
214225 if ( animateTo === animateFrom ) {
215- path . attr ( 'd' , getSvgArc ( animateTo , diameter , pathDiameter , rotation ) ) ;
226+ renderFrame ( animateTo ) ;
216227 } else {
217228 lastDrawFrame = rAF ( function animation ( ) {
218229 var currentTime = $window . Math . max ( 0 , $window . Math . min ( $mdUtil . now ( ) - startTime , animationDuration ) ) ;
219230
220- path . attr ( 'd' , getSvgArc (
221- ease ( currentTime , animateFrom , changeInValue , animationDuration ) ,
222- diameter ,
223- pathDiameter ,
224- rotation
225- ) ) ;
231+ renderFrame ( ease ( currentTime , animateFrom , changeInValue , animationDuration ) ) ;
226232
227233 // Do not allow overlapping animations
228234 if ( id === lastAnimationId && currentTime < animationDuration ) {
229235 lastDrawFrame = rAF ( animation ) ;
230236 }
231237 } ) ;
232238 }
239+
240+ function renderFrame ( value ) {
241+ path . attr ( 'stroke-dashoffset' , getDashLength ( diameter , value , dashLimit ) ) ;
242+ path . attr ( 'transform' , 'rotate(' + ( rotation ) + ' ' + diameter / 2 + ' ' + diameter / 2 + ')' ) ;
243+ }
233244 }
234245
235246 function animateIndeterminate ( ) {
@@ -238,24 +249,22 @@ function MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,
238249 endIndeterminate ,
239250 $mdProgressCircular . easeFnIndeterminate ,
240251 $mdProgressCircular . durationIndeterminate ,
241- rotationIndeterminate
252+ iterationCount ,
253+ 75
242254 ) ;
243255
244- // The % 100 technically isn't necessary, but it keeps the rotation
245- // under 100 , instead of becoming a crazy large number.
246- rotationIndeterminate = ( rotationIndeterminate + endIndeterminate ) % 100 ;
256+ // The %4 technically isn't necessary, but it keeps the rotation
257+ // under 360 , instead of becoming a crazy large number.
258+ iterationCount = ++ iterationCount % 4 ;
247259
248- var temp = startIndeterminate ;
249- startIndeterminate = - endIndeterminate ;
250- endIndeterminate = - temp ;
251260 }
252261
253262 function startIndeterminateAnimation ( ) {
254263 if ( ! interval ) {
255264 // Note that this interval isn't supposed to trigger a digest.
256265 interval = $interval (
257266 animateIndeterminate ,
258- $mdProgressCircular . durationIndeterminate + 50 ,
267+ $mdProgressCircular . durationIndeterminate ,
259268 0 ,
260269 false
261270 ) ;
@@ -278,55 +287,32 @@ function MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,
278287 }
279288
280289 /**
281- * Generates an arc following the SVG arc syntax.
290+ * Returns SVG path data for progress circle
282291 * Syntax spec: https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
283292 *
284- * @param {number } current Current value between 0 and 100.
285293 * @param {number } diameter Diameter of the container.
286- * @param {number } pathDiameter Diameter of the path element.
287- * @param {number=0 } rotation The point at which the semicircle should start rendering.
288- * Used for doing the indeterminate animation.
294+ * @param {boolean } indeterminate Use if progress circle will be used for indeterminate
289295 *
290296 * @returns {string } String representation of an SVG arc.
291297 */
292- function getSvgArc ( current , diameter , pathDiameter , rotation ) {
293- // The angle can't be exactly 360, because the arc becomes hidden.
294- var maximumAngle = 359.99 / 100 ;
295- var startPoint = rotation || 0 ;
298+ function getSvgArc ( diameter , indeterminate ) {
296299 var radius = diameter / 2 ;
297- var pathRadius = pathDiameter / 2 ;
298-
299- var startAngle = startPoint * maximumAngle ;
300- var endAngle = current * maximumAngle ;
301- var start = polarToCartesian ( radius , pathRadius , startAngle ) ;
302- var end = polarToCartesian ( radius , pathRadius , endAngle + startAngle ) ;
303- var arcSweep = endAngle < 0 ? 0 : 1 ;
304- var largeArcFlag ;
305-
306- if ( endAngle < 0 ) {
307- largeArcFlag = endAngle >= - 180 ? 0 : 1 ;
308- } else {
309- largeArcFlag = endAngle <= 180 ? 0 : 1 ;
310- }
311-
312- return 'M' + start + 'A' + pathRadius + ',' + pathRadius +
313- ' 0 ' + largeArcFlag + ',' + arcSweep + ' ' + end ;
300+ return 'M' + radius + ',0'
301+ + 'A' + radius + ',' + radius + ' 0 1 1 0,' + radius // 75% circle
302+ + ( indeterminate ? '' : 'A' + radius + ',' + radius + ' 0 0 1 ' + radius + ',0' ) ;
314303 }
315304
316305 /**
317- * Converts Polar coordinates to Cartesian.
306+ * Return stroke length for progress circle
318307 *
319- * @param {number } radius Radius of the container.
320- * @param {number } pathRadius Radius of the path element
321- * @param {number } angleInDegress Angle at which to place the point.
308+ * @param {number } diameter Diameter of the container.
309+ * @param {number } value Percentage of circle (between 0 and 100)
310+ * @param {number } limit Max percentage for circle
322311 *
323- * @returns {string } Cartesian coordinates in the format of `x,y`.
312+ * @returns {number } Stroke length for progres circle
324313 */
325- function polarToCartesian ( radius , pathRadius , angleInDegrees ) {
326- var angleInRadians = ( angleInDegrees - 90 ) * DEGREE_IN_RADIANS ;
327-
328- return ( radius + ( pathRadius * $window . Math . cos ( angleInRadians ) ) ) +
329- ',' + ( radius + ( pathRadius * $window . Math . sin ( angleInRadians ) ) ) ;
314+ function getDashLength ( diameter , value , limit ) {
315+ return diameter * $window . Math . PI * ( ( 3 * ( limit || 100 ) / 100 ) - ( value / 100 ) ) ;
330316 }
331317
332318 /**
@@ -363,4 +349,5 @@ function MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,
363349 function getStroke ( diameter ) {
364350 return $mdProgressCircular . strokeWidth / 100 * diameter ;
365351 }
352+
366353}
0 commit comments