首页
/ Chart.js 线性数值轴(Linear Scale)详解:stepSize、count、grace 与 beginAtZero 的完整配置实战

Chart.js 线性数值轴(Linear Scale)详解:stepSize、count、grace 与 beginAtZero 的完整配置实战

2026-09-03 17:56:52作者:史锋燃Gardner

本篇技术指南聚焦 Chart.js 中用于绘制数值数据的线性坐标轴(type: 'linear'),系统讲解轴级与刻度级的全部配置选项,包括 stepSizecountgracebeginAtZero 等线性轴专属参数的用法与默认值,并结合仓库源码剖析刻度生成的“nice numbers”算法、像素与数值的线性映射实现,读完后可独立完成数值轴的自定义量程、刻度密度控制与留白设置。

线性轴的定位与基本特性

线性轴用于在坐标轴上绘制数值型数据,可以放在 x 轴或 y 轴上;散点图(scatter)类型会自动为 x 轴配置一个线性轴。顾名思义,线性轴使用线性插值来确定一个数值在轴上的位置。

从源码 src/scales/scale.linear.js 可以确认这一特性,LinearScale 的类注册名为 id = 'linear',其核心方法就是一组线性映射:

getPixelForValue(value) {
  return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
}

getValueForPixel(pixel) {
  return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
}

即:数据值先换算为 [0, 1] 的“小数位置”(getPixelForDecimal),再映射为像素坐标;反向的 getValueForPixel 则用 _startValue_valueRange 做线性还原。这也解释了文档末尾的说明——内部数据格式为纯数字(Internally, the linear scale uses numeric data),解析阶段会把原始值强制转为 +raw(见基类 parse() 方法,src/scales/scale.linearbase.js)。

线性轴还内置了数值格式的默认刻度标签回调:

static defaults = {
  ticks: {
    callback: Ticks.formatters.numeric
  }
};

对应的刻度文本由 getLabelForValue 生成,底层调用 Intl.NumberFormatformatNumber),这正是 ticks.format 选项能够生效的原因。

轴级配置选项(Axis Options)

轴级配置的命名空间为 options.scales[scaleId],例如 options.scales.y

线性轴专属选项

名称 类型 说明
beginAtZero boolean true 时,若量程中不含 0,则强制把 0 纳入量程
grace number | string 在数据范围上下方额外增加的余量:以 % 结尾的字符串表示百分比,数字表示绝对数值。详见 grace

beginAtZero 的实际处理逻辑在基类方法 handleTickRangeOptions() 中(src/scales/scale.linearbase.js):根据当前 min/max 的符号决定向哪一侧扩到 0——若数据全为负数则把 max 抬到 0,全为正数则把 min 压到 0;同时该方法还会处理 min === max 的退化情况(自动外扩约 5% 的范围以避免轴塌缩成一条线)。

所有笛卡尔轴(Cartesian)共享选项

名称 类型 默认值 说明
bounds string 'ticks' 决定量程如何由刻度决定。更多细节见 Scale Bounds
clip boolean true true 时,按坐标轴尺寸(而非 chart area)裁剪数据集绘制
position string | object 轴的位置。更多细节见 Axis Position
stack string 堆叠组。positionstack 都相同的轴会被堆叠在一起
stackWeight number 1 堆叠组内该轴所占空间分配的权重
axis string 轴类型:'x''y'。未设置时从 ID 首字符推断(应为首字母 'x''y'
offset boolean false true 时在轴两端各增加一段空白,轴整体缩放到 chart area 内;柱状图默认开启。源码中该偏移在 configure() 中按 (end - start) / (ticks.length - 1) / 2 计算(src/scales/scale.linearbase.js
title object 轴标题配置。更多细节见 Scale Title Configuration

所有坐标轴共享选项

名称 类型 默认值 说明
type string 使用的轴类型;自定义轴可通过字符串键注册
alignToPixels boolean false 是否把像素值对齐到设备像素
backgroundColor Color 轴区域背景色
border object 边框配置,见 Border Configuration
display boolean | string true 控制轴可见性;display: 'auto' 时仅当至少有一个关联数据集可见时才显示
grid object 网格线配置,见 Grid Line Configuration
min number 用户自定义最小值,覆盖数据推断的最小值。见 Axis Range Settings
max number 用户自定义最大值,覆盖数据推断的最大值
reverse boolean false 反转刻度方向
stacked boolean | string false 是否堆叠数据
suggestedMax number 计算数据最大值时的参考值(不强制截断量程)。见 Axis Range Settings
suggestedMin number 计算数据最小值时的参考值
ticks object 刻度配置,见 Tick Configuration
weight number 0 轴排序权重,数值越大的轴离 chart area 越远

刻度配置选项(Tick Configuration)

刻度级配置的命名空间为 options.scales[scaleId].ticks

线性轴专属刻度选项

名称 类型 Scriptable 默认值 说明
count number Yes undefined 生成的刻度总数。指定后覆盖自动生成逻辑
format object Yes 默认标签格式化器使用的 Intl.NumberFormat 选项
precision number Yes 若定义且未指定 stepSize,步长会被四舍五入到该小数位数
stepSize number Yes 用户指定的固定步长。更多细节见 Step Size

笛卡尔轴共享刻度选项

名称 类型 默认值 说明
align string 'center' 沿轴方向的刻度对齐方式:'start''center''end''inner'(水平轴上首个刻度按 start、末个按 end 对齐)
crossAlign string 'near' 垂直于轴方向的刻度对齐:'near''center''far',见 Tick Alignment
sampleSize number ticks.length 判断能容纳多少标签时采样的刻度数,值越小越快但精度可能下降
autoSkip boolean true 自动计算可显示的标签数量并隐藏多余标签;标签最多旋转到 maxRotation 之后才开始跳显
autoSkipPadding number 3 水平轴上启用 autoSkip 时的刻度间最小间距
includeBounds boolean true 自定义的 min/max 即使不是“整齐”值,也要作为刻度显示
labelOffset number 0 标签相对刻度中心点的偏移像素(x 轴为 x 方向,y 轴为 y 方向),注意边缘标签可能被画布裁掉
maxRotation number 50 压缩标签时的最大旋转角度(仅水平轴)
minRotation number 0 最小旋转角度(仅水平轴)
mirror boolean false 把刻度标签翻到轴内侧显示(仅垂直轴)
padding number 0 刻度标签与轴之间的距离;垂直轴上是水平(X)方向,水平轴上是垂直(Y)方向
maxTicksLimit number 11 最多显示的刻度与网格线数量

所有轴共享刻度选项

名称 类型 Scriptable 默认值 说明
backdropColor Color Yes 'rgba(255, 255, 255, 0.75)' 标签背景色
backdropPadding Padding 2 标签背景内边距
callback function 返回刻度值的显示文本,见 Creating Custom Tick Formats
display boolean true 是否显示刻度标签
color Color Yes Chart.defaults.color 刻度文字颜色
font Font Yes Chart.defaults.font 字体,见 Fonts
major object {} 主刻度(major ticks)样式配置,见 Major Tick Configuration
showLabelBackdrop boolean Yes 径向轴为 true,其余为 false 是否在刻度标签后绘制背景
textStrokeColor Color Yes `` 文字描边颜色
textStrokeWidth number Yes 0 文字描边宽度
z number 0 刻度图层的 z-index;<= 0 绘制在数据集下方,> 0 绘制在上方

Step Size:固定步长控制刻度

设置 stepSize 后,刻度将按 stepSize 的整数倍枚举,每个增量一个刻度;不设置时则使用 nice numbers 算法自动标注。

文档示例:将 y 轴固定为 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5

let options = {
  scales: {
    y: {
      max: 5,
      min: 0,
      ticks: {
        stepSize: 0.5
      }
    }
  }
};

从源码可以确认该行为的实现细节。LinearScaleBasebuildTicks()stepSizecountprecisionminmaxboundsincludeBounds 等一并打包传给 generateTicks()src/scales/scale.linearbase.js),该函数按以下优先级处理(见其头部注释,src/scales/scale.linearbase.js):

  1. 同时定义了 minmaxstepSize(max - min) / step 为整数:刻度生成为 [min, min + step, ..., max],且受 maxCount 约束;
  2. 定义了 minmaxcountspacing = (max - min) / count,刻度为 [min, min + spacing, ..., max]
  3. 只定义了 countspacing = (niceMax - niceMin) / count
  4. 以上皆无:使用 niceNum 算法计算最优步长。

另外两点值得注意:

  • precision 的生效位置在 generateTicks() 内部:spacing = Math.ceil(spacing * 10^precision) / 10^precisionsrc/scales/scale.linearbase.js),且仅当未指定 stepSize 时才有意义(因为 stepSize 直接作为 unit 参与 niceNum 计算);
  • stepSize 过小导致刻度数超过 1000,getTickLimit() 会打印警告并截断为 1000 个刻度(src/scales/scale.linearbase.js)。

Grace:给数据范围增加上下留白

grace 的取值规则:以 % 结尾的字符串按百分比处理,数字按绝对值处理。其效果是把该值加到最大数据值上、从最小数据值上减去,相当于数据比实际“更大”时延伸出量程。

文档示例:数据为 [100, -50],设置 grace: '5%',量程会在 100 与 -50 上下各外扩 5%(相对范围的一半计算,见下文源码)。

const labels = Utils.months({count: 7});
const data = {
  labels: ['Positive', 'Negative'],
  datasets: [{
    data: [100, -50],
    backgroundColor: 'rgb(255, 99, 132)'
  }],
};

const config = {
  type: 'bar',
  data,
  options: {
    scales: {
      y: {
        type: 'linear',
        grace: '5%'
      }
    },
    plugins: {
      legend: false
    }
  }
};

module.exports = {
  actions: [],
  config: config,
};

该功能的核心实现在 src/helpers/helpers.options.ts_addGrace()

export function _addGrace(minmax: { min: number; max: number; }, grace: number | string, beginAtZero: boolean) {
  const {min, max} = minmax;
  const change = toDimension(grace, (max - min) / 2);
  const keepZero = (value: number, add: number) => beginAtZero && value === 0 ? 0 : value + add;
  return {
    min: keepZero(min, -Math.abs(change)),
    max: keepZero(max, change)
  };
}

可以观察到两个实现细节:

  • 百分比的基准是 (max - min) / 2,即量程的一半,toDimension() 负责把 '5%' 换算为对应数值、把数字直接当作绝对值;
  • beginAtZero: true 且边界恰好是 0 时,keepZero() 会把 0 固定住,grace 只向外扩展,不会把 0 挤出量程。

该调用发生在 Scale 的范围确定流程中(src/core/core.scale.jsthis._range = _addGrace(this, grace, beginAtZero)),即 grace 调整的是“数据范围”,而最终的刻度仍会基于这个扩展后的范围由 nice numbers 算法生成。

刻度数量的上限控制:computeTickLimit

线性轴还内置了一套基于轴长的刻度密度控制。LinearScale.computeTickLimit()src/scales/scale.linear.js)按轴向长度、刻度最小旋转角与刻度字体行高计算最多能放下的刻度数,最小间距按 40 像素约束;buildTicks() 再将其与 ticks.maxTicksLimit(默认 11)取小,且保证至少 2 个刻度。若配置了 stepSize,则刻度上限直接由 (max - min) / stepSize 推导,maxTicksLimit 只起上限作用。

内部数据格式小结

线性轴内部使用数值数据:原始值在 parse() 中被转换为 +raw,非有限数(NaN/Infinity)或空值返回 nulldetermineDataLimits() 在数据范围缺失时回退为 min: 0, max: 1src/scales/scale.linear.js)。这一约定保证了无论数据形态如何,轴都能得到一个可用的数值区间,再交由上述范围、grace、stepSize 等配置进一步调整。

参考文件:线性轴文档Cartesian 轴通用文档轴级通用文档src/scales/scale.linear.jssrc/scales/scale.linearbase.jssrc/helpers/helpers.options.ts

登录后查看全文
热门项目推荐
相关项目推荐