Chart.js 雷达图 Scriptable 选项实战:用脚本化函数动态驱动样式与数据点渲染
2026/9/18 17:06:15 网站建设 项目流程

Chart.js 雷达图 Scriptable 选项实战:用脚本化函数动态驱动样式与数据点渲染

【免费下载链接】Chart.jsSimple HTML5 Charts using thetag项目地址: https://gitcode.com/gh_mirrors/ch/Chart.js

本篇指南以 Chart.js 官方示例库中的雷达图脚本化选项示例(docs/samples/scriptable/radar.md)为核心,系统讲解 Scriptable Options 的完整用法:如何让折线颜色、点样式、透明度、点半径等属性随数据集索引、数据索引乃至具体数值动态变化。读完本文,你将掌握 Chart.js 脚本化选项的函数签名、context 上下文结构、选项解析层级,以及雷达图控制器在底层如何消费这些动态选项。

示例概述:一个纯脚本化驱动的雷达图

该示例在type: 'radar'的配置下,没有使用任何静态颜色或尺寸值,所有视觉属性均由脚本化函数在渲染时计算得出。它同时演示了脚本化选项在两类元素上的应用:

  • elements.line(雷达图的外圈折线):折线填充色backgroundColor与描边色borderColor
  • elements.point(雷达图顶点数据点):背景色、悬停背景色、半径、点样式、悬停半径。

示例还包含一个Randomize交互动作,可在运行时重新生成数据并触发重绘,便于观察脚本化函数随数据变化的行为。图例与 Tooltip 均被关闭(legend: falsetooltip: false),让画面焦点完全落在脚本化样式本身。

随机数据与多行标签

示例通过示例库专用工具 docs/scripts/utils.js 生成可复现的随机数据:

const DATA_COUNT = 7; Utils.srand(110); function generateData() { return Utils.numbers({ count: DATA_COUNT, min: 0, max: 100 }); } const data = { labels: [['Eating', 'Dinner'], ['Drinking', 'Water'], 'Sleeping', ['Designing', 'Graphics'], 'Coding', 'Cycling', 'Running'], datasets: [{ data: generateData() }] };

两个值得注意的细节:

  1. Utils.srand(110)固定随机种子srand会重设utils.js内部的线性同余伪随机数生成器(_seed = (_seed * 9301 + 49297) % 233280),保证每次刷新页面渲染出的数据点完全一致,便于对照调试。
  2. 标签支持字符串数组。雷达图 7 个轴点中,部分标签以['Eating', 'Dinner']这样的两段数组形式给出,Chart.js 会自动将数组元素换行排版在径向刻度的pointLabels上。这是雷达图(径向线性刻度)特有的标签能力。

Scriptable 选项:函数即配置

在 docs/general/options.md 中,Scriptable Options 被定义为:

Scriptable options 也接受一个函数,该函数会针对每个底层数据值被调用一次,并接收唯一参数context(上下文信息);同时传入一个 resolver 作为第二个参数,用于在同一上下文中解析其他选项的值。

也就是说,凡是标注为 "Scriptable" 的配置项,都可以把静态值替换为一个函数:

color: function(context) { const index = context.dataIndex; const value = context.dataset.data[index]; return value < 0 ? 'red' : // 负值画红色 index % 2 ? 'blue' : // 否则按索引奇偶交替蓝绿 'green'; }

函数在每次元素更新/绘制解析选项时被调用,因此天然具备"响应数据变化"的能力。官方文档还特别提示:脚本化函数内应对contexttype字段做校验,因为同一个函数可能在不同上下文('chart''dataset''data''scale''tick''pointLabel''tooltip')中被调用。

context 上下文结构

脚本化函数的context是分层继承的对象,子层级自动继承父层级全部字段:

  • chart层级:chart(图表实例)、type: 'chart'
  • dataset层级:在 chart 基础上增加datasetdatasetIndexindex(同 datasetIndex)、activemodetype: 'dataset'
  • data层级:在 dataset 基础上增加dataIndexparsed(已解析数据)、raw(原始数据)、element(当前元素,如 point/arc/bar)、type: 'data'
  • 此外还有scaletickpointLabel(仅径向线性刻度使用)、tooltip等层级。

本示例的脚本化函数全部工作在'data'层级,因此可以放心使用ctx.datasetIndexctx.dataIndexctx.parsed.y

逐项剖析示例中的脚本化函数

1. 按数据集索引取色:getLineColor

function getLineColor(ctx) { return Utils.color(ctx.datasetIndex); }

Utils.color(index)utils.js内置的 9 色COLORS调色板中取色(COLORS[index % COLORS.length]),多数据集时自动循环配色。该函数被同时赋给折线的backgroundColorborderColor以及数据点的backgroundColor,保证同一条雷达图的线、点颜色一致。

2. 按数据索引交替点样式:alternatePointStyles

function alternatePointStyles(ctx) { const index = ctx.dataIndex; return index % 2 === 0 ? 'circle' : 'rect'; }

利用ctx.dataIndex的奇偶性,让雷达图 7 个顶点在圆形circle与矩形rect之间交替出现,直接验证了脚本化选项对pointStyle的逐点控制能力。

3. 透明度控制:makeHalfAsOpaquemake20PercentOpaque

function makeHalfAsOpaque(ctx) { return Utils.transparentize(getLineColor(ctx)); } function make20PercentOpaque(ctx) { return Utils.transparentize(getLineColor(ctx), 0.8); }

Utils.transparentize(value, opacity)的实现中,alpha = opacity === undefined ? 0.5 : 1 - opacity——不传第二参时生成 50% 透明度,传入0.8时生成1 - 0.8 = 0.2的 alpha(即 20% 不透明度)。示例用它们分别设置:

  • 折线填充色backgroundColor: make20PercentOpaque:半透明填充,隐约透出网格;
  • 点悬停背景色hoverBackgroundColor: makeHalfAsOpaque:悬停时点变半透明。

值得注意的是,makeHalfAsOpaque内部先调用了同样以ctx为入参的getLineColor(ctx),体现了脚本化函数之间可以互相组合复用的编码风格。

4. 按数值分级点半径:adjustRadiusBasedOnData

function adjustRadiusBasedOnData(ctx) { const v = ctx.parsed.y; return v < 10 ? 5 : v < 25 ? 7 : v < 50 ? 9 : v < 75 ? 11 : 15; }

这是本示例最具代表性的"数据驱动样式"写法:读取ctx.parsed.y(雷达图数据点经解析后的数值,内部格式为{x, y},参见 docs/charts/radar.md 的 Internal data format 一节),按数值区间返回 5/7/9/11/15 五档半径。数据点越大,点画得越大,让雷达图多了一层可视化信息维度。

元素配置的完整装配

options: { plugins: { legend: false, tooltip: false, }, elements: { line: { backgroundColor: make20PercentOpaque, borderColor: getLineColor, }, point: { backgroundColor: getLineColor, hoverBackgroundColor: makeHalfAsOpaque, radius: adjustRadiusBasedOnData, pointStyle: alternatePointStyles, hoverRadius: 15, } } }

这里有两层结构值得说明:

  1. elements命名空间options.elements.line.*options.elements.point.*分别作用于雷达图的两类核心元素——折线元素(datasetElementType: 'line')与数据点元素(dataElementType: 'point')。若某数据集未显式指定样式,这些值会按选项解析顺序回退到elements层,因此是配置"全部雷达图默认点/线样式"的推荐位置。
  2. 悬停态的单独配置hoverRadius: 15固定为静态值,与脚本化的radius形成对比——脚本化选项与静态值可以混用,Chart.js 会按实际配置逐项解析。

雷达图相关配置项速查

结合 docs/charts/radar.md 的 Dataset Properties 表格,本示例涉及的可脚本化配置项如下:

配置项所属类型默认值说明
backgroundColorlineColor(Scriptable)'rgba(0, 0, 0, 0.1)'折线填充色
borderColorlineColor(Scriptable)'rgba(0, 0, 0, 0.1)'折线描边色
pointBackgroundColorpointColor(Scriptable/Indexable)'rgba(0, 0, 0, 0.1)'点填充色
pointBorderWidthpointnumber(Scriptable/Indexable)1点边框宽度
pointHitRadiuspointnumber(Scriptable/Indexable)1不可见命中区域像素半径
pointHoverBackgroundColorpointColor(Scriptable/Indexable)undefined悬停填充色
pointHoverRadiuspointnumber(Scriptable/Indexable)4悬停半径
pointRadiuspointnumber(Scriptable/Indexable)3点半径,为 0 时不渲染
pointRotationpointnumber(Scriptable/Indexable)0点旋转角度(度)
pointStylepointpointStyle(Scriptable/Indexable)'circle'点形状,如'circle'/'rect'/'triangle'/'star'

除脚本化外,这些点样式属性还支持Indexable(数组)写法:数组第 i 项对应第 i 个数据点,元素少于数据时循环复用;多数场景下脚本化函数表达力更强。

Randomize 动作:运行时验证脚本化逻辑

const actions = [ { name: 'Randomize', handler(chart) { chart.data.datasets.forEach(dataset => { dataset.data = generateData(); }); chart.update(); } }, ];

actions数组是 chart-editor 示例框架约定的交互描述:handler接收图表实例,将每个数据集的data替换为新随机数组后调用chart.update()。由于脚本化选项在每次元素更新时都会重新求值,点击 Randomize 后,点的半径分布、交替样式与悬停透明度会立即随新数据刷新——这是验证"选项是否真正脚本化"的最直观手段。示例模块通过module.exports = {actions, config}导出,供示例渲染器加载。

源码视角:RadarController 如何消费脚本化选项

从源码结构看,脚本化选项的解析发生在控制器更新阶段。src/controllers/controller.radar.js 中RadarController的静态配置明确了雷达图的元素模型:

static defaults = { datasetElementType: 'line', dataElementType: 'point', indexAxis: 'r', showLine: true, elements: { line: { fill: 'start' } }, }; static overrides = { aspectRatio: 1, scales: { r: { type: 'radialLinear', } } };

即:雷达图的"数据集元素"是折线、数据元素是点、径向轴索引为r,默认启用径向线性刻度且纵横比为 1。

updateElements中,每个数据点都会调用this.resolveDataElementOptions(i, ...)——这正是脚本化选项的解析入口,随后通过径向刻度定位每个点的极坐标位置:

const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r); const x = reset ? scale.xCenter : pointPosition.x; const y = reset ? scale.yCenter : pointPosition.y; const properties = { x, y, angle: pointPosition.angle, skip: isNaN(x) || isNaN(y), options };

可以推断,resolveDataElementOptions(i, ...)在解析radiuspointStyle等脚本化属性时,会构造包含datasetIndexdataIndexparsed(含r值,经_parseObjectDataRadialScale归一为{x, y}内部格式)的context,再调用脚本化函数——这就是示例中ctx.parsed.yctx.dataIndex可用性的底层来源。折线部分则由resolveDatasetElementOptions(mode)解析backgroundColorborderColor等,供线元素绘制填充与描边。

完整代码

将上述片段组装,得到完整可运行的示例配置:

const DATA_COUNT = 7; Utils.srand(110); const actions = [ { name: 'Randomize', handler(chart) { chart.data.datasets.forEach(dataset => { dataset.data = generateData(); }); chart.update(); } }, ]; function generateData() { return Utils.numbers({ count: DATA_COUNT, min: 0, max: 100 }); } const data = { labels: [['Eating', 'Dinner'], ['Drinking', 'Water'], 'Sleeping', ['Designing', 'Graphics'], 'Coding', 'Cycling', 'Running'], datasets: [{ data: generateData() }] }; function getLineColor(ctx) { return Utils.color(ctx.datasetIndex); } function alternatePointStyles(ctx) { const index = ctx.dataIndex; return index % 2 === 0 ? 'circle' : 'rect'; } function makeHalfAsOpaque(ctx) { return Utils.transparentize(getLineColor(ctx)); } function make20PercentOpaque(ctx) { return Utils.transparentize(getLineColor(ctx), 0.8); } function adjustRadiusBasedOnData(ctx) { const v = ctx.parsed.y; return v < 10 ? 5 : v < 25 ? 7 : v < 50 ? 9 : v < 75 ? 11 : 15; } const config = { type: 'radar', data: data, options: { plugins: { legend: false, tooltip: false, }, elements: { line: { backgroundColor: make20PercentOpaque, borderColor: getLineColor, }, point: { backgroundColor: getLineColor, hoverBackgroundColor: makeHalfAsOpaque, radius: adjustRadiusBasedOnData, pointStyle: alternatePointStyles, hoverRadius: 15, } } } }; module.exports = { actions, config, };

延伸阅读

  • Options 与 Scriptable Options 详解:选项解析优先级、context 完整字段定义、resolver 第二参数用法;
  • Radar 雷达图图表指南:全部数据集属性表、Point Styling / Line Styling / Interactions 分类说明、scales.r径向刻度配置;
  • Scriptable 示例系列:line.md(折线版同款脚本化函数)、bar.md(按ctx.parsed.y分档配色)、pie.mdpolar.md(按数值区间着色的colorize模式),可对照学习脚本化选项在不同图表类型上的复用与差异;
  • 示例工具 Utils 说明 与 docs/scripts/utils.js:srand/numbers/color/transparentize等示例辅助函数的实现(注意:Utils 属示例专用工具,官方文档明确提示不应在生产环境依赖)。

【免费下载链接】Chart.jsSimple HTML5 Charts using thetag项目地址: https://gitcode.com/gh_mirrors/ch/Chart.js

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询