NexusCS

Chart.js

JavaScript
Chart.js: simple yet flexible charting library for line, bar, pie, radar, and more.
featured

Getting started

Installation

npm install chart.js
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

Auto-register (development)

import Chart from "chart.js/auto";

Imports all chart types and components.

Tree-shakeable (production)

import {
  Chart,
  LineController,
  LineElement,
  PointElement,
  LinearScale,
  CategoryScale,
  Title,
} from "chart.js";

Chart.register(
  LineController,
  LineElement,
  PointElement,
  LinearScale,
  CategoryScale,
  Title,
);

Import only what you need.

Basic example

<canvas id="myChart"></canvas>
new Chart(document.getElementById("myChart"), {
  type: "bar",
  data: {
    labels: ["Red", "Blue", "Yellow"],
    datasets: [
      {
        label: "# of Votes",
        data: [12, 19, 3],
        borderWidth: 1,
      },
    ],
  },
  options: {
    scales: {
      y: { beginAtZero: true },
    },
  },
});

Chart Types

Available types

Type Controller Elements
'line' LineController LineElement, PointElement
'bar' BarController BarElement
'pie' PieController ArcElement
'doughnut' DoughnutController ArcElement
'radar' RadarController LineElement, PointElement
'polarArea' PolarAreaController ArcElement
'bubble' BubbleController PointElement
'scatter' ScatterController PointElement

Horizontal bar

{
  type: 'bar',
  options: {
    indexAxis: 'y'
  }
}

Data Structure

Array format

{
  labels: ['Jan', 'Feb', 'Mar'],
  datasets: [{
    label: 'Sales',
    data: [65, 59, 80],
    backgroundColor: 'rgba(255, 99, 132, 0.2)',
    borderColor: 'rgb(255, 99, 132)',
    borderWidth: 1
  }]
}

Object format

datasets: [
  {
    data: [
      { x: 10, y: 20 },
      { x: 15, y: 25 },
    ],
  },
];

For scatter and bubble charts.

Options

Basic options

options: {
  responsive: true,
  maintainAspectRatio: false,
  aspectRatio: 2
}

Plugins

options: {
  plugins: {
    legend: {
      position: 'top',
      display: true
    },
    tooltip: {
      enabled: true,
      mode: 'index',
      intersect: false
    },
    title: {
      display: true,
      text: 'My Chart'
    }
  }
}

Animations

options: {
  animation: {
    duration: 1000,
    easing: 'easeOutQuart'
  }
}

Scales

Y-axis configuration

options: {
  scales: {
    y: {
      beginAtZero: true,
      min: 0,
      max: 100,
      ticks: {
        callback: value => `$${value}`
      }
    }
  }
}

Stacked charts

options: {
  scales: {
    x: { stacked: true },
    y: { stacked: true }
  }
}

Tooltips

Custom callbacks

plugins: {
  tooltip: {
    callbacks: {
      label: (ctx) => {
        const val = ctx.parsed.y;
        return `${ctx.dataset.label}: $${val}`;
      };
    }
  }
}

External HTML tooltip

{
  enabled: false,
  external: function(context) {
    // Custom implementation
  }
}

Legend

Position and alignment

plugins: {
  legend: {
    position: 'top',  // 'left', 'bottom', 'right'
    align: 'center'   // 'start', 'end'
  }
}

Custom click handler

plugins: {
  legend: {
    onClick: (e, item, legend) => {
      const i = item.datasetIndex;
      legend.chart.isDatasetVisible(i)
        ? legend.chart.hide(i)
        : legend.chart.show(i);
    };
  }
}

Animations

Animation callbacks

options: {
  animation: {
    duration: 1000,
    easing: 'easeOutQuart',
    onComplete: (anim) => {
      console.log('Done');
    },
    onProgress: (anim) => {
      console.log(anim.currentStep);
    }
  }
}

Disable specific animations

options: {
  animations: {
    colors: false,
    x: false
  }
}

Disable all: animation: false

Plugins

Creating a plugin

const bgPlugin = {
  id: "customBg",
  beforeDraw: (chart, args, options) => {
    const { ctx } = chart;
    ctx.save();
    ctx.fillStyle = options.color || "#fff";
    ctx.fillRect(0, 0, chart.width, chart.height);
    ctx.restore();
  },
};

new Chart(ctx, {
  plugins: [bgPlugin],
  options: {
    plugins: {
      customBg: { color: "#f5f5f5" },
    },
  },
});

Global registration

Chart.register(bgPlugin);

Updating Charts

Add data

chart.data.labels.push("New");
chart.data.datasets.forEach((ds) => {
  ds.data.push(newVal);
});
chart.update();

Remove data

chart.data.labels.pop();
chart.data.datasets.forEach((ds) => {
  ds.data.pop();
});
chart.update();

Update without animation

chart.update("none");

Destroy chart

chart.destroy();

Styling

Dataset styling

{
  borderColor: 'rgb(75, 192, 192)',
  borderWidth: 3,
  borderDash: [5, 5],
  tension: 0.1,          // Bezier curve
  pointStyle: 'circle',  // 'cross', 'rect', 'star'
  pointRadius: 3,
  fill: true             // Area fill
}

Color formats

"#ff6384";
"rgb(255, 99, 132)";
"rgba(255, 99, 132, 0.2)";

Responsive

HTML container

<div style="position: relative; width: 80vw; height: 40vh;">
  <canvas id="chart"></canvas>
</div>

Canvas needs relative container.

Responsive options

options: {
  responsive: true,
  maintainAspectRatio: false,
  onResize: (chart, size) => {
    console.log('Resized');
  }
}

React Integration

react-chartjs-2

import { Line } from "react-chartjs-2";
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
} from "chart.js";

ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement);

function MyChart() {
  return <Line data={data} options={options} />;
}

Gotchas

Tree-shaking

⚠️ chart.js/auto disables tree-shaking — import and register components individually for production.

Canvas sizing

⚠️ Canvas needs a relatively-positioned container — direct canvas sizing doesn't work for responsive charts.

Pie vs Doughnut

⚠️ Pie cutout: 0 vs Doughnut cutout: '50%' — same chart type with different defaults.

Animation callbacks

⚠️ onProgress/onComplete callbacks only work at options.animation root level.

Plugin IDs

⚠️ Plugin IDs must be unique and follow npm naming conventions.

Scale references

⚠️ Scale references become invalid after updating chart.options.scales.

Canvas reuse

⚠️ Must call chart.destroy() before creating a new chart on the same canvas.

Also see