diff --git a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts index d6589eda5..fe3f2ca6a 100644 --- a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts +++ b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -191,7 +191,12 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy { type: 'time', time: { tooltipFormat: getDateFormatString(this.locale), - unit: 'year' + unit: 'year', + displayFormats: { + day: 'MMM d', + month: 'MMM yyyy', + year: 'yyyy' + } } }, y: { 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 9fd245485..fa1686b2b 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 @@ -7,14 +7,13 @@ import { import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; import { getBackgroundColor, - getDateFormatString, getLocale, getTextColor, parseDate } from '@ghostfolio/common/helper'; import { LineChartItem } from '@ghostfolio/common/interfaces'; import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface'; -import { ColorScheme, GroupBy } from '@ghostfolio/common/types'; +import { ColorScheme, DateRange, GroupBy } from '@ghostfolio/common/types'; import { ChangeDetectionStrategy, @@ -39,7 +38,14 @@ import { } from 'chart.js'; import 'chartjs-adapter-date-fns'; import annotationPlugin from 'chartjs-plugin-annotation'; -import { isAfter } from 'date-fns'; +import { + isAfter, + startOfMonth, + startOfWeek, + startOfYear, + subDays, + subYears +} from 'date-fns'; @Component({ selector: 'gf-investment-chart', @@ -50,9 +56,10 @@ import { isAfter } from 'date-fns'; }) export class InvestmentChartComponent implements OnChanges, OnDestroy { @Input() benchmarkDataItems: InvestmentItem[] = []; - @Input() benchmarkDataLabel = ''; + @Input() benchmarkDataLabel = $localize`Benchmark`; @Input() colorScheme: ColorScheme; @Input() currency: string; + @Input() dateRange: DateRange; @Input() groupBy: GroupBy; @Input() historicalDataItems: LineChartItem[] = []; @Input() isInPercent = false; @@ -158,6 +165,8 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy { this.chart.options.plugins.tooltip = this.getTooltipPluginConfiguration() as unknown; + this.chart.options.scales.x = this.getChartXAxis() as any; + if ( this.savingsRate && // @ts-ignore @@ -230,21 +239,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy { } as unknown, responsive: true, scales: { - x: { - border: { - color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, - width: this.groupBy ? 0 : 1 - }, - display: true, - grid: { - display: false - }, - type: 'time', - time: { - tooltipFormat: getDateFormatString(this.locale), - unit: 'year' - } - }, + x: this.getChartXAxis() as any, y: { border: { display: false @@ -284,6 +279,75 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy { } } + private getChartXAxis() { + let min: number | undefined; + let unit: 'day' | 'month' | 'week' | 'year' = 'year'; + + switch (this.dateRange) { + case '1d': + min = subDays(new Date(), 1).getTime(); + unit = 'day'; + break; + case 'mtd': + min = startOfMonth(new Date()).getTime(); + unit = 'day'; + break; + case 'wtd': + min = startOfWeek(new Date(), { weekStartsOn: 1 }).getTime(); + unit = 'day'; + break; + case 'ytd': + min = startOfYear(new Date()).getTime(); + unit = 'month'; + break; + case '1y': + min = subYears(new Date(), 1).getTime(); + unit = 'month'; + break; + case '5y': + min = subYears(new Date(), 5).getTime(); + unit = 'year'; + break; + case 'max': + // For 'max', we don't set a min value to show all available data + // Use 'year' unit for better scale with long-term data + unit = 'year'; + break; + default: + // For any other value (like specific years), use year unit + unit = 'year'; + break; + } + + const config: any = { + type: 'time', + time: { + unit, + // Add display formats for better readability + displayFormats: { + day: 'MMM d', + month: 'MMM yyyy', + year: 'yyyy' + } + }, + border: { + color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, + width: this.groupBy ? 0 : 1 + }, + display: true, + grid: { + display: false + } + }; + + // Only add min if it's defined (not for 'max' range) + if (min !== undefined) { + config.min = min; + } + + return config; + } + private getTooltipPluginConfiguration() { return { ...getTooltipOptions({ 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 56c95e40f..a69a3ec22 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -350,6 +350,7 @@ [benchmarkDataItems]="investments" [benchmarkDataLabel]="portfolioEvolutionDataLabel" [currency]="user?.settings?.baseCurrency" + [dateRange]="user?.settings?.dateRange" [historicalDataItems]="performanceDataItems" [isInPercent]="hasImpersonationId || user.settings.isRestrictedView" [isLoading]="isLoadingInvestmentChart" @@ -406,6 +407,7 @@ [benchmarkDataItems]="investmentsByGroup" [benchmarkDataLabel]="investmentTimelineDataLabel" [currency]="user?.settings?.baseCurrency" + [dateRange]="user?.settings?.dateRange" [groupBy]="mode" [isInPercent]="hasImpersonationId || user.settings.isRestrictedView" [isLoading]="isLoadingInvestmentTimelineChart" @@ -441,6 +443,7 @@ [benchmarkDataItems]="dividendsByGroup" [benchmarkDataLabel]="dividendTimelineDataLabel" [currency]="user?.settings?.baseCurrency" + [dateRange]="user?.settings?.dateRange" [groupBy]="mode" [isInPercent]="hasImpersonationId || user.settings.isRestrictedView" [isLoading]="isLoadingDividendTimelineChart"