mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-20 01:34:24 +08:00
insights explorer supports axis chart
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-chart autoresize class="axis-chart-container" :class="{ 'transition-in': skeleton }" :option="chartOptions"
|
<v-chart autoresize :class="finalClass" :option="chartOptions"
|
||||||
@click="clickItem" @legendselectchanged="onLegendSelectChanged" />
|
@click="clickItem" @legendselectchanged="onLegendSelectChanged" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ import { isArray } from '@/lib/common.ts';
|
|||||||
import { getDisplayColor } from '@/lib/color.ts';
|
import { getDisplayColor } from '@/lib/color.ts';
|
||||||
import { sortStatisticsItems } from '@/lib/statistics.ts';
|
import { sortStatisticsItems } from '@/lib/statistics.ts';
|
||||||
|
|
||||||
export type AxisChartDisplayType = 'area' | 'column' | 'bubble';
|
export type AxisChartDisplayType = 'line' | 'area' | 'column' | 'bubble';
|
||||||
|
|
||||||
interface AxisChartDataItem {
|
interface AxisChartDataItem {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -49,9 +49,11 @@ interface AxisChartTooltipItem extends SortableTransactionStatisticDataItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
class?: string;
|
||||||
skeleton?: boolean;
|
skeleton?: boolean;
|
||||||
type: AxisChartDisplayType;
|
type: AxisChartDisplayType;
|
||||||
stacked?: boolean;
|
stacked?: boolean;
|
||||||
|
oneHundredPercentStacked?: boolean;
|
||||||
sortingType: number;
|
sortingType: number;
|
||||||
showValue?: boolean;
|
showValue?: boolean;
|
||||||
showTotalAmountInTooltip?: boolean;
|
showTotalAmountInTooltip?: boolean;
|
||||||
@@ -72,7 +74,7 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'click', itemId: string, categoryIndex: number): void;
|
(e: 'click', itemId: string, categoryIndex: number, item: Record<string, unknown>): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@@ -81,13 +83,29 @@ const {
|
|||||||
tt,
|
tt,
|
||||||
getCurrentLanguageTextDirection,
|
getCurrentLanguageTextDirection,
|
||||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency,
|
||||||
|
formatPercentToLocalizedNumerals
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const selectedLegends = ref<Record<string, boolean>>({});
|
const selectedLegends = ref<Record<string, boolean>>({});
|
||||||
|
|
||||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||||
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
||||||
|
const finalClass = computed<string>(() => {
|
||||||
|
let finalClass = '';
|
||||||
|
|
||||||
|
if (props.skeleton) {
|
||||||
|
finalClass += 'transition-in';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.class) {
|
||||||
|
finalClass += ` ${props.class}`;
|
||||||
|
} else {
|
||||||
|
finalClass += ' axis-chart-container';
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalClass;
|
||||||
|
});
|
||||||
|
|
||||||
const itemsMap = computed<Record<string, Record<string, unknown>>>(() => {
|
const itemsMap = computed<Record<string, Record<string, unknown>>>(() => {
|
||||||
const map: Record<string, Record<string, unknown>> = {};
|
const map: Record<string, Record<string, unknown>> = {};
|
||||||
@@ -125,7 +143,8 @@ const itemsMap = computed<Record<string, Record<string, unknown>>>(() => {
|
|||||||
|
|
||||||
const allSeries = computed<AxisChartDataItem[]>(() => {
|
const allSeries = computed<AxisChartDataItem[]>(() => {
|
||||||
const allSeries: AxisChartDataItem[] = [];
|
const allSeries: AxisChartDataItem[] = [];
|
||||||
let maxAmount: number = 0;
|
const categoryTotalAmount: Record<number, number> = {};
|
||||||
|
let maxAmountOfAllData: number = 0;
|
||||||
|
|
||||||
for (const item of props.items) {
|
for (const item of props.items) {
|
||||||
if (props.hiddenField && item[props.hiddenField]) {
|
if (props.hiddenField && item[props.hiddenField]) {
|
||||||
@@ -138,11 +157,32 @@ const allSeries = computed<AxisChartDataItem[]>(() => {
|
|||||||
|
|
||||||
const allAmounts: number[] = item[props.valuesField] as number[];
|
const allAmounts: number[] = item[props.valuesField] as number[];
|
||||||
|
|
||||||
if (props.type === 'bubble') {
|
for (const [amount, categoryIndex] of itemAndIndex(allAmounts)) {
|
||||||
for (const amount of allAmounts) {
|
let totalAmount: number = categoryTotalAmount[categoryIndex] ?? 0;
|
||||||
if (amount > maxAmount) {
|
totalAmount += amount;
|
||||||
maxAmount = amount;
|
categoryTotalAmount[categoryIndex] = totalAmount;
|
||||||
}
|
|
||||||
|
if (amount > maxAmountOfAllData) {
|
||||||
|
maxAmountOfAllData = amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of props.items) {
|
||||||
|
if (props.hiddenField && item[props.hiddenField]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isArray(item[props.valuesField])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allAmounts: number[] = item[props.valuesField] as number[];
|
||||||
|
|
||||||
|
if (props.oneHundredPercentStacked) {
|
||||||
|
for (const [amount, categoryIndex] of itemAndIndex(allAmounts)) {
|
||||||
|
const totalAmount: number = categoryTotalAmount[categoryIndex] ?? 0;
|
||||||
|
allAmounts[categoryIndex] = totalAmount !== 0 ? amount * 100.0 / totalAmount : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,14 +204,16 @@ const allSeries = computed<AxisChartDataItem[]>(() => {
|
|||||||
finalItem.stack = item[props.idField] as string;
|
finalItem.stack = item[props.idField] as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.type === 'area') {
|
if (props.type === 'line') {
|
||||||
|
finalItem.areaStyle = undefined;
|
||||||
|
} else if (props.type === 'area') {
|
||||||
finalItem.areaStyle = {};
|
finalItem.areaStyle = {};
|
||||||
} else if (props.type === 'column') {
|
} else if (props.type === 'column') {
|
||||||
finalItem.type = 'bar';
|
finalItem.type = 'bar';
|
||||||
} else if (props.type === 'bubble') {
|
} else if (props.type === 'bubble') {
|
||||||
finalItem.type = 'scatter';
|
finalItem.type = 'scatter';
|
||||||
finalItem.symbolSize = (data: number): number => {
|
finalItem.symbolSize = (data: number): number => {
|
||||||
return Math.sqrt(data) / Math.sqrt(maxAmount) * 80 + 5;
|
return Math.sqrt(data) / Math.sqrt(maxAmountOfAllData) * 80 + 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,8 +244,8 @@ const yAxisWidth = computed<number>(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxValueText = props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(maxValue, props.defaultCurrency) : maxValue.toString();
|
const maxValueText = getDisplayValue(maxValue);
|
||||||
const minValueText = props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(minValue, props.defaultCurrency) : minValue.toString();
|
const minValueText = getDisplayValue(minValue);
|
||||||
const maxLengthText = maxValueText.length > minValueText.length ? maxValueText : minValueText;
|
const maxLengthText = maxValueText.length > minValueText.length ? maxValueText : minValueText;
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
@@ -268,7 +310,7 @@ const chartOptions = computed<object>(() => {
|
|||||||
|
|
||||||
for (const item of displayItems) {
|
for (const item of displayItems) {
|
||||||
if (displayItems.length === 1 || item.totalAmount !== 0) {
|
if (displayItems.length === 1 || item.totalAmount !== 0) {
|
||||||
const value = props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(item.totalAmount, props.defaultCurrency) : item.totalAmount.toString();
|
const value = getDisplayValue(item.totalAmount);
|
||||||
tooltip += '<div><span class="chart-pointer" style="background-color: ' + item.color + '"></span>';
|
tooltip += '<div><span class="chart-pointer" style="background-color: ' + item.color + '"></span>';
|
||||||
tooltip += `<span>${item.name}</span><span class="ms-5" style="float: inline-end">${value}</span><br/>`;
|
tooltip += `<span>${item.name}</span><span class="ms-5" style="float: inline-end">${value}</span><br/>`;
|
||||||
tooltip += '</div>';
|
tooltip += '</div>';
|
||||||
@@ -276,8 +318,8 @@ const chartOptions = computed<object>(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.showTotalAmountInTooltip) {
|
if (props.showTotalAmountInTooltip && !props.oneHundredPercentStacked) {
|
||||||
const displayTotalAmount = props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(totalAmount, props.defaultCurrency) : totalAmount.toString();
|
const displayTotalAmount = getDisplayValue(totalAmount);
|
||||||
tooltip = (actualDisplayItemCount > 0 ? '<div style="border-bottom: ' + (isDarkMode.value ? '#eee' : '#333') + ' dashed 1px">' : '<div></div>')
|
tooltip = (actualDisplayItemCount > 0 ? '<div style="border-bottom: ' + (isDarkMode.value ? '#eee' : '#333') + ' dashed 1px">' : '<div></div>')
|
||||||
+ '<span class="chart-pointer" style="background-color: ' + (isDarkMode.value ? '#eee' : '#333') + '"></span>'
|
+ '<span class="chart-pointer" style="background-color: ' + (isDarkMode.value ? '#eee' : '#333') + '"></span>'
|
||||||
+ `<span>${props.totalNameInTooltip}</span><span class="ms-5" style="float: inline-end">${displayTotalAmount}</span><br/>`
|
+ `<span>${props.totalNameInTooltip}</span><span class="ms-5" style="float: inline-end">${displayTotalAmount}</span><br/>`
|
||||||
@@ -322,16 +364,18 @@ const chartOptions = computed<object>(() => {
|
|||||||
yAxis: [
|
yAxis: [
|
||||||
{
|
{
|
||||||
type: 'value',
|
type: 'value',
|
||||||
|
min: props.oneHundredPercentStacked ? 0 : undefined,
|
||||||
|
max: props.oneHundredPercentStacked ? 100 : undefined,
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: isDarkMode.value ? '#888' : '#666',
|
color: isDarkMode.value ? '#888' : '#666',
|
||||||
formatter: (value: string) => {
|
formatter: (value: string) => {
|
||||||
return props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(parseInt(value), props.defaultCurrency): value;
|
return getDisplayValue(parseInt(value));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
label: {
|
label: {
|
||||||
formatter: (params: CallbackDataParams) => {
|
formatter: (params: CallbackDataParams) => {
|
||||||
return props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(Math.trunc(params.value as number), props.defaultCurrency) : params.value;
|
return getDisplayValue(Math.trunc(params.value as number));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -350,6 +394,18 @@ function getItemName(name: string): string {
|
|||||||
return props.translateName ? tt(name) : name;
|
return props.translateName ? tt(name) : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDisplayValue(value: number): string {
|
||||||
|
if (props.oneHundredPercentStacked) {
|
||||||
|
return formatPercentToLocalizedNumerals(value, 2, '<0.01');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.amountValue) {
|
||||||
|
return formatAmountToLocalizedNumeralsWithCurrency(value, props.defaultCurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
function clickItem(e: ECElementEvent): void {
|
function clickItem(e: ECElementEvent): void {
|
||||||
if (!props.enableClickItem || e.componentType !== 'series') {
|
if (!props.enableClickItem || e.componentType !== 'series') {
|
||||||
return;
|
return;
|
||||||
@@ -364,7 +420,7 @@ function clickItem(e: ECElementEvent): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit('click', itemId, e.dataIndex);
|
emit('click', itemId, e.dataIndex, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportData(): { headers: string[], data: string[][] } {
|
function exportData(): { headers: string[], data: string[][] } {
|
||||||
@@ -404,13 +460,13 @@ defineExpose({
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.axis-chart-container {
|
.axis-chart-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 720px;
|
height: 560px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 600px) {
|
@media (min-width: 600px) {
|
||||||
.axis-chart-container {
|
.axis-chart-container {
|
||||||
height: 790px;
|
height: 630px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<axis-chart ref="axisChart" values-field="values"
|
<axis-chart class="trends-chart-container" ref="axisChart" values-field="values"
|
||||||
:skeleton="skeleton" :type="chartDisplayType" :stacked="stacked" :sorting-type="sortingType"
|
:skeleton="skeleton" :type="chartDisplayType" :stacked="stacked" :sorting-type="sortingType"
|
||||||
:show-value="showValue"
|
:show-value="showValue"
|
||||||
:show-total-amount-in-tooltip="showTotalAmountInTooltip" :total-name-in-tooltip="tt('Total Amount')"
|
:show-total-amount-in-tooltip="showTotalAmountInTooltip" :total-name-in-tooltip="tt('Total Amount')"
|
||||||
@@ -289,3 +289,17 @@ defineExpose({
|
|||||||
exportData
|
exportData
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.trends-chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 720px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.trends-chart-container {
|
||||||
|
height: 790px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -146,6 +146,13 @@ export class TransactionExplorerChartType implements NameValue {
|
|||||||
|
|
||||||
public static readonly Pie = new TransactionExplorerChartType('Pie Chart', TransactionExplorerChartTypeValue.Pie, false);
|
public static readonly Pie = new TransactionExplorerChartType('Pie Chart', TransactionExplorerChartTypeValue.Pie, false);
|
||||||
public static readonly Radar = new TransactionExplorerChartType('Radar Chart', TransactionExplorerChartTypeValue.Radar, false);
|
public static readonly Radar = new TransactionExplorerChartType('Radar Chart', TransactionExplorerChartTypeValue.Radar, false);
|
||||||
|
public static readonly ColumnStacked = new TransactionExplorerChartType('Column Chart (Stacked)', TransactionExplorerChartTypeValue.ColumnStacked, true);
|
||||||
|
public static readonly Column100PercentStacked = new TransactionExplorerChartType('Column Chart (100% Stacked)', TransactionExplorerChartTypeValue.Column100PercentStacked, true);
|
||||||
|
public static readonly ColumnGrouped = new TransactionExplorerChartType('Column Chart (Grouped)', TransactionExplorerChartTypeValue.ColumnGrouped, true);
|
||||||
|
public static readonly LineGrouped = new TransactionExplorerChartType('Line Chart (Grouped)', TransactionExplorerChartTypeValue.LineGrouped, true);
|
||||||
|
public static readonly AreaStacked = new TransactionExplorerChartType('Area Chart (Stacked)', TransactionExplorerChartTypeValue.AreaStacked, true);
|
||||||
|
public static readonly Area100PercentStacked = new TransactionExplorerChartType('Area Chart (100% Stacked)', TransactionExplorerChartTypeValue.Area100PercentStacked, true);
|
||||||
|
public static readonly BubbleGrouped = new TransactionExplorerChartType('Bubble Chart (Grouped)', TransactionExplorerChartTypeValue.BubbleGrouped, true);
|
||||||
|
|
||||||
public static readonly Default = TransactionExplorerChartType.Pie;
|
public static readonly Default = TransactionExplorerChartType.Pie;
|
||||||
|
|
||||||
|
|||||||
+30
-31
@@ -87,14 +87,14 @@ export interface CategoriedInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoriedTransactions extends CategoriedInfo {
|
export interface CategoriedTransactions extends CategoriedInfo {
|
||||||
trasactions: Record<string, SeriesedTransactions>;
|
trasactions: Record<string, SeriesTransactions>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoriedTransactionExplorerData extends CategoriedInfo {
|
export interface CategoriedTransactionExplorerData extends CategoriedInfo {
|
||||||
data: CategoriedTransactionExplorerDataItem[];
|
data: CategoriedTransactionExplorerDataItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeriesedInfo {
|
export interface SeriesInfo {
|
||||||
seriesName: string;
|
seriesName: string;
|
||||||
seriesNameNeedI18n?: boolean;
|
seriesNameNeedI18n?: boolean;
|
||||||
seriesNameI18nParameters?: Record<string, string>;
|
seriesNameI18nParameters?: Record<string, string>;
|
||||||
@@ -103,11 +103,11 @@ export interface SeriesedInfo {
|
|||||||
seriesDisplayOrders: number[];
|
seriesDisplayOrders: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeriesedTransactions extends SeriesedInfo {
|
export interface SeriesTransactions extends SeriesInfo {
|
||||||
trasactions: TransactionInsightDataItem[];
|
trasactions: TransactionInsightDataItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoriedTransactionExplorerDataItem extends SeriesedInfo {
|
export interface CategoriedTransactionExplorerDataItem extends SeriesInfo {
|
||||||
value: number;
|
value: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,23 +396,23 @@ export const useExplorersStore = defineStore('explorers', () => {
|
|||||||
categoriedDataMap[categoriedInfo.categoryId] = categoriedData;
|
categoriedDataMap[categoriedInfo.categoryId] = categoriedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const seriesedInfo = getDataCategoryInfo(timezoneUsedForDateRange, seriesDemension, queryName, queryIndex, transaction);
|
const seriesInfo = getDataCategoryInfo(timezoneUsedForDateRange, seriesDemension, queryName, queryIndex, transaction);
|
||||||
let seriesedData = categoriedData.trasactions[seriesedInfo.categoryId];
|
let seriesData = categoriedData.trasactions[seriesInfo.categoryId];
|
||||||
|
|
||||||
if (!seriesedData) {
|
if (!seriesData) {
|
||||||
seriesedData = {
|
seriesData = {
|
||||||
seriesName: seriesedInfo.categoryName,
|
seriesName: seriesInfo.categoryName,
|
||||||
seriesNameNeedI18n: seriesedInfo.categoryNameNeedI18n,
|
seriesNameNeedI18n: seriesInfo.categoryNameNeedI18n,
|
||||||
seriesNameI18nParameters: seriesedInfo.categoryNameI18nParameters,
|
seriesNameI18nParameters: seriesInfo.categoryNameI18nParameters,
|
||||||
seriesId: seriesedInfo.categoryId,
|
seriesId: seriesInfo.categoryId,
|
||||||
seriesIdType: seriesedInfo.categoryIdType,
|
seriesIdType: seriesInfo.categoryIdType,
|
||||||
seriesDisplayOrders: seriesedInfo.categoryDisplayOrders,
|
seriesDisplayOrders: seriesInfo.categoryDisplayOrders,
|
||||||
trasactions: []
|
trasactions: []
|
||||||
};
|
};
|
||||||
categoriedData.trasactions[seriesedInfo.categoryId] = seriesedData;
|
categoriedData.trasactions[seriesInfo.categoryId] = seriesData;
|
||||||
}
|
}
|
||||||
|
|
||||||
seriesedData.trasactions.push(transaction);
|
seriesData.trasactions.push(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadInsightsExplorerList(explorers: InsightsExplorerBasicInfo[]): void {
|
function loadInsightsExplorerList(explorers: InsightsExplorerBasicInfo[]): void {
|
||||||
@@ -633,18 +633,17 @@ export const useExplorersStore = defineStore('explorers', () => {
|
|||||||
|
|
||||||
for (const categoriedTransactions of values(categoriedDataMap)) {
|
for (const categoriedTransactions of values(categoriedDataMap)) {
|
||||||
const dataItems: CategoriedTransactionExplorerDataItem[] = [];
|
const dataItems: CategoriedTransactionExplorerDataItem[] = [];
|
||||||
let allSeriesedTransactions: Record<string, SeriesedTransactions> = categoriedTransactions.trasactions;
|
let allSeriesTransactions: Record<string, SeriesTransactions> = categoriedTransactions.trasactions;
|
||||||
|
|
||||||
// merge all series into one for pie/radar chart
|
if (!chartType.seriesDimensionRequired) {
|
||||||
if (chartType === TransactionExplorerChartType.Pie || chartType === TransactionExplorerChartType.Radar) {
|
|
||||||
const transactions: TransactionInsightDataItem[] = [];
|
const transactions: TransactionInsightDataItem[] = [];
|
||||||
|
|
||||||
for (const seriesedTransactions of values(categoriedTransactions.trasactions)) {
|
for (const seriesTransactions of values(categoriedTransactions.trasactions)) {
|
||||||
transactions.push(...seriesedTransactions.trasactions);
|
transactions.push(...seriesTransactions.trasactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
allSeriesedTransactions = {};
|
allSeriesTransactions = {};
|
||||||
allSeriesedTransactions['none'] = {
|
allSeriesTransactions['none'] = {
|
||||||
seriesName: valueMetric?.name ?? 'Unknown',
|
seriesName: valueMetric?.name ?? 'Unknown',
|
||||||
seriesNameNeedI18n: true,
|
seriesNameNeedI18n: true,
|
||||||
seriesId: 'none',
|
seriesId: 'none',
|
||||||
@@ -654,13 +653,13 @@ export const useExplorersStore = defineStore('explorers', () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const seriesedTransactions of values(allSeriesedTransactions)) {
|
for (const seriesTransactions of values(allSeriesTransactions)) {
|
||||||
const allSourceAmountsInDefaultCurrency: number[] = [];
|
const allSourceAmountsInDefaultCurrency: number[] = [];
|
||||||
let totalSourceAmountSumInDefaultCurrency: number = 0;
|
let totalSourceAmountSumInDefaultCurrency: number = 0;
|
||||||
let minimumSourceAmountInDefaultCurrency: number = Number.MAX_SAFE_INTEGER;
|
let minimumSourceAmountInDefaultCurrency: number = Number.MAX_SAFE_INTEGER;
|
||||||
let maximumSourceAmountInDefaultCurrency: number = Number.MIN_SAFE_INTEGER;
|
let maximumSourceAmountInDefaultCurrency: number = Number.MIN_SAFE_INTEGER;
|
||||||
|
|
||||||
for (const transaction of seriesedTransactions.trasactions) {
|
for (const transaction of seriesTransactions.trasactions) {
|
||||||
let amountInDefaultCurrency: number = transaction.sourceAmount;
|
let amountInDefaultCurrency: number = transaction.sourceAmount;
|
||||||
|
|
||||||
if (transaction.sourceAccount.currency !== defaultCurrency) {
|
if (transaction.sourceAccount.currency !== defaultCurrency) {
|
||||||
@@ -707,12 +706,12 @@ export const useExplorersStore = defineStore('explorers', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dataItems.push({
|
dataItems.push({
|
||||||
seriesName: seriesedTransactions.seriesName,
|
seriesName: seriesTransactions.seriesName,
|
||||||
seriesNameNeedI18n: seriesedTransactions.seriesNameNeedI18n,
|
seriesNameNeedI18n: seriesTransactions.seriesNameNeedI18n,
|
||||||
seriesNameI18nParameters: seriesedTransactions.seriesNameI18nParameters,
|
seriesNameI18nParameters: seriesTransactions.seriesNameI18nParameters,
|
||||||
seriesId: seriesedTransactions.seriesId,
|
seriesId: seriesTransactions.seriesId,
|
||||||
seriesIdType: seriesedTransactions.seriesIdType,
|
seriesIdType: seriesTransactions.seriesIdType,
|
||||||
seriesDisplayOrders: seriesedTransactions.seriesDisplayOrders,
|
seriesDisplayOrders: seriesTransactions.seriesDisplayOrders,
|
||||||
value: value
|
value: value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -763,6 +763,10 @@ watch(() => display.mdAndUp.value, (newValue) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
watch(activeTab, () => {
|
watch(activeTab, () => {
|
||||||
|
if (initing.value || loading.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
router.push(getFilterLinkUrl());
|
router.push(getFilterLinkUrl());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@
|
|||||||
:disabled="loading || disabled"
|
:disabled="loading || disabled"
|
||||||
:label="tt('Axis / Category')"
|
:label="tt('Axis / Category')"
|
||||||
:items="allTransactionExplorerDataDimensions"
|
:items="allTransactionExplorerDataDimensions"
|
||||||
v-model="currentExplorer.categoryDimension"
|
:model-value="currentExplorer.categoryDimension"
|
||||||
|
@update:model-value="updateCategoryDimensionType"
|
||||||
/>
|
/>
|
||||||
<v-select
|
<v-select
|
||||||
class="flex-0-0"
|
class="flex-0-0"
|
||||||
@@ -83,7 +84,6 @@
|
|||||||
id-field="id"
|
id-field="id"
|
||||||
name-field="name"
|
name-field="name"
|
||||||
value-field="value"
|
value-field="value"
|
||||||
color-field="color"
|
|
||||||
v-if="loading"
|
v-if="loading"
|
||||||
/>
|
/>
|
||||||
<pie-chart
|
<pie-chart
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
@click="onClickPieChartItem"
|
@click="onClickPieChartItem"
|
||||||
/>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-text :class="{ 'readonly': loading }" v-if="currentExplorer.chartType === TransactionExplorerChartType.Radar.value">
|
<v-card-text :class="{ 'readonly': loading }" v-else-if="currentExplorer.chartType === TransactionExplorerChartType.Radar.value">
|
||||||
<radar-chart
|
<radar-chart
|
||||||
:items="[
|
:items="[
|
||||||
{name: '---', value: 10},
|
{name: '---', value: 10},
|
||||||
@@ -127,10 +127,47 @@
|
|||||||
v-else-if="!loading"
|
v-else-if="!loading"
|
||||||
/>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
<v-card-text :class="{ 'readonly': loading }" v-else-if="TransactionExplorerChartType.valueOf(currentExplorer.chartType)?.seriesDimensionRequired && axisChartDisplayType">
|
||||||
|
<axis-chart
|
||||||
|
:skeleton="true"
|
||||||
|
:type="axisChartDisplayType"
|
||||||
|
:sorting-type="currentExplorer.chartSortingType"
|
||||||
|
:all-category-names="[]"
|
||||||
|
:items="[]"
|
||||||
|
category-type-name=""
|
||||||
|
name-field="name"
|
||||||
|
values-field="values"
|
||||||
|
v-if="loading"
|
||||||
|
/>
|
||||||
|
<axis-chart
|
||||||
|
ref="axisChart"
|
||||||
|
:type="axisChartDisplayType"
|
||||||
|
:stacked="axisChartStacked"
|
||||||
|
:one-hundred-percent-stacked="axisChart100PercentStacked"
|
||||||
|
:sorting-type="currentExplorer.chartSortingType"
|
||||||
|
:show-value="true"
|
||||||
|
:show-total-amount-in-tooltip="true"
|
||||||
|
:total-name-in-tooltip="currentExplorer.valueMetric === TransactionExplorerValueMetric.TransactionCount.value ? tt('Total Transactions') : tt('Total Amount')"
|
||||||
|
:category-type-name="currentTransactionExplorerCategoryDimensionName"
|
||||||
|
:all-category-names="categoriedNamesSortedByDisplayOrder"
|
||||||
|
:items="seriesDimensionTransactionExplorerData"
|
||||||
|
:amount-value="currentExplorer.valueMetric !== TransactionExplorerValueMetric.TransactionCount.value"
|
||||||
|
:default-currency="defaultCurrency"
|
||||||
|
:enable-click-item="true"
|
||||||
|
id-field="id"
|
||||||
|
name-field="name"
|
||||||
|
values-field="categoryValues"
|
||||||
|
display-orders-field="displayOrders"
|
||||||
|
@click="onClickTrendChartItem"
|
||||||
|
v-else-if="!loading"
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import AxisChart, { type AxisChartDisplayType } from '@/components/desktop/AxisChart.vue';
|
||||||
|
|
||||||
|
import { computed, useTemplateRef } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
@@ -138,13 +175,16 @@ import { useI18n } from '@/locales/helpers.ts';
|
|||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import {
|
import {
|
||||||
type CategoriedInfo,
|
type CategoriedInfo,
|
||||||
type SeriesedInfo,
|
type CategoriedTransactionExplorerData,
|
||||||
|
type SeriesInfo,
|
||||||
|
type CategoriedTransactionExplorerDataItem,
|
||||||
TransactionExplorerDimensionType,
|
TransactionExplorerDimensionType,
|
||||||
useExplorersStore
|
useExplorersStore
|
||||||
} from '@/stores/explorer.ts';
|
} from '@/stores/explorer.ts';
|
||||||
|
|
||||||
import { type NameValue, type TypeAndDisplayName } from '@/core/base.ts';
|
import { type NameValue, type TypeAndDisplayName } from '@/core/base.ts';
|
||||||
import { Month, WeekDay } from '@/core/datetime.ts';
|
import { Month, WeekDay } from '@/core/datetime.ts';
|
||||||
|
import { ChartSortingType } from '@/core/statistics.ts';
|
||||||
import {
|
import {
|
||||||
TransactionExplorerChartType,
|
TransactionExplorerChartType,
|
||||||
TransactionExplorerDataDimensionType,
|
TransactionExplorerDataDimensionType,
|
||||||
@@ -155,10 +195,12 @@ import {
|
|||||||
import { type SortableTransactionStatisticDataItem } from '@/models/transaction.ts';
|
import { type SortableTransactionStatisticDataItem } from '@/models/transaction.ts';
|
||||||
import type { InsightsExplorer } from '@/models/explorer.ts';
|
import type { InsightsExplorer } from '@/models/explorer.ts';
|
||||||
|
|
||||||
import { isDefined } from '@/lib/common.ts';
|
import { isDefined, findNameByValue } from '@/lib/common.ts';
|
||||||
import { parseDateTimeFromString } from '@/lib/datetime.ts';
|
import { parseDateTimeFromString } from '@/lib/datetime.ts';
|
||||||
import { sortStatisticsItems } from '@/lib/statistics.ts';
|
import { sortStatisticsItems } from '@/lib/statistics.ts';
|
||||||
|
|
||||||
|
type AxisChartType = InstanceType<typeof AxisChart>;
|
||||||
|
|
||||||
interface InsightsExplorerDataTableTabProps {
|
interface InsightsExplorerDataTableTabProps {
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -172,6 +214,22 @@ interface CategoryDimensionData extends SortableTransactionStatisticDataItem {
|
|||||||
totalAmount: number;
|
totalAmount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SortableCategoriedTransactionExplorerDataItem extends SortableTransactionStatisticDataItem {
|
||||||
|
name: string;
|
||||||
|
displayOrders: number[];
|
||||||
|
totalAmount: number;
|
||||||
|
originalItem: CategoriedTransactionExplorerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SeriesDimensionData extends SortableTransactionStatisticDataItem, Record<string, unknown> {
|
||||||
|
id: string;
|
||||||
|
dimension: TransactionExplorerDimensionType;
|
||||||
|
name: string;
|
||||||
|
displayOrders: number[];
|
||||||
|
categoryValues: number[];
|
||||||
|
totalAmount: number;
|
||||||
|
}
|
||||||
|
|
||||||
defineProps<InsightsExplorerDataTableTabProps>();
|
defineProps<InsightsExplorerDataTableTabProps>();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -199,12 +257,15 @@ const {
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const explorersStore = useExplorersStore();
|
const explorersStore = useExplorersStore();
|
||||||
|
|
||||||
|
const axisChart = useTemplateRef<AxisChartType>('axisChart');
|
||||||
|
|
||||||
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
||||||
|
|
||||||
const allTransactionExplorerDataDimensions = computed<NameValue[]>(() => getAllTransactionExplorerDataDimensions());
|
const allTransactionExplorerDataDimensions = computed<NameValue[]>(() => getAllTransactionExplorerDataDimensions());
|
||||||
const allTransactionExplorerValueMetrics = computed<NameValue[]>(() => getAllTransactionExplorerValueMetrics());
|
const allTransactionExplorerValueMetrics = computed<NameValue[]>(() => getAllTransactionExplorerValueMetrics());
|
||||||
const allTransactionExplorerChartTypes = computed<NameValue[]>(() => getAllTransactionExplorerChartTypes());
|
const allTransactionExplorerChartTypes = computed<NameValue[]>(() => getAllTransactionExplorerChartTypes());
|
||||||
const allTransactionExplorerChartSortingTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsSortingTypes());
|
const allTransactionExplorerChartSortingTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsSortingTypes());
|
||||||
|
const currentTransactionExplorerCategoryDimensionName = computed<string>(() => findNameByValue(allTransactionExplorerDataDimensions.value, currentExplorer.value.categoryDimension) ?? tt('Unknown'));
|
||||||
|
|
||||||
const currentExplorer = computed<InsightsExplorer>(() => explorersStore.currentInsightsExplorer);
|
const currentExplorer = computed<InsightsExplorer>(() => explorersStore.currentInsightsExplorer);
|
||||||
|
|
||||||
@@ -242,7 +303,128 @@ const categoryDimensionTransactionExplorerData = computed<CategoryDimensionData[
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
function getCategoriedDataDisplayName(info: CategoriedInfo | SeriesedInfo): string {
|
const categoriedDataSortedByDisplayOrder = computed<SortableCategoriedTransactionExplorerDataItem[]>(() => {
|
||||||
|
if (!explorersStore.categoriedTransactionExplorerData || !explorersStore.categoriedTransactionExplorerData.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: SortableCategoriedTransactionExplorerDataItem[] = [];
|
||||||
|
|
||||||
|
for (const categoriedData of explorersStore.categoriedTransactionExplorerData) {
|
||||||
|
result.push({
|
||||||
|
name: getCategoriedDataDisplayName(categoriedData),
|
||||||
|
displayOrders: categoriedData.categoryDisplayOrders,
|
||||||
|
totalAmount: 0,
|
||||||
|
originalItem: categoriedData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sortStatisticsItems(result, ChartSortingType.DisplayOrder.type);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
const categoriedNamesSortedByDisplayOrder = computed<string[]>(() => {
|
||||||
|
if (!categoriedDataSortedByDisplayOrder.value || !categoriedDataSortedByDisplayOrder.value.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: string[] = [];
|
||||||
|
|
||||||
|
for (const categoriedData of categoriedDataSortedByDisplayOrder.value) {
|
||||||
|
result.push(categoriedData.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
const seriesDimensionTransactionExplorerData = computed<SeriesDimensionData[]>(() => {
|
||||||
|
if (!TransactionExplorerChartType.valueOf(currentExplorer.value.chartType)?.seriesDimensionRequired) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!explorersStore.categoriedTransactionExplorerData || !explorersStore.categoriedTransactionExplorerData.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: SeriesDimensionData[] = [];
|
||||||
|
const seriesDimensionDataMap: Record<string, SeriesDimensionData> = {};
|
||||||
|
|
||||||
|
for (const categoriedData of explorersStore.categoriedTransactionExplorerData) {
|
||||||
|
for (const seriesData of categoriedData.data) {
|
||||||
|
const displayName = getCategoriedDataDisplayName(seriesData);
|
||||||
|
let seriesDimensionData: SeriesDimensionData | undefined = seriesDimensionDataMap[seriesData.seriesId];
|
||||||
|
|
||||||
|
if (!seriesDimensionData) {
|
||||||
|
seriesDimensionData = {
|
||||||
|
id: seriesData.seriesId,
|
||||||
|
dimension: seriesData.seriesIdType,
|
||||||
|
name: displayName,
|
||||||
|
displayOrders: seriesData.seriesDisplayOrders,
|
||||||
|
categoryValues: [],
|
||||||
|
totalAmount: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
seriesDimensionDataMap[seriesData.seriesId] = seriesDimensionData;
|
||||||
|
result.push(seriesDimensionData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const categoriedData of categoriedDataSortedByDisplayOrder.value) {
|
||||||
|
const seriesDataMap: Record<string, CategoriedTransactionExplorerDataItem> = {};
|
||||||
|
|
||||||
|
for (const seriesData of categoriedData.originalItem.data) {
|
||||||
|
seriesDataMap[seriesData.seriesId] = seriesData;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const seriesDimensionData of result) {
|
||||||
|
const seriesData = seriesDataMap[seriesDimensionData.id];
|
||||||
|
|
||||||
|
if (isDefined(seriesData)) {
|
||||||
|
seriesDimensionData.categoryValues.push(seriesData.value);
|
||||||
|
seriesDimensionData.totalAmount += seriesData.value;
|
||||||
|
} else {
|
||||||
|
seriesDimensionData.categoryValues.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortStatisticsItems(result, currentExplorer.value.chartSortingType);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
const axisChartDisplayType = computed<AxisChartDisplayType | undefined>(() => {
|
||||||
|
if (currentExplorer.value.chartType === TransactionExplorerChartType.ColumnStacked.value
|
||||||
|
|| currentExplorer.value.chartType === TransactionExplorerChartType.Column100PercentStacked.value
|
||||||
|
|| currentExplorer.value.chartType === TransactionExplorerChartType.ColumnGrouped.value) {
|
||||||
|
return 'column';
|
||||||
|
} else if (currentExplorer.value.chartType === TransactionExplorerChartType.LineGrouped.value) {
|
||||||
|
return 'line';
|
||||||
|
} else if (currentExplorer.value.chartType === TransactionExplorerChartType.AreaStacked.value
|
||||||
|
|| currentExplorer.value.chartType === TransactionExplorerChartType.Area100PercentStacked.value) {
|
||||||
|
return 'area';
|
||||||
|
} else if (currentExplorer.value.chartType === TransactionExplorerChartType.BubbleGrouped.value) {
|
||||||
|
return 'bubble';
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const axisChartStacked = computed<boolean>(() => {
|
||||||
|
return (currentExplorer.value.chartType === TransactionExplorerChartType.ColumnStacked.value
|
||||||
|
|| currentExplorer.value.chartType === TransactionExplorerChartType.Column100PercentStacked.value
|
||||||
|
|| currentExplorer.value.chartType === TransactionExplorerChartType.AreaStacked.value
|
||||||
|
|| currentExplorer.value.chartType === TransactionExplorerChartType.Area100PercentStacked.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const axisChart100PercentStacked = computed<boolean>(() => {
|
||||||
|
return (currentExplorer.value.chartType === TransactionExplorerChartType.Column100PercentStacked.value
|
||||||
|
|| currentExplorer.value.chartType === TransactionExplorerChartType.Area100PercentStacked.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
function getCategoriedDataDisplayName(info: CategoriedInfo | SeriesInfo): string {
|
||||||
let name: string = '';
|
let name: string = '';
|
||||||
let needI18n: boolean | undefined = false;
|
let needI18n: boolean | undefined = false;
|
||||||
let i18nParameters: Record<string, unknown> | undefined = undefined;
|
let i18nParameters: Record<string, unknown> | undefined = undefined;
|
||||||
@@ -315,6 +497,16 @@ function getCategoriedDataDisplayName(info: CategoriedInfo | SeriesedInfo): stri
|
|||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateCategoryDimensionType(dimensionType: TransactionExplorerDataDimensionType): void {
|
||||||
|
if (currentExplorer.value.categoryDimension !== dimensionType) {
|
||||||
|
currentExplorer.value.categoryDimension = dimensionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentExplorer.value.seriesDimension === currentExplorer.value.categoryDimension) {
|
||||||
|
currentExplorer.value.seriesDimension = TransactionExplorerDataDimension.None.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onClickPieChartItem(item: Record<string, unknown>): void {
|
function onClickPieChartItem(item: Record<string, unknown>): void {
|
||||||
if (!item || !('id' in item) || !('dimension' in item)) {
|
if (!item || !('id' in item) || !('dimension' in item)) {
|
||||||
return;
|
return;
|
||||||
@@ -328,6 +520,18 @@ function onClickPieChartItem(item: Record<string, unknown>): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onClickTrendChartItem(itemId: string, categoryIndex: number): void {
|
||||||
|
const categoryData = categoriedDataSortedByDisplayOrder.value[categoryIndex];
|
||||||
|
|
||||||
|
if (categoryData) {
|
||||||
|
const params: string = explorersStore.getTransactionListPageParams(categoryData.originalItem.categoryIdType, categoryData.originalItem.categoryId);
|
||||||
|
|
||||||
|
if (params && categoryData.originalItem.categoryId !== 'none' && categoryData.originalItem.categoryId !== 'unknown') {
|
||||||
|
router.push(`/transaction/list?${params}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function buildExportResults(): { headers: string[], data: string[][] } | undefined {
|
function buildExportResults(): { headers: string[], data: string[][] } | undefined {
|
||||||
if (currentExplorer.value.chartType === TransactionExplorerChartType.Pie.value || currentExplorer.value.chartType === TransactionExplorerChartType.Radar.value) {
|
if (currentExplorer.value.chartType === TransactionExplorerChartType.Pie.value || currentExplorer.value.chartType === TransactionExplorerChartType.Radar.value) {
|
||||||
const valueMetric = TransactionExplorerValueMetric.valueOf(currentExplorer.value.valueMetric);
|
const valueMetric = TransactionExplorerValueMetric.valueOf(currentExplorer.value.valueMetric);
|
||||||
@@ -342,6 +546,8 @@ function buildExportResults(): { headers: string[], data: string[][] } | undefin
|
|||||||
valueMetric?.isAmount ? formatAmountToWesternArabicNumeralsWithoutDigitGrouping(data.totalAmount) : data.totalAmount.toString(10)
|
valueMetric?.isAmount ? formatAmountToWesternArabicNumeralsWithoutDigitGrouping(data.totalAmount) : data.totalAmount.toString(10)
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
|
} else if (TransactionExplorerChartType.valueOf(currentExplorer.value.chartType)?.seriesDimensionRequired && axisChartDisplayType.value) {
|
||||||
|
return axisChart.value?.exportData();
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user