首页
/ Chart.js 3.0 迁移指南:从 2.x 到 3.0 的完整破坏性变更解析与源码印证

Chart.js 3.0 迁移指南:从 2.x 到 3.0 的完整破坏性变更解析与源码印证

2026-09-04 22:55:52作者:乔或婵

Chart.js 3.0 是一次以“性能、可配置性与可维护性”为目标的重大版本升级。本文基于仓库中的 v3-migration.md 迁移指南展开,完整覆盖从 2.x 升级到 3.0 时需要修改的安装方式、图表类型、配置项、默认值、坐标轴、动画、交互与插件 API,并结合当前仓库(4.x 系列源码)中的核心实现——构造函数、注册表、默认值系统、动画器、交互模式与数据控制器——逐条印证这些变更在代码中的落点。读完后你可以完成:把一份 2.x 配置完整改写到 3.0+ 语法、理解 scales/defaults/interaction 新体系的组织方式,以及开发自定义控制器、插件时的 API 迁移路径。

v3.0 升级亮点

官方文档给出的 v3.0 主要变化可以概括为:

  • 大幅的性能提升,包括可以跳过数据解析、通过 Web Workers 并行渲染图表,详见 性能优化
  • 更多的可配置项与 scriptable options,并改善了默认值;
  • 完全重写的动画系统;
  • 重写后的 filler 插件并修复了大量 bug;
  • 文档从 GitBook 迁移到 VuePress;
  • API 文档由 TypeDoc 生成和校验;
  • 不再向页面注入 CSS;
  • 大量 bug 修复;
  • 支持 tree shaking(摇树优化)。

这些亮点并非营销口径,可以从当前仓库源码中找到对应实现,后文会给出文件级证据。

终端用户迁移

安装与入口

  • 分发的文件名改为小写,例如 dist/chart.js
  • 不再提供 Chart.bundle.jsChart.bundle.min.js。如果你之前使用 bundle 构建,请参考 安装集成 文档中推荐的搭建方式。
  • moment 不再是 npm 依赖。如果你使用 timetimeseries 刻度,必须自行引入一个可用的日期适配器(adapter)及对应日期库,构建时也不再需要排除 moment。
  • 当传入的 canvas/context 已被占用时,Chart 构造函数会直接抛出错误。
  • Chart.js 3 支持 tree shaking。如果你以 npm 模块方式使用并希望利用该能力,需要自行 import 并注册要用的 controllers、elements、scales 和 plugins(可注册项清单见 集成)。通过 script 标签引入或从 auto 注册路径以 npm 模块引入时不需要调用 register,但也就享受不到摇树收益。

当前仓库中 package.jsondependencies 只有 @kurkle/color 一项,确认了 moment 已从依赖中移除;构建产物入口由 main/module/exports 字段声明(./dist/chart.cjs./dist/chart.js./auto/*./helpers/*)。

构造函数复用画布会抛错这一点,可以在 core.controller.js 中直接看到:

constructor(item, userConfig) {
  const config = this.config = new Config(userConfig);
  const initialCanvas = getCanvas(item);
  const existingChart = getChart(initialCanvas);
  if (existingChart) {
    throw new Error(
      'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' +
      ' must be destroyed before the canvas with ID \'' + existingChart.canvas.id + '\' can be reused.'
    );
  }
  // ...
}

tree shaking 与注册机制的入口在 src/index.ts:模块导出 controllerselementspluginsscales 四个命名空间,以及聚合了全部注册项的 registerables 数组;而 auto/auto.js 则代表“自动注册”路径——Chart.register(...registerables) 后再导出 Chart

迁移指南中给出的注册示例(保留原样,可直接使用):

import { Chart, LineController, LineElement, PointElement, LinearScale, Title } from 'chart.js'

Chart.register(LineController, LineElement, PointElement, LinearScale, Title);

const chart = new Chart(ctx, {
    type: 'line',
    // data: ...
    options: {
        plugins: {
            title: {
                display: true,
                text: 'Chart Title'
            }
        },
        scales: {
            x: {
                type: 'linear'
            },
            y: {
                type: 'linear'
            }
        }
    }
})

Chart.register 的静态方法在 core.controller.js 中定义为对 registry.add 的转发,并刷新插件缓存(invalidatePlugins),这也是 Chart.plugins.registerChart.register 取代的落点。

图表类型:horizontalBar 被移除

horizontalBar 图表类型被移除,横向柱状图改用新的 indexAxis 选项配置,详见 柱状图文档

在源码中,indexAxis 是一个 chart 级选项:默认值在 core.defaults.js 中定义为 'x',而 controller.bar.js 通过 this.chart.options.indexAxis === 'x' ? dataset.xAxisID : dataset.yAxisID 来决定哪条轴是索引轴。因此迁移时只需把 type: 'horizontalBar' 的图表改为 type: 'bar' 并在 options 中设置 indexAxis: 'y'

配置选项变更

通用变更

  • 可索引(indexable)选项现在是循环的。例如 backgroundColor: ['red', 'green'] 在数据点超过 2 个时会按 'red'/'green' 交替取色。
  • 对象型数据的输入属性名可以自由指定,详见 数据结构
  • 大多数选项现在通过 proxy 解析(resolver),而不是与默认值做合并。这既方便为不同上下文使用不同的解析路由,也允许在 scriptable options 中引用同一上下文里其他已解析的选项:
    • 选项默认是 scriptable 且 indexable 的,除非因故被禁用;
    • scriptable options 的第二个参数是一个 option resolver,用于访问同上下文的其他选项;
    • 解析沿作用域向上回退(falls to upper scopes)。详见 options

当前实现里,defaults.route()core.defaults.js)用 getter/setter 实现了这种“路由回退”,而 core.defaults.js 末尾的 descriptors 声明了 _scriptable/_indexable 等描述符规则,例如 interaction 被标记为不可 scriptable、events 不可 indexable。

具体选项改名与移除

以下逐条对应迁移指南中的 “Specific changes”,建议直接按表改写配置:

2.x 写法 3.0 写法 / 说明
elements.rectangle elements.bar
hover.animationDuration 改为 animation.active.duration
responsiveAnimationDuration 改为 animation.resize.duration
极坐标图 elements.arc.angle 以“度”配置,不再是弧度
极坐标图 startAngle 与 Radar 对齐:0 在正上方、单位为度;默认值由 -½π 改为 0
Doughnut rotation 单位为度且 0 在正上方;默认值由 -½π 改为 0
Doughnut circumference 单位为度;默认值由 改为 360
Doughnut cutoutPercentage 改名为 cutout,接受像素(数字)或以 % 结尾的字符串(百分比)
scale 选项 移除,改用 options.scales.r(或任意 scale id,axis: 'r'
scales.[x/y]Axes 数组 移除。scales 直接挂在 options.scales 对象上,以 scale id 为键
scales.[x/y]Axes.barPercentage 移到数据集选项 barPercentage
scales.[x/y]Axes.barThickness 移到数据集选项 barThickness
scales.[x/y]Axes.categoryPercentage 移到数据集选项 categoryPercentage
scales.[x/y]Axes.maxBarThickness 移到数据集选项 maxBarThickness
scales.[x/y]Axes.minBarLength 移到数据集选项 minBarLength
scales.[x/y]Axes.scaleLabel 改名为 scales[id].title
scales.[x/y]Axes.scaleLabel.labelString 改名为 scales[id].title.text
scales.[x/y]Axes.ticks.beginAtZero 改名为 scales[id].beginAtZero
scales.[x/y]Axes.ticks.max 改名为 scales[id].max
scales.[x/y]Axes.ticks.min 改名为 scales[id].min
scales.[x/y]Axes.ticks.reverse 改名为 scales[id].reverse
scales.[x/y]Axes.ticks.suggestedMax 改名为 scales[id].suggestedMax
scales.[x/y]Axes.ticks.suggestedMin 改名为 scales[id].suggestedMin
scales.[x/y]Axes.ticks.unitStepSize 移除,使用 scales[id].ticks.stepSize
scales.[x/y]Axes.ticks.userCallback 改名为 scales[id].ticks.callback
scales.[x/y]Axes.time.format 改名为 scales[id].time.parser
scales.[x/y]Axes.time.max 改名为 scales[id].max
scales.[x/y]Axes.time.min 改名为 scales[id].min
scales.[x/y]Axes.zeroLine* 系列选项 移除,改用 scriptable scale options
数据集选项 steppedLine 移除,使用 stepped
图表选项 showLines 改名为 showLine,与数据集选项一致(当前默认值见 core.defaults.jsshowLine: true
图表选项 startAngle 移到 radial 刻度选项
覆盖平台类 在 config 对象中传入 platform: PlatformClass。注意传的是类而不是实例;core.controller.js 中对应 `new (config.platform
aspectRatio 默认值 doughnut、pie、polarArea、radar 图表默认变为 1
TimeScale 从对象数据读取 t 不再默认读取 t,默认属性为 xy(取决于方向),如何修改见 数据结构
tooltips 命名空间 改名为 tooltip,与插件名一致
legendtitletooltip 命名空间 options 移到 options.plugins
tooltips.custom 改名为 plugins.tooltip.external

默认值体系(Defaults)

  • defaults 中的 global 命名空间被移除:Chart.defaults.global 现在就是 Chart.defaults
  • 数据集控制器的默认值移到 overrides:例如 Chart.defaults.line 现在是 Chart.overrides.line
  • 默认值去掉了 default 前缀:例如 Chart.defaults.global.defaultColor 现在是 Chart.defaults.color
  • defaultColor 被拆分为 colorborderColorbackgroundColor(三者当前默认值见 core.defaults.js)。
  • defaultFontColor 改名为 color
  • defaultFontFamily 改名为 font.family
  • defaultFontSize 改名为 font.size
  • defaultFontStyle 改名为 font.style
  • defaultLineHeight 改名为 font.lineHeight
  • 横向柱状图的默认 tooltip 交互模式由 'index' 改为 'nearest',以匹配竖向柱状图。
  • legendtitletooltip 命名空间从 Chart.defaults 移到 Chart.defaults.plugins
  • elements.line.fill 默认值由 true 改为 false
  • Line 图表不再覆盖默认的 interaction 模式:默认值由 'index' 改为 'nearest'。当前 core.defaults.jsinteraction 默认为 {mode: 'nearest', intersect: true, includeInvisible: false},与此一致。

overrides 在源码中的形态是 core.defaults.js 的独立对象,Defaults.override(scope, values) 方法(L109-L111)负责写入它。

坐标轴(Scales):v3 中最大的变化

v3 中坐标轴配置是变化最大的部分:xAxes/yAxes 数组被移除,每一条轴现在是以 scale id 为键的独立 scale。

v2 配置:

options: {
  scales: {
    xAxes: [{
      id: 'x',
      type: 'time',
      display: true,
      title: {
        display: true,
        text: 'Date'
      },
      ticks: {
        major: {
          enabled: true
        },
        font: function(context) {
          if (context.tick && context.tick.major) {
            return {
              weight: 'bold',
              color: '#FF0000'
            };
          }
        }
      }
    }],
    yAxes: [{
      id: 'y',
      display: true,
      title: {
        display: true,
        text: 'value'
      }
    }]
  }
}

对应 v3 配置:

options: {
  scales: {
    x: {
      type: 'time',
      display: true,
      title: {
        display: true,
        text: 'Date'
      },
      ticks: {
        major: {
          enabled: true
        },
        color: (context) => context.tick && context.tick.major && '#FF0000',
        font: function(context) {
          if (context.tick && context.tick.major) {
            return {
              weight: 'bold'
            };
          }
        }
      }
    },
    y: {
      display: true,
      title: {
        display: true,
        text: 'value'
      }
    }
  }
}

注意:2.x 中“按 ticks 内的函数返回完整样式”的写法,在 v3 里拆成了多个可 scriptable 的属性(如 ticks.colorticks.font),这与上面“proxy 解析 + scriptable”的通用机制一致。

源码层面,scales 以 id 为键的组织方式体现在 core.controller.jsensureScalesHaveIDs(把 options.scales 的键直接写成 axisOptions.id)以及 buildOrUpdateScales(按 id 复用或新建 scale 实例,未使用的 id 会被清理)。

另外两条与 time 刻度相关的变更:

  • distribution: 'series' 选项被移除,取而代之的是新的 scale 类型 timeseries
  • time 刻度的 autoSkip 现在与其他刻度保持一致,默认开启。

动画(Animations)

动画系统在 v3 中被完全重写,现在每个属性都可以独立配置动画,详见 动画

当前实现中,动画由两个协作部分组成:单例 Animator(基于 requestAnimFrame 的轮询循环,start/stop/running/add 管理各图表的动画项,并触发 progress/complete 监听器)以及 core.controller.js 中把 onComplete/onProgress 回调挂到 animator 上的逻辑。Chart.Animation.animationObject 改名为 Chart.AnimationchartInstance 改名为 chart 的 API 变化,正是服务于这套新结构。

可定制性(Customizability)

  • 元素的 custom 属性被移除,请改用 scriptable options。
  • scriptable options 的 context 对象中,hover 属性改名为 active,以对齐 datalabels 插件的命名。

交互(Interactions)

  • 为支持 DRY 配置,新增了交互选项的根作用域:options.hoveroptions.plugins.tooltip 现在都从 options.interaction 派生。默认值定义在 defaults.interaction 层,因此 hover 与 tooltip 交互默认共享同一套 mode 等设置(当前默认值 {mode: 'nearest', intersect: true, includeInvisible: false}core.defaults.js,且 hover 通过 _fallback: 'interaction' 描述符路由到 interaction)。
  • 交互命中范围被限制在图表区域 + 允许的溢出(overflow)之内。
  • {mode: 'label'}{mode: 'index'} 取代;
  • {mode: 'single'}{mode: 'nearest', intersect: true} 取代;
  • modes['X-axis']{mode: 'index', intersect: false} 取代;
  • options.onClick 现在只在图表区域内生效;
  • options.onClickoptions.onHover 现在会收到 chart 实例作为第 3 个参数;
  • options.onHover 现在收到一个包装后的 event 作为第 1 个参数,原参数值可通过 event.native 访问。
  • options.hover.onHover 被移除,使用 options.onHover

交互模式的实现集中在 core.interaction.jsmodes 对象只提供 indexdatasetpointnearestxy 五种模式——label/single/X-axis 在 v3 中确实不复存在,需要按上表改写。

刻度与网格(Ticks / Grid)

  • options.gridLines 改名为 options.grid
  • options.gridLines.offsetGridLines 改名为 options.grid.offset
  • options.gridLines.tickMarkLength 改名为 options.grid.tickLength
  • options.ticks.fixedStepSize 不再使用,改用 options.ticks.stepSize
  • options.ticks.majoroptions.ticks.minor 被 tick 字体的 scriptable options 取代;
  • Chart.Ticks.formatters.linear 改名为 Chart.Ticks.formatters.numeric
  • options.ticks.backdropPaddingXoptions.ticks.backdropPaddingY 在 radial linear 刻度中被 options.ticks.backdropPadding 取代。

Tooltip

  • xLabelyLabel 被移除,请改用 labelformattedValue
  • filter 选项调用时会收到额外参数,方法签名应为 function(tooltipItem, index, tooltipItems, data)
  • custom 回调现在接收一个带 tooltipchart 属性的 context 对象;
  • tooltip 模型中所有与 tooltip 选项相关的属性都移入 options 属性内;
  • 回调不再接收 data 参数,tooltip item 参数里直接携带 chart 和 dataset;
  • tooltip item 的 index 改名为 dataIndexvalue 改名为 formattedValue
  • xPaddingyPadding 合并为单个 padding 对象。

开发者迁移

终端用户的迁移相对直接,但面向插件作者、自定义控制器/刻度开发者的迁移更复杂。文档提示:如果需要迁移帮助,可以在项目社区渠道(#dev Discord)提问。以下按“移除 / 改名 / 行为变化”三类完整列出变更。

移除的 API

从 Chart 移除

  • Chart.animationService
  • Chart.active
  • Chart.borderWidth
  • Chart.chart.chart
  • Chart.Bar:新图表通过 new Chart 并提供相应 type 参数创建
  • Chart.Bubble:同上
  • Chart.Chart
  • Chart.Controller
  • Chart.Doughnut:同上
  • Chart.innerRadius:现位于 doughnut、pie、polarArea 控制器上
  • Chart.lastActive
  • Chart.Legend:移到 Chart.plugins.legend._element 并变为私有
  • Chart.Line:同 Chart.Bar
  • Chart.LinearScaleBase:需自行 import,不能从 Chart 对象访问
  • Chart.offsetX
  • Chart.offsetY
  • Chart.outerRadius:现位于 doughnut、pie、polarArea 控制器上
  • Chart.plugins:被 Chart.registry 取代(当前 core.controller.jsstatic registry = registry)。插件默认值现在位于 Chart.defaults.plugins[id]
  • Chart.plugins.register:被 Chart.register 取代
  • Chart.PolarArea:同 Chart.Bar
  • Chart.prototype.generateLegend
  • Chart.platform:原本只包含 disableCSSInjection,v3 永不注入 CSS,故移除
  • Chart.PluginBase
  • Chart.Radar:同 Chart.Bar
  • Chart.radiusLength
  • Chart.scaleService:被 Chart.registry 取代。刻度默认值现在位于 Chart.defaults.scales[type]
  • Chart.Scatter:同 Chart.Bar
  • Chart.types
  • Chart.Title:移到 Chart.plugins.title._element 并变为私有
  • Chart.Tooltip:现在由 tooltip 插件提供,positioners 可从 tooltipPlugin.positioners 访问
  • ILayoutItem.minSize

从 Dataset Controller 移除

  • BarController.getDatasetMeta().bar
  • DatasetController.addElementAndReset
  • DatasetController.createMetaData
  • DatasetController.createMetaDataset
  • DoughnutController.getRingIndex

从 Elements 移除

  • Element.getArea
  • Element.height
  • Element.hidden:被 chart 级状态取代,可用 getDataVisibility(index) / toggleDataVisibility(index)(当前实现见 core.controller.js
  • Element.initialize
  • Element.inLabelRange
  • Line.calculatePointY

从 Helpers 移除

  • helpers.addEvent
  • helpers.aliasPixel
  • helpers.arrayEquals
  • helpers.configMerge
  • helpers.findIndex
  • helpers.findNextWhere
  • helpers.findPreviousWhere
  • helpers.extend:改用 Object.assign
  • helpers.getValueAtIndexOrDefault:改用 helpers.resolve
  • helpers.indexOf
  • helpers.lineTo
  • helpers.longestText:变为私有
  • helpers.max
  • helpers.measureText:变为私有
  • helpers.min
  • helpers.nextItem
  • helpers.niceNum
  • helpers.numberOfLabelLines
  • helpers.previousItem
  • helpers.removeEvent
  • helpers.roundedRect
  • helpers.scaleMerge
  • helpers.where

从 Layout 移除

  • Layout.defaults

从 Scales 移除

  • LinearScaleBase.handleDirectionalChanges
  • LogarithmicScale.minNotZero
  • Scale.getRightValue
  • Scale.longestLabelWidth
  • Scale.longestTextCache:变为私有
  • Scale.margins:变为私有
  • Scale.mergeTicksOptions
  • Scale.ticksAsNumbers
  • Scale.tickValues:变为私有
  • TimeScale.getLabelCapacity:变为私有
  • TimeScale.tickFormatFunction:变为私有

从 Plugins(Legend、Title、Tooltip)移除

  • IPlugin.afterScaleUpdate:改用 afterLayout
  • Legend.margins:变为私有
  • Legend 的 onClickonHoveronLeave 选项现在除了隐式的 this 之外,还会把 legend 作为第 3 个参数传入
  • Legend 的 onClickonHoveronLeave 选项现在第 1 个参数是包装后的 event,原值可通过 event.native 访问
  • Title.margins:变为私有
  • tooltip item 的 xy 属性被 element 取代,可改用 element.xelement.yelement.tooltipPosition()

移除的公共 API

以下公共 API 被移除并给出了替代写法:

  • getElementAtEventchart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, false)
  • getElementsAtEventchart.getElementsAtEventForMode(e, 'index', { intersect: true }, false)
  • getElementsAtXAxischart.getElementsAtEventForMode(e, 'index', { intersect: false }, false)
  • getDatasetAtEventchart.getElementsAtEventForMode(e, 'dataset', { intersect: true }, false)

getElementsAtEventForMode 的实现见 core.controller.js:它直接查 Interaction.modes[mode] 并调用对应方法,模式名与上面 modes 对象中的键一一对应。

移除的私有 API

  • Chart._bufferedRender
  • Chart._updating
  • Chart.data.datasets[datasetIndex]._meta
  • DatasetController._getIndexScaleId
  • DatasetController._getIndexScale
  • DatasetController._getValueScaleId
  • DatasetController._getValueScale
  • Element._ctx
  • Element._model
  • Element._view
  • LogarithmicScale._valueOffset
  • TimeScale.getPixelForOffset
  • TimeScale.getLabelWidth
  • Tooltip._lastActive

改名的 API

  • Chart.Animation.animationObjectChart.Animation
  • Chart.Animation.chartInstanceChart.Animation.chart
  • Chart.canvasHelpers 合并进 Chart.helpers
  • Chart.elements.ArcChart.elements.ArcElement
  • Chart.elements.LineChart.elements.LineElement
  • Chart.elements.PointChart.elements.PointElement
  • Chart.elements.RectangleChart.elements.BarElement
  • Chart.layoutServiceChart.layouts
  • Chart.pluginServiceChart.plugins
  • helpers.callCallbackhelpers.callback
  • helpers.drawRoundedRectanglehelpers.roundedRect
  • helpers.getValueOrDefaulthelpers.valueOrDefault
  • LayoutItem.fullWidthLayoutItem.fullSize
  • Point.controlPointPreviousXPoint.cp1x
  • Point.controlPointPreviousYPoint.cp1y
  • Point.controlPointNextXPoint.cp2x
  • Point.controlPointNextYPoint.cp2y
  • Scale.calculateTickRotationScale.calculateLabelRotation
  • Tooltip.options.legendColorBackgroupdTooltip.options.multiKeyBackground

改名的私有 API:

  • BarController.calculateBarIndexPixelsBarController._calculateBarIndexPixels
  • BarController.calculateBarValuePixelsBarController._calculateBarValuePixels
  • BarController.getStackCountBarController._getStackCount
  • BarController.getStackIndexBarController._getStackIndex
  • BarController.getRulerBarController._getRuler
  • Chart.destroyDatasetMetaChart._destroyDatasetMeta
  • Chart.drawDatasetChart._drawDataset
  • Chart.drawDatasetsChart._drawDatasets
  • Chart.eventHandlerChart._eventHandler
  • Chart.handleEventChart._handleEvent
  • Chart.initializeChart._initialize
  • Chart.resetElementsChart._resetElements
  • Chart.unbindEventsChart._unbindEvents
  • Chart.updateDatasetChart._updateDataset
  • Chart.updateDatasetsChart._updateDatasets
  • Chart.updateLayoutChart._updateLayout
  • DatasetController.destroyDatasetController._destroy
  • DatasetController.insertElementsDatasetController._insertElements
  • DatasetController.onDataPopDatasetController._onDataPop
  • DatasetController.onDataPushDatasetController._onDataPush
  • DatasetController.onDataShiftDatasetController._onDataShift
  • DatasetController.onDataSpliceDatasetController._onDataSplice
  • DatasetController.onDataUnshiftDatasetController._onDataUnshift
  • DatasetController.removeElementsDatasetController._removeElements
  • DatasetController.resyncElementsDatasetController._resyncElements
  • LayoutItem.isFullWidthLayoutItem.isFullSize
  • RadialLinearScale.setReductionsRadialLinearScale._setReductions
  • RadialLinearScale.pointLabelsRadialLinearScale._pointLabels
  • Scale.handleMarginsScale._handleMargins

签名与行为变化

动画系统重写带来的影响

动画系统被完全重写且性能更好:

  • Element._modelElement._view 不再使用,属性直接设置在元素上。在 inXRange/inYRangegetCenterPoint 等大多数方法内部需要访问这些属性时,必须改用 getProps 方法。示例可参考仓库内置的元素实现(src/elements 目录)。
  • 在控制器中构建元素时,现在建议调用 updateElement 来提供元素属性;同时新增了 getSharedOptionsincludeOptions 等方法跳过冗余计算。示例可参考仓库内置的控制器(src/controllers 目录)。

getProps 的用法在交互代码中随处可见,例如 core.interaction.jselement.getProps(['startAngle', 'endAngle'], useFinalPosition)

新的数据解析(Parsing)API

刻度引入了新的解析 API:把用户数据转换成更标准的格式。例如允许用户以 string 形式提供数值数据,并在必要时转换为 number。此前这发生在渲染过程中的“临时”阶段,现在提前到数据进入图表时统一完成,并且当用户提供的数据本身格式正确时可以跳过解析以获得更好性能。

  • 如果你使用标准数据格式(x/y),通常不需要做任何事;
  • 如果使用自定义数据格式(如金融图的 {o, h, l, c}),需要覆盖 core.datasetController.js 中的部分 parse 方法。迁移指南以使用 OHLC 数据格式的 chartjs-chart-financial 项目为范例(该示例位于 Chart.js 生态仓库,本仓库中对应的是控制器基类的 parse 钩子)。

Options 相关的控制器影响

以下变化对所有控制器都更“直接”:

  • global 从 defaults 命名空间中移除(它多余且时常不一致);
  • 数据集默认值现在挂在图表类型选项之下(2.x 中为兼容旧行为未能做到这一点),修复它是新图表开发者遇到的最大障碍;
  • 刻度默认选项需按终端用户迁移部分描述更新(例如用 x 而非 xAxesy 而非 yAxes)。

updateElementupdateElements

updateElement 被改为 updateElements,签名变为接收要更新的元素数组、起始索引 start、数量 countmode。这带来了性能收益:更容易复用所有元素间公共的计算,减少函数调用次数。基类钩子在 core.datasetController.js 中为空实现 updateElements(element, start, count, mode) {},而 controller.bar.jscontroller.line.jscontroller.doughnut.jscontroller.radar.js 等内置控制器均遵循该签名。

Scales 的变化

  • Scale.getLabelForIndexscale.getLabelForValue 取代;
  • Scale.getPixelForValue 现在只需要一个参数。对 TimeScale 来说,该参数必须是自 epoch 起的毫秒数。作为性能优化,可接受一个可选的第 2 个参数——数据点索引。

Ticks 相关:

  • Scale.afterBuildTicks 现在与其他回调一样没有参数;
  • Scale.buildTicks 现在要求返回 tick 对象;
  • Scale.convertTicksToLabels 改名为 generateTickLabels,并要求在输入 ticks 上设置 label 属性;
  • Scale.ticks 现在包含对象而不是字符串;
  • 开启 autoSkip 时,Scale.ticks 只包含未被跳过的 ticks,而不是全部 ticks;
  • ticks 现在总是按单调递增顺序生成。

Time Scale:

  • getValueForPixel 现在返回自 epoch 起的毫秒数。

Controllers 的变化

Core Controller:

  • updateHoverStyle 的第 1 个参数现在是一个包含 elementdatasetIndexindex 的对象数组;
  • resize 的签名变化:移除了第 1 个 silent 参数(当前 core.controller.jsresize(width, height) 与私有 _resize(width, height) 的分离与该签名一致)。

Dataset Controllers:

  • updateElementupdateElements 取代,接收待更新元素、start 索引、countmode
  • setHoverStyleremoveHoverStyle 现在额外接收 datasetIndexindex

Interactions 的变化

交互模式的回调方法现在返回对象数组,每个对象包含 elementdatasetIndexindex。这一点在 core.interaction.js 的 typedef 中定义:InteractionItem = {datasetIndex: number, index: number, element: Element},所有 modes 方法的返回值都遵循该结构。

Layout 的变化

  • ILayoutItem.update 不再有返回值。

Helpers 的变化

所有 helpers 现在暴露在一个扁平层级中。例如 Chart.helpers.canvas.clipAreaChart.helpers.clipArea

Canvas helper 细节:

  • drawPoint 的第 2 个参数现在是完整的 options 对象,不再显式传 stylerotationradius
  • helpers.getMaximumHeighthelpers.dom.getMaximumSize 取代;
  • helpers.getMaximumWidthhelpers.dom.getMaximumSize 取代;
  • helpers.clear 改名为 helpers.clearCanvas,现在接收 canvas 与可选的 ctx 参数(core.controller.jsclearCanvas(canvas, ctx) 的调用可见);
  • helpers.retinaScale 接受可选的第 3 个参数 forceStyle,强制覆盖当前 canvas 样式;forceRatio 不再回退到 window.devicePixelRatio,而是默认为 1

Platform 的变化

  • Chart.platform 不再是图表使用的平台对象,每个图表实例现在拥有独立的平台实例(core.controller.jsthis.platform = new (config.platform || _detectPlatform(initialCanvas))());
  • Chart.platforms 是一个对象,包含两个可用平台类 BasicPlatformDomPlatform,还包含所有平台必须继承的基类 BasePlatform
  • 如果传入的 canvas 是 OffscreenCanvas 实例,会自动使用 BasicPlatform
  • platform 上新增 isAttached 方法。

平台实现的三个基类分别位于 platform.base.jsplatform.basic.jsplatform.dom.js,与上述描述一致。

IPlugin 接口的变化

  • 所有插件钩子统一为 3 个参数:chartargsoptions。以下钩子的签名因此变化:beforeInitafterInitresetbeforeLayoutafterLayoutbeforeRenderafterRenderbeforeDrawafterDrawbeforeDatasetsDrawafterDatasetsDrawbeforeEventafterEventresizedestroy
  • afterDatasetsUpdateafterUpdatebeforeDatasetsUpdatebeforeUpdate 现在接收 args 对象作为第 2 个参数;options 参数始终在最后,从第 2 位移到第 3 位;
  • afterEventbeforeEvent 现在把包装后的 event 作为第 2 个参数的 event 属性传入,原生事件可通过 args.event.native 访问;
  • 初始的 resize 不再 silent,意味着 resize 事件可能发生在 beforeInitafterInit 之间;
  • 新增钩子:installstartstopuninstall
  • afterEvent 应通过把 args.changed 设为 true 来声明需要渲染的变化。由于 args 在所有插件间共享,只应将其设为 true 而不应设为 false

在当前仓库(4.x)中复核这些变更

本文引用的仓库版本为 package.json 声明的 4.5.1,即 v3 迁移完成之后的后续版本。上文列出的 v3 破坏性变更在 4.x 源码中均保持为既有事实,迁移时可以放心地以当前源码为最终参照:

迁移要点 当前源码证据
options.scales 以 id 为键、x/y 直接配置 core.controller.js ensureScalesHaveIDs
画布被占用时构造函数抛错 core.controller.js
Chart.register / Chart.registry 取代 Chart.plugins core.controller.js
defaultsglobal 层、overrides 独立存在、interaction 默认 nearest core.defaults.jsL66-L70
交互模式仅剩 index/dataset/point/nearest/x/y,返回 {element, datasetIndex, index} core.interaction.jsL257-L386
重写后的动画系统(单例 Animator + 属性级动画) core.animator.js
控制器统一的 updateElements(data, start, count, mode) 签名 core.datasetController.js 及各内置控制器
getDataVisibility / toggleDataVisibility 取代 Element.hidden core.controller.js
indexAxis 作为横向柱状图的替代方案 controller.bar.js
moment 不再为依赖 package.json

适用前提与小结

  • 本文所有结论以 v3-migration.md 为准,适用于“从 Chart.js 2.x 升级到 3.0(以及基于 3.0 API 的 4.x)”的迁移场景;若你已经在 3.x/4.x 上开发,则只需把本文当作 2.x 旧配置的“翻译字典”。
  • 迁移顺序建议:先改安装方式与注册(tree shaking),再按“具体选项改名表”批量替换配置键,然后处理 scales 数组到对象的结构变化,最后检查交互模式、tooltip 回调签名与插件钩子签名这三处最容易在运行时暴露问题的 API。
  • 对自定义数据格式的图表(非 x/y),重点核对 core.datasetController.js 中需要覆盖的 parse 方法,这是新 parsing API 唯一可能要求你改动代码的地方。
登录后查看全文
热门项目推荐
相关项目推荐