Skip to content

Commit

Permalink
perf(progress-circle): clean up animation on destroy
Browse files Browse the repository at this point in the history
The indeterminate animation is based on an interval that keeps running, even after the element has been destroyed.
This change cleans up when the element is destroyed.

Also adds an extra null check for `performance.now`.
  • Loading branch information
crisbeto committed Jun 2, 2016
1 parent b24d321 commit 146b497
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 9 deletions.
21 changes: 21 additions & 0 deletions src/components/progress-circle/progress-circle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,27 @@ describe('MdProgressCircular', () => {
done();
});
});

it('should clean up the indeterminate animation when the element is destroyed',
(done: () => void) => {
let template = `<md-progress-circle
mode="indeterminate"
*ngIf="!isHidden"></md-progress-circle>`;

builder
.overrideTemplate(TestApp, template)
.createAsync(TestApp)
.then((fixture) => {
fixture.detectChanges();
let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle');
expect(progressElement.componentInstance.interdeterminateInterval).toBeTruthy();

fixture.debugElement.componentInstance.isHidden = true;
fixture.detectChanges();
expect(progressElement.componentInstance.interdeterminateInterval).toBeFalsy();
done();
});
});
});


Expand Down
31 changes: 22 additions & 9 deletions src/components/progress-circle/progress-circle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
HostBinding,
ChangeDetectorRef,
ChangeDetectionStrategy,
OnDestroy,
Input
} from '@angular/core';

Expand Down Expand Up @@ -41,12 +42,22 @@ type EasingFn = (currentTime: number, startValue: number,
styleUrls: ['progress-circle.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MdProgressCircle {
export class MdProgressCircle implements OnDestroy {
/** The id of the last requested animation. */
private _lastAnimationId: number = 0;

/** The id of the indeterminate interval. */
/**
* The id of the indeterminate interval.
* @internal
*/
private _interdeterminateInterval: number;
get interdeterminateInterval() {
return this._interdeterminateInterval;
}
set interdeterminateInterval(interval: number) {
clearInterval(this._interdeterminateInterval);
this._interdeterminateInterval = interval;
}

/** The current path value, representing the progres circle. */
private _currentPath: string;
Expand All @@ -60,6 +71,11 @@ export class MdProgressCircle {
this._changeDetectorRef.markForCheck();
}

/** Clean up any animations that were running. */
ngOnDestroy() {
this._cleanupIndeterminateAnimation();
}

/**
* Value of the progress circle.
*
Expand Down Expand Up @@ -162,8 +178,8 @@ export class MdProgressCircle {
end = -temp;
};

if (!this._interdeterminateInterval) {
this._interdeterminateInterval = setInterval(
if (!this.interdeterminateInterval) {
this.interdeterminateInterval = setInterval(
animate, duration + 50, 0, false);
animate();
}
Expand All @@ -174,10 +190,7 @@ export class MdProgressCircle {
* Removes interval, ending the animation.
*/
private _cleanupIndeterminateAnimation() {
if (this._interdeterminateInterval) {
clearInterval(this._interdeterminateInterval);
this._interdeterminateInterval = null;
}
this.interdeterminateInterval = null;
}
}

Expand Down Expand Up @@ -219,7 +232,7 @@ function clamp(v: number) {
* Returns the current timestamp either based on the performance global or a date object.
*/
function now() {
if (typeof performance !== 'undefined') {
if (typeof performance !== 'undefined' && performance.now) {
return performance.now();
}
return Date.now();
Expand Down

0 comments on commit 146b497

Please sign in to comment.