返回

Vue.js ApexCharts 圆角柱状图(带背景)实现详解

vue.js

Vue.js 中使用 ApexCharts 实现圆角垂直柱状图(带背景容器)

遇到一个需求,要在 Vue.js 项目中用 ApexCharts 创建一个特殊的垂直柱状图。每个柱子不仅要有圆角,还要有一个浅灰色的背景容器,里边填充蓝色的值条,就像一个胶囊形状。虽然 ApexCharts 提供了圆角选项,但实现这个特定的样式还是有点绕。

示意图

目前的代码只能做出基本的圆角柱状图,离目标效果还差得远。

问题出在哪?

主要问题在于 ApexCharts 的 borderRadius 属性只会作用于实际数据对应的柱子(蓝色部分),而不能直接给每个柱子加一个背景容器。 而且单纯通过修改 plotOptions.bar 下的相关设置也做不出想要的两层结构。

解决思路和具体实现

经过一番尝试和研究,整理出下面几种实现方案,一步步来解决这个问题。

方案一:利用 dataLabels 自定义样式 (推荐)

这种方案利用 dataLabelsformatter 方法对每个数据点单独渲染, 生成特定结构来实现背景容器。

原理:

dataLabels 本来是用来显示数据标签的。通过自定义其内容和样式,可以“借用”这个位置来渲染我们的背景和填充条。formatter函数能够提供对每个数据点的自定义控制,对实现复杂样式帮助极大。

实现步骤:

  1. 修改 chartOptions

    const chartOptions = ref({
      chart: {
        type: "bar",
        toolbar: {
          show: false
        }
      },
      plotOptions: {
        bar: {
          borderRadius: 20, // 用于内部蓝色填充条
          columnWidth: '25%'
        },
      },
      grid: {
        show: false
      },
      xaxis: {
        labels: {
          show: false
        },
        axisBorder: {
          show: false,
        },
        axisTicks: {
          show: false
        }
      },
      yaxis: {
        show: false
      },
       dataLabels: {
            enabled: true,
            style: {
              colors: ['#333']  // 不会实际用到,占位
            },
          formatter: function(val, opts) {
              const maxValue = 100; // 根据你的实际最大值修改
                const percent = ((val / maxValue) * 100).toFixed(0);  // 计算百分比
                return `<div style="height: 145px; width: 16px; border-radius: 20px; background-color: #E9EDF7; position: relative; overflow: hidden;">
                        <div style="position: absolute; bottom: 0; left: 0; width: 100%; height: ${percent}%; background-color: #1A75FF; border-radius: 20px;"></div>
                       </div>`
          }
        }
    });
    
    
    • 重点在 dataLabels.formatter: 在这个函数里,直接返回了一个包含两层结构的 HTML 字符串:
    • 外层 div:设置了高度、宽度、圆角和浅灰色背景(#E9EDF7)。position: relative;overflow: hidden; 用于控制内层填充条的显示。
    • 内层 div:通过 height: ${percent}%; 动态设置高度来表示数据值。设置了蓝色背景(#1A75FF)和圆角。
    • dataLabels.style.colors 仅仅是一个占位, 由于我们自定义了formatter返回HTML,因此原本的颜色设置不会生效。

进阶使用技巧:

可以根据具体的数据极值进行计算,让每一个柱形图都可以顶到最上方。修改formatter, 在其中通过opts.series[opts.seriesIndex][opts.dataPointIndex]获取当前点的值,Math.max(...opts.series[opts.seriesIndex])获取当前series的最大值,替换上方代码写死的maxValue.

方案二:使用自定义 Annotation(Custom Annotations)

这种方式通过 ApexCharts 的 custom annotations 功能来实现容器效果,更为灵活,但配置相对复杂一些。

原理:

ApexCharts 的 annotations 允许你在图表上添加自定义元素,例如矩形、文本等。 用矩形来模拟背景容器。

实现步骤:

  1. 修改 chartOptions :
    先计算每个数据点所对应的的 annotation

        const annotations = ref({
              rect: []
        });
    onMounted(() => {
        series.value[0].data.forEach((value, index) => {
            annotations.value.rect.push( createAnnotation(index,value) );
          })
     })
    

再在chartOptions进行应用.

```javascript
  const chartOptions = ref({
      // ... 其他配置 ...
      annotations: annotations.value, //增加配置
         // ... 其他配置 ...
    });
```

```javascript

function createAnnotation(index, value)
{
     const maxValue = 100;  // 最大值

    //根据需要, 计算xy坐标和尺寸
    let x1 = 25 * (index+1)
    let x2 = x1+ 15

    let y1 = maxValue-value
    let y2 = maxValue

      return {
          x: x1,
          x2:x2,
          y:y1,
          y2: y2,

          borderColor: 'transparent',
          fillColor: '#E9EDF7',
            borderRadius:20,
        }
    }
```
  * 计算位置时,可能需要考虑边距和间隔, 上述只是一个范例。
*   添加多个 `rect` annotation 对象到 `annotations.rect` 数组中。每个对象代表一个柱子的背景容器:
    *   `x`、`x2`、`y`、`y2`: 通过计算得到每个矩形的准确位置和尺寸。需要仔细调整这些值来匹配你的图表。
    *   `borderColor`: 设为 `'transparent'`。
    *   `fillColor`: 设为 `#E9EDF7`(浅灰色)。
  1. 修改 Series 部分
    同时, 为了数据柱也能有圆角效果,不要忘记调整Series 部分,增加:

       plotOptions: {
            bar: {
              borderRadius: 20,
              columnWidth: "25%"  //按需进行调整
            }
          },
    

额外建议:

  • 由于涉及较多的手动计算, 为了更准确,建议开启xaxis, yaxis的显示用于位置调试,调整好以后再将其关闭.
  • 要进行数值调整使之更契合真实图标需求。

方案三:利用SVG自定义绘制(不推荐,仅作思路参考)

ApexCharts 底层使用 SVG 渲染,所以可以直接操作生成的 SVG 元素来实现一些高级定制,但比较 hacky,并且要小心潜在的版本兼容性问题。

原理:
通过对 图标的SVG元素进行自定义,手动增加或者修改容器的图形。

这种方式不推荐,因为涉及到非常规的SVG操作,步骤也相对烦琐,容易导致不可预期的问题。不作展开,只作思路参考。

总结

实现这个带有背景容器的圆角柱状图效果,第一种使用dataLabels是最方便的,第二种方案比较通用,但实现更复杂一些. 第三种方案虽然灵活但实现成本非常高,不推荐.