|
@ -36,6 +36,10 @@ export class PortfolioProportionChartComponent |
|
|
public chart: Chart; |
|
|
public chart: Chart; |
|
|
public isLoading = true; |
|
|
public isLoading = true; |
|
|
|
|
|
|
|
|
|
|
|
private colorMap: { |
|
|
|
|
|
[symbol: string]: string; |
|
|
|
|
|
} = {}; |
|
|
|
|
|
|
|
|
public constructor() { |
|
|
public constructor() { |
|
|
Chart.register(ArcElement, DoughnutController, LinearScale, Tooltip); |
|
|
Chart.register(ArcElement, DoughnutController, LinearScale, Tooltip); |
|
|
} |
|
|
} |
|
@ -48,37 +52,67 @@ export class PortfolioProportionChartComponent |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public ngOnDestroy() { |
|
|
|
|
|
this.chart?.destroy(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private initialize() { |
|
|
private initialize() { |
|
|
this.isLoading = true; |
|
|
this.isLoading = true; |
|
|
const chartData: { [symbol: string]: number } = {}; |
|
|
const chartData: { |
|
|
|
|
|
[symbol: string]: { color?: string; value: number }; |
|
|
|
|
|
} = {}; |
|
|
|
|
|
|
|
|
Object.keys(this.positions).forEach((symbol) => { |
|
|
Object.keys(this.positions).forEach((symbol) => { |
|
|
if (this.positions[symbol][this.key]) { |
|
|
if (this.positions[symbol][this.key]) { |
|
|
if (chartData[this.positions[symbol][this.key]]) { |
|
|
if (chartData[this.positions[symbol][this.key]]) { |
|
|
chartData[this.positions[symbol][this.key]] += this.positions[ |
|
|
chartData[this.positions[symbol][this.key]].value += this.positions[ |
|
|
symbol |
|
|
symbol |
|
|
].value; |
|
|
].value; |
|
|
} else { |
|
|
} else { |
|
|
chartData[this.positions[symbol][this.key]] = this.positions[ |
|
|
chartData[this.positions[symbol][this.key]] = { |
|
|
symbol |
|
|
value: this.positions[symbol].value |
|
|
].value; |
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
if (chartData['Other']) { |
|
|
|
|
|
chartData['Other'].value += this.positions[symbol].value; |
|
|
|
|
|
} else { |
|
|
|
|
|
chartData['Other'] = { |
|
|
|
|
|
value: this.positions[symbol].value |
|
|
|
|
|
}; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const chartDataSorted = Object.entries(chartData) |
|
|
const chartDataSorted = Object.entries(chartData) |
|
|
.sort((a, b) => { |
|
|
.sort((a, b) => { |
|
|
return a[1] - b[1]; |
|
|
return a[1].value - b[1].value; |
|
|
}) |
|
|
}) |
|
|
.reverse(); |
|
|
.reverse(); |
|
|
|
|
|
|
|
|
|
|
|
chartDataSorted.forEach(([symbol, item], index) => { |
|
|
|
|
|
if (this.colorMap[symbol]) { |
|
|
|
|
|
// Reuse color
|
|
|
|
|
|
item.color = this.colorMap[symbol]; |
|
|
|
|
|
} else { |
|
|
|
|
|
const color = this.getColorPalette()[index]; |
|
|
|
|
|
|
|
|
|
|
|
// Store color for reuse
|
|
|
|
|
|
this.colorMap[symbol] = color; |
|
|
|
|
|
|
|
|
|
|
|
item.color = color; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
const data = { |
|
|
const data = { |
|
|
datasets: [ |
|
|
datasets: [ |
|
|
{ |
|
|
{ |
|
|
backgroundColor: this.getColorPalette(), |
|
|
backgroundColor: chartDataSorted.map(([, item]) => { |
|
|
|
|
|
return item.color; |
|
|
|
|
|
}), |
|
|
borderWidth: 0, |
|
|
borderWidth: 0, |
|
|
data: chartDataSorted.map(([, value]) => { |
|
|
data: chartDataSorted.map(([, item]) => { |
|
|
return value; |
|
|
return item.value; |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
], |
|
|
], |
|
@ -100,21 +134,13 @@ export class PortfolioProportionChartComponent |
|
|
tooltip: { |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
callbacks: { |
|
|
label: (context) => { |
|
|
label: (context) => { |
|
|
const label = data.labels[context.dataIndex]; |
|
|
const label = context.label; |
|
|
|
|
|
|
|
|
if (this.isInPercent) { |
|
|
if (this.isInPercent) { |
|
|
const value = |
|
|
const value = 100 * <number>context.raw; |
|
|
100 * |
|
|
|
|
|
data.datasets[context.datasetIndex].data[ |
|
|
|
|
|
context.dataIndex |
|
|
|
|
|
]; |
|
|
|
|
|
return `${label} (${value.toFixed(2)}%)`; |
|
|
return `${label} (${value.toFixed(2)}%)`; |
|
|
} else { |
|
|
} else { |
|
|
const value = |
|
|
const value = <number>context.raw; |
|
|
data.datasets[context.datasetIndex].data[ |
|
|
|
|
|
context.dataIndex |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
return `${label} (${value.toLocaleString(this.locale, { |
|
|
return `${label} (${value.toLocaleString(this.locale, { |
|
|
maximumFractionDigits: 2, |
|
|
maximumFractionDigits: 2, |
|
|
minimumFractionDigits: 2 |
|
|
minimumFractionDigits: 2 |
|
@ -153,8 +179,4 @@ export class PortfolioProportionChartComponent |
|
|
'#cc5de8' // grape 5
|
|
|
'#cc5de8' // grape 5
|
|
|
]; |
|
|
]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public ngOnDestroy() { |
|
|
|
|
|
this.chart?.destroy(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|