fix: convert areachart to working barchart in trend-chart.svelte and fixed empty data issue (#930)

Co-authored-by: richarddkenneth <[email protected]>
This commit is contained in:
Richard Kenneth
2026-08-18 17:20:57 +01:00
committed by GitHub
co-authored by richarddkenneth
parent 913db2a525
commit ce663fe365
9 changed files with 210 additions and 169 deletions
+33 -20
View File
@@ -1,8 +1,8 @@
<script lang="ts">
import { getChartContext, Tooltip as TooltipPrimitive } from 'layerchart';
import { cn, type WithElementRef, type WithoutChildren } from '../../tools';
import type { HTMLAttributes } from 'svelte/elements';
import { getPayloadConfigFromPayload, useChart, type TooltipPayload } from './chart-utils';
import { getTooltipContext, Tooltip as TooltipPrimitive } from 'layerchart';
import type { Snippet } from 'svelte';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -48,27 +48,39 @@
} = $props();
const chart = useChart();
const tooltipCtx = getTooltipContext();
const chartCtx = getChartContext();
const visibleSeries = $derived(chartCtx.tooltip.series.filter((s) => s.value !== undefined));
const formattedLabel = $derived.by(() => {
if (hideLabel || !tooltipCtx.payload?.length) return null;
if (hideLabel || !visibleSeries?.length) return null;
const [item] = tooltipCtx.payload;
const key = labelKey ?? item?.label ?? item?.name ?? 'value';
const [item] = visibleSeries;
const tooltipData = chartCtx.tooltip.data;
const itemConfig = getPayloadConfigFromPayload(chart.config, item, key);
const dataLabel = tooltipData != null ? chartCtx.x(tooltipData) : undefined;
const value =
!labelKey && typeof label === 'string'
? (chart.config[label as keyof typeof chart.config]?.label ?? label)
: (itemConfig?.label ?? item.label);
const key = labelKey ?? item?.label ?? 'value';
let value: unknown;
if (!labelKey && typeof label === 'string') {
value = chart.config[label as keyof typeof chart.config]?.label ?? label;
} else {
const itemConfig = getPayloadConfigFromPayload(
chart.config,
item,
key,
tooltipData as Record<string, unknown> | null
);
value = itemConfig?.label ?? dataLabel;
}
if (value === undefined) return null;
if (!labelFormatter) return value;
return labelFormatter(value, tooltipCtx.payload);
return labelFormatter(value, visibleSeries);
});
const nestLabel = $derived(tooltipCtx.payload.length === 1 && indicator !== 'dot');
const nestLabel = $derived(visibleSeries.length === 1 && indicator !== 'dot');
</script>
{#snippet TooltipLabel()}
@@ -85,6 +97,7 @@
<TooltipPrimitive.Root variant="none">
<div
bind:this={ref}
class={cn(
'ui:border-border/50 ui:bg-background ui:grid ui:min-w-[9rem] ui:items-start ui:gap-1.5 ui:rounded-lg ui:border ui:px-2.5 ui:py-1.5 ui:text-xs ui:shadow-xl',
className
@@ -95,23 +108,23 @@
{@render TooltipLabel()}
{/if}
<div class="ui:grid ui:gap-1.5">
{#each tooltipCtx.payload as item, i (item.key + i)}
{@const key = `${nameKey || item.key || item.name || 'value'}`}
{@const itemConfig = getPayloadConfigFromPayload(chart.config, item, key)}
{@const indicatorColor = color || item.payload?.color || item.color}
{#each visibleSeries as item, i (item.key + i)}
{@const key = `${nameKey || item.key || item.label || 'value'}`}
{@const itemConfig = getPayloadConfigFromPayload(chart.config, item, key, chartCtx.tooltip.data)}
{@const indicatorColor = color || item.config?.color || item.color}
<div
class={cn(
'ui:[&>svg]:text-muted-foreground ui:flex ui:w-full ui:flex-wrap ui:items-stretch ui:gap-2 ui:[&>svg]:size-2.5',
indicator === 'dot' && 'ui:items-center'
)}
>
{#if formatter && item.value !== undefined && item.name}
{#if formatter && item.value !== undefined && item.label}
{@render formatter({
value: item.value,
name: item.name,
name: item.label,
item,
index: i,
payload: tooltipCtx.payload
payload: visibleSeries
})}
{:else}
{#if itemConfig?.icon}
@@ -138,7 +151,7 @@
{@render TooltipLabel()}
{/if}
<span class="ui:text-muted-foreground">
{itemConfig?.label || item.name}
{itemConfig?.label || item.label}
</span>
</div>
{#if item.value !== undefined}
+19 -13
View File
@@ -1,5 +1,5 @@
import type { Tooltip } from 'layerchart';
import { getContext, setContext, type Component, type ComponentProps, type Snippet } from 'svelte';
import { getContext, setContext, type Snippet } from 'svelte';
import type { ChartConfig } from './types';
export type { ChartConfig } from './types';
@@ -14,31 +14,37 @@ export type ChartLegendItem = {
export type ExtractSnippetParams<T> = T extends Snippet<[infer P]> ? P : never;
export type TooltipPayload = ExtractSnippetParams<ComponentProps<typeof Tooltip.Root>['children']>['payload'][number];
export type TooltipPayload = Tooltip.TooltipSeries;
// Helper to extract item config from a payload.
export function getPayloadConfigFromPayload(config: ChartConfig, payload: TooltipPayload, key: string) {
export function getPayloadConfigFromPayload(
config: ChartConfig,
payload: TooltipPayload,
key: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data?: Record<string, any> | null
) {
if (typeof payload !== 'object' || payload === null) return undefined;
const payloadPayload =
'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null
? payload.payload
: undefined;
const payloadConfig =
'config' in payload && typeof payload.config === 'object' && payload.config !== null ? payload.config : undefined;
let configLabelKey: string = key;
if (payload.key === key) {
configLabelKey = payload.key;
} else if (payload.name === key) {
configLabelKey = payload.name;
} else if (payload.label === key) {
configLabelKey = payload.label;
} else if (key in payload && typeof payload[key as keyof typeof payload] === 'string') {
configLabelKey = payload[key as keyof typeof payload] as string;
} else if (
payloadPayload !== undefined &&
key in payloadPayload &&
typeof payloadPayload[key as keyof typeof payloadPayload] === 'string'
payloadConfig !== undefined &&
key in payloadConfig &&
typeof payloadConfig[key as keyof typeof payloadConfig] === 'string'
) {
configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;
configLabelKey = payloadConfig[key as keyof typeof payloadConfig] as string;
} else if (data != null && key in data && typeof data[key] === 'string') {
configLabelKey = data[key] as string;
}
return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config];