display all data in statistics & analysis and hide percentages with values below zero

This commit is contained in:
MaysWind
2026-01-16 01:20:29 +08:00
parent 83a34ae322
commit e304f4d3fa
9 changed files with 67 additions and 51 deletions
+16 -10
View File
@@ -13,8 +13,9 @@ export interface CommonPieChartDataItem {
name: string;
displayName: string;
value: number;
actualValue: number;
percent: number;
actualPercent: number;
paintPercent: number;
color: ColorStyleValue;
sourceItem: Record<string, unknown>;
displayPercent?: string;
@@ -30,7 +31,6 @@ export interface CommonPieChartProps {
percentField?: string;
colorField?: string;
hiddenField?: string;
minValidPercent?: number;
amountValue?: boolean;
defaultCurrency?: string;
showValue?: boolean;
@@ -55,32 +55,38 @@ export function usePieChartBase(props: CommonPieChartProps) {
}
const validItems: CommonPieChartDataItem[] = [];
let accumulatedPaintPercent: number = 0;
for (const item of props.items) {
const value = item[props.valueField];
const percent = props.percentField ? item[props.percentField] : -1;
if (isNumber(value) && value > 0 &&
(!props.hiddenField || !item[props.hiddenField]) &&
(!props.minValidPercent || value / totalValidValue > props.minValidPercent)) {
if (isNumber(value) &&
(!props.hiddenField || !item[props.hiddenField])) {
const finalItem: CommonPieChartDataItem = {
id: (props.idField && item[props.idField]) ? item[props.idField] as string : item[props.nameField] as string,
name: (props.idField && item[props.idField]) ? item[props.idField] as string : item[props.nameField] as string,
displayName: item[props.nameField] as string,
value: value,
percent: (isNumber(percent) && percent >= 0) ? percent : (value / totalValidValue * 100),
actualPercent: value / totalValidValue,
value: value > 0 ? value : 0,
actualValue: value,
percent: (isNumber(percent) && percent >= 0) ? percent : (value > 0 ? value / totalValidValue * 100 : 0),
paintPercent: value > 0 ? value / totalValidValue : 0,
color: getDisplayColor((props.colorField && item[props.colorField]) ? item[props.colorField] as ColorValue : DEFAULT_CHART_COLORS[validItems.length % DEFAULT_CHART_COLORS.length]),
sourceItem: item
};
finalItem.displayPercent = formatPercentToLocalizedNumerals(finalItem.percent, 2, '&lt;0.01');
finalItem.displayValue = props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(finalItem.value, props.defaultCurrency) : finalItem.value.toString();
accumulatedPaintPercent += finalItem.paintPercent;
finalItem.displayPercent = formatPercentToLocalizedNumerals(finalItem.percent, 2, '<0.01');
finalItem.displayValue = props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(value, props.defaultCurrency) : value.toString();
validItems.push(finalItem);
}
}
if (validItems.length > 0) {
validItems[validItems.length - 1]!.paintPercent += 1 - accumulatedPaintPercent;
}
return validItems;
});
@@ -267,7 +267,7 @@ const chartOptions = computed<object>(() => {
}
if (isNumber(dataItem.percent) && dataItem.percent > 0) {
const displayPercent = formatPercentToLocalizedNumerals(dataItem.percent, 2, '&lt;0.01');
const displayPercent = formatPercentToLocalizedNumerals(dataItem.percent, 2, '<0.01');
tooltip += `<span class="ms-1" style="float: inline-end">(${displayPercent})</span>`;
}
+1 -1
View File
@@ -396,7 +396,7 @@ function getItemName(name: string): string {
function getDisplayValue(value: number): string {
if (props.oneHundredPercentStacked) {
return formatPercentToLocalizedNumerals(value, 2, '&lt;0.01');
return formatPercentToLocalizedNumerals(value, 2, '<0.01');
}
if (props.amountValue) {
+6 -3
View File
@@ -142,11 +142,14 @@ const chartOptions = computed<object>(() => {
tooltip += `<div class="d-inline-flex">${name}</div><br/>`;
}
if (props.showValue && props.showPercent) {
const showValue = props.showValue;
const showPercent = props.showPercent && params.value && (params.value as number) > 0;
if (showValue && showPercent) {
tooltip += `<div class="d-inline-flex"><span>${value}</span><span class="ms-1">(${percent})</span></div>`;
} else if (props.showValue && !props.showPercent) {
} else if (showValue && !showPercent) {
tooltip += `<div class="d-inline-flex">${value}</div>`;
} else if (!props.showValue && props.showPercent) {
} else if (!showValue && showPercent) {
tooltip += `<div class="d-inline-flex">${percent}</div>`;
}
+11 -10
View File
@@ -37,7 +37,6 @@ const props = defineProps<{
percentField?: string;
colorField?: string;
hiddenField?: string;
minValidPercent?: number;
amountValue?: boolean;
defaultCurrency?: string;
showValue?: boolean;
@@ -74,14 +73,13 @@ const radarData = computed<RadarChartData>(() => {
const value = item[props.valueField];
const percent = props.percentField ? item[props.percentField] : -1;
if (isNumber(value) && value > 0 &&
(!props.hiddenField || !item[props.hiddenField]) &&
(!props.minValidPercent || value / totalValidValue > props.minValidPercent)) {
if (isNumber(value) &&
(!props.hiddenField || !item[props.hiddenField])) {
const name = item[props.nameField] as string;
const color = getDisplayColor((props.colorField && item[props.colorField]) ? item[props.colorField] as ColorValue : DEFAULT_CHART_COLORS[indicators.length % DEFAULT_CHART_COLORS.length]);
const finalPercent = (isNumber(percent) && percent >= 0) ? percent : (value / totalValidValue * 100);
const displayPercent = formatPercentToLocalizedNumerals(finalPercent, 2, '&lt;0.01');
const finalPercent = (isNumber(percent) && percent >= 0) ? percent : (value > 0 ? value / totalValidValue * 100 : 0);
const displayPercent = formatPercentToLocalizedNumerals(finalPercent, 2, '<0.01');
const displayValue = props.amountValue ? formatAmountToLocalizedNumeralsWithCurrency(value, props.defaultCurrency) : value.toString();
indicators.push({
@@ -90,16 +88,19 @@ const radarData = computed<RadarChartData>(() => {
color: isDarkMode.value ? '#ccc' : '#333'
});
values.push(value);
values.push(value > 0 ? value : 0);
tooltip += '<div><span class="chart-pointer" style="background-color: ' + color + '"></span>';
tooltip += `<span>${name}</span>`;
if (props.showValue && props.showPercent) {
const showValue = props.showValue;
const showPercent = props.showPercent && value > 0;
if (showValue && showPercent) {
tooltip += `<span class="ms-1" style="float: inline-end">(${displayPercent})</span><span class="ms-5" style="float: inline-end">${displayValue}</span>`;
} else if (props.showValue && !props.showPercent) {
} else if (showValue && !showPercent) {
tooltip += `<span class="ms-5" style="float: inline-end">${displayValue}</span>`;
} else if (!props.showValue && props.showPercent) {
} else if (!showValue && showPercent) {
tooltip += `<span class="ms-5" style="float: inline-end">${displayPercent}</span>`;
}
+30 -20
View File
@@ -3,18 +3,19 @@
<svg class="pie-chart" :viewBox="`${-diameter} ${-diameter} ${diameter * 2} ${diameter * 2}`">
<circle class="pie-chart-background" cx="0" cy="0" :r="diameter"></circle>
<circle class="pie-chart-item"
fill="transparent"
cx="0" cy="0"
:r="diameter / 2"
:stroke="item.color"
:stroke-width="diameter"
:stroke-dasharray="getItemStrokeDash(item)"
:stroke-dashoffset="getItemDashOffset(item, validItems, itemCommonDashOffset)"
:key="idx"
v-for="(item, idx) in validItems"
@click="switchSelectedIndex(idx)">
</circle>
<template :key="idx" v-for="(item, idx) in validItems">
<circle class="pie-chart-item"
fill="transparent"
cx="0" cy="0"
:r="diameter / 2"
:stroke="item.color"
:stroke-width="diameter"
:stroke-dasharray="getItemStrokeDash(item)"
:stroke-dashoffset="getItemDashOffset(item, validItems, itemCommonDashOffset)"
@click="switchSelectedIndex(idx)"
v-if="item.actualValue > 0 && item.paintPercent > minPaintPercent">
</circle>
</template>
<circle class="pie-chart-text-background"
cx="0" cy="0"
@@ -44,7 +45,7 @@
</f7-link>
<div class="pie-chart-toolbox-info">
<p v-if="showPercent && selectedItem">
<p v-if="showPercent && selectedItem && selectedItem.actualValue >= 0">
<f7-chip class="chip-placeholder" outline v-if="skeleton">
<span class="skeleton-text">Percent</span>
</f7-chip>
@@ -53,7 +54,7 @@
:style="getColorStyle(selectedItem?.color, '--f7-chip-outline-border-color')"
v-else-if="!skeleton"></f7-chip>
</p>
<p v-else-if="showPercent && (!validItems || !validItems.length)">
<p v-else-if="showPercent && (!validItems || !validItems.length || !selectedItem || selectedItem.actualValue < 0)">
<f7-chip outline text="---"></f7-chip>
</p>
<f7-link class="pie-chart-selected-item-info" :no-link-class="!enableClickItem" v-if="selectedItem" @click="clickItem(selectedItem)">
@@ -99,6 +100,7 @@ const emit = defineEmits<{
const { tt } = useI18n();
const { selectedIndex, validItems } = usePieChartBase(props);
const minPaintPercent = 0.0001; // 0.01%
const diameter: number = 100;
const circumference: number = diameter * Math.PI;
@@ -106,7 +108,9 @@ const totalValidValue = computed<number>(() => {
let totalValidValue = 0;
for (const item of validItems.value) {
totalValidValue += item.value;
if (item.actualValue > 0 && item.paintPercent > minPaintPercent) {
totalValidValue += item.value;
}
}
return totalValidValue;
@@ -122,11 +126,17 @@ const itemCommonDashOffset = computed<number>(() => {
for (let i = 0; i < Math.min(selectedIndex.value + 1, validItems.value.length); i++) {
const item = validItems.value[i] as CommonPieChartDataItem;
if (item.actualPercent > 0) {
if (item.actualValue > 0 && item.paintPercent > minPaintPercent) {
if (i === selectedIndex.value) {
offset += -circumference * (1 - item.actualPercent) / 2;
offset += -circumference * (1 - item.paintPercent) / 2;
} else {
offset += -circumference * (1 - item.actualPercent);
offset += -circumference * (1 - item.paintPercent);
}
} else {
if (i === selectedIndex.value) {
offset += -circumference / 2;
} else {
offset += -circumference;
}
}
}
@@ -147,7 +157,7 @@ function getColorStyle(color: ColorStyleValue, additionalFieldName?: string): Re
}
function getItemStrokeDash(item: CommonPieChartDataItem): string {
const length = item.actualPercent * circumference;
const length = item.paintPercent * circumference;
return `${length} ${circumference - length}`;
}
@@ -159,7 +169,7 @@ function getItemDashOffset(item: CommonPieChartDataItem, items: CommonPieChartDa
break;
}
allPreviousPercent += curItem.actualPercent;
allPreviousPercent += curItem.paintPercent > 0 ? curItem.paintPercent : 0;
}
if (offset) {
@@ -117,7 +117,6 @@
/>
<radar-chart
:items="categoryDimensionTransactionExplorerData && categoryDimensionTransactionExplorerData.length ? categoryDimensionTransactionExplorerData : []"
:min-valid-percent="0.0001"
:show-value="true"
:show-percent="true"
:amount-value="currentExplorer.valueMetric !== TransactionExplorerValueMetric.TransactionCount.value"
@@ -263,7 +263,6 @@
/>
<pie-chart
:items="categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length ? categoricalAnalysisData.items : []"
:min-valid-percent="0.0001"
:show-value="showAmountInChart"
:show-percent="showPercentInCategoricalChart"
:enable-click-item="true"
@@ -316,7 +315,7 @@
<div class="d-flex flex-column ms-2">
<div class="d-flex">
<span>{{ item.name }}</span>
<small class="statistics-percent" v-if="showPercentInCategoricalChart && item.percent >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '&lt;0.01') }}</small>
<small class="statistics-percent" v-if="showPercentInCategoricalChart && item.percent >= 0 && item.totalAmount >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '<0.01') }}</small>
<v-spacer/>
<span class="statistics-amount">{{ getDisplayAmount(item.totalAmount, defaultCurrency) }}</span>
</div>
@@ -351,7 +350,6 @@
/>
<radar-chart
:items="categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length ? categoricalAnalysisData.items : []"
:min-valid-percent="0.0001"
:show-value="showAmountInChart"
:show-percent="showPercentInCategoricalChart"
:amount-value="true"
@@ -80,7 +80,6 @@
></pie-chart>
<pie-chart
:items="categoricalAnalysisData.items"
:min-valid-percent="0.0001"
:show-value="showAmountInChart"
:show-percent="showPercentInCategoricalChart"
:show-center-text="true"
@@ -183,7 +182,7 @@
<template #title>
<div class="statistics-list-item-text">
<span>{{ item.name }}</span>
<small class="statistics-percent" v-if="showPercentInCategoricalChart && item.percent >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '&lt;0.01') }}</small>
<small class="statistics-percent" v-if="showPercentInCategoricalChart && item.percent >= 0 && item.totalAmount >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '<0.01') }}</small>
</div>
</template>