如何在Rails的Chartkick中配置Chart.js的图例与提示框自定义选项
在Rails中用Chartkick结合Chart.js实现自定义配置(含函数)
我明白你遇到的问题了——直接在ERB的area_chart helper里写Chart.js的函数式配置会被Ruby转义成纯字符串,Chart.js根本认不出这是可执行的函数。下面给你两种靠谱的解决方法,优先推荐第一种,可读性和维护性都更好:
方法一:把自定义配置抽成独立的JS对象(推荐)
这个思路是先在页面里定义好包含所有自定义函数的Chart.js配置对象,再让Chartkick直接引用它,完美避开ERB的转义问题。
第一步:在视图里定义JS配置对象
在你的ERB视图文件(比如对应的页面模板)里,添加一个<script>标签,把你需要的图例和提示框配置写成完整的JS对象:
<script> // 定义Chart.js的自定义配置 const customConsultChartConfig = { legend: { position: 'right', labels : { generateLabels: function(chart){ var data = chart.data; var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) { return { text: dataset.label, fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]), hidden: !chart.isDatasetVisible(i), lineCap: dataset.borderCapStyle, lineDash: dataset.borderDash, lineDashOffset: dataset.borderDashOffset, lineJoin: dataset.borderJoinStyle, lineWidth: dataset.borderWidth, strokeStyle: dataset.borderColor, pointStyle: dataset.pointStyle, datasetIndex: i }; }, this) : []; // 添加自定义图例标签 const customLegendItem = { text: 'Past 6 months: $826.53', strokeStyle: 'transparent', fillStyle: 'transparent', lineWidth: 0 }; legends.push(customLegendItem); return legends; }, boxWidth: 15, boxHeight: 20 } }, tooltips: { yAlign: 'bottom', callbacks: { title: function(tooltipItem, data) { return "September "+data['labels'][tooltipItem[0]['index']]; }, label: function(tooltipItem, data) { return "$"+data['datasets'][0]['data'][tooltipItem['index']]; }, }, backgroundColor: 'grey' } }; </script>
第二步:在Chartkick helper里引用这个配置
修改你的area_chart代码,把library选项设置为刚才定义的JS对象名,注意要用raw()包裹,这样Ruby就不会转义它:
<%= area_chart data, library: raw("customConsultChartConfig"), id: 'consult-chart', adapter: 'chartjs' %>
这样Chartkick会直接把customConsultChartConfig作为Chart.js的配置对象传入,里面的函数就能正常执行了,完全不会有转义问题。
方法二:直接在ERB中嵌入带函数的配置(不推荐,仅作备选)
如果你不想单独写JS对象,也可以把配置写成Ruby哈希,但要把所有JS函数用字符串包裹,并且整个library用raw()输出,避免转义:
<%= area_chart data, library: raw({ legend: { position: 'right', labels: { generateLabels: "function(chart){ var data = chart.data; var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) { return { text: dataset.label, fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]), hidden: !chart.isDatasetVisible(i), lineCap: dataset.borderCapStyle, lineDash: dataset.borderDash, lineDashOffset: dataset.borderDashOffset, lineJoin: dataset.borderJoinStyle, lineWidth: dataset.borderWidth, strokeStyle: dataset.borderColor, pointStyle: dataset.pointStyle, datasetIndex: i }; }, this) : []; var title_o = { text: 'Past 6 months: $826.53', strokeStyle: 'transparent', fillStyle: 'transparent', lineWidth: 0 }; legends.push(title_o); return legends; }", boxWidth: 15, boxHeight: 20 } }, tooltips: { yAlign: 'bottom', callbacks: { title: "function(tooltipItem, data) { return 'September '+data['labels'][tooltipItem[0]['index']]; }", label: "function(tooltipItem, data) { return '$'+data['datasets'][0]['data'][tooltipItem['index']]; }" }, backgroundColor: 'grey' } }.to_json), id: 'consult-chart', adapter: 'chartjs' %>
这种方法虽然能工作,但代码可读性极差,后期修改起来很麻烦,所以除非特殊情况,不建议用。
最后要注意的验证点
- 确保Chart.js 2.9.4已经正确引入(不管是用Chartkick的
Chart.bundle还是单独引入资源) - 检查浏览器控制台有没有JS报错,比如配置对象未定义、函数语法错误之类的
- 一定要把JS配置对象定义在
area_chart渲染之前,保证Chartkick调用时对象已经存在
内容的提问来源于stack exchange,提问作者Bala
相关产品推荐
相关产品推荐

