Bring Your Own Shape in JavaScript

Using ApexCharts with JavaScript

This Bring Your Own Shape 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
// Nothing here is in the catalog. `shapeFrom` and `strokeFrom` take an outline of
// your own and pack it with the same engine the 39 built-in shapes use, so a logo,
// a product silhouette or a national symbol needs no release from us.

// A paw print: one pad and four toes, drawn as five subpaths in a 0-100 box.
// Every subpath is wound the same way, so they union into one shape. Wind one the
// other way (flip an arc's sweep flag) and it would cut a hole instead.
var PAW =
  'M 26 71 A 24 21 0 1 1 74 71 A 24 21 0 1 1 26 71 Z ' +
  'M 10 48 A 9.5 12 -35 1 1 27 36 A 9.5 12 -35 1 1 10 48 Z ' +
  'M 29 33 A 10 12.5 -12 1 1 48 29 A 10 12.5 -12 1 1 29 33 Z ' +
  'M 52 29 A 10 12.5 12 1 1 71 33 A 10 12.5 12 1 1 52 29 Z ' +
  'M 73 36 A 9.5 12 35 1 1 90 48 A 9.5 12 35 1 1 73 36 Z'

var paw = ApexUnitShapes.shapeFrom(PAW, {
  name: 'paw',
  // The count below which the toes stop reading as toes. Ask for fewer and the
  // chart says so in the console rather than drawing mush.
  minUnits: 180,
})

// A ridge line: for a thing with no interior, give a CENTRELINE and a width
// instead of drawing both sides of it by hand. `order: 'cols'` makes the season
// bands run along the walk rather than slicing it.
var ridge = ApexUnitShapes.strokeFrom(
  'M 6 76 L 24 44 L 40 60 L 58 22 L 74 46 L 94 30',
  {
    name: 'ridge',
    width: 12,
    order: 'cols',
  },
)

// No outline at all, and no import either: `positions` is just a function of the
// marks and the plot rectangle, so a rule that computes places is a shape too.
// This is the sunflower spiral - each mark one golden angle round from the last,
// its distance from the centre following the square root of its index so the
// density stays even.
function sunflower(objects, rect) {
  var cx = rect.x + rect.width / 2
  var cy = rect.y + rect.height / 2
  var span = Math.min(rect.width, rect.height) / 2 - 6
  var golden = Math.PI * (3 - Math.sqrt(5))
  return objects.map(function (o, i) {
    var t = Math.sqrt((i + 0.5) / objects.length)
    var angle = i * golden
    return {
      id: o.id,
      x: cx + Math.cos(angle) * span * t,
      y: cy + Math.sin(angle) * span * t,
    }
  })
}

var options = {
  series: [1840, 1260, 220, 140],
  chart: {
    type: 'unit',
    height: 430,
    animations: {
      enabled: true,
      speed: 900,
    },
  },
  labels: ['Dogs', 'Cats', 'Rabbits', 'Others'],
  colors: ['#008FFB', '#00A96E', '#C98A00', '#E8264F'],
  plotOptions: {
    unit: {
      layout: 'custom',
      // Defined in the head script from path data, not imported from the catalog.
      positions: paw,
      transition: 'flow',
      unitValue: 5,
      clusterLabels: {
        show: false,
      },
    },
  },
  legend: {
    position: 'bottom',
  },
}

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

var options1 = {
  series: [4200, 6800, 3100, 900],
  chart: {
    type: 'unit',
    height: 380,
    animations: {
      enabled: true,
      speed: 900,
    },
  },
  labels: ['Spring', 'Summer', 'Autumn', 'Winter'],
  colors: ['#00A96E', '#7CB342', '#C98A00', '#0EB8C4'],
  plotOptions: {
    unit: {
      layout: 'custom',
      // A centreline plus a width, also from the head script.
      positions: ridge,
      transition: 'flow',
      unitValue: 24,
      clusterLabels: {
        show: false,
      },
    },
  },
  legend: {
    position: 'bottom',
  },
}

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

var options2 = {
  series: [520, 300, 120, 60],
  chart: {
    type: 'unit',
    height: 430,
    animations: {
      enabled: true,
      speed: 900,
    },
  },
  labels: ['Weekend', 'Day pass', 'Camping', 'Crew'],
  colors: ['#008FFB', '#00A96E', '#C98A00', '#E8264F'],
  plotOptions: {
    unit: {
      layout: 'custom',
      // A function, not a shape object: this chart imports nothing from the kit.
      positions: sunflower,
      transition: 'flow',
      clusterLabels: {
        show: false,
      },
    },
  },
  legend: {
    position: 'bottom',
  },
}

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