Chart.js 散点图中正确添加数据标签的完整指南

1次阅读

Chart.js 散点图中正确添加数据标签的完整指南

本文详解如何在 Chart.js 4.x 中安全、规范地为散点图(scatter)添加自定义标签,重点解决 Jinja2 模板中因 HTML 实体转义导致的 Unexpected Token ‘&’ 报错问题,并推荐使用 |tojson 过滤器实现 JavaScript 数据的无损传递。

本文详解如何在 chart.js 4.x 中安全、规范地为散点图(scatter)添加自定义标签,重点解决 jinja2 模板中因 html 实体转义导致的 `unexpected token ‘&’` 报错问题,并推荐使用 `|tojson` 过滤器实现 javascript 数据的无损传递。

在 Chart.js 中,labels 并非 dataset 的属性,而是属于顶层 data 对象的字段——这是引发本次错误的根本原因。你当前将 labels: {{ labels }} 错误地写在了某个 scatter 数据集内部(如第四个 dataset),而 Chart.js 会忽略该配置,更关键的是:Jinja2 默认会对变量输出进行 HTML 转义,将单引号 ‘ 替换为 ‘、双引号 ” 变为 “,而像 [‘test1’, ‘test2’] 这样的字符串在渲染时会变成 [‘test1’, ‘test2’],最终被浏览器解析为非法 JS 语法,抛出 Uncaught SyntaxError: Unexpected token ‘&’。

✅ 正确做法是:将 labels 提升至图表 data 对象顶层,并与 datasets 同级;同时,必须使用 Jinja2 的 |tojson 过滤器,它能将 Python 对象(如 [‘test1’, ‘test2’, ‘test3’])序列化为标准、安全、未转义的 JSON 字符串(如 [“test1″,”test2″,”test3”]),并自动处理引号、斜杠等特殊字符。

以下是修正后的完整代码示例(适配 Chart.js v4.2.1 + flask + Jinja2):

<script src="https://cdn.jsdelivr.net/npm/chart.js@4.2.1"></script> <canvas id="myChart" width="400" height="400"></canvas>  <script>     // ✅ 正确:labels 在 data 顶层,且使用 |tojson 过滤器     const chartData = {         labels: {{ labels | tojson }}, // ← 关键:安全注入字符串数组         datasets: [             {                 type: 'line',                 label: 'Baseline',                 data: [],                 backgroundColor: 'rgb(168, 38, 8)',                 borderColor: 'rgb(168, 38, 8)',                 pointRadius: 0,                 borderWidth: 3,                 order: 2             },             {                 type: 'scatter',                 label: 'Group A',                 data: [],                 backgroundColor: 'rgb(168, 38, 8)',                 borderColor: 'rgb(168, 38, 8)',                 pointRadius: 3,                 order: 3             },             {                 type: 'scatter',                 label: 'Group B',                 data: [],                 backgroundColor: 'rgb(46, 179, 84)',                 borderColor: 'rgb(46, 179, 84)',                 pointRadius: 3,                 order: 1             },             {                 type: 'scatter',                 label: 'Annotated Points', // ✅ 推荐为每个 dataset 显式设置 label                 data: {{ data | tojson }}, // ← 同样需 |tojson                 backgroundColor: 'rgb(52, 110, 235)',                 borderColor: 'rgb(52, 110, 235)',                 pointRadius: 1,                 order: 4             }         ]     };      const config = {         type: 'scatter',         data: chartData, // ← 引用顶层 data 对象         options: {             maintainAspectRatio: true,             aspectRatio: 1,             plugins: {                 legend: { display: false }             },             scales: {                 x: { display: false },                 y: { display: false }             }         }     };      const myChart = new Chart(         document.getElementById('myChart'),         config     ); </script>

⚠️ 重要注意事项

  • labels 数组长度应与所有 scatter 数据集中 data 的总点数匹配(若需为每个点独立标注),但 Chart.js 散点图默认不显示轴标签;如需在悬停提示(tooltip)中显示自定义文本,请配合 options.plugins.tooltip.callbacks.label 自定义;
  • |tojson 是 Flask/Jinja2 官方推荐方案,不可替换为 |safe ——后者仅禁用转义,不保证 JSON 格式合法,存在 xss 风险;
  • 若后端传入的 labels 为 None 或空列表,|tojson 会正确输出 NULL 或 [],无需额外判空;
  • Chart.js v4 要求 data 中的 labels 与 datasets[i].data 的索引一一对应(尤其当混合 line/scatter 时),确保数据结构对齐。

总结:添加标签的核心在于「位置正确 + 序列化安全」。牢记 labels 属于 data,而非 dataset;坚持使用 {{ var | tojson }},即可彻底规避模板注入错误,让动态图表数据稳定可靠地呈现。

text=ZqhQzanResources