From 3ec4a73b35416103f00772711e134203cbcf5506 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 2 Oct 2021 20:38:41 +0200 Subject: [PATCH] Feature/improve tooltips (#403) * Improve tooltips * Update changelog --- CHANGELOG.md | 1 + .../world-map-chart.component.ts | 17 +++++++- .../allocations/allocations-page.component.ts | 40 +++++++++++++++---- .../allocations/allocations-page.html | 17 ++++---- .../portfolio-proportion-chart.component.ts | 37 ++++++++++++----- 5 files changed, 87 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a551c83..f273bc66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the symbol conversion for _Yahoo Finance_: Support for _Solana USD_ (`SOL1-USD`) +- Improved the tooltips of the allocations page - Upgraded `envalid` from version `7.1.0` to `7.2.1` ## 1.57.0 - 29.09.2021 diff --git a/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts b/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts index 85f5bc69..3b2f3b72 100644 --- a/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts +++ b/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts @@ -18,6 +18,7 @@ import svgMap from 'svgmap'; export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit { @Input() baseCurrency: string; @Input() countries: { [code: string]: { name: string; value: number } }; + @Input() isInPercent = false; public isLoading = true; public svgMapElement; @@ -41,6 +42,20 @@ export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit { } private initialize() { + if (this.isInPercent) { + // Convert value of countries to percentage + let sum = 0; + Object.keys(this.countries).map((country) => { + sum += this.countries[country].value; + }); + + Object.keys(this.countries).map((country) => { + this.countries[country].value = Number( + ((this.countries[country].value * 100) / sum).toFixed(2) + ); + }); + } + this.svgMapElement = new svgMap({ colorMax: '#22bdb9', colorMin: '#c3f1f0', @@ -49,7 +64,7 @@ export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit { applyData: 'value', data: { value: { - format: `{0} ${this.baseCurrency}` + format: this.isInPercent ? `{0}%` : `{0} ${this.baseCurrency}` } }, values: this.countries diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index dd9ef0c1..de29311a 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -37,13 +37,23 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { { label: 'Current', value: 'current' } ]; public portfolioDetails: PortfolioDetails; - public positions: { [symbol: string]: any }; + public positions: { + [symbol: string]: Pick< + PortfolioPosition, + | 'assetClass' + | 'assetSubClass' + | 'currency' + | 'exchange' + | 'name' + | 'value' + >; + }; public positionsArray: PortfolioPosition[]; public sectors: { [name: string]: { name: string; value: number }; }; public symbols: { - [name: string]: { name: string; value: number }; + [name: string]: { name: string; symbol: string; value: number }; }; public user: User; @@ -121,6 +131,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { this.symbols = { [UNKNOWN_KEY]: { name: UNKNOWN_KEY, + symbol: UNKNOWN_KEY, value: 0 } }; @@ -137,15 +148,29 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { for (const [symbol, position] of Object.entries( this.portfolioDetails.holdings )) { + let value = 0; + + if (aPeriod === 'original') { + if (this.hasImpersonationId) { + value = position.allocationInvestment; + } else { + value = position.investment; + } + } else { + if (this.hasImpersonationId) { + value = position.allocationCurrent; + } else { + value = position.value; + } + } + this.positions[symbol] = { + value, assetClass: position.assetClass, assetSubClass: position.assetSubClass, currency: position.currency, exchange: position.exchange, - value: - aPeriod === 'original' - ? position.allocationInvestment - : position.allocationCurrent + name: position.name }; this.positionsArray.push(position); @@ -221,7 +246,8 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { if (position.assetClass === AssetClass.EQUITY) { this.symbols[symbol] = { - name: symbol, + symbol, + name: position.name, value: aPeriod === 'original' ? position.investment : position.value }; } diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html index eee9081d..eb8a4a71 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html @@ -19,7 +19,7 @@ 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 917a1fe6..cf65e44f 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 @@ -35,7 +35,10 @@ export class PortfolioProportionChartComponent @Input() maxItems?: number; @Input() showLabels = false; @Input() positions: { - [symbol: string]: Pick & { value: number }; + [symbol: string]: Pick & { + name: string; + value: number; + }; } = {}; @ViewChild('chartCanvas') chartCanvas: ElementRef; @@ -80,6 +83,7 @@ export class PortfolioProportionChartComponent const chartData: { [symbol: string]: { color?: string; + name: string; subCategory: { [symbol: string]: { value: number } }; value: number; }; @@ -106,6 +110,7 @@ export class PortfolioProportionChartComponent } } else { chartData[this.positions[symbol][this.keys[0]]] = { + name: this.positions[symbol].name, subCategory: {}, value: this.positions[symbol].value }; @@ -123,6 +128,7 @@ export class PortfolioProportionChartComponent chartData[UNKNOWN_KEY].value += this.positions[symbol].value; } else { chartData[UNKNOWN_KEY] = { + name: this.positions[symbol].name, subCategory: this.keys[1] ? { [this.keys[1]]: { value: 0 } } : undefined, @@ -152,7 +158,7 @@ export class PortfolioProportionChartComponent if (!unknownItem) { const index = chartDataSorted.push([ UNKNOWN_KEY, - { subCategory: {}, value: 0 } + { name: UNKNOWN_KEY, subCategory: {}, value: 0 } ]); unknownItem = chartDataSorted[index]; } @@ -160,6 +166,7 @@ export class PortfolioProportionChartComponent rest.forEach((restItem) => { if (unknownItem?.[1]) { unknownItem[1] = { + name: UNKNOWN_KEY, subCategory: {}, value: unknownItem[1].value + restItem[1].value }; @@ -278,17 +285,29 @@ export class PortfolioProportionChartComponent const labelIndex = (data.datasets[context.datasetIndex - 1]?.data?.length ?? 0) + context.dataIndex; - const label = context.chart.data.labels?.[labelIndex] ?? ''; + const symbol = + context.chart.data.labels?.[labelIndex] ?? ''; + + const name = this.positions[symbol]?.name; + + let sum = 0; + context.dataset.data.map((item) => { + sum += item; + }); + + const percentage = (context.parsed * 100) / sum; if (this.isInPercent) { - const value = 100 * context.raw; - return `${label} (${value.toFixed(2)}%)`; + return `${name ?? symbol} (${percentage.toFixed(2)}%)`; } else { const value = context.raw; - return `${label} (${value.toLocaleString(this.locale, { - maximumFractionDigits: 2, - minimumFractionDigits: 2 - })} ${this.baseCurrency})`; + return `${name ?? symbol}: ${value.toLocaleString( + this.locale, + { + maximumFractionDigits: 2, + minimumFractionDigits: 2 + } + )} ${this.baseCurrency} (${percentage.toFixed(2)}%)`; } } }