diff --git a/apps/client/src/app/components/investment-chart/investment-chart.component.ts b/apps/client/src/app/components/investment-chart/investment-chart.component.ts index 5492ddd4c..469d29f7c 100644 --- a/apps/client/src/app/components/investment-chart/investment-chart.component.ts +++ b/apps/client/src/app/components/investment-chart/investment-chart.component.ts @@ -61,6 +61,8 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { @Input() isLoading = false; @Input() locale = getLocale(); @Input() savingsRate = 0; + @Input() xMax: Date; + @Input() xMin: Date; @ViewChild('chartCanvas') chartCanvas; @@ -241,6 +243,8 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { grid: { display: false }, + max: this.xMax?.getTime(), + min: this.xMin?.getTime(), type: 'time', time: { tooltipFormat: getDateFormatString(this.locale), diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index 26d474f73..c8a7ed4b7 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -73,11 +73,15 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { public deviceType: string; public dividendsByGroup: InvestmentItem[]; public dividendTimelineDataLabel = $localize`Dividend`; + public dividendTimelineXMax: Date; + public dividendTimelineXMin: Date; public firstOrderDate: Date; public hasImpersonationId: boolean; public hasPermissionToReadAiPrompt: boolean; public investments: InvestmentItem[]; public investmentTimelineDataLabel = $localize`Investment`; + public investmentTimelineXMax: Date; + public investmentTimelineXMin: Date; public investmentsByGroup: InvestmentItem[]; public isLoadingAnalysisPrompt: boolean; public isLoadingBenchmarkComparator: boolean; @@ -94,6 +98,8 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { public performanceDataItems: HistoricalDataItem[]; public performanceDataItemsInPercentage: HistoricalDataItem[]; public portfolioEvolutionDataLabel = $localize`Investment`; + public portfolioEvolutionXMax: Date; + public portfolioEvolutionXMin: Date; public streaks: PortfolioInvestments['streaks']; public top3: PortfolioPosition[]; public unitCurrentStreak: string; @@ -241,6 +247,8 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { this.isLoadingDividendTimelineChart = false; + this.updateDateRanges(); + this.changeDetectorRef.markForCheck(); }); @@ -273,6 +281,8 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { this.isLoadingInvestmentTimelineChart = false; + this.updateDateRanges(); + this.changeDetectorRef.markForCheck(); }); } @@ -327,6 +337,8 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { this.updateBenchmarkDataItems(); + this.updateDateRanges(); + this.changeDetectorRef.markForCheck(); }); @@ -402,4 +414,51 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { } } } + + private updateDateRanges() { + // Calculate min and max dates for chart scaling based on filtered data + // This ensures charts are scaled proportionally to the selected time period + + if (this.performanceDataItems && this.performanceDataItems.length > 0) { + const dates = this.performanceDataItems.map( + (item) => new Date(item.date) + ); + this.portfolioEvolutionXMin = new Date( + Math.min(...dates.map((d) => d.getTime())) + ); + this.portfolioEvolutionXMax = new Date( + Math.max(...dates.map((d) => d.getTime())) + ); + } else { + // Fallback to undefined if no data, allowing chart to use default scaling + this.portfolioEvolutionXMin = undefined; + this.portfolioEvolutionXMax = undefined; + } + + if (this.investmentsByGroup && this.investmentsByGroup.length > 0) { + const dates = this.investmentsByGroup.map((item) => new Date(item.date)); + this.investmentTimelineXMin = new Date( + Math.min(...dates.map((d) => d.getTime())) + ); + this.investmentTimelineXMax = new Date( + Math.max(...dates.map((d) => d.getTime())) + ); + } else { + this.investmentTimelineXMin = undefined; + this.investmentTimelineXMax = undefined; + } + + if (this.dividendsByGroup && this.dividendsByGroup.length > 0) { + const dates = this.dividendsByGroup.map((item) => new Date(item.date)); + this.dividendTimelineXMin = new Date( + Math.min(...dates.map((d) => d.getTime())) + ); + this.dividendTimelineXMax = new Date( + Math.max(...dates.map((d) => d.getTime())) + ); + } else { + this.dividendTimelineXMin = undefined; + this.dividendTimelineXMax = undefined; + } + } } diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index d33d5e570..a0a878e49 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -354,6 +354,8 @@ [isInPercent]="hasImpersonationId || user.settings.isRestrictedView" [isLoading]="isLoadingInvestmentChart" [locale]="user?.settings?.locale" + [xMax]="portfolioEvolutionXMax" + [xMin]="portfolioEvolutionXMin" /> @@ -411,6 +413,8 @@ [isLoading]="isLoadingInvestmentTimelineChart" [locale]="user?.settings?.locale" [savingsRate]="savingsRate" + [xMax]="investmentTimelineXMax" + [xMin]="investmentTimelineXMin" /> @@ -445,6 +449,8 @@ [isInPercent]="hasImpersonationId || user.settings.isRestrictedView" [isLoading]="isLoadingDividendTimelineChart" [locale]="user?.settings?.locale" + [xMax]="dividendTimelineXMax" + [xMin]="dividendTimelineXMin" /> diff --git a/libs/ui/src/lib/line-chart/line-chart.component.ts b/libs/ui/src/lib/line-chart/line-chart.component.ts index 0afef5959..bad9975fc 100644 --- a/libs/ui/src/lib/line-chart/line-chart.component.ts +++ b/libs/ui/src/lib/line-chart/line-chart.component.ts @@ -66,6 +66,8 @@ export class GfLineChartComponent @Input() yMaxLabel: string; @Input() yMin: number; @Input() yMinLabel: string; + @Input() xMax: Date; + @Input() xMin: Date; @ViewChild('chartCanvas') chartCanvas; @@ -218,6 +220,8 @@ export class GfLineChartComponent grid: { display: false }, + max: this.xMax?.getTime(), + min: this.xMin?.getTime(), time: { tooltipFormat: getDateFormatString(this.locale), unit: 'year'