Chart.js多图表同步垂直标线异常:非活跃图表标线残留未清除
Fixing Persistent Vertical Lines on Inactive Chart.js Charts
我完全懂你遇到的糟心问题——鼠标在活跃图表上移动时,非活跃图表的垂直标线只会不断叠加,旧的线根本不会被清除,到最后整个图表都被线铺满了。这是因为你之前在单个图表的draw方法里循环给所有图表画标线,但非活跃图表不会主动触发完整重绘来清除旧内容,而且每个图表的draw被调用时都会重复画一遍,自然就堆成一团了。
下面是修正后的方案,核心思路是让每个图表独立管理自己的标线,同时通过全局鼠标事件同步所有图表的标线位置,确保每次重绘时都会先清除旧标线:
var charts = []; $(document).ready(function () { // 全局变量存储当前鼠标在X轴的位置 var currentMouseX = null; Chart.defaults.LineWithLine = Chart.defaults.line; Chart.controllers.LineWithLine = Chart.controllers.line.extend({ draw: function(ease) { // 先调用父类的draw方法,这会自动清除画布并绘制图表主体 Chart.controllers.line.prototype.draw.call(this, ease); var chart = this.chart; var ctx = chart.ctx; var yScale = chart.scales['y-axis-0']; // 如果有当前鼠标位置,才绘制标线 if (currentMouseX !== null) { ctx.save(); ctx.beginPath(); ctx.moveTo(currentMouseX, yScale.top); ctx.lineTo(currentMouseX, yScale.bottom); ctx.lineWidth = 2; ctx.strokeStyle = '#07C'; ctx.stroke(); ctx.restore(); } } }); // 创建图表1 var ctx1 = document.getElementById('myChart1').getContext('2d'); var chart1 = new Chart(ctx1, { type: 'LineWithLine', data: { labels: ['Segment 1', 'Segment 2', 'Segment 3','Segment 4','Segment 5','Segment 6','Segment 7','Segment 8','Segment 9','Segment 10','Segment 11','Segment 12'], datasets: [{ lineTension: 0, backgroundColor: "rgb(34,139,34)", borderColor: "rgb(34,139,34)", data: [14, 19, 20, 10, 6, 15, 8, 27, 25, 14, 36, 22], fill: false, pointRadius: 1.5, pointHoverRadius: 1, borderWidth :1.5 }] }, options: { maintainAspectRatio: false, hover: { mode: 'index', intersect: false, }, legend: { display: false }, tooltips: { mode: 'index', intersect: false, }, } }); // 创建图表2 var ctx2 = document.getElementById('myChart2').getContext('2d'); var chart2 = new Chart(ctx2, { type: 'LineWithLine', data: { labels: ['Segment 1', 'Segment 2', 'Segment 3','Segment 4','Segment 5','Segment 6','Segment 7','Segment 8','Segment 9','Segment 10','Segment 11','Segment 12'], datasets: [{ lineTension: 0, backgroundColor: "rgb(34,139,34)", borderColor: "rgb(34,139,34)", data: [14, 11, 10, 20, 20, 15, 25, 15, 13, 14, 16, 8], fill: false, pointRadius: 1.5, pointHoverRadius: 1, borderWidth :1.5 }] }, options: { maintainAspectRatio: false, legend: { display: false }, tooltips: { mode: 'index', intersect: false, }, } }); charts.push(chart1, chart2); // 全局鼠标移动事件,同步所有图表的标线位置 $('canvas').on('mousemove', function(e) { var targetChart = charts.find(chart => chart.canvas === e.target); if (!targetChart) return; // 获取鼠标在图表坐标系中的X位置 var chartArea = targetChart.chartArea; currentMouseX = e.offsetX - chartArea.left; // 确保X位置在图表范围内 if (currentMouseX < 0 || currentMouseX > chartArea.width) { currentMouseX = null; } // 触发所有图表重绘,这样每个图表都会清除旧标线并绘制新的 charts.forEach(chart => chart.update()); }); // 鼠标离开画布时清除标线 $('canvas').on('mouseleave', function() { currentMouseX = null; charts.forEach(chart => chart.update()); }); });
关键改动说明:
- 移除跨图表循环绘制:每个图表只负责绘制自己的标线,避免重复叠加绘制的问题。
- 全局鼠标事件同步位置:通过监听所有canvas的
mousemove事件,计算当前鼠标在图表中的X坐标,然后触发所有图表重绘,保证标线位置同步。 - 依赖父类draw自动清除:每次调用父类的
draw方法时,Chart.js会自动清除画布并重新绘制图表主体,旧标线自然被清除,再绘制新的标线就不会有残留。 - 鼠标离开时清空标线:确保鼠标移开后所有图表的标线都会及时消失。
这样修改后,不管是活跃还是非活跃图表,都会在鼠标移动时同步更新标线,既不会有残留问题,也不会出现卡顿的情况。
内容的提问来源于stack exchange,提问作者Marianpol
相关产品推荐
相关产品推荐

