Highcharts

Highcharts and Its Commercial Licence

Highcharts 19,788 , from Highsoft AS in Norway, is the long-standing commercial choice: SVG charts with exporting, an accessibility module (descriptions, keyboard navigation, ARIA) and stock, map and Gantt add-ons. Its source is on GitHub 29 (github.com/highcharts/highcharts (https://github.com/highcharts/highcharts 12,493 )) and it installs with npm 2,036 install highcharts, but it is source available, not open source. Commercial use needs a paid Internal, SaaS or OEM licence, and non-commercial use falls under separate terms from Highsoft. On 26 September 2026 the online shop listed Highcharts Core at US$366 per seat.

A book that is sold is commercial use, so Highcharts was not run here and this listing has no figure. It expects highcharts.js 13.1.1 (npm or jsDelivr 15,886 ), the two BookNest scripts and a <div id="hc">:

The same chart in Highcharts 13.1.1 (not run here: commercial licence)JavaScript
Highcharts.chart('hc', {
  chart: { type: 'bar', width: 560, height: 190 },         // 'bar' is horizontal in Highcharts
  title: { text: null },
  xAxis: { categories: TOTALS.map(r => r.title) },          // the category axis
  yAxis: { title: { text: 'Units sold' } },
  legend: { enabled: false },
  plotOptions: { series: { animation: false } },
  series: [{ name: 'Units', data: TOTALS.map(r => ({ y: r.units, color: r.color })) }]
});

Its bar is horizontal (column is vertical), so xAxis is the vertical category axis. ECharts 129 is the closest free match to its option-object style.

Charting libraries by licence, drawn with D3: Highcharts is source-available and paid for commercial useHTMLLive
<!doctype html>
<style>
  body { margin: 0; padding: 8px; background: #fafaf7; font: 11px system-ui, sans-serif; color: #263238; }
  svg { width: 100%; max-width: 600px; display: block; }
</style>
<script src="https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js"></script>
<svg viewBox="0 0 600 270" font-size="11"></svg>
<p id="out">Hover a library. (Highcharts itself is not loaded here: a sold book is commercial use.)</p>
<script>
  // Licence and cost for a team of n developers building a commercial product (list prices, September 2026)
  const LIBS = [
    { name: 'D3.js', licence: 'ISC', kind: 'open', cost: () => 0 },
    { name: 'Observable Plot', licence: 'ISC', kind: 'open', cost: () => 0 },
    { name: 'Chart.js', licence: 'MIT', kind: 'open', cost: () => 0 },
    { name: 'Apache ECharts', licence: 'Apache-2.0', kind: 'open', cost: () => 0 },
    { name: 'Vega-Lite', licence: 'BSD-3-Clause', kind: 'open', cost: () => 0 },
    { name: 'Plotly.js', licence: 'MIT', kind: 'open', cost: () => 0 },
    { name: 'Highcharts Core', licence: 'Commercial (source available)', kind: 'paid', cost: n => 366 * n },
  ];
  const colors = { open: '#3f7d3a', paid: '#b5452f' };
  const svg = d3.select('svg');
  const n = 5;                                                // a five-developer team
  const y = d3.scaleBand(LIBS.map(l => l.name), [30, 240]).padding(0.25);
  const x = d3.scaleLinear([0, 366 * n], [130, 440]);
  svg.append('text').attr('x', 130).attr('y', 16).attr('font-weight', 'bold')
    .text(`Licence cost for ${n} developers, commercial use (US$)`);
  svg.append('g').attr('transform', 'translate(0,240)').call(d3.axisBottom(x).ticks(5, '$,.0f'));
  const row = svg.selectAll('g.lib').data(LIBS).join('g').attr('class', 'lib')
    .attr('transform', l => `translate(0,${y(l.name)})`)
    .on('pointerenter', (e, l) => d3.select('#out').text(`${l.name}: ${l.licence}` +
      (l.kind === 'paid' ? ` · $366 per seat · npm install works, but commercial use needs a paid Internal, SaaS or OEM licence` : ' · free for any use')));
  row.append('text').attr('x', 124).attr('y', y.bandwidth() / 2).attr('dy', '0.35em').attr('text-anchor', 'end').text(l => l.name);
  row.append('rect').attr('x', 130).attr('height', y.bandwidth()).attr('fill', l => colors[l.kind])
    .attr('width', 0).transition().duration(800).attr('width', l => Math.max(3, x(l.cost(n)) - 130));
  row.append('text').attr('x', l => x(l.cost(n)) + 8).attr('y', y.bandwidth() / 2).attr('dy', '0.35em')
    .text(l => l.cost(n) ? `$${l.cost(n).toLocaleString()} · ${l.licence}` : `free · ${l.licence}`);
</script>