更新记录

1.0.0(2026-04-29)

  • feat: 首次公开发布 hans-charts,提供基于 spec / theme / frameuni-app x 图表组件 API。
  • feat: 支持 linebarcombopieroseradar 六类图表。
  • feat: 支持 stack / percent stack、折线面积填充、axisKey / yAxes 双轴表达,以及 loading / empty state。
  • feat: 支持图例切换、tooltip、selection、zoom / pan 等基础交互,并统一输出 @action 事件。
  • feat: 提供 appendDataupdateDatasetViewportshowTooltiphighlightresetexportImage 等实例方法。
  • feat: 内置 minimaleditorialdashboard 三套 preset,支持 light / dark 模式与主题定制。
  • feat: 补齐 uni-app x App Android / iOS 平台实现,并提供 playground 场景化回归页。
  • test: Android 自动化回归用例 pages/index/index.test.js 当前通过 78/78
  • docs: 完善插件 readme.md、平台支持说明与发布变更记录。

平台兼容性

uni-app x(5.07)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - -

hans-charts 图表组件

hans-charts 是面向 uni-app x 的 UVUE Canvas 图表组件,使用 spec / theme / frame 三个入口描述图表语义、视觉主题和宿主尺寸。

平台支持

平台 支持情况
uni-app x App Android 支持
uni-app x App iOS 支持
uni-app x Web 未作为当前主验证目标
uni-app x HarmonyOS 支持(当前为首轮适配,建议继续真机验证)
uni-app Vue2/Vue3、小程序、快应用 不支持

要求 HBuilderX 4.0+,项目需要使用 uni-app x

安装与引入

将插件放在项目的 uni_modules/hans-charts 目录下后,可在页面或组件中直接使用:

<template>
  <hans-charts :spec="spec" :theme="theme" :frame="frame" />
</template>

如需使用类型,在 script setup lang="uts" 中引入:

import type {
  HansChartSpec,
  HansChartTheme,
  HansChartFrame,
  HansChartsExposed
} from '@/uni_modules/hans-charts'

快速示例

<script setup lang="uts">
import { ref } from 'vue'
import type { HansChartFrame, HansChartSpec, HansChartTheme } from '@/uni_modules/hans-charts'

const spec = ref<HansChartSpec>({
  type: 'line',
  title: 'Weekly Visits',
  interaction: {
    legend: {
      show: true,
      interactive: true
    },
    tooltip: {
      show: true,
      confine: true,
      placement: 'auto'
    },
    gesture: {
      zoomEnabled: true,
      panEnabled: true,
      minScale: 0.8,
      maxScale: 3
    }
  },
  axis: {
    x: {
      show: true,
      labelMaxLength: 10,
      labelStrategy: 'autoSkip'
    },
    y: {
      show: true,
      tickCount: 5
    }
  },
  data: {
    categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    series: [
      {
        key: 'visits',
        name: 'Visits',
        values: [120, 132, 101, 134, 90, 230, 210],
        color: '#2563eb'
      }
    ]
  }
})

const theme = ref<HansChartTheme>({
  preset: 'editorial',
  mode: 'light',
  palette: ['#2563eb', '#06b6d4', '#22c55e'],
  line: {
    smoothing: 'smooth',
    width: 2.4,
    pointRadius: 4,
    areaOpacity: 0.14
  },
  layout: {
    padding: {
      top: 20,
      right: 18,
      bottom: 38,
      left: 16
    }
  }
})

const frame = ref<HansChartFrame>({
  width: 320,
  height: 220
})
</script>

<template>
  <hans-charts :spec="spec" :theme="theme" :frame="frame" />
</template>

Props

属性 类型 必填 说明
spec HansChartSpec 图表类型、数据、坐标轴、交互、加载态等语义配置。
theme HansChartTheme \| null 视觉主题配置,包括色板、排版、网格、图例、tooltip、图形样式等。
frame HansChartFrame \| null 图表宽高和像素比。缺省或宽高小于等于 0 时走自动测量。
debug boolean 调试辅助开关,默认 false。生产环境建议保持关闭。

frame 的字段如下:

type HansChartFrame = {
  width?: number
  height?: number
  pixelRatio?: number
}

未显式传入 frame.width / frame.height 时,组件会优先测量宿主宽度,并按自动高度策略重绘。业务页面如果有固定图表区域,建议直接传入明确的 widthheight

支持的图表类型

spec.type 图表 数据入口
line 折线图 data.categories + data.series[].valuesdata.series[].data
bar 柱状图 data.categories + data.series[].valuesdata.series[].data
combo 折线/柱状复合图 data.categories + data.series[],每个系列用 type: 'line' \| 'bar' 区分
pie 饼图 data.series[] 切片数组
rose 玫瑰图 data.series[] 切片数组,可为切片设置 radius
radar 雷达图 data.indicators + data.series[].values

数据写法

折线图、柱状图、复合图

const spec: HansChartSpec = {
  type: 'combo',
  data: {
    categories: ['Mon', 'Tue', 'Wed'],
    series: [
      {
        type: 'bar',
        key: 'orders',
        name: 'Orders',
        values: [42, 48, 52],
        stack: 'traffic'
      },
      {
        type: 'line',
        key: 'rate',
        name: 'Conversion',
        values: [18, 21, 23],
        axisKey: 'rate',
        area: false
      }
    ]
  }
}

values 适合简单数值数组,data 适合需要稳定 key、原始业务对象或连续坐标的场景:

{
  key: 'visits',
  name: 'Visits',
  values: [120, null, 156],
  data: [
    { key: 'mon', value: 120, rawDatum: { id: 1, day: 'Mon' } },
    { key: 'tue', value: null, rawDatum: { id: 2, day: 'Tue' } },
    { key: 'wed', y: 156, rawDatum: { id: 3, day: 'Wed' } }
  ]
}

说明:

  • null 表示空点。
  • data.y 优先于 data.value
  • data.key 会用于事件、tooltip、selection 和数据更新后的状态恢复;类目文案可能变化时建议显式传入。
  • rawDatum 会透传到点击事件、tooltip formatter 和 data labels formatter。

饼图与玫瑰图

const pieSpec: HansChartSpec = {
  type: 'pie',
  data: {
    series: [
      { key: 'search', name: 'Search', value: 46, color: '#2563eb' },
      { key: 'ads', name: 'Ads', value: 28, color: '#f97316' },
      { key: 'direct', name: 'Direct', value: 26, color: '#22c55e' }
    ]
  }
}

玫瑰图支持额外的 radius 字段:

const roseSpec: HansChartSpec = {
  type: 'rose',
  data: {
    series: [
      { key: 'a', name: 'A', value: 35, radius: 0.7 },
      { key: 'b', name: 'B', value: 48, radius: 0.92 }
    ]
  }
}

雷达图

const radarSpec: HansChartSpec = {
  type: 'radar',
  axis: {
    show: true,
    labelStrategy: 'truncate',
    labelMaxLength: 8
  },
  thresholds: {
    items: [
      { value: 60, color: '#f97316', label: 'Target' }
    ],
    lineDash: [4, 5]
  },
  data: {
    indicators: ['Quality', 'Speed', 'Cost', 'Risk', 'Growth'],
    series: [
      {
        key: 'current',
        name: 'Current',
        values: [82, 70, 64, 76, 88]
      }
    ]
  }
}

坐标轴与业务表达

笛卡尔图表支持 axisscaledataZoombrushlabelsannotations

const comboSpec: HansChartSpec = {
  type: 'combo',
  axis: {
    x: {
      type: 'category',
      labelStrategy: 'autoSkip',
      labelMaxLength: 10
    },
    y: {
      axisKey: 'volume',
      type: 'value'
    },
    yAxes: [
      { axisKey: 'volume', position: 'left', type: 'value' },
      { axisKey: 'rate', position: 'right', type: 'value', min: 0, max: 40 }
    ]
  },
  scale: {
    negative: 'allowNegative'
  },
  dataZoom: {
    show: true,
    type: 'inside',
    start: 10,
    end: 90
  },
  labels: {
    show: true,
    position: 'top'
  },
  annotations: {
    show: true,
    items: [
      { type: 'average', label: 'Avg' },
      { type: 'max', label: 'Max' }
    ]
  },
  data: {
    categories: ['Mon', 'Tue', 'Wed'],
    series: [
      { type: 'bar', key: 'organic', name: 'Organic', values: [42, 48, 52], stack: 'traffic' },
      { type: 'bar', key: 'paid', name: 'Paid', values: [28, 24, 32], stack: 'traffic' },
      { type: 'line', key: 'rate', name: 'Conversion', axisKey: 'rate', values: [18, 21, 23] }
    ]
  }
}

常用字段:

配置 说明
axis.x / axis.y 坐标轴显示、类型、刻度数、最大/最小值、反向、label 策略。
axis.yAxes 多 y 轴配置,系列通过 axisKey 绑定。
scale.negative 负值策略,clampZeroallowNegative
series.stack 柱状图堆叠分组。
series.stackMode normalpercent
series.area 折线面积填充,可传 boolean{ show, opacity, baseline }
dataZoom 类目轴窗口裁剪,当前建议使用 type: 'inside'
brush 已有配置结构,框选 UI 和正式框选事件不建议在业务中依赖。

交互配置

const interaction = {
  legend: {
    show: true,
    interactive: true,
    singleSelect: false
  },
  tooltip: {
    show: true,
    confine: true,
    placement: 'auto',
    offset: { x: 10, y: -56 },
    formatter: (params) => {
      return params.seriesName + ': ' + params.displayValue
    }
  },
  gesture: {
    zoomEnabled: true,
    panEnabled: true,
    minScale: 0.8,
    maxScale: 3
  }
}

tooltip.formatter 入参包含 chartType / legendIndex / seriesIndex / dataIndex / dataKey / seriesName / label / value / rawDatum / displayLabel / displayValue 等字段。

主题配置

const theme: HansChartTheme = {
  preset: 'dashboard',
  mode: 'dark',
  palette: ['#60a5fa', '#34d399', '#f97316'],
  surface: {
    radius: 10,
    shadow: 1
  },
  grid: {
    strength: 'soft',
    dash: [3, 7],
    opacity: 0.72,
    lineWidth: 0.9
  },
  typography: {
    title: 15,
    axis: 10,
    legend: 13,
    tooltipTitle: 12,
    tooltipValue: 13
  },
  legend: {
    position: 'bottom',
    wrap: true,
    dotSize: 8
  },
  tooltip: {
    style: 'glass',
    maxWidth: 240,
    paddingX: 12,
    paddingY: 10,
    radius: 10
  },
  layout: {
    touchTarget: 44,
    emptyText: 'No data',
    padding: {
      top: 20,
      right: 18,
      bottom: 38,
      left: 16
    }
  }
}

可用 preset:minimaleditorialdashboard。可用模式:lightdark

加载态与空态

const loadingSpec: HansChartSpec = {
  type: 'line',
  loading: {
    show: true,
    text: 'Loading...'
  },
  data: {
    categories: [],
    series: []
  }
}

空态文案通过 theme.layout.emptyText 配置。数据为空或有效点为空时,组件会显示空态。

Events

<hans-charts
  :spec="spec"
  :theme="theme"
  :frame="frame"
  @ready="onReady"
  @action="onAction"
  @pointClick="onPointClick"
  @legendClick="onLegendClick"
  @selectionChange="ionChange"
  @tooltipChange="onTooltipChange"
  @viewportChange="onViewportChange"
  @zoom="onZoom"
  @pan="onPan"
/>
事件 说明
ready canvas 初始化完成后触发,返回 canvasId / width / height / pixelRatio / renderBounds
action 统一动作事件,覆盖点选、图例切换、selection、zoom、pan、dataZoom、brush。
pointClick 点击图形元素时触发,返回系列、数据索引、key、label、value、percentage、rawDatum 等。
legendClick 点击图例时触发,返回图例索引、当前激活状态、隐藏/激活索引列表。
selectionChange 选中点变化时触发。
tooltipChange tooltip 或 cursor 状态变化时触发。
viewportChange 缩放和平移状态变化时触发。
zoom 缩放手势或命令触发时返回当前 viewport。
pan 平移手势或命令触发时返回当前 viewport。
stateChange 运行时状态变化事件,适合需要同步完整状态的场景。
inspect 调试快照事件,业务侧通常不需要依赖。

事件类型可从插件导入:

import type {
  HansChartActionEvent,
  HansChartReadyEvent,
  HansPointClickEvent,
  HansLegendClickEvent,
  HansChartSelectionChangeEvent,
  HansChartTooltipChangeEvent,
  HansChartViewportChangeEvent,
  HansChartZoomEvent,
  HansChartPanEvent,
  HansChartStateChangeEvent
} from '@/uni_modules/hans-charts'

实例方法

需要由外部按钮、筛选器或多图联动驱动图表时,可以通过组件 ref 调用实例方法。

<script setup lang="uts">
import { ref } from 'vue'
import type { HansChartsExposed } from '@/uni_modules/hans-charts'

const chartRef = ref<HansChartsExposed | null>(null)

function zoomIn(): void {
  chartRef.value?.setViewport({ scale: 1.5 })
}

function showThirdPoint(): void {
  chartRef.value?.showTooltip({ legendIndex: 0, dataIndex: 2 })
}

function resetChart(): void {
  chartRef.value?.reset()
}
</script>

<template>
  <hans-charts ref="chartRef" :spec="spec" :theme="theme" :frame="frame" />
</template>
方法 说明
getRuntimeState() 获取当前图例隐藏、selection、tooltip、viewport、cursor 等运行时状态。
setViewport(viewport) 设置 scale / translateX / translateY,会按手势配置和画布边界自动约束。
clearInteraction() 清空 selection、tooltip、cursor、activeLegend,不重置当前 viewport。
highlight(target) 程序化高亮指定点位,不主动显示 tooltip。
showTooltip(target) 程序化显示 tooltip,并同步 activeLegend 和 cursor。
hideTooltip() 主动关闭 tooltip。
appendData(input) line / bar / combo 的类目和系列尾部追加数据。
updateData(input) 替换 line / bar / combo 的类目或指定系列数据。
reset() 重置 viewport、图例、selection、tooltip、cursor 等交互状态。
resize() 重新计算尺寸并重绘,适合外部原地修改 frame 后主动触发。
exportImage() 返回 PNG dataURL;当前宿主不支持 toDataURL 时返回空字符串。
dispatchCommand(command) 低层命令入口,业务侧优先使用上面的高层方法。

target 支持以下字段,可按索引或 key 定位:

type HansChartTarget = {
  legendIndex?: number
  legendKey?: string
  dataIndex?: number
  dataKey?: string
}

appendData()updateData() 的输入格式:

{
  categories?: string[]
  series: [
    {
      legendIndex?: number
      legendKey?: string
      values?: (number | null)[]
      data?: Array<{
        key?: string
        x?: number | string | null
        y?: number | null
        value?: number | null
        rawDatum?: any | null
      }>
    }
  ]
}

使用限制

  • 当前主要支持 uni-app x 的 App Android 和 App iOS。
  • dataZoom 建议使用 inside 窗口裁剪;slider UI 不是当前稳定能力。
  • brush 已提供配置结构,但框选 UI 和正式框选事件不建议在业务中依赖。
  • exportImage() 依赖宿主 canvas 的 toDataURL 能力,App 端不可用时会返回空字符串。
  • 如果外部通过 appendData()updateData() 修改运行时数据,之后再传入新的 props.spec 时,以新的外部 spec 为准。

隐私与权限

插件不包含广告,不采集数据,不声明额外系统权限,也不依赖额外第三方 SDK。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。