|
|
@ -1,6 +1,5 @@ |
|
|
import { |
|
|
import { |
|
|
getTooltipOptions, |
|
|
getTooltipOptions, |
|
|
getTooltipPositionerMapTop, |
|
|
|
|
|
getVerticalHoverLinePlugin |
|
|
getVerticalHoverLinePlugin |
|
|
} from '@ghostfolio/common/chart-helper'; |
|
|
} from '@ghostfolio/common/chart-helper'; |
|
|
import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; |
|
|
import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; |
|
|
@ -19,12 +18,14 @@ import { |
|
|
ChangeDetectionStrategy, |
|
|
ChangeDetectionStrategy, |
|
|
ChangeDetectorRef, |
|
|
ChangeDetectorRef, |
|
|
Component, |
|
|
Component, |
|
|
|
|
|
type ElementRef, |
|
|
Input, |
|
|
Input, |
|
|
OnChanges, |
|
|
OnChanges, |
|
|
OnDestroy, |
|
|
OnDestroy, |
|
|
ViewChild |
|
|
ViewChild |
|
|
} from '@angular/core'; |
|
|
} from '@angular/core'; |
|
|
import { |
|
|
import { |
|
|
|
|
|
type AnimationsSpec, |
|
|
Chart, |
|
|
Chart, |
|
|
Filler, |
|
|
Filler, |
|
|
LinearScale, |
|
|
LinearScale, |
|
|
@ -33,11 +34,13 @@ import { |
|
|
PointElement, |
|
|
PointElement, |
|
|
TimeScale, |
|
|
TimeScale, |
|
|
Tooltip, |
|
|
Tooltip, |
|
|
TooltipPosition |
|
|
type TooltipOptions |
|
|
} from 'chart.js'; |
|
|
} from 'chart.js'; |
|
|
import 'chartjs-adapter-date-fns'; |
|
|
import 'chartjs-adapter-date-fns'; |
|
|
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; |
|
|
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; |
|
|
|
|
|
|
|
|
|
|
|
import { registerChartConfiguration } from '../chart'; |
|
|
|
|
|
|
|
|
@Component({ |
|
|
@Component({ |
|
|
changeDetection: ChangeDetectionStrategy.OnPush, |
|
|
changeDetection: ChangeDetectionStrategy.OnPush, |
|
|
imports: [CommonModule, NgxSkeletonLoaderModule], |
|
|
imports: [CommonModule, NgxSkeletonLoaderModule], |
|
|
@ -67,7 +70,7 @@ export class GfLineChartComponent |
|
|
@Input() yMin: number; |
|
|
@Input() yMin: number; |
|
|
@Input() yMinLabel: string; |
|
|
@Input() yMinLabel: string; |
|
|
|
|
|
|
|
|
@ViewChild('chartCanvas') chartCanvas; |
|
|
@ViewChild('chartCanvas') chartCanvas: ElementRef<HTMLCanvasElement>; |
|
|
|
|
|
|
|
|
public chart: Chart<'line'>; |
|
|
public chart: Chart<'line'>; |
|
|
public isLoading = true; |
|
|
public isLoading = true; |
|
|
@ -85,8 +88,7 @@ export class GfLineChartComponent |
|
|
Tooltip |
|
|
Tooltip |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
Tooltip.positioners['top'] = (_elements, position: TooltipPosition) => |
|
|
registerChartConfiguration(); |
|
|
getTooltipPositionerMapTop(this.chart, position); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public ngAfterViewInit() { |
|
|
public ngAfterViewInit() { |
|
|
@ -117,9 +119,9 @@ export class GfLineChartComponent |
|
|
|
|
|
|
|
|
private initialize() { |
|
|
private initialize() { |
|
|
this.isLoading = true; |
|
|
this.isLoading = true; |
|
|
const benchmarkPrices = []; |
|
|
const benchmarkPrices: number[] = []; |
|
|
const labels: string[] = []; |
|
|
const labels: string[] = []; |
|
|
const marketPrices = []; |
|
|
const marketPrices: number[] = []; |
|
|
|
|
|
|
|
|
this.historicalDataItems?.forEach((historicalDataItem, index) => { |
|
|
this.historicalDataItems?.forEach((historicalDataItem, index) => { |
|
|
benchmarkPrices.push(this.benchmarkDataItems?.[index]?.value); |
|
|
benchmarkPrices.push(this.benchmarkDataItems?.[index]?.value); |
|
|
@ -129,11 +131,14 @@ export class GfLineChartComponent |
|
|
|
|
|
|
|
|
const gradient = this.chartCanvas?.nativeElement |
|
|
const gradient = this.chartCanvas?.nativeElement |
|
|
?.getContext('2d') |
|
|
?.getContext('2d') |
|
|
.createLinearGradient( |
|
|
?.createLinearGradient( |
|
|
0, |
|
|
0, |
|
|
0, |
|
|
0, |
|
|
0, |
|
|
0, |
|
|
(this.chartCanvas.nativeElement.parentNode.offsetHeight * 4) / 5 |
|
|
((this.chartCanvas.nativeElement.parentNode as HTMLElement) |
|
|
|
|
|
.offsetHeight * |
|
|
|
|
|
4) / |
|
|
|
|
|
5 |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
if (gradient && this.showGradient) { |
|
|
if (gradient && this.showGradient) { |
|
|
@ -169,27 +174,25 @@ export class GfLineChartComponent |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
if (this.chartCanvas) { |
|
|
if (this.chartCanvas) { |
|
|
|
|
|
const animations = { |
|
|
|
|
|
x: this.getAnimationConfigurationForAxis({ labels, axis: 'x' }), |
|
|
|
|
|
y: this.getAnimationConfigurationForAxis({ labels, axis: 'y' }) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
if (this.chart) { |
|
|
if (this.chart) { |
|
|
this.chart.data = data; |
|
|
this.chart.data = data; |
|
|
|
|
|
this.chart.options.plugins ??= {}; |
|
|
this.chart.options.plugins.tooltip = |
|
|
this.chart.options.plugins.tooltip = |
|
|
this.getTooltipPluginConfiguration() as unknown; |
|
|
this.getTooltipPluginConfiguration(); |
|
|
this.chart.options.animation = |
|
|
this.chart.options.animations = this.isAnimated |
|
|
this.isAnimated && |
|
|
? animations |
|
|
({ |
|
|
: undefined; |
|
|
x: this.getAnimationConfigurationForAxis({ labels, axis: 'x' }), |
|
|
|
|
|
y: this.getAnimationConfigurationForAxis({ labels, axis: 'y' }) |
|
|
|
|
|
} as unknown); |
|
|
|
|
|
this.chart.update(); |
|
|
this.chart.update(); |
|
|
} else { |
|
|
} else { |
|
|
this.chart = new Chart(this.chartCanvas.nativeElement, { |
|
|
this.chart = new Chart(this.chartCanvas.nativeElement, { |
|
|
data, |
|
|
data, |
|
|
options: { |
|
|
options: { |
|
|
animation: |
|
|
animations: this.isAnimated ? animations : undefined, |
|
|
this.isAnimated && |
|
|
|
|
|
({ |
|
|
|
|
|
x: this.getAnimationConfigurationForAxis({ labels, axis: 'x' }), |
|
|
|
|
|
y: this.getAnimationConfigurationForAxis({ labels, axis: 'y' }) |
|
|
|
|
|
} as unknown), |
|
|
|
|
|
aspectRatio: 16 / 9, |
|
|
aspectRatio: 16 / 9, |
|
|
elements: { |
|
|
elements: { |
|
|
point: { |
|
|
point: { |
|
|
@ -208,7 +211,7 @@ export class GfLineChartComponent |
|
|
verticalHoverLine: { |
|
|
verticalHoverLine: { |
|
|
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` |
|
|
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` |
|
|
} |
|
|
} |
|
|
} as unknown, |
|
|
}, |
|
|
scales: { |
|
|
scales: { |
|
|
x: { |
|
|
x: { |
|
|
border: { |
|
|
border: { |
|
|
@ -298,7 +301,7 @@ export class GfLineChartComponent |
|
|
}: { |
|
|
}: { |
|
|
axis: 'x' | 'y'; |
|
|
axis: 'x' | 'y'; |
|
|
labels: string[]; |
|
|
labels: string[]; |
|
|
}) { |
|
|
}): Partial<AnimationsSpec<'line'>[string]> { |
|
|
const delayBetweenPoints = this.ANIMATION_DURATION / labels.length; |
|
|
const delayBetweenPoints = this.ANIMATION_DURATION / labels.length; |
|
|
|
|
|
|
|
|
return { |
|
|
return { |
|
|
@ -308,7 +311,7 @@ export class GfLineChartComponent |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
context[`${axis}Started`] = true; |
|
|
context[`${axis}Started`] = true; |
|
|
return context.index * delayBetweenPoints; |
|
|
return context.dataIndex * delayBetweenPoints; |
|
|
}, |
|
|
}, |
|
|
duration: delayBetweenPoints, |
|
|
duration: delayBetweenPoints, |
|
|
easing: 'linear', |
|
|
easing: 'linear', |
|
|
@ -317,7 +320,7 @@ export class GfLineChartComponent |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private getTooltipPluginConfiguration() { |
|
|
private getTooltipPluginConfiguration(): Partial<TooltipOptions<'line'>> { |
|
|
return { |
|
|
return { |
|
|
...getTooltipOptions({ |
|
|
...getTooltipOptions({ |
|
|
colorScheme: this.colorScheme, |
|
|
colorScheme: this.colorScheme, |
|
|
@ -326,7 +329,7 @@ export class GfLineChartComponent |
|
|
unit: this.unit |
|
|
unit: this.unit |
|
|
}), |
|
|
}), |
|
|
mode: 'index', |
|
|
mode: 'index', |
|
|
position: 'top' as unknown, |
|
|
position: 'top', |
|
|
xAlign: 'center', |
|
|
xAlign: 'center', |
|
|
yAlign: 'bottom' |
|
|
yAlign: 'bottom' |
|
|
}; |
|
|
}; |
|
|
|