feat(charts): enhance tooltip functionality and improve data sorting logic

This commit is contained in:
CaIon 2026-04-29 10:23:15 +08:00
parent 75af3db11f
commit 438410708f
No known key found for this signature in database
GPG Key ID: 0CFA613529A9921D

View File

@ -9,6 +9,16 @@ import type {
} from '@/features/dashboard/types'
type TFunction = (key: string) => string
type TooltipLineItem = {
key: string
value: string | number
datum?: Record<string, unknown>
hasShape?: boolean
shapeType?: string
shapeFill?: string
shapeStroke?: string
shapeSize?: number
}
function getVChartDefaultColors(domainLength: number) {
const scheme =
@ -19,15 +29,6 @@ function getVChartDefaultColors(domainLength: number) {
return scheme.scheme
}
function buildModelColorSpec(models: string[]) {
const domain = Array.from(new Set(models))
return {
type: 'ordinal',
domain,
range: getVChartDefaultColors(domain.length),
}
}
function renderQuotaCompat(rawQuota: number, digits = 4): string {
const { config, meta } = getCurrencyDisplay()
if (meta.kind === 'tokens') return rawQuota.toLocaleString()
@ -59,19 +60,24 @@ export function processChartData(
const formatQuotaTotal = (value: number) => renderQuotaCompat(value, 2)
const MAX_TOOLTIP_MODELS = 15
const isOtherTooltipKey = (key: string) =>
key === 'Other' || key === otherLabel
const makeTooltipDimensionUpdateContent = (options?: {
collapseOverflow?: boolean
}) => {
const collapseOverflow = options?.collapseOverflow ?? true
return (array: TooltipLineItem[]) => {
const modelItems = array.filter((item) => !isOtherTooltipKey(item.key))
const otherItems = array.filter((item) => isOtherTooltipKey(item.key))
modelItems.sort(
(a, b) => (Number(b.value) || 0) - (Number(a.value) || 0)
)
array = [...modelItems, ...otherItems]
const makeTooltipDimensionUpdateContent = () => {
return (
array: Array<{
key: string
value: string | number
datum?: Record<string, unknown>
}>
) => {
array.sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
let sum = 0
for (let i = 0; i < array.length; i++) {
if (array[i].key === 'Other' || array[i].key === otherLabel) continue
const v = Number(array[i].value) || 0
if (
array[i].datum &&
@ -83,20 +89,27 @@ export function processChartData(
array[i].value = formatQuotaValue(v)
}
if (array.length > MAX_TOOLTIP_MODELS) {
const visible = array.slice(0, MAX_TOOLTIP_MODELS)
let otherSum = 0
for (let i = MAX_TOOLTIP_MODELS; i < array.length; i++) {
const raw = array[i].datum
? Number((array[i].datum as Record<string, unknown>)?.rawQuota) || 0
: 0
otherSum += raw
}
visible.push({
key: otherLabel,
value: formatQuotaValue(otherSum),
})
array = visible
if (collapseOverflow && array.length > MAX_TOOLTIP_MODELS) {
const visible = modelItems.slice(0, MAX_TOOLTIP_MODELS)
const otherSum = [...modelItems.slice(MAX_TOOLTIP_MODELS), ...otherItems]
.reduce((sum, item) => {
const raw = item.datum
? Number((item.datum as Record<string, unknown>)?.rawQuota) || 0
: 0
return sum + raw
}, 0)
array = [
...visible,
{
key: otherLabel,
value: formatQuotaValue(otherSum),
hasShape: true,
shapeType: 'square',
shapeFill: otherTooltipColor,
shapeStroke: otherTooltipColor,
shapeSize: 8,
},
]
}
array.unshift({
@ -226,7 +239,16 @@ export function processChartData(
const allModels = Array.from(modelTotalsMap.keys())
const sortedTimes = Array.from(timeModelMap.keys()).sort()
const sortedModels = [...allModels].sort()
const modelColor = buildModelColorSpec([...sortedModels, otherLabel])
const modelColorDomain = Array.from(new Set([...sortedModels, otherLabel]))
const modelColorRange = getVChartDefaultColors(modelColorDomain.length)
const otherColor = modelColorRange[modelColorDomain.indexOf(otherLabel)]
const otherTooltipColor =
typeof otherColor === 'string' ? otherColor : '#FF8A00'
const modelColor = {
type: 'ordinal',
domain: modelColorDomain,
range: modelColorRange,
}
// Pad time points if too few (default 7 points)
const MAX_TREND_POINTS = MAX_CHART_TREND_POINTS
@ -508,7 +530,9 @@ export function processChartData(
Number(datum?.rawQuota) || 0,
},
],
updateContent: makeTooltipDimensionUpdateContent(),
updateContent: makeTooltipDimensionUpdateContent({
collapseOverflow: false,
}),
},
},
area: {
@ -564,9 +588,17 @@ export function processChartData(
value: string | number
}>
) => {
array.sort(
const modelItems = array.filter(
(item) => !isOtherTooltipKey(item.key)
)
const otherItems = array.filter((item) =>
isOtherTooltipKey(item.key)
)
modelItems.sort(
(a, b) => (Number(b.value) || 0) - (Number(a.value) || 0)
)
array = [...modelItems, ...otherItems]
let sum = 0
for (let i = 0; i < array.length; i++) {
const v = Number(array[i].value) || 0