src/ngx-donutchart.component.ts
changeDetection | ChangeDetectionStrategy.OnPush |
selector | ngx-donutchart |
templateUrl | ./ngx-donutchart.component.html |
Properties |
|
Methods |
|
Inputs |
Outputs |
innerRadius
|
Default value: |
Defined in src/ngx-donutchart.component.ts:39
|
size
|
Default value: |
Defined in src/ngx-donutchart.component.ts:33
|
slices
|
Type:
Default value: |
Defined in src/ngx-donutchart.component.ts:51
|
title
|
Type: |
Defined in src/ngx-donutchart.component.ts:45
|
onSliceHover
|
$event type: EventEmitter<NgXDonutChartSlice>
|
Defined in src/ngx-donutchart.component.ts:57
|
Private _canRenderEmptySlice |
_canRenderEmptySlice()
|
Defined in src/ngx-donutchart.component.ts:180
|
Returns :
boolean
|
Private _getAbbreviatedNumber | ||||||||||||
_getAbbreviatedNumber(number: number, digits: )
|
||||||||||||
Defined in src/ngx-donutchart.component.ts:221
|
||||||||||||
Parameters :
Returns :
number
|
Private _getCalculatedAnchors | ||||||||||||||||||||
_getCalculatedAnchors(startAngle: number, endAngle: number, outerRadius: number, innerRadius: number)
|
||||||||||||||||||||
Defined in src/ngx-donutchart.component.ts:188
|
||||||||||||||||||||
Parameters :
Returns :
SliceAnchors
|
Private _getCompoundPathData | ||||||||
_getCompoundPathData(slice: NgXDonutChartSlice)
|
||||||||
Defined in src/ngx-donutchart.component.ts:159
|
||||||||
Parameters :
Returns :
string
|
Private _getEmptyPathData |
_getEmptyPathData()
|
Defined in src/ngx-donutchart.component.ts:145
|
Returns :
string
|
Private _getScaledData | ||||||||
_getScaledData(value: number)
|
||||||||
Defined in src/ngx-donutchart.component.ts:217
|
||||||||
Parameters :
Returns :
number
|
Public canRenderPath | ||||||||
canRenderPath(slice: NgXDonutChartSlice)
|
||||||||
Defined in src/ngx-donutchart.component.ts:134
|
||||||||
Parameters :
Returns :
boolean
|
Public getDataAutomationSelector |
getDataAutomationSelector(selector: string, index?: number)
|
Defined in src/ngx-donutchart.component.ts:113
|
Returns :
string
|
Public getPathData | ||||||||
getPathData(slice: NgXDonutChartSlice)
|
||||||||
Defined in src/ngx-donutchart.component.ts:141
|
||||||||
Parameters :
Returns :
string
|
Public getPathFill | ||||||||
getPathFill(slice: NgXDonutChartSlice)
|
||||||||
Defined in src/ngx-donutchart.component.ts:127
|
||||||||
Parameters :
Returns :
string
|
Public getPXSize |
getPXSize()
|
Defined in src/ngx-donutchart.component.ts:71
|
Returns :
string
|
Public getSize |
getSize()
|
Defined in src/ngx-donutchart.component.ts:78
|
Returns :
number
|
Public getTitle |
getTitle()
|
Defined in src/ngx-donutchart.component.ts:85
|
Returns :
string
|
Public getTotal |
getTotal()
|
Defined in src/ngx-donutchart.component.ts:120
|
Returns :
number
|
Public getViewBox |
getViewBox()
|
Defined in src/ngx-donutchart.component.ts:64
|
Returns :
string
|
Public handleMouseEnter | ||||||||
handleMouseEnter(slice: NgXDonutChartSlice)
|
||||||||
Defined in src/ngx-donutchart.component.ts:99
|
||||||||
Parameters :
Returns :
void
|
Public handleMouseLeave |
handleMouseLeave()
|
Defined in src/ngx-donutchart.component.ts:106
|
Returns :
void
|
Public trackByFn | ||||||||||||
trackByFn(index: number, item: NgXDonutChartSlice)
|
||||||||||||
Defined in src/ngx-donutchart.component.ts:92
|
||||||||||||
Parameters :
Returns :
number
|
Private _startAngle |
_startAngle:
|
Default value : 0
|
Defined in src/ngx-donutchart.component.ts:59
|
import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core';
import {NgXDonutChartSlice} from './ngx-donutchart.type';
type SliceAnchors = {
P: {
x: number
y: number
}
Q: {
x: number
y: number
}
R: {
x: number
y: number
}
S: {
x: number
y: number
}
};
@Component({
selector: 'ngx-donutchart',
templateUrl: './ngx-donutchart.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NgXDonutChartComponent {
/**
* @description Component size
*/
@Input()
public size = 0;
/**
* @description Inner circle size
*/
@Input()
public innerRadius = 0;
/**
* @description Title string
*/
@Input()
public title: string;
/**
* @description Slices to be rendered
*/
@Input()
public slices: NgXDonutChartSlice[] = [];
/**
* @description Output method with slice hovered
*/
@Output()
public onSliceHover: EventEmitter<NgXDonutChartSlice> = new EventEmitter<NgXDonutChartSlice>();
private _startAngle = 0;
/**
* @description Retrieve svg viewBox
*/
public getViewBox(): string {
return `0 0 ${this.getSize()} ${this.getSize()}`;
}
/**
* @description Retrieve svg size in pixels
*/
public getPXSize(): string {
return `${this.size.toString()}px`;
}
/**
* @description Retrieve component size
*/
public getSize(): number {
return this.size;
}
/**
* @description Retrieve title
*/
public getTitle(): string {
return this.title;
}
/**
* @description Track by function for path
*/
public trackByFn(index: number, item: NgXDonutChartSlice): number {
return index;
}
/**
* @description Triggered when mouse enters
*/
public handleMouseEnter(slice: NgXDonutChartSlice): void {
this.onSliceHover.emit(slice)
}
/**
* @description Triggered when mouse leaves
*/
public handleMouseLeave(): void {
this.onSliceHover.emit(null)
}
/**
* @description Retrieve data automation selector
*/
public getDataAutomationSelector(selector: string, index?: number): string {
return `${selector}${index || index === 0 ? '-' + index : ''}`;
}
/**
* @description Retrieve summed value slices
*/
public getTotal(): number {
return this.slices.reduce((a: number, b: NgXDonutChartSlice) => a + b.value, 0);
}
/**
* @description Retrieve fill of slice passed in
*/
public getPathFill(slice: NgXDonutChartSlice): string {
return slice.color;
}
/**
* @description Checks if a given path can be rendered
*/
public canRenderPath(slice: NgXDonutChartSlice): boolean {
return slice.value > 0 && this.getTotal() > 0;
}
/**
* @description Retrieve path data of empty slice or path data of slice passed in
*/
public getPathData(slice: NgXDonutChartSlice): string {
return this._canRenderEmptySlice() ? this._getEmptyPathData() : this._getCompoundPathData(slice);
}
private _getEmptyPathData(): string {
const outerRadius: number = this.getSize() / 2;
return `
M ${outerRadius} ${outerRadius}
m 0 -${outerRadius}
a ${outerRadius} ${outerRadius} 0 1 0 1 0
Z
m 0 ${outerRadius - this.innerRadius}
a ${this.innerRadius} ${this.innerRadius} 0 1 1 -1 0
Z
`;
}
private _getCompoundPathData(slice: NgXDonutChartSlice): string {
const outerRadius: number = this.getSize() / 2;
const sectorAngle: number = this._getScaledData(slice.value);
const calculatedAnchor: SliceAnchors = this._getCalculatedAnchors(this._startAngle, this._startAngle + sectorAngle, outerRadius, this.innerRadius);
const {P, Q, R, S} = calculatedAnchor;
this._startAngle += sectorAngle;
const endAngle: number = this._startAngle + sectorAngle;
const largeArc: boolean = endAngle - this._startAngle > Math.PI;
return `
M ${P.x}, ${P.y}
A ${outerRadius} ${outerRadius} 0 ${largeArc ? '1,1' : '0,1'} ${Q.x} ${Q.y}
L ${R.x} ${R.y}
A ${this.innerRadius} ${this.innerRadius} 0 ${largeArc ? '1,0' : '0,0'} ${S.x} ${S.y}
Z
`;
}
private _canRenderEmptySlice(): boolean {
let slicesWithValue = 0;
this.slices.map((slice: NgXDonutChartSlice) => slice.value > 0 ? slicesWithValue++ : null);
return slicesWithValue === 1;
}
private _getCalculatedAnchors(startAngle: number, endAngle: number, outerRadius: number, innerRadius: number): SliceAnchors {
const sinAlpha: number = this._getAbbreviatedNumber(Math.sin(startAngle));
const cosAlpha: number = this._getAbbreviatedNumber(Math.cos(startAngle));
const sinBeta: number = this._getAbbreviatedNumber(Math.sin(endAngle));
const cosBeta: number = this._getAbbreviatedNumber(Math.cos(endAngle));
const P = {
x: outerRadius + (outerRadius * sinAlpha),
y: outerRadius - (outerRadius * cosAlpha)
};
const Q = {
x: outerRadius + (outerRadius * sinBeta),
y: outerRadius - (outerRadius * cosBeta)
};
const R = {
x: outerRadius + (innerRadius * sinBeta),
y: outerRadius - (innerRadius * cosBeta)
};
const S = {
x: outerRadius + (innerRadius * sinAlpha),
y: outerRadius - (innerRadius * cosAlpha)
};
return {P, Q, R, S};
}
private _getScaledData(value: number): number {
return (value * Math.PI * 2) / this.getTotal() || 0;
}
private _getAbbreviatedNumber(number: number, digits = 12): number {
return parseFloat(Number(number).toFixed(digits));
}
}
<svg #donutChart
[attr.data-automation]="getDataAutomationSelector('donut-chart')"
[attr.viewBox]="getViewBox()"
[attr.width]="getPXSize()"
[attr.height]="getPXSize()">
<text *ngIf="getTitle()"
x="50%"
y="50%"
text-anchor="middle">{{getTitle()}}</text>
<ng-container *ngFor="let slice of slices; trackBy: trackByFn; let i = index;">
<path *ngIf="canRenderPath(slice)"
[attr.data-automation]="getDataAutomationSelector('donut-chart-path', i)"
[attr.d]="getPathData(slice)"
[attr.fill]="getPathFill(slice)"
(mouseenter)="handleMouseEnter(slice)"
(mouseleave)="handleMouseLeave()">
</path>
</ng-container>
</svg>