|
|
@ -13,12 +13,11 @@ import { |
|
|
ChangeDetectionStrategy, |
|
|
ChangeDetectionStrategy, |
|
|
Component, |
|
|
Component, |
|
|
ElementRef, |
|
|
ElementRef, |
|
|
EventEmitter, |
|
|
|
|
|
Input, |
|
|
Input, |
|
|
OnChanges, |
|
|
OnChanges, |
|
|
OnDestroy, |
|
|
OnDestroy, |
|
|
Output, |
|
|
output, |
|
|
ViewChild |
|
|
viewChild |
|
|
} 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'; |
|
|
@ -81,15 +80,16 @@ export class GfPortfolioProportionChartComponent |
|
|
@Input() maxItems?: number; |
|
|
@Input() maxItems?: number; |
|
|
@Input() showLabels = false; |
|
|
@Input() showLabels = false; |
|
|
|
|
|
|
|
|
@Output() proportionChartClicked = new EventEmitter<AssetProfileIdentifier>(); |
|
|
|
|
|
|
|
|
|
|
|
@ViewChild('chartCanvas') chartCanvas: ElementRef<HTMLCanvasElement>; |
|
|
|
|
|
|
|
|
|
|
|
public chart: Chart<'doughnut'>; |
|
|
public chart: Chart<'doughnut'>; |
|
|
public isLoading = true; |
|
|
public isLoading = true; |
|
|
|
|
|
|
|
|
|
|
|
protected readonly proportionChartClicked = output<AssetProfileIdentifier>(); |
|
|
|
|
|
|
|
|
private readonly OTHER_KEY = 'OTHER'; |
|
|
private readonly OTHER_KEY = 'OTHER'; |
|
|
|
|
|
|
|
|
|
|
|
private readonly chartCanvas = |
|
|
|
|
|
viewChild.required<ElementRef<HTMLCanvasElement>>('chartCanvas'); |
|
|
|
|
|
|
|
|
private colorMap: { |
|
|
private colorMap: { |
|
|
[symbol: string]: string; |
|
|
[symbol: string]: string; |
|
|
} = {}; |
|
|
} = {}; |
|
|
@ -130,45 +130,45 @@ export class GfPortfolioProportionChartComponent |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
if (this.keys.length > 0) { |
|
|
if (this.keys.length > 0) { |
|
|
|
|
|
const primaryKey = this.keys[0]; |
|
|
|
|
|
const secondaryKey = this.keys[1]; |
|
|
|
|
|
|
|
|
Object.keys(this.data).forEach((symbol) => { |
|
|
Object.keys(this.data).forEach((symbol) => { |
|
|
if (this.data[symbol][this.keys[0]]?.toUpperCase()) { |
|
|
const asset = this.data[symbol]; |
|
|
if (chartData[this.data[symbol][this.keys[0]].toUpperCase()]) { |
|
|
const assetValue = asset.value || 0; |
|
|
chartData[this.data[symbol][this.keys[0]].toUpperCase()].value = |
|
|
const primaryKeyValue = (asset[primaryKey] as string)?.toUpperCase(); |
|
|
chartData[ |
|
|
const secondaryKeyValue = asset[secondaryKey] as string; |
|
|
this.data[symbol][this.keys[0]].toUpperCase() |
|
|
|
|
|
].value.plus(this.data[symbol].value || 0); |
|
|
if (primaryKeyValue) { |
|
|
|
|
|
if (chartData[primaryKeyValue]) { |
|
|
if ( |
|
|
chartData[primaryKeyValue].value = |
|
|
chartData[this.data[symbol][this.keys[0]].toUpperCase()] |
|
|
chartData[primaryKeyValue].value.plus(assetValue); |
|
|
.subCategory[this.data[symbol][this.keys[1]]] |
|
|
|
|
|
) { |
|
|
const targetSubCategory = |
|
|
chartData[ |
|
|
chartData[primaryKeyValue].subCategory?.[secondaryKeyValue]; |
|
|
this.data[symbol][this.keys[0]].toUpperCase() |
|
|
if (targetSubCategory) { |
|
|
].subCategory[this.data[symbol][this.keys[1]]].value = chartData[ |
|
|
targetSubCategory.value = |
|
|
this.data[symbol][this.keys[0]].toUpperCase() |
|
|
targetSubCategory.value.plus(assetValue); |
|
|
].subCategory[this.data[symbol][this.keys[1]]].value.plus( |
|
|
|
|
|
this.data[symbol].value || 0 |
|
|
|
|
|
); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
chartData[ |
|
|
if (chartData[primaryKeyValue].subCategory) { |
|
|
this.data[symbol][this.keys[0]].toUpperCase() |
|
|
chartData[primaryKeyValue].subCategory[ |
|
|
].subCategory[this.data[symbol][this.keys[1]] ?? UNKNOWN_KEY] = { |
|
|
secondaryKeyValue ?? UNKNOWN_KEY |
|
|
value: new Big(this.data[symbol].value || 0) |
|
|
] = { |
|
|
|
|
|
value: new Big(assetValue) |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
chartData[this.data[symbol][this.keys[0]].toUpperCase()] = { |
|
|
chartData[primaryKeyValue] = { |
|
|
name: this.data[symbol][this.keys[0]], |
|
|
name: asset[primaryKey] as string, |
|
|
subCategory: {}, |
|
|
subCategory: {}, |
|
|
value: new Big(this.data[symbol].value || 0) |
|
|
value: new Big(assetValue) |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
if (this.data[symbol][this.keys[1]]) { |
|
|
if (secondaryKeyValue) { |
|
|
chartData[ |
|
|
chartData[primaryKeyValue].subCategory = { |
|
|
this.data[symbol][this.keys[0]].toUpperCase() |
|
|
[secondaryKeyValue]: { |
|
|
].subCategory = { |
|
|
value: new Big(assetValue) |
|
|
[this.data[symbol][this.keys[1]]]: { |
|
|
|
|
|
value: new Big(this.data[symbol].value || 0) |
|
|
|
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
@ -181,10 +181,10 @@ export class GfPortfolioProportionChartComponent |
|
|
} else { |
|
|
} else { |
|
|
chartData[UNKNOWN_KEY] = { |
|
|
chartData[UNKNOWN_KEY] = { |
|
|
name: this.data[symbol].name, |
|
|
name: this.data[symbol].name, |
|
|
subCategory: this.keys[1] |
|
|
subCategory: secondaryKey |
|
|
? { [this.keys[1]]: { value: new Big(0) } } |
|
|
? { [secondaryKey]: { value: new Big(0) } } |
|
|
: undefined, |
|
|
: undefined, |
|
|
value: new Big(this.data[symbol].value || 0) |
|
|
value: new Big(assetValue) |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -278,13 +278,15 @@ export class GfPortfolioProportionChartComponent |
|
|
|
|
|
|
|
|
Object.keys(item.subCategory ?? {}).forEach((subCategory) => { |
|
|
Object.keys(item.subCategory ?? {}).forEach((subCategory) => { |
|
|
if (item.name === UNKNOWN_KEY) { |
|
|
if (item.name === UNKNOWN_KEY) { |
|
|
backgroundColorSubCategory.push(item.color); |
|
|
backgroundColorSubCategory.push(item.color ?? ''); |
|
|
} else { |
|
|
} else { |
|
|
backgroundColorSubCategory.push( |
|
|
backgroundColorSubCategory.push( |
|
|
Color(item.color).lighten(lightnessRatio).hex() |
|
|
Color(item.color).lighten(lightnessRatio).hex() |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
dataSubCategory.push(item.subCategory[subCategory].value.toNumber()); |
|
|
dataSubCategory.push( |
|
|
|
|
|
item.subCategory?.[subCategory].value.toNumber() ?? 0 |
|
|
|
|
|
); |
|
|
labelSubCategory.push(subCategory); |
|
|
labelSubCategory.push(subCategory); |
|
|
|
|
|
|
|
|
lightnessRatio += 0.1; |
|
|
lightnessRatio += 0.1; |
|
|
@ -334,7 +336,7 @@ export class GfPortfolioProportionChartComponent |
|
|
labels |
|
|
labels |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
if (this.chartCanvas) { |
|
|
if (this.chartCanvas()) { |
|
|
if (this.chart) { |
|
|
if (this.chart) { |
|
|
this.chart.data = data; |
|
|
this.chart.data = data; |
|
|
this.chart.options.plugins ??= {}; |
|
|
this.chart.options.plugins ??= {}; |
|
|
@ -343,7 +345,7 @@ export class GfPortfolioProportionChartComponent |
|
|
|
|
|
|
|
|
this.chart.update(); |
|
|
this.chart.update(); |
|
|
} else { |
|
|
} else { |
|
|
this.chart = new Chart<'doughnut'>(this.chartCanvas.nativeElement, { |
|
|
this.chart = new Chart<'doughnut'>(this.chartCanvas().nativeElement, { |
|
|
data, |
|
|
data, |
|
|
options: { |
|
|
options: { |
|
|
animation: false, |
|
|
animation: false, |
|
|
|