From ce6b5fb7cb2fe1135544994b78c0f9c6a4ba508a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 1 May 2022 08:38:57 +0200 Subject: [PATCH] Bugfix/fix tooltip in proportion chart after update (#882) * Keep tooltip configuration up to date * Update changelog --- CHANGELOG.md | 4 + .../portfolio-proportion-chart.component.ts | 92 ++++++++++--------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a09b7cad1..0f2d4c10a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for private equity - Extended the form to set the asset and asset sub class for (wealth) items +### Fixed + +- Fixed the tooltip update in the portfolio proportion chart component + ### Todo - Apply data migration (`yarn database:migrate`) diff --git a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts index a81e585cd..94130e60e 100644 --- a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts +++ b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -15,7 +15,7 @@ import { getTextColor } from '@ghostfolio/common/helper'; import { PortfolioPosition, UniqueAsset } from '@ghostfolio/common/interfaces'; import { DataSource } from '@prisma/client'; import Big from 'big.js'; -import { Tooltip } from 'chart.js'; +import { ChartConfiguration, Tooltip } from 'chart.js'; import { LinearScale } from 'chart.js'; import { ArcElement } from 'chart.js'; import { DoughnutController } from 'chart.js'; @@ -215,7 +215,7 @@ export class PortfolioProportionChartComponent }); }); - const datasets = [ + const datasets: ChartConfiguration['data']['datasets'] = [ { backgroundColor: chartDataSorted.map(([, item]) => { return item.color; @@ -247,7 +247,7 @@ export class PortfolioProportionChartComponent datasets[0].data[0] = Number.MAX_SAFE_INTEGER; } - const data = { + const data: ChartConfiguration['data'] = { datasets, labels }; @@ -255,6 +255,8 @@ export class PortfolioProportionChartComponent if (this.chartCanvas) { if (this.chart) { this.chart.data = data; + this.chart.options.plugins.tooltip = + this.getTooltipPluginConfiguration(data); this.chart.update(); } else { this.chart = new Chart(this.chartCanvas.nativeElement, { @@ -302,46 +304,7 @@ export class PortfolioProportionChartComponent } }, legend: { display: false }, - tooltip: { - callbacks: { - label: (context) => { - const labelIndex = - (data.datasets[context.datasetIndex - 1]?.data?.length ?? - 0) + context.dataIndex; - let symbol = context.chart.data.labels?.[labelIndex] ?? ''; - - if (symbol === this.OTHER_KEY) { - symbol = 'Other'; - } else if (symbol === UNKNOWN_KEY) { - symbol = 'Unknown'; - } - - const name = this.positions[symbol]?.name; - - let sum = 0; - context.dataset.data.map((item) => { - sum += item; - }); - - const percentage = (context.parsed * 100) / sum; - - if (context.raw === Number.MAX_SAFE_INTEGER) { - return 'No data available'; - } else if (this.isInPercent) { - return [`${name ?? symbol}`, `${percentage.toFixed(2)}%`]; - } else { - const value = context.raw; - return [ - `${name ?? symbol}`, - `${value.toLocaleString(this.locale, { - maximumFractionDigits: 2, - minimumFractionDigits: 2 - })} ${this.baseCurrency} (${percentage.toFixed(2)}%)` - ]; - } - } - } - } + tooltip: this.getTooltipPluginConfiguration(data) } }, plugins: [ChartDataLabels], @@ -373,4 +336,47 @@ export class PortfolioProportionChartComponent '#cc5de8' // grape 5 ]; } + + private getTooltipPluginConfiguration(data: ChartConfiguration['data']) { + return { + callbacks: { + label: (context) => { + const labelIndex = + (data.datasets[context.datasetIndex - 1]?.data?.length ?? 0) + + context.dataIndex; + let symbol = context.chart.data.labels?.[labelIndex] ?? ''; + + if (symbol === this.OTHER_KEY) { + symbol = 'Other'; + } else if (symbol === UNKNOWN_KEY) { + symbol = 'Unknown'; + } + + const name = this.positions[symbol]?.name; + + let sum = 0; + for (const item of context.dataset.data) { + sum += item; + } + + const percentage = (context.parsed * 100) / sum; + + if (context.raw === Number.MAX_SAFE_INTEGER) { + return 'No data available'; + } else if (this.isInPercent) { + return [`${name ?? symbol}`, `${percentage.toFixed(2)}%`]; + } else { + const value = context.raw; + return [ + `${name ?? symbol}`, + `${value.toLocaleString(this.locale, { + maximumFractionDigits: 2, + minimumFractionDigits: 2 + })} ${this.baseCurrency} (${percentage.toFixed(2)}%)` + ]; + } + } + } + }; + } }