UNPKG

@progress/kendo-angular-progressbar

Version:

Kendo UI Angular component starter template

371 lines (370 loc) 15.6 kB
/**----------------------------------------------------------------------------------------- * 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`&mdash;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 }] }] } });