javascriptvuejs3apexcharts

How do I get thousands separator with center label on hover with ApexCharts donut chart?


I am building a donut chart using ApexCharts for Vue JS 3 Composition API. My goal is to have the data displayed with a thousand separator. So far, the chart correctly applies a separator to the total displayed in the middle of the donut, but when you hover over either data series and the middle text changes to them, the values are not shown with a separator:

Total displayed with separator

On hover over a series, center text is NOT formatted with separator

How do I have the center text display the series data with a separator as well?

Initially, This post helped me in formatting the total in the middle of the chart

I've tried adding a formatter function returning value.toLocaleString() to plotOptions.donut.labels.value but it has no effect on the values displayed in the center when hovering over the donut sections. I have replicated the chart itself in this CodePen

Chart options:

const options = {
  series: [12039, 1899],
  chart: {
    type: "donut"
  },
  title: {
    text: "Customers Within Standards",
    align: "center",
    style: {
      fontSize: "14px"
    }
  },
  labels: ["Within Standards", "Not Within Standards"],
  dataLabels: {
    enabled: false
  },
  dataLabels: {
    enabled: false
  },
  plotOptions: {
    pie: {
      customScale: 0.8,
      expandOnClick: false,
      dataLabels: {
        enabled: false
      },
      donut: {
        size: "60%",
        labels: {
          show: true,
          value: {
            formatter: function (value) {
              return value.toLocaleString(); // doesn't appear to apply to text
            }
          },
          total: {
            show: true,
            formatter: function (value) {
              let total = value.globals.seriesTotals.reduce((a, b) => a + b, 0);
              return total.toLocaleString();
            }
          }
        }
      }
    }
  },
  legend: {
    position: "bottom",
    offsetY: -20
  },
  tooltip: {
    enabled: false
  },

Solution

  • Issue

    When you compute an aggregated total the value type is number, but the input value value type is string. All objects inherit a toLocaleString method from Object.prptotype, but only certain other types implement or override this method. See Object toLocaleString for details. Strings just return strings.

    console.log("123456.78".toLocaleString());         // "123456.78"
    console.log(Number("123456.78").toLocaleString()); // "123,456.78"

    Solution

    Cast the value in the label formatter to a number first so that internationalization can format it properly as a number.

    plotOptions: {
      pie: {
        customScale: 0.8,
        expandOnClick: false,
        dataLabels: {
          enabled: false
        },
        donut: {
          size: "60%",
          labels: {
            show: true,
            value: {
              formatter: function (value) {
                return Number(value).toLocaleString(); // <-- Cast to number
              }
            },
            total: {
              show: true,
              formatter: function (value) {
                let total = value.globals.seriesTotals.reduce((a, b) => a + b, 0);
                return total.toLocaleString();
              }
            }
          }
        }
      }
    },