ghostfolio/apps/client/src/app/components/investment-chart/investment-chart.component.ts

163 lines
3.8 KiB
TypeScript
Raw Normal View History

2021-04-13 21:53:58 +02:00
import 'chartjs-adapter-date-fns';
import {
ChangeDetectionStrategy,
Component,
Input,
OnChanges,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
import { primaryColorRgb } from '@ghostfolio/common/config';
2021-08-01 09:41:44 +02:00
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
2021-04-13 21:53:58 +02:00
import {
Chart,
2021-04-13 21:53:58 +02:00
LineController,
LineElement,
2021-08-01 09:41:44 +02:00
LinearScale,
2021-04-13 21:53:58 +02:00
PointElement,
TimeScale
} from 'chart.js';
import { addMonths, isAfter, parseISO, subMonths } from 'date-fns';
2021-04-13 21:53:58 +02:00
@Component({
selector: 'gf-investment-chart',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './investment-chart.component.html',
styleUrls: ['./investment-chart.component.scss']
})
export class InvestmentChartComponent implements OnChanges, OnDestroy, OnInit {
@Input() investments: InvestmentItem[];
2021-04-13 21:53:58 +02:00
@ViewChild('chartCanvas') chartCanvas;
public chart: Chart;
public isLoading = true;
public constructor() {
Chart.register(
LinearScale,
2021-04-13 21:53:58 +02:00
LineController,
LineElement,
PointElement,
TimeScale
);
}
public ngOnInit() {}
public ngOnChanges() {
if (this.investments) {
2021-04-13 21:53:58 +02:00
this.initialize();
}
}
public ngOnDestroy() {
this.chart?.destroy();
}
2021-04-13 21:53:58 +02:00
private initialize() {
this.isLoading = true;
if (this.investments?.length > 0) {
// Extend chart by three months (before)
const firstItem = this.investments[0];
this.investments.unshift({
...firstItem,
date: subMonths(parseISO(firstItem.date), 3).toISOString(),
investment: 0
});
// Extend chart by three months (after)
const lastItem = this.investments[this.investments.length - 1];
this.investments.push({
...lastItem,
date: addMonths(new Date(), 3).toISOString()
});
}
2021-04-13 21:53:58 +02:00
const data = {
labels: this.investments.map((position) => {
2021-04-13 21:53:58 +02:00
return position.date;
}),
datasets: [
{
borderColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderWidth: 2,
data: this.investments.map((position) => {
2021-04-13 21:53:58 +02:00
return position.investment;
}),
segment: {
borderColor: (context: unknown) =>
this.isInFuture(
context,
`rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.67)`
),
borderDash: (context: unknown) => this.isInFuture(context, [2, 2])
},
stepped: true
2021-04-13 21:53:58 +02:00
}
]
};
if (this.chartCanvas) {
if (this.chart) {
this.chart.data = data;
this.chart.update();
} else {
this.chart = new Chart(this.chartCanvas.nativeElement, {
data,
options: {
elements: {
line: {
tension: 0
},
point: {
radius: 0
}
},
maintainAspectRatio: true,
plugins: {
legend: {
display: false
}
},
responsive: true,
scales: {
x: {
display: true,
2021-04-13 21:53:58 +02:00
grid: {
display: false
},
type: 'time',
time: {
unit: 'year'
}
},
y: {
display: false,
grid: {
display: false
},
ticks: {
display: false
}
}
}
},
type: 'line'
});
this.isLoading = false;
}
}
}
private isInFuture<T>(aContext: any, aValue: T) {
return isAfter(new Date(aContext?.p1?.parsed?.x), new Date())
? aValue
: undefined;
2021-04-13 21:53:58 +02:00
}
}