Subscription Forecast with One Region Highlighted in JavaScript

Using ApexCharts with JavaScript

This Subscription Forecast with One Region Highlighted 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.
//
// New subscriptions per month by plan (the wholes), and the ones sold in one
// region (the parts). The last three months are a forecast. Picking a region
// keeps every plan on both charts: the whole is dashed or faded, the region's
// share is solid, and past the forecast cut both keep the forecast look.
var MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']
var PLANS = ['Team', 'Personal']
var SUBSCRIPTIONS = [
  [120, 132, 128, 145, 150, 162, 170, 178, 186],
  [80, 84, 90, 88, 96, 101, 104, 110, 114],
]
var REGIONS = {
  europe: [
    [52, 58, 55, 63, 66, 71, 74, 78, 81],
    [30, 33, 35, 34, 38, 40, 41, 43, 45],
  ],
  americas: [
    [48, 51, 50, 57, 58, 63, 66, 69, 72],
    [36, 37, 40, 39, 42, 44, 46, 49, 50],
  ],
}

function seriesFor(region) {
  return PLANS.map(function (name, i) {
    var s = { name: name, data: SUBSCRIPTIONS[i] }
    if (region) s.highlightData = REGIONS[region][i]
    return s
  })
}

// One call per chart and pick: the parts go in, each chart animates from what
// is on screen. Clearing is the same call without them.
function pickRegion(region) {
  document.querySelectorAll('[data-region]').forEach(function (b) {
    b.classList.toggle('active', b.getAttribute('data-region') === region)
  })
  return Promise.all(
    ['plans-stacked', 'plans-line'].map(function (id) {
      return ApexCharts.getChartByID(id).updateSeries(seriesFor(region))
    }),
  )
}

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

var options = {
  series: seriesFor('europe'),
  chart: {
    id: 'plans-stacked',
    type: 'bar',
    height: 320,
    stacked: true,
    toolbar: { show: false },
  },
  colors: ['#0f766e', '#d97706'],
  plotOptions: {
    bar: {
      columnWidth: '55%',
      borderRadius: 4,
      borderRadiusApplication: 'end',
    },
  },
  forecastDataPoints: {
    count: 3,
    fillOpacity: 0.5,
    dashArray: 4,
    strokeWidth: 1,
  },
  dataLabels: { enabled: false },
  xaxis: { categories: MONTHS },
  yaxis: { title: { text: 'New subscriptions' } },
  legend: { position: 'bottom' },
  tooltip: { shared: true, intersect: false },
}

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

var options1 = {
  series: seriesFor('europe'),
  chart: {
    id: 'plans-line',
    type: 'line',
    height: 320,
    toolbar: { show: false },
  },
  colors: ['#0f766e', '#d97706'],
  stroke: { curve: 'stepline', width: 3 },
  forecastDataPoints: { count: 3, dashArray: 6 },
  dataLabels: { enabled: false },
  xaxis: { categories: MONTHS },
  yaxis: { min: 0, title: { text: 'New subscriptions' } },
  legend: { position: 'bottom' },
  tooltip: { shared: true, intersect: false },
}

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

wireRegions()