echarts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ECharts

ECharts

Use this skill to build, audit, or fix Apache ECharts charts without turning the task into an option-reference lookup. Match the project's existing setup first; only introduce wrappers or new dependencies when the project has none.
使用此技能可以构建、审计或修复Apache ECharts图表,无需反复查阅选项参考文档。首先匹配项目现有配置;仅当项目未使用任何相关依赖时,才引入包装器或新依赖。

Decision Tree

决策树

User task -> Does the project already use ECharts?
    - Yes -> Find existing chart components/helpers, reuse their init, theme,
             and resize patterns. Match import style (full vs echarts/core).
    - No -> Pick integration by framework:
        - React -> echarts-for-react wrapper, or a small hook around
                   init/dispose if the project avoids extra deps
        - Vue 3 -> vue-echarts wrapper, or composable around init/dispose
        - Vanilla / other -> echarts.init on a sized container

Next -> Bundle size a concern (app ships to users)?
    - Yes -> Import from 'echarts/core' and register only the used charts,
             components, and renderer (tree-shaking)
    - No / internal tool / prototype -> import * as echarts from 'echarts'

Then -> Build the smallest working option, render it, then layer on
        interactivity (tooltip, dataZoom, toolbox) and theming.
用户任务 -> 项目是否已使用ECharts?
    - 是 -> 查找现有图表组件/辅助工具,复用其初始化、主题和缩放模式。匹配导入风格(完整导入 vs echarts/core)。
    - 否 -> 根据框架选择集成方式:
        - React -> 使用echarts-for-react包装器,若项目避免额外依赖则基于init/dispose编写小型钩子
        - Vue 3 -> 使用vue-echarts包装器,或基于init/dispose编写组合式函数
        - 原生JS / 其他 -> 在已设置尺寸的容器上调用echarts.init

下一步 -> 是否关注包体积(应用需交付给用户)?
    - 是 -> 从'echarts/core'导入,并仅注册使用到的图表、组件和渲染器(摇树优化)
    - 否 / 内部工具 / 原型 -> 导入* as echarts from 'echarts'

然后 -> 构建最小可用配置并渲染,再逐步添加交互功能(提示框、数据区域缩放、工具栏)和主题配置。

Core Workflow

核心工作流

  1. Inspect first: find existing ECharts usage, themes, and shared option helpers before writing a new chart.
  2. Size the container: the container element must have non-zero width and height before
    echarts.init
    runs; a chart in a display:none or unmounted tab renders blank.
  3. Own the lifecycle: one
    init
    per container,
    resize()
    on container size change,
    dispose()
    on unmount. Wrappers handle this; hand-rolled code must.
  4. Update via
    setOption
    : default merge mode for incremental updates (streaming, new data);
    notMerge: true
    when the chart type or structure changes.
  5. Verify visually: render the chart and check axes, labels, and tooltip against real data before polishing.
  1. 先检查:在编写新图表前,查找现有ECharts用法、主题和共享配置辅助工具。
  2. 设置容器尺寸:在
    echarts.init
    执行前,容器元素必须具备非零宽高;处于display:none状态或未挂载标签页中的图表会渲染为空白。
  3. 管理生命周期:每个容器对应一次
    init
    ,容器尺寸变化时调用
    resize()
    ,卸载时调用
    dispose()
    。包装器会处理这些逻辑;手动编写的代码必须实现这些步骤。
  4. 通过
    setOption
    更新:默认合并模式用于增量更新(流式数据、新数据);当图表类型或结构变化时,使用
    notMerge: true
  5. 视觉验证:渲染图表后,对照真实数据检查坐标轴、标签和提示框,再进行优化。

Setup

安装

bash
npm install echarts                      # core library (always)
npm install echarts-for-react            # React wrapper (optional)
npm install vue-echarts                  # Vue 3 wrapper (optional)
Tree-shakeable imports for production bundles:
ts
import * as echarts from 'echarts/core';
import { LineChart, BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent, DataZoomComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';

echarts.use([LineChart, BarChart, GridComponent, TooltipComponent, DataZoomComponent, CanvasRenderer]);
A missing registration fails at runtime with a console error naming the missing chart/component — register it, do not switch to full import to silence the error. It is a
console.error
, not a thrown exception, so unit tests pass silently over it; catch it by asserting on the console or the rendered output.
With multiple chart components in one codebase, prefer a shared registration module (one
echarts.use([...])
call imported everywhere) over per-component
use
lists — per-component lists drift out of sync and hide missing registrations until a component renders alone. Deliberate feature-specific registration in code-split routes is a valid exception for lazy-loaded dashboards.
Type imports:
import type { ... } from 'echarts'
is erased at compile time and does not affect the bundle — only value imports from the root package pull everything in. Some types (
XAXisComponentOption
,
DefaultLabelFormatterCallbackParams
) are exported only from the root, so mixing
import type
from
'echarts'
with values from
'echarts/core'
is normal; prefer
ComposeOption
from
'echarts/core'
for option types:
ts
import type { ComposeOption } from 'echarts/core';
import type { LineSeriesOption } from 'echarts/charts';
import type { GridComponentOption, TooltipComponentOption } from 'echarts/components';

type ChartOption = ComposeOption<LineSeriesOption | GridComponentOption | TooltipComponentOption>;
bash
npm install echarts                      # 核心库(必装)
npm install echarts-for-react            # React包装器(可选)
npm install vue-echarts                  # Vue 3包装器(可选)
生产包的摇树优化导入方式:
ts
import * as echarts from 'echarts/core';
import { LineChart, BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent, DataZoomComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';

echarts.use([LineChart, BarChart, GridComponent, TooltipComponent, DataZoomComponent, CanvasRenderer]);
缺少注册会在运行时触发控制台错误,提示缺失的图表/组件——注册该组件即可,不要通过完整导入来掩盖错误。这是
console.error
而非抛出异常,因此单元测试会静默通过;可通过断言控制台输出或渲染结果来捕获该问题。
若代码库中有多个图表组件,优先使用共享注册模块(一处
echarts.use([...])
调用,各处导入),而非每个组件单独维护
use
列表——单独列表会逐渐不一致,且只有当组件单独渲染时才会暴露缺失的注册。对于懒加载仪表盘,在代码拆分路由中刻意进行特定功能的注册是合理的例外情况。
类型导入:
import type { ... } from 'echarts'
会在编译时被移除,不影响包体积——只有从根包导入才会引入全部内容。部分类型(如
XAXisComponentOption
DefaultLabelFormatterCallbackParams
)仅从根包导出,因此混合使用
import type
(来自
'echarts'
)和值导入(来自
'echarts/core'
)是正常的;优先使用
'echarts/core'
中的
ComposeOption
作为配置类型:
ts
import type { ComposeOption } from 'echarts/core';
import type { LineSeriesOption } from 'echarts/charts';
import type { GridComponentOption, TooltipComponentOption } from 'echarts/components';

type ChartOption = ComposeOption<LineSeriesOption | GridComponentOption | TooltipComponentOption>;

Lifecycle Rules

生命周期规则

  • Vanilla: keep the chart instance; call
    chart.resize()
    from a
    ResizeObserver
    on the container; call
    chart.dispose()
    before removing the container.
  • React (echarts-for-react): pass
    option
    as a prop; use
    notMerge
    prop when replacing structure; get the instance via
    ref.getEchartsInstance()
    only for imperative needs (streaming
    setOption
    ,
    dispatchAction
    ).
  • React (hand-rolled hook):
    init
    in an effect,
    dispose
    in its cleanup; keep
    option
    updates in a separate effect so the chart is not re-created on every render.
  • Vue (vue-echarts): use
    :option
    binding with
    autoresize
    ; access the instance via template ref for
    dispatchAction
    . Pass
    :update-options="{ notMerge: true }"
    for structural option changes (chart type, series count, removing axes/series) — merge mode keeps stale series. Switch themes via the
    theme
    prop or
    THEME_KEY
    injection, not
    update-options
    (on older ECharts/vue-echarts versions, remount/re-init instead). Use the
    group
    prop to link charts (equivalent to
    echarts.connect
    ).
  • Never call
    echarts.init
    twice on the same DOM node; reuse the instance or dispose first (
    echarts.getInstanceByDom
    to check).
  • 原生JS:保留图表实例;通过容器上的
    ResizeObserver
    调用
    chart.resize()
    ;移除容器前调用
    chart.dispose()
  • React(echarts-for-react):将
    option
    作为属性传递;替换结构时使用
    notMerge
    属性;仅在需要命令式操作(流式
    setOption
    dispatchAction
    )时,通过
    ref.getEchartsInstance()
    获取实例。
  • React(手动编写钩子):在副作用中执行
    init
    ,在清理函数中执行
    dispose
    ;将
    option
    更新放在单独的副作用中,避免图表在每次渲染时重新创建。
  • Vue(vue-echarts):使用
    :option
    绑定并开启
    autoresize
    ;通过模板引用访问实例以执行
    dispatchAction
    。当配置结构变化(图表类型、系列数量、移除坐标轴/系列)时,传递
    :update-options="{ notMerge: true }"
    ——合并模式会保留过时的系列数据。通过
    theme
    属性或
    THEME_KEY
    注入切换主题,而非使用
    update-options
    (在旧版ECharts/vue-echarts中,需重新挂载/初始化)。使用
    group
    属性关联图表(等同于
    echarts.connect
    )。
  • 切勿在同一DOM节点上多次调用
    echarts.init
    ;复用实例或先执行
    dispose
    (可通过
    echarts.getInstanceByDom
    检查)。

Data and Options

数据与配置

  • Prefer the
    dataset
    component (
    source
    +
    encode
    ) when multiple series or charts share one table of data; use per-series
    data
    for simple single-series charts.
  • Time series: use
    xAxis: { type: 'time' }
    with
    [timestamp, value]
    pairs instead of pre-formatting date strings into a category axis.
  • Large categorical axes: set
    axisLabel.interval
    /
    rotate
    deliberately instead of accepting overlap.
  • Tooltips:
    trigger: 'axis'
    for line/bar time series,
    trigger: 'item'
    for pie/scatter/map.
  • Use
    valueFormatter
    or
    tooltip.formatter
    for units; keep number formatting in one shared helper when the dashboard has many charts.
  • HTML tooltip
    formatter
    output is injected as HTML: escape untrusted data (series names, user-generated labels) with a shared escape helper, or use
    tooltip.renderMode: 'richText'
    to opt out of HTML entirely.
  • 当多个系列或图表共享一份数据表时,优先使用
    dataset
    组件(
    source
    +
    encode
    );简单单系列图表使用每个系列的
    data
  • 时间序列:使用
    xAxis: { type: 'time' }
    搭配
    [时间戳, 值]
    数组,而非将日期字符串预格式化为分类坐标轴。
  • 大型分类坐标轴:刻意设置
    axisLabel.interval
    /
    rotate
    ,避免标签重叠。
  • 提示框:折线/柱状时间序列使用
    trigger: 'axis'
    ,饼图/散点图/地图使用
    trigger: 'item'
  • 使用
    valueFormatter
    tooltip.formatter
    处理单位;当仪表盘包含多个图表时,将数字格式化逻辑放在共享辅助工具中。
  • HTML提示框的
    formatter
    输出会以HTML形式注入:使用共享转义工具对不可信数据(系列名称、用户生成的标签)进行转义,或使用
    tooltip.renderMode: 'richText'
    完全禁用HTML。

Performance

性能优化

  • Canvas (default renderer) is fine up to ~100K points; use SVG renderer only for small charts needing crisp export or DOM-level styling.
  • For large line/scatter series: enable
    large: true
    and
    sampling: 'lttb'
    on the series; turn off
    animation
    for initial render of big datasets.
  • Millions of points: use
    echarts-gl
    (WebGL) — a separate dependency; add it only when actually needed.
  • Streaming: call
    setOption({ series: [{ data }] })
    on the existing instance (merge mode); do not re-init or pass
    notMerge
    per tick.
  • Many charts on one page: share a single
    ResizeObserver
    /resize handler and use
    echarts.connect
    for linked tooltips/dataZoom instead of duplicating handlers.
    connect
    is also a UX feature for dashboards:
    chart.group = 'name'; echarts.connect('name')
    (or the vue-echarts
    group
    prop) syncs tooltips and dataZoom across related charts. Only link charts with compatible axis semantics (same x-axis type and domain); a chart with a different axis belongs in its own group or unlinked.
  • Canvas(默认渲染器)在处理约10万数据点时表现良好;仅在需要清晰导出或DOM级样式的小型图表中使用SVG渲染器。
  • 大型折线/散点系列:在系列上启用
    large: true
    sampling: 'lttb'
    ;大数据集初始渲染时关闭
    animation
  • 百万级数据点:使用
    echarts-gl
    (WebGL)——这是一个独立依赖;仅在实际需要时添加。
  • 流式数据:在现有实例上调用
    setOption({ series: [{ data }] })
    (合并模式);不要每次更新都重新初始化或传递
    notMerge
  • 单页多图表:共享单个
    ResizeObserver
    /缩放处理函数,并使用
    echarts.connect
    实现关联提示框/数据区域缩放,避免重复处理函数。
    connect
    也是仪表盘的UX特性:
    chart.group = 'name'; echarts.connect('name')
    (或vue-echarts的
    group
    属性)可同步关联图表的提示框和数据区域缩放。仅关联具有兼容坐标轴语义(相同x轴类型和范围)的图表;坐标轴不同的图表应单独分组或不关联。

Theming

主题配置

  • Register a theme once (
    echarts.registerTheme('name', themeObject)
    ) and pass the name to every
    init
    ; do not copy color arrays into each chart's option.
  • Dark mode: prefer
    init(el, null, ...)
    plus a registered dark theme, or
    darkMode: true
    in the option. Switch themes at runtime with
    chart.setTheme(...)
    (ECharts 6) or the vue-echarts
    theme
    prop; on ECharts 5 themes are fixed at init time — re-init (dispose + init) there.
  • Keep chart-independent styling (font family, palette) in the theme; keep data-dependent styling (visualMap ranges, markLines) in the option.
  • 注册一次主题(
    echarts.registerTheme('name', themeObject)
    ),并在每次
    init
    时传递主题名称;不要将颜色数组复制到每个图表的配置中。
  • 暗黑模式:优先使用
    init(el, null, ...)
    搭配已注册的暗黑主题,或在配置中设置
    darkMode: true
    。在运行时切换主题可使用
    chart.setTheme(...)
    (ECharts 6)或vue-echarts的
    theme
    属性;在ECharts 5中主题在初始化时固定——需重新初始化(dispose + init)。
  • 将与图表无关的样式(字体族、调色板)放在主题中;将与数据相关的样式(视觉映射范围、标记线)放在配置中。

SSR and Export

SSR与导出

  • Server-side rendering (reports, emails, OG images):
    echarts.init(null, null, { renderer: 'svg', ssr: true, width, height })
    then
    renderToSVGString()
    — Node only, no DOM needed.
  • If option builders are shared between the browser and a Node SVG renderer, keep both
    echarts.use([...])
    registration points covering the same set — a narrower server-side list silently renders without the missing components.
  • Client image export: enable
    toolbox.feature.saveAsImage
    , or call
    chart.getDataURL({ pixelRatio: 2 })
    programmatically.
  • 服务端渲染(报表、邮件、OG图片):
    echarts.init(null, null, { renderer: 'svg', ssr: true, width, height })
    ,然后调用
    renderToSVGString()
    ——仅支持Node环境,无需DOM。
  • 若配置构建器在浏览器和Node SVG渲染器之间共享,确保两处
    echarts.use([...])
    注册的组件集一致——服务端注册范围过窄会静默渲染缺失的组件。
  • 客户端图片导出:启用
    toolbox.feature.saveAsImage
    ,或通过编程方式调用
    chart.getDataURL({ pixelRatio: 2 })

ECharts 6 Migration Notes

ECharts 6迁移注意事项

  • grid.containLabel
    is deprecated. The semantics-preserving migration is
    containLabel: true
    { outerBoundsMode: 'same', outerBoundsContain: 'axisLabel' }
    ; set
    grid.outerBounds
    only when you need a custom constraint rect (it is a separate part of the new layout API). The legacy behavior still works only if
    LegacyGridContainLabel
    (from
    'echarts/features'
    ) is registered — treat remaining
    containLabel: true
    usages as tech debt when auditing.
  • The default theme changed in v6 (palette and component layout). To keep the v5 look during migration:
    import 'echarts/theme/v5'
    and pass
    'v5'
    as the theme to
    init
    .
  • Axis label overflow prevention and axis-name overlap prevention are on by default in v6, which can shift layouts slightly; disable with
    grid.outerBoundsMode: 'none'
    and
    xAxis/yAxis.nameMoveOverlap: false
    when pixel-parity with v5 matters.
  • Check the installed major version (
    node_modules/echarts/package.json
    ) before recommending options; deprecations surface as console warnings, not errors.
  • grid.containLabel
    已废弃。语义保留的迁移方式是
    containLabel: true
    { outerBoundsMode: 'same', outerBoundsContain: 'axisLabel' }
    ;仅当需要自定义约束矩形时才设置
    grid.outerBounds
    (这是新布局API的独立部分)。只有注册了
    LegacyGridContainLabel
    (来自
    'echarts/features'
    ),旧行为才会生效——审计时将剩余的
    containLabel: true
    用法视为技术债务。
  • v6默认主题已更改(调色板和组件布局)。若迁移期间需保留v5外观:
    import 'echarts/theme/v5'
    并在
    init
    时传递
    'v5'
    作为主题。
  • v6默认启用坐标轴标签溢出预防和轴名称重叠预防,这可能导致布局略有偏移;当需要与v5像素级一致时,可通过
    grid.outerBoundsMode: 'none'
    xAxis/yAxis.nameMoveOverlap: false
    禁用。
  • 在推荐配置前,检查已安装的主版本(
    node_modules/echarts/package.json
    );废弃API会以控制台警告而非错误形式出现。

Auditing Existing Usage

审计现有用法

When reviewing (not building) a codebase's ECharts usage, check in order:
  1. Registrations: one shared
    use([...])
    module vs per-component lists that drift; missing or duplicated registrations; with SSR, verify the client and server
    use([...])
    lists cover the same components.
  2. Lifecycle: every
    init
    has a matching
    dispose
    ; resize observed on the container, not the window.
  3. Update semantics:
    notMerge
    /
    update-options
    used where chart type, series count, or axes/series are removed.
  4. Imports: value imports from root
    'echarts'
    in tree-shaken builds;
    import type
    is fine.
  5. Deprecated API:
    containLabel
    and other version-migration debt (see migration notes above).
  6. Duplication: repeated option/formatter logic that belongs in a shared helper or registered theme.
审查(而非构建)代码库中的ECharts用法时,按以下顺序检查:
  1. 注册:是否使用单个共享
    use([...])
    模块,而非逐渐不一致的组件单独列表;是否存在缺失或重复注册;若使用SSR,验证客户端和服务端
    use([...])
    列表包含相同组件。
  2. 生命周期:每个
    init
    是否对应
    dispose
    ;是否监听容器而非窗口的缩放事件。
  3. 更新语义:在图表类型、系列数量或坐标轴/系列被移除时,是否使用
    notMerge
    /
    update-options
  4. 导入:摇树优化构建中是否从根
    'echarts'
    导入值;
    import type
    是允许的。
  5. 废弃API
    containLabel
    及其他版本迁移债务(见上述迁移注意事项)。
  6. 重复代码:重复的配置/格式化逻辑是否应放在共享辅助工具或已注册的主题中。

Common Failure Modes

常见故障模式

  • Blank chart, no error: container had zero size at init (hidden tab, flex parent without height, init before mount). Fix sizing/timing, then call
    resize()
    .
  • Chart does not update: a new option object with merge mode silently keeps stale series/axes — use
    notMerge: true
    when removing series or changing chart type.
  • Legend/dataZoom selection lost after update:
    notMerge: true
    resets interactive state; capture
    chart.getOption().legend[0].selected
    (and dataZoom range) before the update and pass it back in the new option.
  • "Component xxx not exists" / missing chart: tree-shaken build without the registration; add it to
    echarts.use([...])
    .
  • Memory growth in SPA: instances not disposed on route change; verify
    dispose()
    runs in unmount cleanup.
  • Chart wrong size after sidebar/panel toggle: window
    resize
    event never fired; observe the container (ResizeObserver /
    autoresize
    ), not the window.
  • Tooltip clipped: set
    tooltip.confine: true
    or
    appendToBody
    -style
    tooltip.appendTo
    when the chart sits in an overflow-hidden container.
  • Sluggish with big data: animation on + no sampling; set
    animation: false
    ,
    sampling: 'lttb'
    ,
    large: true
    before reaching for WebGL.
  • 空白图表,无错误:初始化时容器尺寸为零(隐藏标签页、无高度的flex父元素、挂载前初始化)。修复尺寸/时机后调用
    resize()
  • 图表不更新:合并模式下的新配置对象会静默保留过时的系列/坐标轴——移除系列或更改图表类型时使用
    notMerge: true
  • 更新后图例/数据区域缩放选择丢失
    notMerge: true
    会重置交互状态;更新前捕获
    chart.getOption().legend[0].selected
    (以及数据区域缩放范围),并在新配置中传递回去。
  • "Component xxx not exists" / 图表缺失:摇树优化构建未注册该组件;将其添加到
    echarts.use([...])
    中。
  • SPA中内存增长:路由切换时未销毁实例;验证
    dispose()
    在卸载清理时执行。
  • 侧边栏/面板切换后图表尺寸错误:未触发窗口
    resize
    事件;监听容器(ResizeObserver /
    autoresize
    )而非窗口。
  • 提示框被裁剪:当图表处于overflow-hidden容器中时,设置
    tooltip.confine: true
    或类似
    appendToBody
    tooltip.appendTo
  • 大数据下性能缓慢:启用了动画且未使用采样;在考虑WebGL前,先设置
    animation: false
    sampling: 'lttb'
    large: true

Reference Examples

参考示例

  • examples/vanilla_line.html
    - Vanilla JS time-series line chart with resize handling
  • examples/react_chart.tsx
    - React component with tree-shaken imports and echarts-for-react
  • examples/vue_chart.vue
    - Vue 3 component using vue-echarts with autoresize
  • examples/vanilla_line.html
    - 原生JS时间序列折线图,带缩放处理
  • examples/react_chart.tsx
    - React组件,使用摇树优化导入和echarts-for-react
  • examples/vue_chart.vue
    - Vue 3组件,使用vue-echarts并启用自动缩放