Gauges and Radial Bars in JavaScript

Using ApexCharts with JavaScript

This Gauges and Radial Bars example uses ApexCharts.js directly in JavaScript, with no wrapper component.

Install it with npm install apexcharts, then mount the chart with new ApexCharts(element, options).render().

JavaScript installation guide
// Shared by the vanilla-js, React and Vue builds.
//
// The company's figures are the wholes and one region's are the parts. A
// pick is an ordinary update of highlightFilter.data, one value per ring;
// null clears it.
//
// Sums: the company's figure is the regions added up, so every part fits
// inside its whole. Orders shipped this month (against a target of 12,000),
// and each team's progress toward its quarterly goal, split by the region
// that contributed it (the three regions add up to the team's figure).
var TARGET = 12000
var SHIPPED = 9300
var SHIPPED_BY_REGION = { americas: 4100, europe: 3200, apac: 2000 }
var TEAMS = ['Sales', 'Support', 'Product']
var GOALS = [72, 58, 85]
var GOALS_BY_REGION = {
  americas: [32, 20, 38],
  europe: [24, 22, 27],
  apac: [16, 16, 20],
}

// Averages: a score or a rate over every region, which one region can beat.
// Customer satisfaction (split in lanes) and tickets resolved the same day
// (a second needle).
var SATISFACTION = 78
var SATISFACTION_BY_REGION = { americas: 84, europe: 71, apac: 66 }
var SAME_DAY = 64
var SAME_DAY_BY_REGION = { americas: 71, europe: 58, apac: 49 }

function pickRegion(region) {
  document.querySelectorAll('[data-region]').forEach(function (b) {
    b.classList.toggle('active', b.getAttribute('data-region') === region)
  })
  ApexCharts.getChartByID('shipped').updateOptions({
    highlightFilter: { data: region ? [SHIPPED_BY_REGION[region]] : null },
  })
  ApexCharts.getChartByID('goals').updateOptions({
    highlightFilter: { data: region ? GOALS_BY_REGION[region] : null },
  })
  ApexCharts.getChartByID('satisfaction').updateOptions({
    highlightFilter: { data: region ? [SATISFACTION_BY_REGION[region]] : null },
  })
  ApexCharts.getChartByID('same-day').updateOptions({
    highlightFilter: { data: region ? [SAME_DAY_BY_REGION[region]] : null },
  })
}

function wireRegions() {
  document.querySelectorAll('[data-region]').forEach(function (b) {
    b.addEventListener('click', function () {
      pickRegion(b.getAttribute('data-region'))
    })
  })
}

var options = {
  series: [SHIPPED],
  chart: {
    id: 'shipped',
    type: 'gauge',
    height: 300,
    toolbar: { show: false },
  },
  labels: ['Orders shipped'],
  colors: ['#0284c7'],
  plotOptions: {
    radialBar: {
      // A count on its own domain: 0 to the month's target.
      min: 0,
      max: TARGET,
      dataLabels: {
        value: {
          fontSize: '28px',
          formatter: function (v) {
            return Number(v).toLocaleString()
          },
        },
      },
    },
  },
  tooltip: {
    y: {
      formatter: function (v) {
        return Number(v).toLocaleString()
      },
    },
  },
  title: {
    text: 'Orders shipped this month, target 12,000',
    style: { fontSize: '13px' },
  },
  highlightFilter: { data: [SHIPPED_BY_REGION.americas] },
}

var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()

var options1 = {
  series: GOALS,
  chart: {
    id: 'goals',
    type: 'radialBar',
    height: 340,
    toolbar: { show: false },
  },
  labels: TEAMS,
  colors: ['#0284c7', '#f59e0b', '#e11d48'],
  plotOptions: {
    radialBar: {
      hollow: { size: '38%' },
      track: { margin: 4 },
      dataLabels: {
        name: { fontSize: '13px' },
        value: { fontSize: '20px' },
        total: {
          show: true,
          label: 'Average',
          // While a region is picked the totals read its parts (the default
          // highlightFilter.dataLabels.total: 'part'), so this averages the
          // region's contributions; cleared, the teams' progress.
          formatter: function (w) {
            var t = w.globals.seriesTotals
            return (
              Math.round(
                t.reduce(function (a, b) {
                  return a + b
                }, 0) / t.length,
              ) + '%'
            )
          },
        },
      },
    },
  },
  legend: { show: true, position: 'bottom' },
  title: {
    text: 'Quarterly goal reached, by team',
    style: { fontSize: '13px' },
  },
  highlightFilter: { data: GOALS_BY_REGION.americas },
}

var chart1 = new ApexCharts(document.querySelector('#chart2'), options1)
chart1.render()

var options2 = {
  series: [SATISFACTION],
  chart: {
    id: 'satisfaction',
    type: 'gauge',
    height: 300,
    toolbar: { show: false },
  },
  labels: ['Satisfaction'],
  colors: ['#0f766e'],
  plotOptions: {
    radialBar: {
      dataLabels: {
        value: {
          fontSize: '28px',
          // The centre reads the region; while one is picked, a second line
          // under it reads the whole (opts.lane is 'whole' for that line).
          formatter: function (v, w, opts) {
            return (opts && opts.lane === 'whole' ? 'company ' : '') + v + '%'
          },
        },
      },
    },
  },
  title: { text: 'Customer satisfaction', style: { fontSize: '13px' } },
  highlightFilter: {
    data: [SATISFACTION_BY_REGION.americas],
    // Made for a part that can pass its whole: two lanes, never overlapping.
    radialBar: { indicator: 'lanes' },
  },
}

var chart2 = new ApexCharts(document.querySelector('#chart3'), options2)
chart2.render()

var options3 = {
  series: [SAME_DAY],
  chart: {
    id: 'same-day',
    type: 'gauge',
    height: 300,
    toolbar: { show: false },
  },
  labels: ['Same-day resolution'],
  colors: ['#ea580c'],
  plotOptions: {
    radialBar: {
      shape: 'needle',
      needle: { length: '78%' },
      ticks: {
        show: true,
        major: { count: 6, length: 6 },
        minor: { count: 1, length: 3 },
        labels: { show: true, fontSize: '10px' },
      },
      dataLabels: { value: { fontSize: '22px' } },
    },
  },
  title: { text: 'Tickets resolved the same day', style: { fontSize: '13px' } },
  highlightFilter: { data: [SAME_DAY_BY_REGION.americas] },
}

var chart3 = new ApexCharts(document.querySelector('#chart4'), options3)
chart3.render()

wireRegions()