You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

217 lines
5.4 KiB

import 'chartjs-adapter-date-fns';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Input,
OnChanges,
OnDestroy,
ViewChild
} from '@angular/core';
import {
Chart,
Filler,
LineController,
LineElement,
LinearScale,
PointElement,
TimeScale
} from 'chart.js';
import {
primaryColorRgb,
secondaryColorRgb
} from '../../../../common/src/lib/config'; // TODO: @ghostfolio/common/config
import { getBackgroundColor } from '../../../../common/src/lib/helper'; // TODO: @ghostfolio/common/helper
import { LineChartItem } from './interfaces/line-chart.interface';
@Component({
selector: 'gf-line-chart',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './line-chart.component.html',
styleUrls: ['./line-chart.component.scss']
})
export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
@Input() benchmarkDataItems: LineChartItem[] = [];
@Input() benchmarkLabel = '';
@Input() historicalDataItems: LineChartItem[];
@Input() showGradient = false;
@Input() showLegend = false;
@Input() showLoader = true;
@Input() showXAxis = false;
@Input() showYAxis = false;
@Input() symbol: string;
@Input() yMax: number;
@Input() yMaxLabel: string;
@Input() yMin: number;
@Input() yMinLabel: string;
@ViewChild('chartCanvas') chartCanvas;
public chart: Chart;
public isLoading = true;
public constructor(private changeDetectorRef: ChangeDetectorRef) {
Chart.register(
Filler,
LineController,
LineElement,
PointElement,
LinearScale,
TimeScale
);
}
public ngAfterViewInit() {
if (this.historicalDataItems) {
setTimeout(() => {
// Wait for the chartCanvas
this.initialize();
this.changeDetectorRef.markForCheck();
});
}
}
public ngOnChanges() {
if (this.historicalDataItems) {
setTimeout(() => {
// Wait for the chartCanvas
this.initialize();
this.changeDetectorRef.markForCheck();
});
}
}
public ngOnDestroy() {
this.chart?.destroy();
}
private initialize() {
this.isLoading = true;
const benchmarkPrices = [];
const labels = [];
const marketPrices = [];
this.historicalDataItems?.forEach((historicalDataItem, index) => {
benchmarkPrices.push(this.benchmarkDataItems?.[index]?.value);
labels.push(historicalDataItem.date);
marketPrices.push(historicalDataItem.value);
});
const gradient = this.chartCanvas?.nativeElement
?.getContext('2d')
.createLinearGradient(
0,
0,
0,
(this.chartCanvas.nativeElement.parentNode.offsetHeight * 4) / 5
);
if (gradient && this.showGradient) {
gradient.addColorStop(
0,
`rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.01)`
);
gradient.addColorStop(1, getBackgroundColor());
}
const data = {
labels,
datasets: [
{
borderColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
borderWidth: 1,
data: benchmarkPrices,
fill: false,
label: this.benchmarkLabel,
pointRadius: 0
},
{
backgroundColor: gradient,
borderColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderWidth: 2,
data: marketPrices,
fill: true,
label: this.symbol,
pointRadius: 0
}
]
};
if (this.chartCanvas) {
if (this.chart) {
this.chart.data = data;
this.chart.update();
} else {
this.chart = new Chart(this.chartCanvas.nativeElement, {
data,
options: {
animation: false,
plugins: {
legend: {
align: 'start',
display: this.showLegend,
position: 'bottom'
}
},
scales: {
x: {
display: this.showXAxis,
grid: {
display: false
},
time: {
unit: 'year'
},
type: 'time'
},
y: {
display: this.showYAxis,
grid: {
display: false
},
max: this.yMax,
min: this.yMin,
ticks: {
display: this.showYAxis,
callback: (tickValue, index, ticks) => {
if (index === 0 || index === ticks.length - 1) {
// Only print last and first legend entry
if (index === 0 && this.yMinLabel) {
return this.yMinLabel;
}
if (index === ticks.length - 1 && this.yMaxLabel) {
return this.yMaxLabel;
}
if (typeof tickValue === 'number') {
return tickValue.toFixed(2);
}
return tickValue;
}
return '';
},
mirror: true,
z: 1
},
type: 'linear'
}
},
spanGaps: true
},
type: 'line'
});
}
}
this.isLoading = false;
}
}