typescriptvue.jschartsvuejs3apexcharts

How to create a vertical bar chart with rounded containers in Vue.js using ApexCharts?


[![Image shows a minimalist vertical bar chart with 7 vertically-oriented "pill" shaped bars. Each bar consists of:

  1. An outer container:

    • Light gray color (#E9EDF7)
    • Fully rounded ends (high border-radius)
    • Full height
    • Width approximately 16px
  2. An inner fill bar:

    • Bright blue color (#1A75FF)
    • Matches the container's rounded style
    • Variable heights representing different values
    • Same width as container
    • Aligned to bottom

The bars are evenly spaced with approximately 20px between them. No axis lines, labels, or grid are shown. The first bar shows dimensions of 145.58 x 15.91 pixels. The overall effect is clean and modern, with each bar appearing as a gray pill partially filled from the bottom with blue.](https://i.sstatic.net/BOqHlTLz.png)](https://i.sstatic.net/BOqHlTLz.png)

I'm trying to create a vertical bar chart in Vue.js that has a specific design: each bar should have a light gray rounded container with a blue fill bar inside it. Here's what I'm trying to achieve:

[Image description: A bar chart with 7 vertical bars. Each bar has a light gray (#E9EDF7) rounded container that extends full height, with a blue (#1A75FF) rounded bar inside it showing the actual value. The bars appear to have significant border radius, giving them a pill-like shape.]

Here's my current attempt:

<template>
  <div class="p-4">
    <ClientOnly>
      <apexchart type="bar" :options="chartOptions" :series="series" height="250" />
    </ClientOnly>
  </div>
</template>

<script lang="ts" setup>
import { ref } from "vue";

const series = ref([
  {
    name: "Value",
    data: [80, 40, 70, 35, 60, 85, 25]
  }
]);

const chartOptions = ref({
  chart: {
    type: "bar",
    toolbar: {
      show: false
    }
  },
  plotOptions: {
    bar: {
      borderRadius: 20,
      columnWidth: "25%"
    }
  },
  grid: {
    show: false
  },
  xaxis: {
    labels: {
      show: false
    }
  },
  yaxis: {
    show: false
  }
});
</script>

However, I can't figure out how to:

Create the gray container effect for each bar Get the proper rounded corners on both the container and fill bar Maintain consistent spacing between the bars

I'm using:

Vue 3 ApexCharts (vue3-apexcharts) TypeScript

Has anyone achieved something similar? I'd appreciate any guidance on how to create this effect.


Solution

  • To set bar and bar container colors, use the colors and plotOptions.bar.colors.backgroundBarColors option:

    const chartOptions = ref({
      ...
      colors: ['#1A75FF'],
      plotOptions: {
        bar: {
          colors: {
            backgroundBarColors: ['#e7ebf5'],
          }
        }
      },
    

    Similarly, you can set radius with the options plotOptions.bar.borderRadius and plotOptions.bar.colors.backgroundBarRadius:

    const chartOptions = ref({
      plotOptions: {
        bar: {
          borderRadius: 15,
          colors: {
            backgroundBarRadius: 15,
          }
        }
      },
    

    Note thatborderRadius expects a pixel value. So unless you use fixed width, the value has to adjust for evenly rounded corners on different container/screen sizes.

    One way to do this is in the updated event. It receives the chart object as parameter, so you can check radius and update it if necessary:

    
    const updateRadius = (chart) => {
      const barWidth = chart.w.globals.barWidth
      const expectedRadius = 0.5 * barWidth
      const currentRadius = chart.w.config.plotOptions.bar.borderRadius
      
      if (currentRadius !== expectedRadius) { // <--- endless loop if you screw this up
        const optionsUpdate = {
          plotOptions: {
            bar: {
              borderRadius: expectedRadius,
              colors: {
                backgroundBarRadius: expectedRadius,
              }
            }
          }
        }
        chart.updateOptions(optionsUpdate, false, false)
      }
    }
    

    For other approaches (like ResizeObserver) you need a reference to the chart object, which is exposed by the apexchart component:

    <template>
        <apexchart type="bar" ref="apexRef"/>
    </template>
    <script setup>
      const apexRef = ref() // bind template ref
      const chart = computed(() => apexRef.value.chart) // access exposed chart object
    </script>
    

    Here it is in playground