如何在ChartJS柱状图中实现精准的悬停项后方高亮阴影?
问题根因
原有实现的阴影范围失控,来自几个核心逻辑偏差:
- 绘制方式不合理:依靠超粗stroke线条模拟阴影区域,受线条居中绘制、随意设置的宽度/偏移系数影响,尺寸完全不可控
- 位置计算无依据:没有取当前x轴分类的实际边界,仅靠柱子宽度乘系数硬算偏移量,很容易跨到相邻分类区域
- 边界取值错误:纵轴方向的上下边界设为固定的1000000和0,会导致阴影超出图表绘图区域
- 原型调用错误:bar控制器中错误调用了line控制器的draw方法,存在渲染异常隐患
调整后的实现代码
// 保留原有bar控制器引用,避免原型链覆盖异常 const OriginalBarController = Chart.controllers.bar; Chart.controllers.bar = OriginalBarController.extend({ draw: function (ease) { // 先绘制阴影,保证阴影在柱子图层下方 if (this.chart.tooltip._active && this.chart.tooltip._active.length) { const activePoint = this.chart.tooltip._active[0]; const ctx = this.chart.ctx; const xScale = activePoint._xScale; const chartArea = this.chart.chartArea; // 获取当前激活分类的中心像素位置 const categoryCenterX = xScale.getPixelForTick(activePoint.index); // 计算单个x轴分类的总区间宽度 const categoryTotalWidth = xScale.width / xScale.ticks.length; // 计算当前分类对应的左右边界 const categoryLeftX = categoryCenterX - categoryTotalWidth / 2; const categoryRightX = categoryCenterX + categoryTotalWidth / 2; ctx.save(); ctx.fillStyle = 'rgba(160, 160, 160, 0.11)'; // 在绘图区全高、当前分类全宽范围内绘制填充阴影 ctx.fillRect( categoryLeftX, chartArea.top, categoryRightX - categoryLeftX, chartArea.bottom - chartArea.top ); ctx.restore(); } // 调用原有bar控制器的绘制逻辑,让柱子盖在阴影上层 OriginalBarController.prototype.draw.call(this, ease); } });
关键调整说明
- 图层顺序优化:先绘制阴影矩形,再执行原有bar的绘制流程,保证柱子始终在阴影上层,不会被半透阴影遮挡
- 边界精准对齐:直接基于x轴分类刻度的像素位置,计算当前分类的完整左右边界,阴影宽度完全和x轴标注的分类区域匹配,不会跨到相邻分类
- 绘图范围适配:纵轴方向直接使用图表实际绘图区的上下边界,阴影不会超出图表的有效绘图范围
- 绘制方式替换:用尺寸完全可控的 fillRect 替代原来的粗线条stroke,彻底解决线宽偏移、尺寸不准的问题
内容的提问来源于stack exchange,提问作者NiceToMytyuk
相关产品推荐
相关产品推荐

