Browse Source

fix(ui): portfolio proportion chart type safety

pull/6277/head
KenTandrian 7 days ago
parent
commit
8905893dbb
  1. 50
      libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts

50
libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts

@ -22,11 +22,16 @@ import {
} from '@angular/core'; } from '@angular/core';
import { DataSource } from '@prisma/client'; import { DataSource } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { ChartConfiguration, Tooltip } from 'chart.js'; import {
import { LinearScale } from 'chart.js'; ArcElement,
import { ArcElement } from 'chart.js'; Chart,
import { DoughnutController } from 'chart.js'; type ChartData,
import { Chart } from 'chart.js'; type ChartDataset,
DoughnutController,
LinearScale,
Tooltip,
type TooltipOptions
} from 'chart.js';
import ChartDataLabels from 'chartjs-plugin-datalabels'; import ChartDataLabels from 'chartjs-plugin-datalabels';
import { isUUID } from 'class-validator'; import { isUUID } from 'class-validator';
import Color from 'color'; import Color from 'color';
@ -286,7 +291,7 @@ export class GfPortfolioProportionChartComponent
}); });
}); });
const datasets: ChartConfiguration<'doughnut'>['data']['datasets'] = [ const datasets: ChartDataset<'doughnut'>[] = [
{ {
backgroundColor: chartDataSorted.map(([, item]) => { backgroundColor: chartDataSorted.map(([, item]) => {
return item.color; return item.color;
@ -324,7 +329,7 @@ export class GfPortfolioProportionChartComponent
datasets[1].data[1] = Number.MAX_SAFE_INTEGER; datasets[1].data[1] = Number.MAX_SAFE_INTEGER;
} }
const data: ChartConfiguration<'doughnut'>['data'] = { const data: ChartData<'doughnut'> = {
datasets, datasets,
labels labels
}; };
@ -332,9 +337,9 @@ export class GfPortfolioProportionChartComponent
if (this.chartCanvas) { if (this.chartCanvas) {
if (this.chart) { if (this.chart) {
this.chart.data = data; this.chart.data = data;
this.chart.options.plugins.tooltip = this.getTooltipPluginConfiguration( this.chart.options.plugins ??= {};
data this.chart.options.plugins.tooltip =
) as unknown; this.getTooltipPluginConfiguration(data);
this.chart.update(); this.chart.update();
} else { } else {
this.chart = new Chart<'doughnut'>(this.chartCanvas.nativeElement, { this.chart = new Chart<'doughnut'>(this.chartCanvas.nativeElement, {
@ -345,21 +350,22 @@ export class GfPortfolioProportionChartComponent
layout: { layout: {
padding: this.showLabels === true ? 100 : 0 padding: this.showLabels === true ? 100 : 0
}, },
onClick: (event, activeElements) => { onClick: (_, activeElements, chart) => {
try { try {
const dataIndex = activeElements[0].index; const dataIndex = activeElements[0].index;
const symbol: string = event.chart.data.labels[dataIndex]; const symbol = chart.data.labels?.[dataIndex] as string;
const dataSource = this.data[symbol]?.dataSource; const dataSource = this.data[symbol].dataSource;
if (dataSource) {
this.proportionChartClicked.emit({ dataSource, symbol }); this.proportionChartClicked.emit({ dataSource, symbol });
}
} catch {} } catch {}
}, },
onHover: (event, chartElement) => { onHover: (event, chartElement) => {
if (this.cursor) { if (this.cursor) {
event.native.target.style.cursor = chartElement[0] (event.native?.target as HTMLElement).style.cursor =
? this.cursor chartElement[0] ? this.cursor : 'default';
: 'default';
} }
}, },
plugins: { plugins: {
@ -392,7 +398,7 @@ export class GfPortfolioProportionChartComponent
legend: { display: false }, legend: { display: false },
tooltip: this.getTooltipPluginConfiguration(data) tooltip: this.getTooltipPluginConfiguration(data)
} }
} as unknown, },
plugins: [ChartDataLabels], plugins: [ChartDataLabels],
type: 'doughnut' type: 'doughnut'
}); });
@ -419,19 +425,23 @@ export class GfPortfolioProportionChartComponent
]; ];
} }
private getTooltipPluginConfiguration(data: ChartConfiguration['data']) { private getTooltipPluginConfiguration(
data: ChartData<'doughnut'>
): Partial<TooltipOptions<'doughnut'>> {
return { return {
...getTooltipOptions({ ...getTooltipOptions({
colorScheme: this.colorScheme, colorScheme: this.colorScheme,
currency: this.baseCurrency, currency: this.baseCurrency,
locale: this.locale locale: this.locale
}), }),
// @ts-expect-error: no need to set all attributes in callbacks.
callbacks: { callbacks: {
label: (context) => { label: (context) => {
const labelIndex = const labelIndex =
(data.datasets[context.datasetIndex - 1]?.data?.length ?? 0) + (data.datasets[context.datasetIndex - 1]?.data?.length ?? 0) +
context.dataIndex; context.dataIndex;
let symbol = context.chart.data.labels?.[labelIndex] ?? ''; let symbol =
(context.chart.data.labels?.[labelIndex] as string) ?? '';
if (symbol === this.OTHER_KEY) { if (symbol === this.OTHER_KEY) {
symbol = $localize`Other`; symbol = $localize`Other`;
@ -439,7 +449,7 @@ export class GfPortfolioProportionChartComponent
symbol = $localize`No data available`; symbol = $localize`No data available`;
} }
const name = translate(this.data[symbol as string]?.name); const name = translate(this.data[symbol]?.name);
let sum = 0; let sum = 0;
for (const item of context.dataset.data) { for (const item of context.dataset.data) {

Loading…
Cancel
Save