🌐 Nodejs.cn

漂亮的图表。使用 Unovis 构建。复制并粘贴到你的应用中。

Bar Chart - Interactive

Showing total visitors for the last 3 months

介绍 Charts。一组图表组件,你可以将它们复制并粘贴到你的应用中。

🌐 Introducing Charts. A collection of chart components that you can copy and paste into your apps.

图表设计时就具有很好的外观。它们与其他组件配合良好,并且可以完全自定义以适应你的项目。

🌐 Charts are designed to look great out of the box. They work well with the other components and are fully customizable to fit your project.

浏览图表库

组件

🌐 Component

我们在底层使用 Unovis

🌐 We use Unovis under the hood.

我们在设计 chart 组件时考虑到了组合性。你使用 Unovis 组件构建图表,只有在需要的时间和地点才引入自定义组件,例如 ChartTooltip

🌐 We designed the chart component with composition in mind. You build your charts using Unovis components and only bring in custom components, such as ChartTooltip, when and where you need it.

<script setup lang="ts">
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer, ChartTooltipContent } from '@/components/ui/chart'
</script>

<template>
  <ChartContainer :config="chartConfig">
    <VisXYContainer :data="data">
      <VisGroupedBar :x="(d) => d.month" :y="(d) => d.value" />
      <ChartTooltip :template="componentToString(chartConfig, ChartTooltipContent)" />
    </VisXYContainer>
  </ChartContainer>
</template>

我们不对 Unovis 进行封装。这意味着你不会被锁定在某种抽象中。当新的 Unovis 版本发布时,你可以按照官方升级路径升级你的图表。

🌐 We do not wrap Unovis. This means you're not locked into an abstraction. When a new Unovis version is released, you can follow the official upgrade path to upgrade your charts.

组件是你的。

安装

🌐 Installation

pnpm dlx shadcn-vue@latest add chart

用法

🌐 Usage

<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import {
  ChartContainer,
  ChartCrosshair,
  ChartTooltip,
  ChartTooltipContent,
  componentToString,
} from '@/components/ui/chart'

const chartData = [
  { date: new Date("2024-01-01"), desktop: 186, mobile: 80 },
  { date: new Date("2024-02-01"), desktop: 305, mobile: 200 },
  { date: new Date("2024-03-01"), desktop: 237, mobile: 120 },
];
type Data = (typeof chartData)[number]

const chartConfig = {
  desktop: {
    label: "Desktop",
    color: "var(--chart-1)",
  },
  mobile: {
    label: "Mobile",
    color: "var(--chart-2)",
  },
} satisfies ChartConfig
</script>
<template>
  <ChartContainer :config="chartConfig" class="min-h-[400px] w-full">
    <VisXYContainer :data="chartData">
      <VisGroupedBar
        :x="(d: Data) => d.date"
        :y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
      />
      <ChartTooltip />
      <ChartCrosshair
        :template="
          componentToString(chartConfig, ChartTooltipContent, {
            labelFormatter(d) {
              return new Date(d).toLocaleDateString('en-US', {
                month: 'long',
              });
            },
          })
        "
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
      />
    </VisXYContainer>
  </ChartContainer>
</template>

你的第一个图表

🌐 Your First Chart

让我们来创建你的第一个图表。我们将创建一个柱状图,添加网格、坐标轴、提示信息和图例。

🌐 Let's build your first chart. We'll build a bar chart, add a grid, axis, tooltip and legend.

::步骤 首先定义你的数据 ::

以下数据代表每个月的桌面和移动用户数量。

const chartData = [
  { 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 },
]

::步骤 定义你的图表配置 ::

图表配置保存图表的配置。在这里你可以放置可读的字符串,例如标签、图标和用于主题的颜色令牌。

import type { ChartConfig } from '@/components/ui/chart'

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: 'var(--chart-1)',
  },
  mobile: {
    label: 'Mobile',
    color: 'var(--chart-2)',
  },
} satisfies ChartConfig

::步骤 构建你的图表 ::

你现在可以使用 Unovis 组件构建你的图表。

components/ExampleChart.vue
<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer } from '@/components/ui/chart'

const chartData = [
  { date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
  { date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
  { date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
  { date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
  { date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
  { date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]

type Data = typeof chartData[number]

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: '#2563eb',
  },
  mobile: {
    label: 'Mobile',
    color: '#60a5fa',
  },
} satisfies ChartConfig
</script>

<template>
  <ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
    <VisXYContainer :data="chartData">
      <VisGroupedBar
        :x="(d: Data) => d.date"
        :y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
        :rounded-corners="4"
        bar-padding="0.1"
        group-padding="0"
      />
    </VisXYContainer>
  </ChartContainer>
</template>
<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer } from '@/components/ui/chart'

const chartData = [
  { date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
  { date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
  { date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
  { date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
  { date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
  { date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]

type Data = typeof chartData[number]

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: '#2563eb',
  },
  mobile: {
    label: 'Mobile',
    color: '#60a5fa',
  },
} satisfies ChartConfig
</script>

<template>
  <ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
    <VisXYContainer :data="chartData">
      <VisGroupedBar
        :x="(d: Data) => d.date"
        :y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
        :rounded-corners="4"
        bar-padding="0.1"
        group-padding="0"
      />
    </VisXYContainer>
  </ChartContainer>
</template>

添加轴

🌐 Add an Axis

要向图表添加坐标轴,我们使用 VisAxis 组件。

🌐 To add axes to the chart, we use the VisAxis component.

::步骤 导入 VisAxis 组件 ::

import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'

::步骤 将 VisAxis 组件添加到你的图表中 ::

<template>
  <VisAxis
    type="x"
    :x="(d: Data) => d.date"
    :tick-line="false"
    :domain-line="false"
    :grid-line="false"
    :tick-format="(d: number) => {
      const date = new Date(d)
      return date.toLocaleDateString('en-US', {
        month: 'short',
      })
    }"
    :tick-values="chartData.map(d => d.date)"
  />
  <VisAxis
    type="y"
    :tick-format="(d: number) => ''"
    :tick-line="false"
    :domain-line="false"
    :grid-line="true"
  />
</template>
<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer } from '@/components/ui/chart'

const chartData = [
  { date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
  { date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
  { date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
  { date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
  { date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
  { date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]

type Data = typeof chartData[number]

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: '#2563eb',
  },
  mobile: {
    label: 'Mobile',
    color: '#60a5fa',
  },
} satisfies ChartConfig
</script>

<template>
  <ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
    <VisXYContainer :data="chartData">
      <VisGroupedBar
        :x="(d: Data) => d.date"
        :y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
        :rounded-corners="4"
        bar-padding="0.1"
        group-padding="0"
      />
      <VisAxis
        type="x"
        :x="(d: Data) => d.date"
        :tick-line="false"
        :domain-line="false"
        :grid-line="false"
        :tick-format="(d: number) => {
          const date = new Date(d)
          return date.toLocaleDateString('en-US', {
            month: 'short',
          })
        }"
        :tick-values="chartData.map(d => d.date)"
      />
      <VisAxis
        type="y"
        :tick-format="(d: number) => ''"
        :tick-line="false"
        :domain-line="false"
        :grid-line="true"
      />
    </VisXYContainer>
  </ChartContainer>
</template>

添加工具提示

🌐 Add Tooltip

要添加工具提示,我们将使用来自 chart 的自定义 ChartTooltipChartTooltipContent 组件。

🌐 To add a tooltip, we'll use the custom ChartTooltip and ChartTooltipContent components from chart.

::步骤 导入 ChartTooltipChartTooltipContent 组件 ::

import { ChartTooltip, ChartTooltipContent, componentToString } from '@/components/ui/chart'

::步骤 将组件添加到你的图表 ::

<ChartTooltip />

<ChartCrosshair :template="componentToString(chartConfig, ChartTooltipContent)" />
<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString } from '@/components/ui/chart'

const chartData = [
  { date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
  { date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
  { date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
  { date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
  { date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
  { date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]

type Data = typeof chartData[number]

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: '#2563eb',
  },
  mobile: {
    label: 'Mobile',
    color: '#60a5fa',
  },
} satisfies ChartConfig
</script>

<template>
  <ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
    <VisXYContainer :data="chartData">
      <VisGroupedBar
        :x="(d: Data) => d.date"
        :y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
        :rounded-corners="4"
        bar-padding="0.1"
        group-padding="0"
      />
      <VisAxis
        type="x"
        :x="(d: Data) => d.date"
        :tick-line="false"
        :domain-line="false"
        :grid-line="false"
        :tick-format="(d: number) => {
          const date = new Date(d)
          return date.toLocaleDateString('en-US', {
            month: 'short',
          })
        }"
        :tick-values="chartData.map(d => d.date)"
      />
      <VisAxis
        type="y"
        :tick-format="(d: number) => ''"
        :tick-line="false"
        :domain-line="false"
        :grid-line="true"
      />
      <ChartTooltip />
      <ChartCrosshair
        :template="componentToString(chartConfig, ChartTooltipContent, {
          labelFormatter(d) {
            return new Date(d).toLocaleDateString('en-US', {
              month: 'long',
            })
          },
        })"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
      />
    </VisXYContainer>
  </ChartContainer>
</template>

将鼠标悬停以查看工具提示。很简单,对吧?两个组件,我们就有了一个漂亮的工具提示。

添加图例

🌐 Add Legend

我们将对图例做同样的处理。我们将使用 chart 中的 ChartLegendChartLegendContent 组件。

🌐 We'll do the same for the legend. We'll use the ChartLegend and ChartLegendContent components from chart.

::步骤 导入 ChartLegendContent 组件。 ::

import { ChartLegendContent } from '@/components/ui/chart'

::步骤 将组件添加到你的图表中。 ::

<template>
  <ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
    <VisXYContainer :data="chartData" />
    <ChartLegendContent />
  </ChartContainer>
</template>
<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer, ChartCrosshair, ChartLegendContent, ChartTooltip, ChartTooltipContent, componentToString } from '@/components/ui/chart'

const chartData = [
  { date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
  { date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
  { date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
  { date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
  { date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
  { date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]

type Data = typeof chartData[number]

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: '#2563eb',
  },
  mobile: {
    label: 'Mobile',
    color: '#60a5fa',
  },
} satisfies ChartConfig
</script>

<template>
  <ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
    <VisXYContainer :data="chartData">
      <VisGroupedBar
        :x="(d: Data) => d.date"
        :y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
        :rounded-corners="4"
        bar-padding="0.1"
        group-padding="0"
      />
      <VisAxis
        type="x"
        :x="(d: Data) => d.date"
        :tick-line="false"
        :domain-line="false"
        :grid-line="false"
        :tick-format="(d: number) => {
          const date = new Date(d)
          return date.toLocaleDateString('en-US', {
            month: 'short',
          })
        }"
        :tick-values="chartData.map(d => d.date)"
      />
      <VisAxis
        type="y"
        :tick-format="(d: number) => ''"
        :tick-line="false"
        :domain-line="false"
        :grid-line="true"
      />
      <ChartTooltip />
      <ChartCrosshair
        :template="componentToString(chartConfig, ChartTooltipContent, {
          labelFormatter(d) {
            return new Date(d).toLocaleDateString('en-US', {
              month: 'long',
            })
          },
        })"
        :color="[chartConfig.desktop.color, chartConfig.mobile.color]"
      />
    </VisXYContainer>

    <ChartLegendContent />
  </ChartContainer>
</template>

完成了。你已经创建了你的第一个图表!接下来做什么?

🌐 Done. You've built your first chart! What's next?

图表配置

🌐 Chart Config

图表配置是你定义图表的标签、图标和颜色的地方。

🌐 The chart config is where you define the labels, icons and colors for a chart.

它有意与图表数据分离。

🌐 It is intentionally decoupled from chart data.

这允许你在图表之间共享配置和颜色令牌。对于数据或颜色令牌存储在远程或不同格式的情况,它也可以独立工作。

🌐 This allows you to share config and color tokens between charts. It can also works independently for cases where your data or color tokens live remotely or in a different format.

<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { Monitor } from 'lucide-vue-next'

const chartConfig = {
  desktop: {
    label: 'Desktop',
    icon: Monitor,
    // A color like 'hsl(220, 98%, 61%)' or 'var(--color-name)'
    color: 'var(--chart-1)',
    // OR a theme object with 'light' and 'dark' keys
    theme: {
      light: 'var(--chart-1)',
      dark: 'var(--chart-2)',
    },
  },
} satisfies ChartConfig
</script>

主题

🌐 Theming

Charts 内置了对主题的支持。你可以使用 CSS 变量(推荐)或任何颜色格式的颜色值,例如 hex、hsl 或 oklch。

🌐 Charts has built-in support for theming. You can use css variables (recommended) or color values in any color format, such as hex, hsl or oklch.

CSS 变量

🌐 CSS Variables

::步骤 在你的 CSS 文件中定义你的颜色 ::

@layer base {
  :root {
    --chart-1: oklch(0.646 0.222 41.116);
    --chart-2: oklch(0.6 0.118 184.704);
  }

  .dark {
    --chart-1: oklch(0.488 0.243 264.376);
    --chart-2: oklch(0.696 0.17 162.48);
  }
}

::步骤 将颜色添加到你的 chartConfig ::

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: 'var(--chart-1)',
  },
  mobile: {
    label: 'Mobile',
    color: 'var(--chart-2)',
  },
} satisfies ChartConfig

hex、hsl 或 oklch

🌐 hex, hsl or oklch

你也可以直接在图表配置中定义颜色。使用你喜欢的颜色格式。

🌐 You can also define your colors directly in the chart config. Use the color format you prefer.

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: '#2563eb',
  },
} satisfies ChartConfig

使用颜色

🌐 Using Colors

要在图表中使用主题颜色,请使用 var(--color-KEY) 格式引用颜色。

🌐 To use the theme colors in your chart, reference the colors using the format var(--color-KEY).

组件

🌐 Components

<VisGroupedBar
  :x="(d) => d.month"
  :y="(d) => d.desktop"
  color="var(--color-desktop)"
/>

图表数据

🌐 Chart Data

const chartData = [
  { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
  { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
]

工具提示

🌐 Tooltip

图表提示包含标签、名称、指示器和值。你可以组合使用这些元素来自定义提示。

🌐 A chart tooltip contains a label, name, indicator and value. You can use a combination of these to customize your tooltip.

你可以使用 hideLabelhideIndicator 属性开启或关闭其中的任何一个,并使用 indicator 属性自定义指示器样式。

🌐 You can turn on/off any of these using the hideLabel, hideIndicator props and customize the indicator style using the indicator prop.

使用 labelKeynameKey 来为工具提示标签和名称使用自定义键。

🌐 Use labelKey and nameKey to use a custom key for the tooltip label and name.

图表附带 ChartTooltipChartTooltipContent 组件。你可以使用这两个组件为图表添加自定义提示信息。

🌐 Chart comes with the ChartTooltip and ChartTooltipContent components. You can use these two components to add custom tooltips to your chart.

import { ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
<template>
  <ChartTooltip />
  <ChartCrosshair
    :template="componentToString(chartConfig, ChartTooltipContent)"
  />
</template>

属性

🌐 Props

使用以下属性自定义工具提示。

🌐 Use the following props to customize the tooltip.

属性类型描述
labelKey字符串用于标签的配置或数据键。
nameKey字符串用于名称的配置或数据键。
indicatordot linedashed工具提示的指示器样式。
hideLabel布尔值是否隐藏标签。
hideIndicator布尔值是否隐藏指示器。

颜色

🌐 Colors

颜色自动从图表配置中引用。

🌐 Colors are automatically referenced from the chart config.

自定义

🌐 Custom

要为工具提示标签和名称使用自定义键,请使用 labelKeynameKey 属性。

🌐 To use a custom key for tooltip label and names, use the labelKey and nameKey props.

const chartData = [
  { browser: 'chrome', visitors: 187, fill: 'var(--color-chrome)' },
  { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
]

const chartConfig = {
  visitors: {
    label: 'Total Visitors',
  },
  chrome: {
    label: 'Chrome',
    color: 'var(--chart-1)',
  },
  safari: {
    label: 'Safari',
    color: 'var(--chart-2)',
  },
} satisfies ChartConfig
<template>
  <ChartCrosshair
    :template="componentToString(chartConfig, ChartTooltipContent, {
      labelKey: 'visitors',
      nameKey: 'browser',
    })"
  />
</template>

这将使用 Total Visitors 作为标签,ChromeSafari 作为工具提示名称。

🌐 This will use Total Visitors for label and Chrome and Safari for the tooltip names.

图例

🌐 Legend

你可以使用自定义 <ChartLegendContent> 组件为你的图表添加图例。

🌐 You can use the custom <ChartLegendContent> components to add a legend to your chart.

import { ChartLegendContent } from '@/components/ui/chart'
<template>
  <ChartLegendContent />
</template>

颜色

🌐 Colors

颜色自动从图表配置中引用。

🌐 Colors are automatically referenced from the chart config.

自定义

🌐 Custom

要为图例名称使用自定义键,请使用 nameKey 属性。

🌐 To use a custom key for legend names, use the nameKey prop.

const chartData = [
  { browser: 'chrome', visitors: 187, fill: 'var(--color-chrome)' },
  { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
]

const chartConfig = {
  chrome: {
    label: 'Chrome',
    color: 'hsl(var(--chart-1))',
  },
  safari: {
    label: 'Safari',
    color: 'hsl(var(--chart-2))',
  },
} satisfies ChartConfig
<template>
  <ChartLegendContent name-key="browser" />
</template>

这将使用 ChromeSafari 作为图例名称。

🌐 This will use Chrome and Safari for the legend names.