UNPKG

ng-circle-progress

Version:
863 lines (857 loc) 42.8 kB
import * as i0 from '@angular/core'; import { EventEmitter, Component, Output, Input, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { DOCUMENT, CommonModule } from '@angular/common'; import { timer } from 'rxjs'; class CircleProgressOptions { constructor() { this.class = ''; this.backgroundGradient = false; this.backgroundColor = 'transparent'; this.backgroundGradientStopColor = 'transparent'; this.backgroundOpacity = 1; this.backgroundStroke = 'transparent'; this.backgroundStrokeWidth = 0; this.backgroundPadding = 5; this.percent = 0; this.radius = 90; this.space = 4; this.toFixed = 0; this.maxPercent = 1000; this.renderOnClick = true; this.units = '%'; this.unitsFontSize = '10'; this.unitsFontWeight = 'normal'; this.unitsColor = '#444444'; this.outerStrokeGradient = false; this.outerStrokeWidth = 8; this.outerStrokeColor = '#78C000'; this.outerStrokeGradientStopColor = 'transparent'; this.outerStrokeLinecap = 'round'; this.innerStrokeColor = '#C7E596'; this.innerStrokeWidth = 4; this.titleFormat = undefined; this.title = 'auto'; this.titleColor = '#444444'; this.titleFontSize = '20'; this.titleFontWeight = 'normal'; this.subtitleFormat = undefined; this.subtitle = 'progress'; this.subtitleColor = '#A9A9A9'; this.subtitleFontSize = '10'; this.subtitleFontWeight = 'normal'; this.imageSrc = undefined; this.imageHeight = 0; this.imageWidth = 0; this.animation = true; this.animateTitle = true; this.animateSubtitle = false; this.animationDuration = 500; this.showTitle = true; this.showSubtitle = true; this.showUnits = true; this.showImage = false; this.showBackground = true; this.showInnerStroke = true; this.clockwise = true; this.responsive = false; this.startFromZero = true; this.showZeroOuterStroke = true; this.lazy = false; } } class CircleProgressComponent { constructor(defaultOptions, ngZone, elRef, injector) { this.ngZone = ngZone; this.elRef = elRef; this.onClick = new EventEmitter(); // <svg> of component this.svgElement = null; // whether <svg> is in viewport this.isInViewport = false; // event for notifying viewport change caused by scrolling or resizing this.onViewportChanged = new EventEmitter(); this._viewportChangedSubscriber = null; this.options = new CircleProgressOptions(); this.defaultOptions = new CircleProgressOptions(); this._lastPercent = 0; this._gradientUUID = null; this.render = () => { this.applyOptions(); if (this.options.lazy) { // Draw svg if it doesn't exist this.svgElement === null && this.draw(this._lastPercent); // Draw it only when it's in the viewport if (this.isInViewport) { // Draw it at the latest position when I am in. if (this.options.animation && this.options.animationDuration > 0) { this.animate(this._lastPercent, this.options.percent); } else { this.draw(this.options.percent); } this._lastPercent = this.options.percent; } } else { if (this.options.animation && this.options.animationDuration > 0) { this.animate(this._lastPercent, this.options.percent); } else { this.draw(this.options.percent); } this._lastPercent = this.options.percent; } }; this.polarToCartesian = (centerX, centerY, radius, angleInDegrees) => { let angleInRadius = angleInDegrees * Math.PI / 180; let x = centerX + Math.sin(angleInRadius) * radius; let y = centerY - Math.cos(angleInRadius) * radius; return { x: x, y: y }; }; this.draw = (percent) => { // make percent reasonable percent = (percent === undefined) ? this.options.percent : Math.abs(percent); // circle percent shouldn't be greater than 100%. let circlePercent = (percent > 100) ? 100 : percent; // determine box size let boxSize = this.options.radius * 2 + this.options.outerStrokeWidth * 2; if (this.options.showBackground) { boxSize += (this.options.backgroundStrokeWidth * 2 + this.max(0, this.options.backgroundPadding * 2)); } // the centre of the circle let centre = { x: boxSize / 2, y: boxSize / 2 }; // the start point of the arc let startPoint = { x: centre.x, y: centre.y - this.options.radius }; // get the end point of the arc let endPoint = this.polarToCartesian(centre.x, centre.y, this.options.radius, 360 * (this.options.clockwise ? circlePercent : (100 - circlePercent)) / 100); // #################### // We'll get an end point with the same [x, y] as the start point when percent is 100%, so move x a little bit. if (circlePercent === 100) { endPoint.x = endPoint.x + (this.options.clockwise ? -0.01 : +0.01); } // largeArcFlag and sweepFlag let largeArcFlag, sweepFlag; if (circlePercent > 50) { [largeArcFlag, sweepFlag] = this.options.clockwise ? [1, 1] : [1, 0]; } else { [largeArcFlag, sweepFlag] = this.options.clockwise ? [0, 1] : [0, 0]; } // percent may not equal the actual percent let titlePercent = this.options.animateTitle ? percent : this.options.percent; let titleTextPercent = titlePercent > this.options.maxPercent ? `${this.options.maxPercent.toFixed(this.options.toFixed)}+` : titlePercent.toFixed(this.options.toFixed); let subtitlePercent = this.options.animateSubtitle ? percent : this.options.percent; // get title object let title = { x: centre.x, y: centre.y, textAnchor: 'middle', color: this.options.titleColor, fontSize: this.options.titleFontSize, fontWeight: this.options.titleFontWeight, texts: [], tspans: [] }; // from v0.9.9, both title and titleFormat(...) may be an array of string. if (this.options.titleFormat !== undefined && this.options.titleFormat.constructor.name === 'Function') { let formatted = this.options.titleFormat(titlePercent); if (formatted instanceof Array) { title.texts = [...formatted]; } else { title.texts.push(formatted.toString()); } } else { if (this.options.title === 'auto') { title.texts.push(titleTextPercent); } else { if (this.options.title instanceof Array) { title.texts = [...this.options.title]; } else { title.texts.push(this.options.title.toString()); } } } // get subtitle object let subtitle = { x: centre.x, y: centre.y, textAnchor: 'middle', color: this.options.subtitleColor, fontSize: this.options.subtitleFontSize, fontWeight: this.options.subtitleFontWeight, texts: [], tspans: [] }; // from v0.9.9, both subtitle and subtitleFormat(...) may be an array of string. if (this.options.subtitleFormat !== undefined && this.options.subtitleFormat.constructor.name === 'Function') { let formatted = this.options.subtitleFormat(subtitlePercent); if (formatted instanceof Array) { subtitle.texts = [...formatted]; } else { subtitle.texts.push(formatted.toString()); } } else { if (this.options.subtitle instanceof Array) { subtitle.texts = [...this.options.subtitle]; } else { subtitle.texts.push(this.options.subtitle.toString()); } } // get units object let units = { text: `${this.options.units}`, fontSize: this.options.unitsFontSize, fontWeight: this.options.unitsFontWeight, color: this.options.unitsColor }; // get total count of text lines to be shown let rowCount = 0, rowNum = 1; this.options.showTitle && (rowCount += title.texts.length); this.options.showSubtitle && (rowCount += subtitle.texts.length); // calc dy for each tspan for title if (this.options.showTitle) { for (let span of title.texts) { title.tspans.push({ span: span, dy: this.getRelativeY(rowNum, rowCount) }); rowNum++; } } // calc dy for each tspan for subtitle if (this.options.showSubtitle) { for (let span of subtitle.texts) { subtitle.tspans.push({ span: span, dy: this.getRelativeY(rowNum, rowCount) }); rowNum++; } } // create ID for gradient element if (null === this._gradientUUID) { this._gradientUUID = this.uuid(); } // Bring it all together this.svg = { viewBox: `0 0 ${boxSize} ${boxSize}`, // Set both width and height to '100%' if it's responsive width: this.options.responsive ? '100%' : boxSize, height: this.options.responsive ? '100%' : boxSize, backgroundCircle: { cx: centre.x, cy: centre.y, r: this.options.radius + this.options.outerStrokeWidth / 2 + this.options.backgroundPadding, fill: this.options.backgroundColor, fillOpacity: this.options.backgroundOpacity, stroke: this.options.backgroundStroke, strokeWidth: this.options.backgroundStrokeWidth, }, path: { // A rx ry x-axis-rotation large-arc-flag sweep-flag x y (https://developer.mozilla.org/en/docs/Web/SVG/Tutorial/Paths#Arcs) d: `M ${startPoint.x} ${startPoint.y} A ${this.options.radius} ${this.options.radius} 0 ${largeArcFlag} ${sweepFlag} ${endPoint.x} ${endPoint.y}`, stroke: this.options.outerStrokeColor, strokeWidth: this.options.outerStrokeWidth, strokeLinecap: this.options.outerStrokeLinecap, fill: 'none' }, circle: { cx: centre.x, cy: centre.y, r: this.options.radius - this.options.space - this.options.outerStrokeWidth / 2 - this.options.innerStrokeWidth / 2, fill: 'none', stroke: this.options.innerStrokeColor, strokeWidth: this.options.innerStrokeWidth, }, title: title, units: units, subtitle: subtitle, image: { x: centre.x - this.options.imageWidth / 2, y: centre.y - this.options.imageHeight / 2, src: this.options.imageSrc, width: this.options.imageWidth, height: this.options.imageHeight, }, outerLinearGradient: { id: 'outer-linear-' + this._gradientUUID, colorStop1: this.options.outerStrokeColor, colorStop2: this.options.outerStrokeGradientStopColor === 'transparent' ? '#FFF' : this.options.outerStrokeGradientStopColor, }, radialGradient: { id: 'radial-' + this._gradientUUID, colorStop1: this.options.backgroundColor, colorStop2: this.options.backgroundGradientStopColor === 'transparent' ? '#FFF' : this.options.backgroundGradientStopColor, } }; }; this.getAnimationParameters = (previousPercent, currentPercent) => { const MIN_INTERVAL = 10; let times, step, interval; let fromPercent = this.options.startFromZero ? 0 : (previousPercent < 0 ? 0 : previousPercent); let toPercent = currentPercent < 0 ? 0 : this.min(currentPercent, this.options.maxPercent); let delta = Math.abs(Math.round(toPercent - fromPercent)); if (delta >= 100) { // we will finish animation in 100 times times = 100; if (!this.options.animateTitle && !this.options.animateSubtitle) { step = 1; } else { // show title or subtitle animation even if the arc is full, we also need to finish it in 100 times. step = Math.round(delta / times); } } else { // we will finish in as many times as the number of percent. times = delta; step = 1; } // Get the interval of timer interval = Math.round(this.options.animationDuration / times); // Readjust all values if the interval of timer is extremely small. if (interval < MIN_INTERVAL) { interval = MIN_INTERVAL; times = this.options.animationDuration / interval; if (!this.options.animateTitle && !this.options.animateSubtitle && delta > 100) { step = Math.round(100 / times); } else { step = Math.round(delta / times); } } // step must be greater than 0. if (step < 1) { step = 1; } return { times: times, step: step, interval: interval }; }; this.animate = (previousPercent, currentPercent) => { if (this._timerSubscription && !this._timerSubscription.closed) { this._timerSubscription.unsubscribe(); } let fromPercent = this.options.startFromZero ? 0 : previousPercent; let toPercent = currentPercent; let { step: step, interval: interval } = this.getAnimationParameters(fromPercent, toPercent); let count = fromPercent; if (fromPercent < toPercent) { this._timerSubscription = timer(0, interval).subscribe(() => { count += step; if (count <= toPercent) { if (!this.options.animateTitle && !this.options.animateSubtitle && count >= 100) { this.draw(toPercent); this._timerSubscription.unsubscribe(); } else { this.draw(count); } } else { this.draw(toPercent); this._timerSubscription.unsubscribe(); } }); } else { this._timerSubscription = timer(0, interval).subscribe(() => { count -= step; if (count >= toPercent) { if (!this.options.animateTitle && !this.options.animateSubtitle && toPercent >= 100) { this.draw(toPercent); this._timerSubscription.unsubscribe(); } else { this.draw(count); } } else { this.draw(toPercent); this._timerSubscription.unsubscribe(); } }); } }; this.applyOptions = () => { // the options of <circle-progress> may change already for (let name of Object.keys(this.options)) { if (this.hasOwnProperty(name) && this[name] !== undefined) { this.options[name] = this[name]; } else if (this.templateOptions && this.templateOptions[name] !== undefined) { this.options[name] = this.templateOptions[name]; } } // make sure key options valid this.options.radius = Math.abs(+this.options.radius); this.options.space = +this.options.space; this.options.percent = +this.options.percent > 0 ? +this.options.percent : 0; this.options.maxPercent = Math.abs(+this.options.maxPercent); this.options.animationDuration = Math.abs(this.options.animationDuration); this.options.outerStrokeWidth = Math.abs(+this.options.outerStrokeWidth); this.options.innerStrokeWidth = Math.abs(+this.options.innerStrokeWidth); this.options.backgroundPadding = +this.options.backgroundPadding; }; this.getRelativeY = (rowNum, rowCount) => { // why '-0.18em'? It's a magic number when property 'alignment-baseline' equals 'baseline'. :) let initialOffset = -0.18, offset = 1; return (initialOffset + offset * (rowNum - rowCount / 2)).toFixed(2) + 'em'; }; this.min = (a, b) => { return a < b ? a : b; }; this.max = (a, b) => { return a > b ? a : b; }; this.uuid = () => { // https://www.w3resource.com/javascript-exercises/javascript-math-exercise-23.php var dt = new Date().getTime(); var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = (dt + Math.random() * 16) % 16 | 0; dt = Math.floor(dt / 16); return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16); }); return uuid; }; this.checkViewport = () => { this.findSvgElement(); let previousValue = this.isInViewport; this.isInViewport = this.isElementInViewport(this.svgElement); if (previousValue !== this.isInViewport && this.onViewportChanged.observers.length > 0) { this.ngZone.run(() => { this.onViewportChanged.emit({ oldValue: previousValue, newValue: this.isInViewport }); }); } }; this.onScroll = (event) => { this.checkViewport(); }; this.loadEventsForLazyMode = () => { if (this.options.lazy) { this.ngZone.runOutsideAngular(() => { this.document.addEventListener('scroll', this.onScroll, true); this.window.addEventListener('resize', this.onScroll, true); }); if (this._viewportChangedSubscriber === null) { this._viewportChangedSubscriber = this.onViewportChanged.subscribe(({ oldValue, newValue }) => { newValue ? this.render() : null; }); } // svgElement must be created in DOM before being checked. // Is there a better way to check the existence of svgElemnt? let _timer = timer(0, 50).subscribe(() => { this.svgElement === null ? this.checkViewport() : _timer.unsubscribe(); }); } }; this.unloadEventsForLazyMode = () => { // Remove event listeners this.document.removeEventListener('scroll', this.onScroll, true); this.window.removeEventListener('resize', this.onScroll, true); // Unsubscribe onViewportChanged if (this._viewportChangedSubscriber !== null) { this._viewportChangedSubscriber.unsubscribe(); this._viewportChangedSubscriber = null; } }; this.document = injector.get(DOCUMENT); this.window = this.document.defaultView; Object.assign(this.options, defaultOptions); Object.assign(this.defaultOptions, defaultOptions); } emitClickEvent(event) { if (this.options.renderOnClick) { this.animate(0, this.options.percent); } if (this.onClick.observers.length > 0) { this.onClick.emit(event); } } isDrawing() { return (this._timerSubscription && !this._timerSubscription.closed); } findSvgElement() { if (this.svgElement === null) { let tags = this.elRef.nativeElement.getElementsByTagName('svg'); if (tags.length > 0) { this.svgElement = tags[0]; } } } isElementInViewport(el) { // Return false if el has not been created in page. if (el === null || el === undefined) return false; // Check if the element is out of view due to a container scrolling let rect = el.getBoundingClientRect(), parent = el.parentNode, parentRect; do { parentRect = parent.getBoundingClientRect(); if (rect.top >= parentRect.bottom) return false; if (rect.bottom <= parentRect.top) return false; if (rect.left >= parentRect.right) return false; if (rect.right <= parentRect.left) return false; parent = parent.parentNode; } while (parent != this.document.body); // Check its within the document viewport if (rect.top >= (this.window.innerHeight || this.document.documentElement.clientHeight)) return false; if (rect.bottom <= 0) return false; if (rect.left >= (this.window.innerWidth || this.document.documentElement.clientWidth)) return false; if (rect.right <= 0) return false; return true; } ngOnInit() { this.loadEventsForLazyMode(); } ngOnDestroy() { this.unloadEventsForLazyMode(); } ngOnChanges(changes) { this.render(); if ('lazy' in changes) { changes.lazy.currentValue ? this.loadEventsForLazyMode() : this.unloadEventsForLazyMode(); } } } CircleProgressComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CircleProgressComponent, deps: [{ token: CircleProgressOptions }, { token: i0.NgZone }, { token: i0.ElementRef }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component }); CircleProgressComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CircleProgressComponent, selector: "circle-progress", inputs: { name: "name", class: "class", backgroundGradient: "backgroundGradient", backgroundColor: "backgroundColor", backgroundGradientStopColor: "backgroundGradientStopColor", backgroundOpacity: "backgroundOpacity", backgroundStroke: "backgroundStroke", backgroundStrokeWidth: "backgroundStrokeWidth", backgroundPadding: "backgroundPadding", radius: "radius", space: "space", percent: "percent", toFixed: "toFixed", maxPercent: "maxPercent", renderOnClick: "renderOnClick", units: "units", unitsFontSize: "unitsFontSize", unitsFontWeight: "unitsFontWeight", unitsColor: "unitsColor", outerStrokeGradient: "outerStrokeGradient", outerStrokeWidth: "outerStrokeWidth", outerStrokeColor: "outerStrokeColor", outerStrokeGradientStopColor: "outerStrokeGradientStopColor", outerStrokeLinecap: "outerStrokeLinecap", innerStrokeColor: "innerStrokeColor", innerStrokeWidth: "innerStrokeWidth", titleFormat: "titleFormat", title: "title", titleColor: "titleColor", titleFontSize: "titleFontSize", titleFontWeight: "titleFontWeight", subtitleFormat: "subtitleFormat", subtitle: "subtitle", subtitleColor: "subtitleColor", subtitleFontSize: "subtitleFontSize", subtitleFontWeight: "subtitleFontWeight", imageSrc: "imageSrc", imageHeight: "imageHeight", imageWidth: "imageWidth", animation: "animation", animateTitle: "animateTitle", animateSubtitle: "animateSubtitle", animationDuration: "animationDuration", showTitle: "showTitle", showSubtitle: "showSubtitle", showUnits: "showUnits", showImage: "showImage", showBackground: "showBackground", showInnerStroke: "showInnerStroke", clockwise: "clockwise", responsive: "responsive", startFromZero: "startFromZero", showZeroOuterStroke: "showZeroOuterStroke", lazy: "lazy", templateOptions: ["options", "templateOptions"] }, outputs: { onClick: "onClick" }, usesOnChanges: true, ngImport: i0, template: ` <svg xmlns="http://www.w3.org/2000/svg" *ngIf="svg" [attr.viewBox]="svg.viewBox" preserveAspectRatio="xMidYMid meet" [attr.height]="svg.height" [attr.width]="svg.width" (click)="emitClickEvent($event)" [attr.class]="options.class"> <defs> <linearGradient *ngIf="options.outerStrokeGradient" [attr.id]="svg.outerLinearGradient.id"> <stop offset="5%" [attr.stop-color]="svg.outerLinearGradient.colorStop1" [attr.stop-opacity]="1"/> <stop offset="95%" [attr.stop-color]="svg.outerLinearGradient.colorStop2" [attr.stop-opacity]="1"/> </linearGradient> <radialGradient *ngIf="options.backgroundGradient" [attr.id]="svg.radialGradient.id"> <stop offset="5%" [attr.stop-color]="svg.radialGradient.colorStop1" [attr.stop-opacity]="1"/> <stop offset="95%" [attr.stop-color]="svg.radialGradient.colorStop2" [attr.stop-opacity]="1"/> </radialGradient> </defs> <ng-container *ngIf="options.showBackground"> <circle *ngIf="!options.backgroundGradient" [attr.cx]="svg.backgroundCircle.cx" [attr.cy]="svg.backgroundCircle.cy" [attr.r]="svg.backgroundCircle.r" [attr.fill]="svg.backgroundCircle.fill" [attr.fill-opacity]="svg.backgroundCircle.fillOpacity" [attr.stroke]="svg.backgroundCircle.stroke" [attr.stroke-width]="svg.backgroundCircle.strokeWidth"/> <circle *ngIf="options.backgroundGradient" [attr.cx]="svg.backgroundCircle.cx" [attr.cy]="svg.backgroundCircle.cy" [attr.r]="svg.backgroundCircle.r" attr.fill="url({{window.location.href}}#{{svg.radialGradient.id}})" [attr.fill-opacity]="svg.backgroundCircle.fillOpacity" [attr.stroke]="svg.backgroundCircle.stroke" [attr.stroke-width]="svg.backgroundCircle.strokeWidth"/> </ng-container> <circle *ngIf="options.showInnerStroke" [attr.cx]="svg.circle.cx" [attr.cy]="svg.circle.cy" [attr.r]="svg.circle.r" [attr.fill]="svg.circle.fill" [attr.stroke]="svg.circle.stroke" [attr.stroke-width]="svg.circle.strokeWidth"/> <ng-container *ngIf="+options.percent!==0 || options.showZeroOuterStroke"> <path *ngIf="!options.outerStrokeGradient" [attr.d]="svg.path.d" [attr.stroke]="svg.path.stroke" [attr.stroke-width]="svg.path.strokeWidth" [attr.stroke-linecap]="svg.path.strokeLinecap" [attr.fill]="svg.path.fill"/> <path *ngIf="options.outerStrokeGradient" [attr.d]="svg.path.d" attr.stroke="url({{window.location.href}}#{{svg.outerLinearGradient.id}})" [attr.stroke-width]="svg.path.strokeWidth" [attr.stroke-linecap]="svg.path.strokeLinecap" [attr.fill]="svg.path.fill"/> </ng-container> <text *ngIf="!options.showImage && (options.showTitle || options.showUnits || options.showSubtitle)" alignment-baseline="baseline" [attr.x]="svg.circle.cx" [attr.y]="svg.circle.cy" [attr.text-anchor]="svg.title.textAnchor"> <ng-container *ngIf="options.showTitle"> <tspan *ngFor="let tspan of svg.title.tspans" [attr.x]="svg.title.x" [attr.y]="svg.title.y" [attr.dy]="tspan.dy" [attr.font-size]="svg.title.fontSize" [attr.font-weight]="svg.title.fontWeight" [attr.fill]="svg.title.color">{{tspan.span}}</tspan> </ng-container> <tspan *ngIf="options.showUnits" [attr.font-size]="svg.units.fontSize" [attr.font-weight]="svg.units.fontWeight" [attr.fill]="svg.units.color">{{svg.units.text}}</tspan> <ng-container *ngIf="options.showSubtitle"> <tspan *ngFor="let tspan of svg.subtitle.tspans" [attr.x]="svg.subtitle.x" [attr.y]="svg.subtitle.y" [attr.dy]="tspan.dy" [attr.font-size]="svg.subtitle.fontSize" [attr.font-weight]="svg.subtitle.fontWeight" [attr.fill]="svg.subtitle.color">{{tspan.span}}</tspan> </ng-container> </text> <image *ngIf="options.showImage" preserveAspectRatio="none" [attr.height]="svg.image.height" [attr.width]="svg.image.width" [attr.xlink:href]="svg.image.src" [attr.x]="svg.image.x" [attr.y]="svg.image.y" /> </svg> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CircleProgressComponent, decorators: [{ type: Component, args: [{ selector: 'circle-progress', template: ` <svg xmlns="http://www.w3.org/2000/svg" *ngIf="svg" [attr.viewBox]="svg.viewBox" preserveAspectRatio="xMidYMid meet" [attr.height]="svg.height" [attr.width]="svg.width" (click)="emitClickEvent($event)" [attr.class]="options.class"> <defs> <linearGradient *ngIf="options.outerStrokeGradient" [attr.id]="svg.outerLinearGradient.id"> <stop offset="5%" [attr.stop-color]="svg.outerLinearGradient.colorStop1" [attr.stop-opacity]="1"/> <stop offset="95%" [attr.stop-color]="svg.outerLinearGradient.colorStop2" [attr.stop-opacity]="1"/> </linearGradient> <radialGradient *ngIf="options.backgroundGradient" [attr.id]="svg.radialGradient.id"> <stop offset="5%" [attr.stop-color]="svg.radialGradient.colorStop1" [attr.stop-opacity]="1"/> <stop offset="95%" [attr.stop-color]="svg.radialGradient.colorStop2" [attr.stop-opacity]="1"/> </radialGradient> </defs> <ng-container *ngIf="options.showBackground"> <circle *ngIf="!options.backgroundGradient" [attr.cx]="svg.backgroundCircle.cx" [attr.cy]="svg.backgroundCircle.cy" [attr.r]="svg.backgroundCircle.r" [attr.fill]="svg.backgroundCircle.fill" [attr.fill-opacity]="svg.backgroundCircle.fillOpacity" [attr.stroke]="svg.backgroundCircle.stroke" [attr.stroke-width]="svg.backgroundCircle.strokeWidth"/> <circle *ngIf="options.backgroundGradient" [attr.cx]="svg.backgroundCircle.cx" [attr.cy]="svg.backgroundCircle.cy" [attr.r]="svg.backgroundCircle.r" attr.fill="url({{window.location.href}}#{{svg.radialGradient.id}})" [attr.fill-opacity]="svg.backgroundCircle.fillOpacity" [attr.stroke]="svg.backgroundCircle.stroke" [attr.stroke-width]="svg.backgroundCircle.strokeWidth"/> </ng-container> <circle *ngIf="options.showInnerStroke" [attr.cx]="svg.circle.cx" [attr.cy]="svg.circle.cy" [attr.r]="svg.circle.r" [attr.fill]="svg.circle.fill" [attr.stroke]="svg.circle.stroke" [attr.stroke-width]="svg.circle.strokeWidth"/> <ng-container *ngIf="+options.percent!==0 || options.showZeroOuterStroke"> <path *ngIf="!options.outerStrokeGradient" [attr.d]="svg.path.d" [attr.stroke]="svg.path.stroke" [attr.stroke-width]="svg.path.strokeWidth" [attr.stroke-linecap]="svg.path.strokeLinecap" [attr.fill]="svg.path.fill"/> <path *ngIf="options.outerStrokeGradient" [attr.d]="svg.path.d" attr.stroke="url({{window.location.href}}#{{svg.outerLinearGradient.id}})" [attr.stroke-width]="svg.path.strokeWidth" [attr.stroke-linecap]="svg.path.strokeLinecap" [attr.fill]="svg.path.fill"/> </ng-container> <text *ngIf="!options.showImage && (options.showTitle || options.showUnits || options.showSubtitle)" alignment-baseline="baseline" [attr.x]="svg.circle.cx" [attr.y]="svg.circle.cy" [attr.text-anchor]="svg.title.textAnchor"> <ng-container *ngIf="options.showTitle"> <tspan *ngFor="let tspan of svg.title.tspans" [attr.x]="svg.title.x" [attr.y]="svg.title.y" [attr.dy]="tspan.dy" [attr.font-size]="svg.title.fontSize" [attr.font-weight]="svg.title.fontWeight" [attr.fill]="svg.title.color">{{tspan.span}}</tspan> </ng-container> <tspan *ngIf="options.showUnits" [attr.font-size]="svg.units.fontSize" [attr.font-weight]="svg.units.fontWeight" [attr.fill]="svg.units.color">{{svg.units.text}}</tspan> <ng-container *ngIf="options.showSubtitle"> <tspan *ngFor="let tspan of svg.subtitle.tspans" [attr.x]="svg.subtitle.x" [attr.y]="svg.subtitle.y" [attr.dy]="tspan.dy" [attr.font-size]="svg.subtitle.fontSize" [attr.font-weight]="svg.subtitle.fontWeight" [attr.fill]="svg.subtitle.color">{{tspan.span}}</tspan> </ng-container> </text> <image *ngIf="options.showImage" preserveAspectRatio="none" [attr.height]="svg.image.height" [attr.width]="svg.image.width" [attr.xlink:href]="svg.image.src" [attr.x]="svg.image.x" [attr.y]="svg.image.y" /> </svg> ` }] }], ctorParameters: function () { return [{ type: CircleProgressOptions }, { type: i0.NgZone }, { type: i0.ElementRef }, { type: i0.Injector }]; }, propDecorators: { onClick: [{ type: Output }], name: [{ type: Input }], class: [{ type: Input }], backgroundGradient: [{ type: Input }], backgroundColor: [{ type: Input }], backgroundGradientStopColor: [{ type: Input }], backgroundOpacity: [{ type: Input }], backgroundStroke: [{ type: Input }], backgroundStrokeWidth: [{ type: Input }], backgroundPadding: [{ type: Input }], radius: [{ type: Input }], space: [{ type: Input }], percent: [{ type: Input }], toFixed: [{ type: Input }], maxPercent: [{ type: Input }], renderOnClick: [{ type: Input }], units: [{ type: Input }], unitsFontSize: [{ type: Input }], unitsFontWeight: [{ type: Input }], unitsColor: [{ type: Input }], outerStrokeGradient: [{ type: Input }], outerStrokeWidth: [{ type: Input }], outerStrokeColor: [{ type: Input }], outerStrokeGradientStopColor: [{ type: Input }], outerStrokeLinecap: [{ type: Input }], innerStrokeColor: [{ type: Input }], innerStrokeWidth: [{ type: Input }], titleFormat: [{ type: Input }], title: [{ type: Input }], titleColor: [{ type: Input }], titleFontSize: [{ type: Input }], titleFontWeight: [{ type: Input }], subtitleFormat: [{ type: Input }], subtitle: [{ type: Input }], subtitleColor: [{ type: Input }], subtitleFontSize: [{ type: Input }], subtitleFontWeight: [{ type: Input }], imageSrc: [{ type: Input }], imageHeight: [{ type: Input }], imageWidth: [{ type: Input }], animation: [{ type: Input }], animateTitle: [{ type: Input }], animateSubtitle: [{ type: Input }], animationDuration: [{ type: Input }], showTitle: [{ type: Input }], showSubtitle: [{ type: Input }], showUnits: [{ type: Input }], showImage: [{ type: Input }], showBackground: [{ type: Input }], showInnerStroke: [{ type: Input }], clockwise: [{ type: Input }], responsive: [{ type: Input }], startFromZero: [{ type: Input }], showZeroOuterStroke: [{ type: Input }], lazy: [{ type: Input }], templateOptions: [{ type: Input, args: ['options'] }] } }); class NgCircleProgressModule { static forRoot(options = {}) { return { ngModule: NgCircleProgressModule, providers: [ { provide: CircleProgressOptions, useValue: options } ] }; } } NgCircleProgressModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: NgCircleProgressModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NgCircleProgressModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: NgCircleProgressModule, declarations: [CircleProgressComponent], imports: [CommonModule], exports: [CircleProgressComponent] }); NgCircleProgressModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: NgCircleProgressModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: NgCircleProgressModule, decorators: [{ type: NgModule, args: [{ declarations: [CircleProgressComponent], imports: [ CommonModule ], exports: [CircleProgressComponent] }] }] }); /* * Public API Surface of ng-circle-progress */ /** * Generated bundle index. Do not edit. */ export { CircleProgressComponent, CircleProgressOptions, NgCircleProgressModule }; //# sourceMappingURL=ng-circle-progress.mjs.map