@swimlane/ngx-charts
Version:
Declarative Charting Framework for Angular2 and beyond!
241 lines (198 loc) • 6.21 kB
text/typescript
import {
Component,
Input,
ElementRef,
ViewChild,
AfterViewInit,
ChangeDetectionStrategy
} from '@angular/core';
import d3 from '../d3';
import { BaseChartComponent } from '../common/base-chart.component';
import { calculateViewDimensions, ViewDimensions } from '../common/view-dimensions.helper';
import { ColorHelper } from '../common/color.helper';
export class GaugeComponent extends BaseChartComponent implements AfterViewInit {
min: number = 0;
max: number = 100;
units: string;
bigSegments: number = 10;
smallSegments: number = 5;
results: any[];
showAxis: boolean = true;
startAngle: number = -120;
angleSpan: number = 240;
schemeType: string = 'ordinal';
textEl: ElementRef;
dims: ViewDimensions;
domain: any[];
valueDomain: any;
valueScale: any;
colors: ColorHelper;
transform: string;
margin: any[];
outerRadius: number;
textRadius: number; // max available radius for the text
resizeScale: number = 1;
rotation: string = '';
textTransform: string = '';
cornerRadius: number = 10;
arcs: any[];
displayValue: string;
ngAfterViewInit(): void {
super.ngAfterViewInit();
setTimeout(() => this.scaleText());
}
update(): void {
super.update();
this.zone.run(() => {
if (!this.showAxis) {
this.margin = [10, 20, 10, 20];
} else {
this.margin = [60, 100, 60, 100];
}
// make the starting angle positive
if (this.startAngle < 0) {
this.startAngle = (this.startAngle % 360) + 360;
}
this.dims = calculateViewDimensions({
width: this.width,
height: this.height,
margins: this.margin
});
this.domain = this.getDomain();
this.valueDomain = this.getValueDomain();
this.valueScale = this.getValueScale();
this.displayValue = this.getDisplayValue();
this.outerRadius = Math.min(this.dims.width, this.dims.height) / 2;
this.arcs = this.getArcs();
this.setColors();
let xOffset = this.margin[3] + this.dims.width / 2;
let yOffset = this.margin[0] + this.dims.height / 2;
this.transform = `translate(${ xOffset }, ${ yOffset })`;
this.rotation = `rotate(${ this.startAngle })`;
this.scaleText();
});
}
getArcs(): any[] {
let arcs = [];
let availableRadius = this.outerRadius * 0.7;
let radiusPerArc = Math.min(availableRadius / this.results.length, 10);
let arcWidth = radiusPerArc * 0.7;
this.textRadius = this.outerRadius - this.results.length * radiusPerArc;
this.cornerRadius = Math.floor(arcWidth / 2);
let i = 0;
for (let d of this.results) {
let outerRadius = this.outerRadius - (i * radiusPerArc);
let innerRadius = outerRadius - arcWidth;
let backgroundArc = {
endAngle: this.angleSpan * Math.PI / 180,
innerRadius,
outerRadius,
data: {
value: this.max,
name: d.name
}
};
let valueArc = {
endAngle: Math.min(this.valueScale(d.value), this.angleSpan) * Math.PI / 180,
innerRadius,
outerRadius,
data: {
value: d.value,
name: d.name
}
};
let arc = {
backgroundArc,
valueArc
};
arcs.push(arc);
i++;
}
return arcs;
}
getDomain(): any[] {
return this.results.map(d => d.name);
}
getValueDomain(): any[] {
let values = this.results.map(d => d.value);
let dataMin = Math.min(...values);
let dataMax = Math.max(...values);
if (this.min !== undefined) {
this.min = Math.min(this.min, dataMin);
} else {
this.min = dataMin;
}
if (this.max !== undefined) {
this.max = Math.max(this.max, dataMax);
} else {
this.max = dataMax;
}
return [this.min, this.max];
}
getValueScale(): any {
return d3.scaleLinear()
.range([0, this.angleSpan])
.domain(this.valueDomain);
}
getDisplayValue(): string {
let value = this.results.map(d => d.value).reduce((a, b) => { return a + b; }, 0);
return value.toLocaleString();
}
scaleText(): void {
const { width } = this.textEl.nativeElement.getBoundingClientRect();
if (width === 0) return;
const oldScale = this.resizeScale;
const availableSpace = this.textRadius;
this.resizeScale = Math.floor((availableSpace / (width / this.resizeScale)) * 100) / 100;
if (this.resizeScale !== oldScale) {
this.textTransform = `scale(${this.resizeScale}, ${this.resizeScale})`;
this.cd.markForCheck();
setTimeout(() => { this.scaleText(); });
}
}
onClick(data): void {
this.select.emit(data);
}
setColors(): void {
this.colors = new ColorHelper(this.scheme, 'ordinal', this.domain, this.customColors);
}
}