
本文详解如何在 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 }},即可彻底规避模板注入错误,让动态图表数据稳定可靠地呈现。










