@progress/kendo-angular-progressbar
Version:
Kendo UI Angular component starter template
371 lines (370 loc) • 15.6 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { ProgressBarBase } from './common/progressbar-base';
import { Component, Input, NgZone, Renderer2, ViewChild, ElementRef, Output, EventEmitter } from '@angular/core';
import { formatValue, calculateRatio, runAnimation, stopCurrentAnimation } from './common/util';
import { LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
import { hasObservers } from '@progress/kendo-angular-common';
import { NgStyle, NgClass, NgIf } from '@angular/common';
import { LocalizedProgressBarMessagesDirective } from './common/localization/localized-messages.directive';
import * as i0 from "@angular/core";
import * as i1 from "@progress/kendo-angular-l10n";
/**
* Represents the [Kendo UI ProgressBar component for Angular]({% slug overview_progressbar %}).
*
* @example
* ```ts-preview
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-progressbar [value]="value">
* </kendo-progressbar>
* `
* })
* class AppComponent {
* public value = 50;
* }
* ```
*/
export class ProgressBarComponent extends ProgressBarBase {
localization;
elem;
renderer;
zone;
/**
* Determines whether the status label will be visible.
* Defaults to `true`—the label will be visible and displayed with the default
* `LabelSettings` having its position set to `end` and its format set to `value`.
*/
label = true;
/**
* The CSS styles that will be rendered on the inner element which represents the full portion of the progress bar
* ([see example]({% slug progressbar_appearance %})).
* Supports the type of values that are supported by [`ngStyle`](link:site.data.urls.angular['ngstyleapi']).
*/
progressCssStyle;
/**
* The CSS classes that will be rendered on the inner element which represents the full portion of the progress bar
* ([see example]({% slug progressbar_appearance %})).
* Supports the type of values that are supported by [`ngClass`](link:site.data.urls.angular['ngclassapi']).
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
progressCssClass;
/**
* The CSS styles that will be rendered on the inner element which represents the empty portion of the progress bar
* ([see example]({% slug progressbar_appearance %})).
* Supports the type of values that are supported by [`ngStyle`](link:site.data.urls.angular['ngstyleapi']).
*/
emptyCssStyle;
/**
* The CSS classes that will be rendered on the inner element which represents the empty portion of the progress bar
* ([see example]({% slug progressbar_appearance %})).
* Supports the type of values that are supported by [`ngClass`](link:site.data.urls.angular['ngclassapi']).
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
emptyCssClass;
/**
* The animation configuration of the ProgressBar.
* Defaults to `false`.
*/
animation = false;
/**
* Fires when the animation which indicates the latest value change is completed.
*/
animationEnd = new EventEmitter();
/**
* @hidden
*/
get showLabel() {
if (typeof this.label === 'boolean') {
return this.label;
}
else {
if (this.label && !this.label.hasOwnProperty('visible')) {
this.label.visible = true;
}
return this.label.visible;
}
}
/**
* @hidden
*/
get labelPosition() {
if (typeof this.label === 'boolean') {
return 'end';
}
else {
if (this.label && !this.label.hasOwnProperty('position')) {
this.label.position = 'end';
}
return this.label.position;
}
}
/**
* @hidden
*/
get isPositionStart() {
return this.labelPosition === 'start';
}
/**
* @hidden
*/
get isPositionCenter() {
return this.labelPosition === 'center';
}
/**
* @hidden
*/
get isPositionEnd() {
return this.labelPosition === 'end';
}
/**
* @hidden
*/
get formattedLabelValue() {
return formatValue(this.displayValue, this.min, this.max, this.label);
}
progressStatusElement;
progressStatusWrapperElement;
animationFrame;
cancelCurrentAnimation;
isAnimationInProgress;
/**
* @hidden
*/
constructor(localization, elem, renderer, zone) {
super(elem, renderer, localization);
this.localization = localization;
this.elem = elem;
this.renderer = renderer;
this.zone = zone;
}
/**
* @hidden
*/
ngOnChanges(changes) {
super.ngOnChanges(changes);
if (this.isAnimationInProgress && stopCurrentAnimation(changes)) {
this.cancelCurrentAnimation = true;
}
if (runAnimation(changes, this.animation, this.previousValue, this.displayValue) && !changes['value'].firstChange) {
this.startAnimation(this.previousValue);
}
}
/**
* @hidden
*/
ngOnDestroy() {
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
}
/**
* @hidden
*/
startAnimation(previousValue) {
this.isAnimationInProgress = true;
const element = this.progressStatusElement.nativeElement;
const wrapperElement = this.progressStatusWrapperElement.nativeElement;
const animationOptions = this.getAnimationOptions(previousValue);
this.zone.runOutsideAngular(() => {
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
const animate = () => {
const elapsed = new Date().getTime() - animationOptions.startTime;
const position = Math.min(elapsed / animationOptions.duration, 1);
const size = animationOptions.startSize + animationOptions.deltaSize * position;
const wrapperSize = (100 / size) * 100;
this.renderValueChange(element, wrapperElement, animationOptions.property, size, wrapperSize);
if (position < 1) {
if (this.cancelCurrentAnimation) {
this.resetProgress(element, wrapperElement, animationOptions.property);
return;
}
this.animationFrame = requestAnimationFrame(animate);
}
else {
this.stopAnimation(previousValue);
}
};
animate();
});
}
/**
* @hidden
*/
get animationDuration() {
if (typeof this.animation === 'boolean') {
return 400;
}
else {
if (this.animation && !this.animation.hasOwnProperty('duration')) {
this.animation.duration = 400;
}
return this.animation.duration;
}
}
stopAnimation(value) {
if (hasObservers(this.animationEnd)) {
this.zone.run(() => {
this.animationEnd.emit({
from: value,
to: this.displayValue
});
});
}
this.zone.run(() => {
this.isAnimationInProgress = false;
});
}
getAnimationOptions(value) {
const isHorizontal = this.orientation === 'horizontal';
const previousRatio = calculateRatio(this.min, this.max, value);
const previousStatusWidth = isHorizontal ? previousRatio * 100 : 100;
const previousStatusHeight = !isHorizontal ? previousRatio * 100 : 100;
const property = isHorizontal ? 'width' : 'height';
const startTime = new Date().getTime();
const startSize = isHorizontal ? previousStatusWidth : previousStatusHeight;
const deltaSize = isHorizontal ? this.statusWidth - previousStatusWidth : this.statusHeight - previousStatusHeight;
const duration = this.animationDuration * Math.abs((deltaSize / 100));
return {
property,
startTime,
startSize,
deltaSize,
duration
};
}
renderValueChange(element, wrapperElement, property, size, wrapperSize) {
this.renderer.setStyle(element, property, size + '%');
this.renderer.setStyle(wrapperElement, property, wrapperSize + '%');
}
resetProgress(element, wrapperElement, property) {
const size = calculateRatio(this.min, this.max, this.value);
const newSize = size * 100;
const newWrapperSize = 100 / size;
this.renderValueChange(element, wrapperElement, property, newSize, newWrapperSize);
this.zone.run(() => {
this.cancelCurrentAnimation = false;
this.isAnimationInProgress = false;
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProgressBarComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ProgressBarComponent, isStandalone: true, selector: "kendo-progressbar", inputs: { label: "label", progressCssStyle: "progressCssStyle", progressCssClass: "progressCssClass", emptyCssStyle: "emptyCssStyle", emptyCssClass: "emptyCssClass", animation: "animation" }, outputs: { animationEnd: "animationEnd" }, providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.progressbar'
}
], viewQueries: [{ propertyName: "progressStatusElement", first: true, predicate: ["progressStatus"], descendants: true }, { propertyName: "progressStatusWrapperElement", first: true, predicate: ["progressStatusWrap"], descendants: true }], exportAs: ["kendoProgressBar"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
<ng-container kendoProgressBarLocalizedMessages
i18n-progressBarLabel="kendo.progressbar.progressBarLabel|The aria-label attribute for the ProgressBar component."
progressBarLabel="Progressbar"
>
</ng-container>
<span class="k-progress-status-wrap"
[class.k-progress-start]="isPositionStart"
[class.k-progress-center]="isPositionCenter"
[class.k-progress-end]="isPositionEnd"
[ngStyle]="emptyCssStyle"
[ngClass]="emptyCssClass">
<span *ngIf="showLabel" class="k-progress-status">{{formattedLabelValue}}</span>
</span>
<div
#progressStatus
class="k-selected k-progressbar-value"
[class.k-complete]="isCompleted"
[ngStyle]="progressCssStyle"
[ngClass]="progressCssClass"
[style.width.%]="statusWidth"
[style.height.%]="statusHeight"
>
<span
#progressStatusWrap
class="k-progress-status-wrap"
[style.width.%]="statusWrapperWidth"
[style.height.%]="statusWrapperHeight"
[class.k-progress-start]="isPositionStart"
[class.k-progress-center]="isPositionCenter"
[class.k-progress-end]="isPositionEnd"
>
<span *ngIf="showLabel" class="k-progress-status">{{formattedLabelValue}}</span>
</span>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedProgressBarMessagesDirective, selector: "[kendoProgressBarLocalizedMessages]" }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProgressBarComponent, decorators: [{
type: Component,
args: [{
exportAs: 'kendoProgressBar',
selector: 'kendo-progressbar',
template: `
<ng-container kendoProgressBarLocalizedMessages
i18n-progressBarLabel="kendo.progressbar.progressBarLabel|The aria-label attribute for the ProgressBar component."
progressBarLabel="Progressbar"
>
</ng-container>
<span class="k-progress-status-wrap"
[class.k-progress-start]="isPositionStart"
[class.k-progress-center]="isPositionCenter"
[class.k-progress-end]="isPositionEnd"
[ngStyle]="emptyCssStyle"
[ngClass]="emptyCssClass">
<span *ngIf="showLabel" class="k-progress-status">{{formattedLabelValue}}</span>
</span>
<div
#progressStatus
class="k-selected k-progressbar-value"
[class.k-complete]="isCompleted"
[ngStyle]="progressCssStyle"
[ngClass]="progressCssClass"
[style.width.%]="statusWidth"
[style.height.%]="statusHeight"
>
<span
#progressStatusWrap
class="k-progress-status-wrap"
[style.width.%]="statusWrapperWidth"
[style.height.%]="statusWrapperHeight"
[class.k-progress-start]="isPositionStart"
[class.k-progress-center]="isPositionCenter"
[class.k-progress-end]="isPositionEnd"
>
<span *ngIf="showLabel" class="k-progress-status">{{formattedLabelValue}}</span>
</span>
</div>
`,
providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.progressbar'
}
],
standalone: true,
imports: [LocalizedProgressBarMessagesDirective, NgStyle, NgClass, NgIf]
}]
}], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { label: [{
type: Input
}], progressCssStyle: [{
type: Input
}], progressCssClass: [{
type: Input
}], emptyCssStyle: [{
type: Input
}], emptyCssClass: [{
type: Input
}], animation: [{
type: Input
}], animationEnd: [{
type: Output
}], progressStatusElement: [{
type: ViewChild,
args: ['progressStatus', { static: false }]
}], progressStatusWrapperElement: [{
type: ViewChild,
args: ['progressStatusWrap', { static: false }]
}] } });