Line Chart
Trend over an ordered axis: interactive range chart, curve types, multiple series, dots, coloured dots and labels.
Line charts built on the Chart component (install and API live there). 2px round-joined line; markers only where the point itself matters.
Interactive
Section titled “Interactive”import { Card, CardContent, CardDescription, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartStatWell, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { useMemo, useState } from "react";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";
const desktop = [ 223, 243, 240, 188, 168, 232, 245, 275, 233, 205, 197, 257, 283, 292, 225, 151, 179, 227, 259, 230, 215, 159, 189, 219, 226, 189, 161, 155, 198, 190, 185, 174, 142, 145, 157, 180, 155, 145, 145, 172, 182, 169, 204, 167, 138, 183, 213, 205, 203, 162, 152, 227, 263, 260, 216, 157, 199, 255, 269, 262, 217, 143, 221, 278, 256, 241, 191, 185, 216, 229, 227, 229, 164, 190, 204, 219, 218, 195, 157, 187, 178, 200, 166, 182, 143, 169, 192, 184, 159, 142, 154,];
const mobile = [ 168, 206, 170, 122, 151, 195, 160, 179, 197, 169, 126, 182, 229, 203, 142, 138, 168, 153, 167, 193, 178, 107, 141, 193, 170, 121, 140, 157, 141, 126, 166, 159, 100, 113, 158, 149, 102, 127, 152, 131, 120, 153, 178, 116, 105, 171, 171, 130, 154, 162, 124, 143, 201, 212, 146, 112, 177, 198, 167, 183, 192, 123, 139, 206, 211, 163, 128, 167, 180, 147, 159, 198, 139, 122, 161, 192, 154, 128, 148, 168, 121, 141, 162, 153, 96, 138, 178, 139, 106, 137, 152,];
// Apr 1 to Jun 30const data = desktop.map((d, i) => ({ date: new Date(Date.UTC(2024, 3, 1 + i)).toISOString(), desktop: d, mobile: mobile[i],}));
const config = { views: { label: "Page Views" }, desktop: { label: "Desktop", color: "var(--chart-1)" }, mobile: { label: "Mobile", color: "var(--chart-2)" },} satisfies ChartConfig;
const formatDate = (value: string | number) => new Date(value).toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC", });
export default function Demo() { const [active, setActive] = useState<"desktop" | "mobile">("desktop"); const total = useMemo( () => ({ desktop: data.reduce((sum, d) => sum + d.desktop, 0), mobile: data.reduce((sum, d) => sum + d.mobile, 0), }), [], );
return ( <Card className="w-full gap-0 py-0"> <div className="flex items-stretch justify-between border-border border-b"> <div className="flex flex-col justify-center gap-1 px-6 pt-5.5 pb-4.5"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Interactive </CardTitle> <CardDescription className="text-[13.5px]"> Showing total visitors for the last 3 months </CardDescription> </div> <div className="flex"> {(["desktop", "mobile"] as const).map((key) => ( <ChartStatWell key={key} active={active === key} onClick={() => setActive(key)} > {config[key].label} <b>{total[key].toLocaleString()}</b> </ChartStatWell> ))} </div> </div> <CardContent className="items-center px-5 pt-5 pb-5"> <ChartContainer config={config} className="aspect-auto h-64 w-full"> <LineChart data={data} margin={{ left: 12, right: 12 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="date" tickLine={false} axisLine={false} tickMargin={8} minTickGap={32} tickFormatter={formatDate} /> <ChartTooltip content={ <ChartTooltipContent className="w-40" nameKey="views" labelFormatter={(value) => formatDate(String(value))} /> } /> <Line dataKey={active} type="monotone" stroke={`var(--color-${active})`} strokeWidth={2} dot={false} /> </LineChart> </ChartContainer> </CardContent> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisXYContainer } from "@unovis/vue";import { computed, ref } from "vue";import { Card, CardContent, CardDescription, CardTitle } from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartStatWell, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Key = "desktop" | "mobile";type Row = { date: number; desktop: number; mobile: number };
const desktop = [ 223, 243, 240, 188, 168, 232, 245, 275, 233, 205, 197, 257, 283, 292, 225, 151, 179, 227, 259, 230, 215, 159, 189, 219, 226, 189, 161, 155, 198, 190, 185, 174, 142, 145, 157, 180, 155, 145, 145, 172, 182, 169, 204, 167, 138, 183, 213, 205, 203, 162, 152, 227, 263, 260, 216, 157, 199, 255, 269, 262, 217, 143, 221, 278, 256, 241, 191, 185, 216, 229, 227, 229, 164, 190, 204, 219, 218, 195, 157, 187, 178, 200, 166, 182, 143, 169, 192, 184, 159, 142, 154,];
const mobile = [ 168, 206, 170, 122, 151, 195, 160, 179, 197, 169, 126, 182, 229, 203, 142, 138, 168, 153, 167, 193, 178, 107, 141, 193, 170, 121, 140, 157, 141, 126, 166, 159, 100, 113, 158, 149, 102, 127, 152, 131, 120, 153, 178, 116, 105, 171, 171, 130, 154, 162, 124, 143, 201, 212, 146, 112, 177, 198, 167, 183, 192, 123, 139, 206, 211, 163, 128, 167, 180, 147, 159, 198, 139, 122, 161, 192, 154, 128, 148, 168, 121, 141, 162, 153, 96, 138, 178, 139, 106, 137, 152,];
// Apr 1 to Jun 30const data: Row[] = desktop.map((d, i) => ({ date: Date.UTC(2024, 3, 1 + i), desktop: d, mobile: mobile[i],}));
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, mobile: { label: "Mobile", color: "var(--chart-2)" },} satisfies ChartConfig;
const keys: Key[] = ["desktop", "mobile"];const active = ref<Key>("desktop");const total = { desktop: data.reduce((sum, d) => sum + d.desktop, 0), mobile: data.reduce((sum, d) => sum + d.mobile, 0),};
const formatDate = (value: number) => new Date(value).toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC", });
const x = (_: Row, i: number) => i;const y = (d: Row) => d[active.value];const tickFormat = (i: number) => formatDate(data[i]?.date ?? 0);
// One "Page Views" row per datum; the tooltip config is picked by the active series.const tooltipConfig = (key: Key) => ({ [key]: { label: "Page Views", color: config[key].color } }) satisfies ChartConfig;const templates = { desktop: componentToString(tooltipConfig("desktop"), ChartTooltipContent, { class: "w-40", labelFormatter: (i) => tickFormat(Number(i)), }), mobile: componentToString(tooltipConfig("mobile"), ChartTooltipContent, { class: "w-40", labelFormatter: (i) => tickFormat(Number(i)), }),};const template = computed(() => templates[active.value]);</script>
<template> <Card class="w-full gap-0 py-0"> <div class="flex items-stretch justify-between border-border border-b"> <div class="flex flex-col justify-center gap-1 px-6 pt-5.5 pb-4.5"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Interactive</CardTitle> <CardDescription class="text-[13.5px]">Showing total visitors for the last 3 months</CardDescription> </div> <div class="flex"> <ChartStatWell v-for="key in keys" :key="key" :active="active === key" @click="active = key" > {{ config[key].label }} <b>{{ total[key].toLocaleString() }}</b> </ChartStatWell> </div> </div> <CardContent class="items-center px-5 pt-5 pb-5"> <ChartContainer :config="config" class="aspect-auto h-64 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]"> <VisLine :x="x" :y="y" :color="config[active].color" :curve-type="CurveType.MonotoneX" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="y" :template="(d: Row, i: number) => template?.({ [active]: d[active], date: d.date }, i)" :color="config[active].color" /> </VisXYContainer> </ChartContainer> </CardContent> </Card></template><script lang="ts"> import { LineChart } from "layerchart"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart";
type Key = "desktop" | "mobile";
const desktop = [ 223, 243, 240, 188, 168, 232, 245, 275, 233, 205, 197, 257, 283, 292, 225, 151, 179, 227, 259, 230, 215, 159, 189, 219, 226, 189, 161, 155, 198, 190, 185, 174, 142, 145, 157, 180, 155, 145, 145, 172, 182, 169, 204, 167, 138, 183, 213, 205, 203, 162, 152, 227, 263, 260, 216, 157, 199, 255, 269, 262, 217, 143, 221, 278, 256, 241, 191, 185, 216, 229, 227, 229, 164, 190, 204, 219, 218, 195, 157, 187, 178, 200, 166, 182, 143, 169, 192, 184, 159, 142, 154, ];
const mobile = [ 168, 206, 170, 122, 151, 195, 160, 179, 197, 169, 126, 182, 229, 203, 142, 138, 168, 153, 167, 193, 178, 107, 141, 193, 170, 121, 140, 157, 141, 126, 166, 159, 100, 113, 158, 149, 102, 127, 152, 131, 120, 153, 178, 116, 105, 171, 171, 130, 154, 162, 124, 143, 201, 212, 146, 112, 177, 198, 167, 183, 192, 123, 139, 206, 211, 163, 128, 167, 180, 147, 159, 198, 139, 122, 161, 192, 154, 128, 148, 168, 121, 141, 162, 153, 96, 138, 178, 139, 106, 137, 152, ];
// Apr 1 to Jun 30 const rows = desktop.map((d, i) => ({ i, date: Date.UTC(2024, 3, 1 + i), desktop: d, mobile: mobile[i], }));
const config = { views: { label: "Page Views" }, desktop: { label: "Desktop", color: "var(--chart-1)" }, mobile: { label: "Mobile", color: "var(--chart-2)" }, } satisfies Chart.ChartConfig;
const keys: Key[] = ["desktop", "mobile"]; let active = $state<Key>("desktop"); const total = { desktop: rows.reduce((sum, d) => sum + d.desktop, 0), mobile: rows.reduce((sum, d) => sum + d.mobile, 0), }; // One "views" value per row: the tooltip row is always "Page Views". const data = $derived(rows.map((r) => ({ i: r.i, date: r.date, views: r[active] })));
const formatDate = (i: number) => new Date(rows[i]?.date ?? 0).toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC", });</script>
<Card.Root class="w-full gap-0 py-0"> <div class="flex items-stretch justify-between border-border border-b"> <div class="flex flex-col justify-center gap-1 px-6 pt-5.5 pb-4.5"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Interactive</Card.Title> <Card.Description class="text-[13.5px]">Showing total visitors for the last 3 months</Card.Description> </div> <div class="flex"> {#each keys as key (key)} <Chart.StatWell active={active === key} onclick={() => (active = key)}> {config[key].label} <b>{total[key].toLocaleString()}</b> </Chart.StatWell> {/each} </div> </div> <Card.Content class="items-center px-5 pt-5 pb-5"> <Chart.Container {config} class="aspect-auto h-64 w-full"> <LineChart {data} x="i" series={[{ key: "views", label: "Page Views", color: `var(--color-${active})` }]} padding={{ left: 12, right: 12, bottom: 24 }} props={{ spline: { strokeWidth: 2 }, xAxis: { format: formatDate, ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet tooltip()} <Chart.Tooltip labelFormatter={formatDate} /> {/snippet} </LineChart> </Chart.Container> </Card.Content></Card.Root>import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Line dataKey="desktop" type="natural" stroke="var(--color-desktop)" strokeWidth={2} dot={false} /> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number };
const data: Row[] = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Natural" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart"; import { curveNatural } from "./_chart-curves";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186 }, { i: 1, desktop: 305 }, { i: 2, desktop: 237 }, { i: 3, desktop: 73 }, { i: 4, desktop: 209 }, { i: 5, desktop: 214 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, ]} padding={{ left: 12, right: 12, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} curve={curveNatural} strokeWidth={2} /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="dot" hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>Linear
Section titled “Linear”import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Linear </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Line dataKey="desktop" type="linear" stroke="var(--color-desktop)" strokeWidth={2} dot={false} /> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number };
const data: Row[] = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Linear</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Linear" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186 }, { i: 1, desktop: 305 }, { i: 2, desktop: 237 }, { i: 3, desktop: 73 }, { i: 4, desktop: 209 }, { i: 5, desktop: 214 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Linear</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, ]} padding={{ left: 12, right: 12, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} strokeWidth={2} /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="dot" hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Step </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Line dataKey="desktop" type="step" stroke="var(--color-desktop)" strokeWidth={2} dot={false} /> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number };
const data: Row[] = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Step</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Step" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart"; import { curveStep } from "./_chart-curves";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186 }, { i: 1, desktop: 305 }, { i: 2, desktop: 237 }, { i: 3, desktop: 73 }, { i: 4, desktop: 209 }, { i: 5, desktop: 214 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Step</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, ]} padding={{ left: 12, right: 12, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} curve={curveStep} strokeWidth={2} /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="dot" hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>Multiple
Section titled “Multiple”import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186, mobile: 80 }, { month: "February", desktop: 305, mobile: 200 }, { month: "March", desktop: 237, mobile: 120 }, { month: "April", desktop: 73, mobile: 190 }, { month: "May", desktop: 209, mobile: 130 }, { month: "June", desktop: 214, mobile: 140 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, mobile: { label: "Mobile", color: "var(--chart-2)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Multiple </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} /> <ChartLegend content={<ChartLegendContent swatch="line" />} /> <Line dataKey="desktop" type="natural" stroke="var(--color-desktop)" strokeWidth={2} dot={false} /> <Line dataKey="mobile" type="natural" stroke="var(--color-mobile)" strokeWidth={2} dot={false} /> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartLegendContent, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number; mobile: number };
const data: Row[] = [ { month: "January", desktop: 186, mobile: 80 }, { month: "February", desktop: 305, mobile: 200 }, { month: "March", desktop: 237, mobile: 120 }, { month: "April", desktop: 73, mobile: 190 }, { month: "May", desktop: 209, mobile: 130 }, { month: "June", desktop: 214, mobile: 140 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, mobile: { label: "Mobile", color: "var(--chart-2)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "line", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Multiple</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-52 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Natural" /> <VisLine :x="x" :y="(d: Row) => d.mobile" color="var(--chart-2)" :curve-type="CurveType.Natural" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop, (d: Row) => d.mobile]" :template="template" color="var(--chart-1)" /> </VisXYContainer> <ChartLegendContent swatch="line" /> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart"; import { curveNatural } from "./_chart-curves";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186, mobile: 80 }, { i: 1, desktop: 305, mobile: 200 }, { i: 2, desktop: 237, mobile: 120 }, { i: 3, desktop: 73, mobile: 190 }, { i: 4, desktop: 209, mobile: 130 }, { i: 5, desktop: 214, mobile: 140 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, mobile: { label: "Mobile", color: "var(--chart-2)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Multiple</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-52 w-full"> <LineChart {data} x="i" legend series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, { key: "mobile", label: config.mobile.label, color: "var(--color-mobile)" }, ]} padding={{ left: 12, right: 12, bottom: 44 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} curve={curveNatural} strokeWidth={2} /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="line" labelFormatter={(v: number) => labels[v] ?? ""} /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Dots </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Line dataKey="desktop" type="natural" stroke="var(--color-desktop)" strokeWidth={2} dot={{ r: 4, fill: "var(--color-desktop)", stroke: "var(--card)", strokeWidth: 2, }} activeDot={{ r: 6 }} /> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisScatter, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number };
const data: Row[] = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Dots</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Natural" /> <VisScatter :x="x" :y="(d: Row) => d.desktop" :size="8" :size-range="[8, 8]" color="var(--chart-1)" stroke-color="var(--card)" :stroke-width="2" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Points, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart"; import { curveNatural } from "./_chart-curves";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186 }, { i: 1, desktop: 305 }, { i: 2, desktop: 237 }, { i: 3, desktop: 73 }, { i: 4, desktop: 209 }, { i: 5, desktop: 214 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Dots</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, ]} padding={{ left: 12, right: 12, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} curve={curveNatural} strokeWidth={2} /> <Points seriesKey={s.key} r={4} stroke="var(--card)" strokeWidth={2} /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="dot" hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>Custom Dots
Section titled “Custom Dots”import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Custom Dots </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Line dataKey="desktop" type="natural" stroke="var(--color-desktop)" strokeWidth={2} dot={({ cx, cy, index }) => ( <circle key={index} cx={cx} cy={cy} r={4} fill="var(--card)" stroke="var(--color-desktop)" strokeWidth={2} /> )} /> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisScatter, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number };
const data: Row[] = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Custom Dots</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Natural" /> <VisScatter :x="x" :y="(d: Row) => d.desktop" :size="8" :size-range="[8, 8]" color="var(--card)" stroke-color="var(--chart-1)" :stroke-width="2" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Points, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart"; import { curveNatural } from "./_chart-curves";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186 }, { i: 1, desktop: 305 }, { i: 2, desktop: 237 }, { i: 3, desktop: 73 }, { i: 4, desktop: 209 }, { i: 5, desktop: 214 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Custom Dots</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, ]} padding={{ left: 12, right: 12, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} curve={curveNatural} strokeWidth={2} /> <Points seriesKey={s.key} r={4} fill="var(--card)" stroke={s.color} strokeWidth={2} /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="dot" hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>Dots Colors
Section titled “Dots Colors”import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" }, { browser: "safari", visitors: 200, fill: "var(--color-safari)" }, { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" }, { browser: "edge", visitors: 173, fill: "var(--color-edge)" }, { browser: "other", visitors: 90, fill: "var(--color-other)" },];
const config = { visitors: { label: "Visitors", color: "var(--chart-1)" }, chrome: { label: "Chrome", color: "var(--chart-1)" }, safari: { label: "Safari", color: "var(--chart-2)" }, firefox: { label: "Firefox", color: "var(--chart-3)" }, edge: { label: "Edge", color: "var(--chart-4)" }, other: { label: "Other", color: "var(--chart-5)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Dots Colors </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 24, right: 24 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="browser" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => config[value as keyof typeof config]?.label } /> <ChartTooltip cursor={false} content={<ChartTooltipContent nameKey="visitors" hideLabel />} /> <Line dataKey="visitors" type="linear" stroke="var(--color-visitors)" strokeWidth={2} dot={({ cx, cy, payload, index }) => ( <circle key={index} cx={cx} cy={cy} r={4} fill={payload.fill} stroke="var(--card)" strokeWidth={2} /> )} /> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType } from "@unovis/ts";import { VisAxis, VisLine, VisScatter, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { browser: string; visitors: number; fill: string };
const data: Row[] = [ { browser: "Chrome", visitors: 275, fill: "var(--chart-1)" }, { browser: "Safari", visitors: 200, fill: "var(--chart-2)" }, { browser: "Firefox", visitors: 187, fill: "var(--chart-3)" }, { browser: "Edge", visitors: 173, fill: "var(--chart-4)" }, { browser: "Other", visitors: 90, fill: "var(--chart-5)" },];
const config = { visitors: { label: "Visitors", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.browser ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", hideLabel: true,});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Dots Colors</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, undefined]" :x-domain="[0, 4]"> <VisLine :x="x" :y="(d: Row) => d.visitors" color="var(--chart-1)" :curve-type="CurveType.Linear" /> <VisScatter :x="x" :y="(d: Row) => d.visitors" :size="8" :size-range="[8, 8]" :color="(d: Row) => d.fill" stroke-color="var(--card)" :stroke-width="2" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="5" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.visitors]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Circle, Points, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart";
const labels = [ "Chrome", "Safari", "Firefox", "Edge", "Other", ]; const data = [ { i: 0, browser: "Chrome", visitors: 275, fill: "var(--chart-1)" }, { i: 1, browser: "Safari", visitors: 200, fill: "var(--chart-2)" }, { i: 2, browser: "Firefox", visitors: 187, fill: "var(--chart-3)" }, { i: 3, browser: "Edge", visitors: 173, fill: "var(--chart-4)" }, { i: 4, browser: "Other", visitors: 90, fill: "var(--chart-5)" }, ];
const config = { visitors: { label: "Visitors", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Dots Colors</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[{ key: "visitors", label: "Visitors", color: "var(--color-visitors)" }]} padding={{ left: 12, right: 12, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 5 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} strokeWidth={2} /> <Points seriesKey={s.key}> {#snippet children({ points })} {#each points as p} <Circle cx={p.x} cy={p.y} r={4} fill={p.data.fill} stroke="var(--card)" strokeWidth={2} /> {/each} {/snippet} </Points> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, LabelList, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Label </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12, top: 20 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Line dataKey="desktop" type="natural" stroke="var(--color-desktop)" strokeWidth={2} dot={{ r: 4, fill: "var(--color-desktop)", stroke: "var(--card)", strokeWidth: 2, }} activeDot={{ r: 6 }} > <LabelList position="top" offset={12} className="fill-foreground" fontSize={12} /> </Line> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType, Position } from "@unovis/ts";import { VisAxis, VisLine, VisScatter, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number };
const data: Row[] = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Label</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, 340]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Natural" /> <VisScatter :x="x" :y="(d: Row) => d.desktop" :size="8" :size-range="[8, 8]" color="var(--chart-1)" stroke-color="var(--card)" :stroke-width="2" :label="(d: Row) => String(d.desktop)" :label-position="Position.Top" label-color="var(--foreground)" :label-font-size="12" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Labels, Points, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart"; import { curveNatural } from "./_chart-curves";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186 }, { i: 1, desktop: 305 }, { i: 2, desktop: 237 }, { i: 3, desktop: 73 }, { i: 4, desktop: 209 }, { i: 5, desktop: 214 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Label</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, ]} padding={{ left: 12, right: 12, top: 20, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} curve={curveNatural} strokeWidth={2} /> <Points seriesKey={s.key} r={4} stroke="var(--card)" strokeWidth={2} /> <Labels seriesKey={s.key} placement="outside" offset={12} class="fill-foreground text-xs" /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="dot" hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>Custom Label
Section titled “Custom Label”import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { CartesianGrid, LabelList, Line, LineChart, XAxis } from "recharts";import { IconPlaceholder } from "@/edmi/icon-placeholder";
const data = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
export default function Demo() { return ( <Card className="w-full max-w-sm gap-0 py-0"> <CardHeader className="gap-1 px-6 pt-5.5 pb-0"> <CardTitle className="font-semibold text-base tracking-[-0.2px]"> Line Chart - Custom Label </CardTitle> <CardDescription className="text-[13.5px]"> January - June 2024 </CardDescription> </CardHeader> <CardContent className="items-center px-5 pt-2.5 pb-0"> <ChartContainer config={config} className="aspect-auto h-44 w-full"> <LineChart data={data} margin={{ left: 12, right: 12, top: 20 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Line dataKey="desktop" type="natural" stroke="var(--color-desktop)" strokeWidth={2} dot={{ r: 4, fill: "var(--color-desktop)", stroke: "var(--card)", strokeWidth: 2, }} activeDot={{ r: 6 }} > <LabelList dataKey="desktop" content={({ x, y, value }) => ( <text key={`${x}-${y}`} x={x} y={Number(y) - 12} textAnchor="middle" fontSize={12} fontWeight={600} className="fill-foreground" > {value} </text> )} /> </Line> </LineChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b className="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" className="size-4" /> </b> <span className="text-muted-foreground"> Showing total visitors for the last 6 months </span> </CardFooter> </Card> );}<script setup lang="ts">import { CurveType, Position } from "@unovis/ts";import { VisAxis, VisLine, VisScatter, VisXYContainer } from "@unovis/vue";import { TrendingUpIcon } from "@lucide/vue";import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";import { type ChartConfig, ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString,} from "@/components/ui/chart";
type Row = { month: string; desktop: number };
const data: Row[] = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" },} satisfies ChartConfig;
const x = (_: Row, i: number) => i;const tickFormat = (i: number) => data[i]?.month.slice(0, 3) ?? "";const template = componentToString(config, ChartTooltipContent, { indicator: "dot", labelFormatter: (i) => data[Number(i)]?.month ?? "",});</script>
<template> <Card class="w-full max-w-sm gap-0 py-0"> <CardHeader class="gap-1 px-6 pt-5.5 pb-0"> <CardTitle class="font-semibold text-base tracking-[-0.2px]">Line Chart - Custom Label</CardTitle> <CardDescription class="text-[13.5px]">January - June 2024</CardDescription> </CardHeader> <CardContent class="items-center px-5 pt-2.5 pb-0"> <ChartContainer :config="config" class="aspect-auto h-44 w-full" cursor> <VisXYContainer :data="data" :margin="{ left: 12, right: 12 }" :y-domain="[0, 340]" :x-domain="[0, 5]"> <VisLine :x="x" :y="(d: Row) => d.desktop" color="var(--chart-1)" :curve-type="CurveType.Natural" /> <VisScatter :x="x" :y="(d: Row) => d.desktop" :size="8" :size-range="[8, 8]" color="var(--chart-1)" stroke-color="var(--card)" :stroke-width="2" :label="(d: Row) => String(d.desktop)" :label-position="Position.Top" label-color="var(--foreground)" :label-font-size="12" /> <VisAxis type="y" :tick-format="() => ''" :num-ticks="3" :tick-line="false" :domain-line="false" /> <VisAxis type="x" :x="x" :tick-format="tickFormat" :num-ticks="6" :tick-line="false" :domain-line="false" :grid-line="false" /> <ChartTooltip /> <ChartCrosshair :x="x" :y="[(d: Row) => d.desktop]" :template="template" color="var(--chart-1)" /> </VisXYContainer> </ChartContainer> </CardContent> <CardFooter class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <TrendingUpIcon class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </CardFooter> </Card></template><script lang="ts"> import { LineChart, Labels, Points, Spline } from "layerchart"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte"; import * as Card from "$lib/components/ui/card"; import * as Chart from "$lib/components/ui/chart"; import { curveNatural } from "./_chart-curves";
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; const data = [ { i: 0, desktop: 186 }, { i: 1, desktop: 305 }, { i: 2, desktop: 237 }, { i: 3, desktop: 73 }, { i: 4, desktop: 209 }, { i: 5, desktop: 214 }, ];
const config = { desktop: { label: "Desktop", color: "var(--chart-1)" }, } satisfies Chart.ChartConfig;</script>
<Card.Root class="w-full max-w-sm gap-0 py-0"> <Card.Header class="gap-1 px-6 pt-5.5 pb-0"> <Card.Title class="font-semibold text-base tracking-[-0.2px]">Line Chart - Custom Label</Card.Title> <Card.Description class="text-[13.5px]">January - June 2024</Card.Description> </Card.Header> <Card.Content class="items-center px-5 pt-2.5 pb-0"> <Chart.Container {config} class="aspect-auto h-44 w-full"> <LineChart {data} x="i"
series={[ { key: "desktop", label: config.desktop.label, color: "var(--color-desktop)" }, ]} padding={{ left: 12, right: 12, top: 20, bottom: 24 }} props={{ xAxis: { format: (v: number) => labels[v] ?? "", ticks: 6 }, yAxis: { format: () => "", ticks: 3 }, }} > {#snippet marks({ context })} {#each context.series.visibleSeries as s (s.key)} <Spline seriesKey={s.key} curve={curveNatural} strokeWidth={2} /> <Points seriesKey={s.key} r={4} stroke="var(--card)" strokeWidth={2} /> <Labels seriesKey={s.key} placement="outside" offset={12} class="fill-foreground text-xs font-semibold" /> {/each} {/snippet} {#snippet tooltip()} <Chart.Tooltip indicator="dot" hideLabel /> {/snippet} </LineChart> </Chart.Container> </Card.Content> <Card.Footer class="flex-col items-stretch gap-1 px-6 pt-3.5 pb-5.5 text-[13.5px]"> <b class="flex items-center gap-1.5 font-medium"> Trending up by 5.2% this month <IconPlaceholder lucide="TrendingUpIcon" tabler="IconTrendingUp" hugeicons="ChartUpIcon" phosphor="TrendUpIcon" remixicon="RiArrowUpLine" class="size-4" /> </b> <span class="text-muted-foreground">Showing total visitors for the last 6 months</span> </Card.Footer></Card.Root>