Chart.js 2.9.4 可点击标签跳转报Cannot read property 'top'错误
报错原因定位
- 直接触发报错的问题:jQuery选择器和实际DOM不匹配。你初始化图表的canvas元素实际id为
barChart-mostSold,但在onClick回调中使用$('#chartmostSold')选择元素,无法匹配到对应DOM,调用.offset()会返回undefined,读取undefined的top属性就会抛出Cannot read property 'top' of undefined的错误。 - 原有逻辑的适配缺陷:你使用的是
horizontalBar横向条形图,类别标签默认渲染在左侧y轴,而原参考方案针对的是垂直柱状图的底部x轴标签场景,就算解决了选择器问题,原有坐标判断逻辑也完全错位,无法正确命中标签区域。
适配Chart.js 2.9.4的可点击标签实现方案
实现思路:放弃手动计算DOM偏移、刻度宽度的脆弱逻辑,直接调用2.9.4版本内置的坐标轴API完成标签命中判断,适配横向条形图的轴结构。
var ctx = document.getElementById("barChart-mostSold").getContext('2d'); // 提前维护标签与跳转路径的映射,顺序与labels数组一一对应即可 const labelRedirectMap = [ '/page-a', // 对应labels[0]的跳转地址 '/page-b', // 对应labels[1]的跳转地址 // 按实际标签顺序补全剩余路径 ]; this.chartmostSold = new Chart(ctx, { type: 'horizontalBar', data: { labels: {{listTopIssuerSoldLabel | tojson }}, datasets: [ { data: {{listTopIssuerSoldValue | tojson }} } ] }, options: { events: ["mousemove", "mouseout", "click", "touchstart", "touchmove", "touchend"], onClick: function(e) { // 先判断点击是否命中条形块,命中则不触发标签跳转逻辑 const activeBars = this.getElementAtEvent(e); if (activeBars.length === 0) { const yScale = this.scales['y-axis-0']; const tickCount = yScale.ticks.length; // 遍历所有y轴刻度,判断点击坐标是否落在标签渲染范围内 for (let i = 0; i < tickCount; i++) { const tickCenterY = yScale.getPixelForTick(i); // 计算当前标签的上下覆盖区间,取相邻刻度间距的一半作为边界 const nextTickCenterY = i < tickCount -1 ? yScale.getPixelForTick(i+1) : yScale.bottom; const tickRange = Math.abs(nextTickCenterY - tickCenterY); if (e.offsetY > (tickCenterY - tickRange/2) && e.offsetY < (tickCenterY + tickRange/2)) { window.location.href = labelRedirectMap[i]; break; } } } }, // 可选:鼠标悬停在标签上时切换为手型,提升交互感知 onHover: function(e) { const activeBars = this.getElementAtEvent(e); if (activeBars.length === 0) { const yScale = this.scales['y-axis-0']; const tickCount = yScale.ticks.length; for (let i = 0; i < tickCount; i++) { const tickCenterY = yScale.getPixelForTick(i); const nextTickCenterY = i < tickCount -1 ? yScale.getPixelForTick(i+1) : yScale.bottom; const tickRange = Math.abs(nextTickCenterY - tickCenterY); if (e.offsetY > (tickCenterY - tickRange/2) && e.offsetY < (tickCenterY + tickRange/2)) { e.target.style.cursor = 'pointer'; return; } } } e.target.style.cursor = 'default'; } } });
方案核心说明
- 不需要依赖jQuery计算页面滚动偏移,所有坐标判断都基于canvas自身的坐标系完成,减少跨环境兼容问题。
- 针对横向条形图的y轴标签做命中判断,和垂直柱图的x轴标签逻辑做了适配,不会出现轴错位问题。
- 跳转路径和图表标签解耦维护,不需要修改原有图表数据结构,调整跳转逻辑时只需要维护
labelRedirectMap数组即可。 - 完全适配2.9.4版本的API能力,不需要升级Chart.js版本或者引入第三方插件。
内容的提问来源于stack exchange,提问作者Damiano Dotto
相关产品推荐
相关产品推荐

