Chart.js
Chart.js is a free and open-source JavaScript library for data visualization that enables the creation of animated, interactive, and responsive charts using the HTML5 <canvas> element.[1] It is designed for simplicity and flexibility, allowing developers to build a variety of charts with minimal code while supporting customization through plugins and configuration options.[2]
The library supports eight core chart types—bar, line, area, pie and doughnut, bubble, polar area, radar, and scatter—along with the ability to create mixed charts combining multiple types. Key features include high rendering performance across modern browsers, automatic responsiveness that redraws charts on window resize, advanced animations for properties like colors and positions, and built-in plugins for functionalities such as data decimation for handling large datasets and color palettes.[2] Chart.js is distributed via npm with tree-shaking support in version 4.0 and later, enabling optimized bundle sizes as small as 14 KB for specific use cases.[3]
First announced in 2013, Chart.js was initially developed by Nick Downie and has since evolved through community contributions on GitHub under the MIT license, with over 60,000 stars and millions of weekly npm downloads as of 2025.[2] Major releases include version 2.0 in April 2016, which enhanced animations, introduced mixed charts, and added new axis types;[4] version 3.0 in April 2021, focusing on performance improvements like handling large datasets with decimation;[5] and version 4.0 in April 2022, adding features like a colors plugin, subtitle support, and ESM-only distribution for better modularity.[6] As of November 2025, the latest stable version is 4.5.1, maintaining its position as a lightweight alternative to more complex charting solutions.[7]
Overview
Description
Chart.js is a free and open-source JavaScript library designed for creating animated and interactive charts using the HTML5 canvas element.[2] It enables developers to render visualizations directly in web browsers, leveraging the 2D canvas API for efficient drawing and manipulation of graphical elements.[2]
The core purpose of Chart.js is to simplify data visualization in web applications, eliminating the need for complex backend processing or vector-based rendering like SVG, which can introduce performance overhead with large datasets.[2] By providing built-in animations that are enabled by default and built-in support for interactive features like tooltips, along with extensibility through plugins for additional capabilities such as zooming, it facilitates engaging presentations of data without additional libraries.[2]
Chart.js finds primary use in embedding charts within websites, dashboards, reports, and single-page applications (SPAs) to represent diverse datasets, including sales metrics, user analytics, and scientific observations.[2] Its technical foundation ensures broad compatibility with modern browsers such as Chrome, Edge, Firefox, and Safari (IE11 support was dropped in version 3.0), making it suitable for cross-platform web development.[8]
Among its key advantages, Chart.js remains lightweight at approximately 48 KB when minified, with potential reductions to 14 KB via tree-shaking to include only necessary components; it offers responsive design by default, automatically redrawing charts on window resizes for optimal scaling; and it operates with no external dependencies, promoting easy integration into existing projects.[1]
Licensing and distribution
Chart.js is released under the MIT License, a permissive open-source license that permits free use, modification, and distribution of the software in both commercial and non-commercial projects, provided that the original copyright notice and permission notice are included in all copies or substantial portions of the software.
The project is hosted on GitHub under the chartjs organization, where it is actively maintained through contributions from a global community of developers who submit pull requests, report issues, and participate in discussions via platforms such as the project's Discord server and GitHub issues.[9][10]
Distribution of Chart.js occurs primarily through several channels to accommodate different development workflows. It is available as an npm package named chart.js, which can be installed via the command npm install chart.js for integration into Node.js-based projects and modern bundlers.[7][3] For browser-based usage without build tools, pre-built files are accessible via content delivery networks (CDNs) such as CDNJS and jsDelivr, allowing direct script inclusion from URLs like https://cdnjs.cloudflare.com/ajax/libs/Chart.js/latest/Chart.min.js or https://cdn.jsdelivr.net/npm/chart.js@latest/dist/chart.min.js.[11][12] Additionally, users can download release bundles directly from the GitHub releases page, though building from source is required if cloning the repository.[13][3]
Chart.js adheres to semantic versioning (SemVer), where version numbers follow the MAJOR.MINOR.PATCH format to indicate compatibility levels, with major releases introducing breaking changes and occurring infrequently—typically every two to three years—to prioritize backward compatibility for existing integrations.[14][10] Minor and patch releases, which add features or fix bugs without breaking changes, are issued regularly, often on a near-monthly basis, as evidenced by the project's release history.[15]
To optimize bundle sizes in production environments, Chart.js supports tree-shaking in modern module bundlers such as Webpack and Rollup, enabling developers to import and register only the specific controllers, elements, scales, and plugins required for their charts, thereby excluding unused code during the build process.[16]
History
Inception and early development
Chart.js was developed by web developer Nick Downie in early 2013 as a personal project aimed at creating a simple, lightweight JavaScript library for rendering charts directly on HTML5 canvas elements.[17] The library emerged as an alternative to more complex and resource-intensive charting solutions like D3.js, which relied on SVG rendering, or proprietary options like Highcharts, focusing instead on ease of integration for responsive web designs in an era of mobile-first development.[17] By leveraging the canvas API, Chart.js avoided dependencies on Flash or vector-based graphics, enabling smooth performance across browsers without heavy overhead.[17]
The first public release, version 0.1, occurred on March 17, 2013, marking the library's debut as an open-source tool under the MIT license hosted on GitHub.[17] This initial version provided core functionality for fundamental chart types, including line, bar, radar, and polar area charts, emphasizing simplicity in configuration and rendering to appeal to both designers and developers.[17] Although basic animations were not prominently featured in the earliest iteration, the design prioritized quick setup and visual appeal through canvas-based drawing.
Early adoption was swift, with the project attracting interest from the web development community shortly after launch, prompting its continued maintenance and evolution beyond Downie's personal repository. This community engagement facilitated the library's migration to a dedicated GitHub organization, solidifying its open-source status and paving the way for collaborative contributions leading to the first stable release, version 1.0, in January 2015.
Major version releases
Chart.js has undergone several major version releases since its early development, each introducing significant enhancements, performance improvements, and architectural shifts while addressing security and compatibility concerns. The progression from version 2.0 onward reflects a focus on modularity, extensibility, and modern web standards.
Version 2.0, released on April 9, 2016, marked a substantial rewrite emphasizing better modularity through the introduction of dataset controllers and a generic layout system.[4] Key additions included support for time scales to handle date/time data effectively, stacked bar and area charts for layered visualizations, and improved mobile responsiveness with percentage-based sizing constraints.[4] Multiple axes support and interactive legends were also integrated, enabling more complex chart configurations without external dependencies.[18]
Version 3.0, released on April 2, 2021,[5] brought breaking changes to scales and plugins to enhance flexibility and security, including the removal of script injection vulnerabilities associated with prior dependencies like Moment.js.[19] Notable features encompassed refined dataset controllers for easier extension, native support for mixed chart types combining elements like lines and bars in a single instance, and optimizations for rendering efficiency.[19] These updates shifted away from global dependencies, promoting a more plugin-oriented architecture.[20]
Version 4.0, released on November 14, 2022,[21] further advanced TypeScript integration with comprehensive type definitions and NodeNext module compatibility, alongside the introduction of a new filler plugin for creating gradients and area fills.[22] Performance optimizations targeted large datasets through tree-shaking support and ESM-only builds, reducing bundle sizes significantly.[1] Global registration was deprecated in favor of explicit plugin management, streamlining integrations with modern frameworks.[22]
The most recent minor update, v4.5.1, released on October 13, 2025, focused on bug fixes without introducing breaking changes, including resolutions for doughnut chart legend synchronization and tooltip callback typing in TypeScript.[23] It also addressed rendering issues like chart shrinking in certain browser zoom levels.[23]
Across these releases, Chart.js has trended toward a robust plugin architecture for extensibility, enhanced accessibility features such as ARIA labels for better screen reader support, and seamless integration with frameworks like React and Vue through dedicated adapters.
Features
Supported chart types
Chart.js provides a variety of native chart types designed for common data visualization needs, each tailored to specific analytical purposes such as comparison, trend analysis, and correlation. These core types include bar, line, area, pie, doughnut, radar, polar area, bubble, and scatter charts, all rendered using HTML5 Canvas for efficient browser-based display.[24]
Bar charts represent categorical data through vertical or horizontal rectangular bars, where bar lengths correspond to values, facilitating direct comparisons across categories; they support stacking to show cumulative totals and grouping for multiple datasets side-by-side.[25] Line charts connect discrete data points with straight lines to illustrate trends over a continuous axis, such as time, and include area variants that fill the space beneath the line to emphasize volume or magnitude.[26] Pie and doughnut charts depict proportional data in a circular format divided into slices, with each slice's size reflecting its share of the whole; the doughnut variant introduces a central cutout, allowing for additional visual elements like labels or logos in the empty space.
Radar charts, also known as spider or web charts, plot multivariate data on a polygonal grid with radial axes extending from a central point, enabling multi-attribute comparisons by connecting points to form a closed shape that highlights strengths and weaknesses across dimensions. Polar area charts extend this radial concept by filling areas between the center and data points with proportional segments, similar to a bar chart wrapped around a circle, to visualize relative magnitudes in a compact, circular layout. Bubble charts enhance scatter plots by incorporating a third variable through the size of circular markers (bubbles), where position indicates two dimensions and radius represents magnitude, useful for datasets with three interrelated metrics. Scatter charts focus on plotting individual data points based on x and y coordinates to reveal correlations, clusters, or distributions without connecting lines, ideal for exploring relationships in numerical datasets.
All chart types in Chart.js share a consistent data structure centered on datasets, which typically include an array of labels for categories or axes, a data array containing numerical values or objects (such as {x, y} for scatter or {x, y, r} for bubble), and options for background colors to differentiate elements visually.[27] This unified approach allows datasets to be easily configured and reused across types, with colors applied as arrays for single or multiple series.[27]
Animation, interactivity, and customization
Chart.js provides robust animation capabilities that enhance the visual appeal and user experience of charts. Animations are enabled by default and apply to transitions during chart loading, hovering, and updates. The default easing function is 'easeOutQuart', which creates smooth deceleration at the end of animations, though other options like 'linear' or 'easeInQuad' can be configured for specific effects. For instance, on initial load, animations typically last 1000 milliseconds, while hover interactions (under the 'active' state) default to 400 milliseconds with an 'easeOutQuart' easing. Line charts allow customization of tension to control curve smoothness, adjustable via the animations.tension property.[28]
Interactivity in Chart.js is built-in to facilitate user engagement without requiring external libraries. Tooltips appear on hover by default, displaying data values in a customizable format; users can modify the content using callback functions for labels and titles, such as adding currency symbols or formatting numbers. Legends serve as interactive elements that allow toggling dataset visibility with a click, using the default onClick handler to hide or show data series. Click events enable selection of data points, configurable through the onClick option, which receives event coordinates and can map them to specific chart elements for actions like drilling down into data. Hover modes, such as 'point', 'nearest', or 'index', determine which elements respond to mouse movements, with intersection detection enabled by default to ensure precise interactions.[29][30][31]
Customization options in Chart.js allow extensive tailoring of chart appearance and behavior to suit diverse needs. Scales support types including linear (default for continuous data), logarithmic (for exponential ranges), and category (for discrete labels), each configurable under the scales namespace. Axes can be positioned on the left, right, top, or bottom, with grid lines customizable for color, thickness, and visibility to improve readability. Colors extend beyond solids to include gradients via CanvasGradient objects and patterns using CanvasPattern or libraries like Patternomaly for textured fills, enhancing accessibility for color-deficient users. Fonts are globally settable through Chart.defaults.font, with defaults like "Helvetica Neue" at 12px size, but overridable for elements like titles or labels. Responsive design is handled via the maintainAspectRatio option, defaulting to true to preserve the canvas's width-to-height ratio during container resizes, ensuring adaptability across devices.[18][32][33][34]
Accessibility features in Chart.js prioritize compatibility with assistive technologies. ARIA attributes, such as role="img" and aria-label on the canvas element, provide descriptive names for screen readers, enabling users to understand chart content without visual access. Fallback text within the canvas tag serves as an additional alternative for non-canvas-supporting browsers or tools. While high-contrast modes are not natively enforced, color and pattern customizations allow manual adjustments to meet WCAG guidelines for better visibility in such environments.[35]
For performance, Chart.js includes decimation to manage large datasets efficiently, particularly in line charts. This plugin, disabled by default, reduces data points using algorithms like 'min-max' (preserving peaks) or 'lttb' (largest triangle three buckets for trend approximation) when the dataset exceeds four times the canvas width, minimizing rendering overhead without significant loss of visual fidelity. It requires a linear or time-based x-axis and applies only to mutable datasets.[36]
Usage
Installation methods
Chart.js requires modern web browsers for optimal performance and compatibility, including Chrome, Edge, Firefox, and Safari, with support for the HTML5 <canvas> element enabled by default in these environments.[8] As of version 3.0, Internet Explorer 11 support has been discontinued, though polyfills may enable limited functionality in older browsers for earlier versions.[8]
The primary method for installing Chart.js in Node.js-based projects is via npm, which handles dependencies and module resolution efficiently. Run the command npm install chart.js to add the latest version to your project, then import it using ES modules as import Chart from 'chart.js/auto'; to include all controllers, elements, scales, and plugins automatically.[3] For tree-shaking in bundlers like Webpack or Rollup, import specific components, such as import { Chart, BarController, BarElement, CategoryScale, LinearScale } from 'chart.js'; Chart.register(BarController, BarElement, CategoryScale, LinearScale);, to reduce bundle size.[16]
For projects without a build system, Chart.js can be included via a content delivery network (CDN) for immediate global access to the Chart object. Use a script tag like <script src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.umd.js"></script> from jsDelivr, which loads the UMD build and makes Chart.js available without imports.[3] Alternatively, CDNJS provides similar access at <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.js"></script>.[3] Specify a version for stability, e.g., <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.js"></script>.
Direct downloads are possible from the Chart.js GitHub repository, where users can clone or download the source and build the distribution files, including dist/chart.umd.js, using tools like pnpm as outlined in the contributing guide.[3] Prebuilt files are not included in release assets, so building from source is required for custom setups without npm.[13]
Integration with front-end frameworks is facilitated through community-maintained adapters that wrap Chart.js components. For React, use the react-chartjs-2 package (npm install react-chartjs-2 chart.js), which provides declarative chart components compatible with Chart.js versions 2 through 4.[37] In Vue applications, the vue-chartjs wrapper (npm install vue-chartjs chart.js) enables reactive chart rendering, supporting the same Chart.js versions.[37] For Angular, ng2-charts (npm install ng2-charts chart.js) offers directives for seamless integration, also compatible across Chart.js versions 2 to 4.[37] Bundler configurations for ES modules are typically handled automatically, but ensure peer dependencies like date-fns for time scales are installed via adapters such as chartjs-adapter-date-fns.[16]
Version management is straightforward in npm projects by specifying the desired version in package.json, such as "chart.js": "^4.5.1", which pins to the latest minor release while allowing security updates.[7] For CDN usage, append the version to the URL to avoid automatic updates, and monitor peer dependencies for time-related scales, which may require libraries like date-fns or luxon for parsing.[16] This approach ensures reproducibility across environments.[7]
Basic implementation and configuration
To implement a basic Chart.js chart, first set up the HTML structure by including a <canvas> element in the document body, typically wrapped in a container div for sizing control. For example:
html
<div style="width: 800px;">
<canvas id="myChart"></canvas>
</div>
<div style="width: 800px;">
<canvas id="myChart"></canvas>
</div>
This canvas serves as the rendering surface, with an ID for JavaScript reference.[38]
In JavaScript, initialize the chart by acquiring the 2D rendering context from the canvas element and passing it to the Chart constructor along with a configuration object. The configuration specifies the chart type, data, and options. A basic example for a bar chart is:
javascript
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
This creates a responsive bar chart with labeled categories on the x-axis and vote counts on the y-axis, starting from zero.[38]
The data structure consists of a data object with a labels array for axis categories (e.g., strings or numbers) and a datasets array containing one or more dataset objects. Each dataset includes a label for legend identification, a data array of numerical values matching the labels length, and optional styling properties like backgroundColor for fill and borderColor for outlines. Mismatched lengths between labels and data can lead to rendering inconsistencies, so ensure arrays align in size. Null values in data are supported to skip points without breaking the series.[27]
Common configurations adjust layout and interaction via the options object. For responsiveness, set responsive: true (default) to automatically resize the canvas on container changes, paired with maintainAspectRatio: true to preserve proportions; wrap the canvas in a positioned relative container with defined dimensions for best results. To display a title, configure options.plugins.title with display: true and text: 'Chart Title', positioning it at the top by default with bold font. Legends are enabled via options.plugins.legend.display: true (default), with options for position (e.g., 'top') and alignment. For tooltip formatting, use callbacks in options.plugins.tooltip.callbacks, such as label: function(context) { return context.parsed.y + ' votes'; } to append units to values on hover.[34][39][30][29]
To avoid rendering issues, validate data types before initialization: ensure data values are numbers or null, labels are strings or numbers, and arrays have consistent lengths; invalid types like strings in numerical data trigger console warnings or silent failures. For dynamic updates, modify the data object (e.g., myChart.data.datasets[0].data.push(42);) and call myChart.update() to refresh scales, legends, and redraw the chart, optionally with a mode like 'active' for partial animations.[27][40]
Migration between versions involves handling import differences: pre-v3 relied on a global Chart object from script tags without explicit registration, while v3+ supports modular ES imports (e.g., import Chart from 'chart.js/auto';) for tree-shaking, requiring manual registration of components like controllers in non-auto bundles to optimize bundle size.[19][16]
Plugins and extensions
Built-in plugins
Chart.js includes several built-in plugins that provide essential functionalities for chart visualization and interaction, such as displaying legends, titles, tooltips, filled areas, and data decimation for performance. These plugins are included in standard builds, with most enabled by default (e.g., Legend, Tooltip, Filler) though some, like Decimation, require explicit enabling. They can be configured through the options.plugins namespace.[41]
The Legend plugin displays interactive keys for datasets, allowing users to identify series at a glance. It supports configurable positions such as 'top', 'left', 'bottom', 'right', or 'chartArea' (default: 'top'), along with alignment options like 'start', 'center', or 'end' (default: 'center'). An onClick handler can be defined to toggle dataset visibility or perform custom actions, receiving arguments including the event, legend item, and legend object. The plugin is enabled by default and can be disabled via options.plugins.legend.display: false.[30]
The Title plugin adds customizable titles or subtitles at the top of the chart. Key options include display (default: false) to toggle visibility, text for the title content, font settings (default weight: 'bold') for styling, and [padding](/page/Padding) (default: 10) for spacing around the title. These are configured under options.plugins.title, with global defaults available at Chart.defaults.plugins.title.[39]
The Tooltip plugin provides hover-based data details, enhancing interactivity by showing values, labels, and more on data points. It supports external tooltips via a custom external function for HTML rendering outside the canvas, and custom callbacks under options.plugins.tooltip.callbacks for modifying titles, labels, and colors. Additional configurations include enabled (default: true) for on-canvas tooltips, mode for interaction type, and position options like 'average' or 'nearest'.[29]
The Filler plugin, rewritten in version 3.0 with numerous bug fixes, fills areas under lines or between datasets in area charts, supporting gradients, patterns, or solid colors for visual emphasis. It uses the dataset's fill option, which can target boundaries like 'origin', 'start', or 'end', and specify colors such as above and below for segmented fills (e.g., fill: { target: 'origin', above: 'rgb(255, 0, 0)', below: 'rgb(0, 0, 255)' }). This is particularly useful for highlighting trends or ranges in line-based charts.[42][19]
The Decimation plugin optimizes performance for large datasets in line charts by sampling data points while preserving trends. It activates when points exceed four times the canvas width (configurable threshold) and supports algorithms like Largest Triangle Three Buckets (LTTB), which samples approximately one point per pixel for smooth curves, or Min-Max, which retains up to four points per pixel to capture peaks in noisy data. Decimation occurs automatically on chart initialization, requiring conditions such as index axis 'x' and mutable datasets.[36]
The Colors plugin, introduced in version 4.0, automatically assigns colors from a predefined palette to datasets if not explicitly specified, cycling through seven brand colors for backgrounds and borders. It is enabled by default in UMD builds but requires registration in modular setups. Key options include enabled (default: true) to toggle, and forceOverride (default: false) to override existing colors in dynamic scenarios, configured under options.plugins.colors.[32]
Built-in plugins are automatically registered in modular builds of Chart.js, ensuring they are available without additional setup. In tree-shaken bundles, manual registration is required using Chart.register(), for example, import { [Legend](/page/Legend), [Title](/page/Title), [Tooltip](/page/Tooltip), Filler, [Decimation](/page/Decimation) } from 'chart.js'; Chart.register([Legend](/page/Legend), [Title](/page/Title), [Tooltip](/page/Tooltip), Filler, [Decimation](/page/Decimation));, to include only necessary components and reduce bundle size.[41]
Custom plugin development
Custom plugins in Chart.js allow developers to extend the library's core functionality by injecting custom logic at specific points in the chart's lifecycle, enabling features such as annotations, watermarks, or advanced interactions without modifying the source code.[41] Introduced in version 2.1.0, plugins are objects that define an identifier, default options, and optional hook functions that execute during chart initialization, updates, rendering, and events.[41] This modular approach promotes reusability and maintainability, as plugins can be registered globally or scoped to individual charts.[41]
The basic structure of a custom plugin is a JavaScript object with a required id property for unique identification—following npm naming conventions (lowercase, no dots or underscores, URL-safe)—and an optional defaults object for predefined options.[41] Hook functions, such as beforeDraw or afterDatasetDraw, are defined as methods on this object and receive parameters including the chart instance, hook-specific arguments (e.g., scale or event details), and resolved options.[43] These hooks integrate seamlessly into the chart's rendering pipeline, allowing modifications like drawing overlays or altering data before display.[41]
Chart.js provides over 30 lifecycle hooks for precise control over chart stages, categorized by phases such as initialization (beforeInit, afterInit), updates (beforeUpdate, afterUpdate), layout (beforeLayout, afterLayout), datasets (beforeDatasetsDraw, afterDatasetsDraw, beforeDatasetDraw, afterDatasetDraw), rendering (beforeDraw, afterDraw, beforeRender, afterRender), events (beforeEvent, afterEvent), and destruction (beforeDestroy, afterDestroy).[43] Many hooks are cancelable, returning false to halt further processing, while others like afterEvent can trigger re-renders by modifying arguments.[43] Developers inject logic at these points to perform tasks like computing custom scales in afterDataLimits or handling resizes in resize.[43]
For instance, a custom watermark plugin can add a text overlay during the drawing phase:
javascript
const watermarkPlugin = {
id: 'customWatermark',
defaults: {
text: 'Confidential',
color: 'rgba(0,0,0,0.1)',
font: '14px Arial'
},
beforeDraw: (chart, args, pluginOptions) => {
const { ctx, width, height } = chart;
ctx.save();
ctx.globalAlpha = 0.5;
ctx.fillStyle = pluginOptions.color;
ctx.font = pluginOptions.font;
ctx.textAlign = 'center';
ctx.fillText(pluginOptions.text, width / 2, height / 2);
ctx.restore();
}
};
const watermarkPlugin = {
id: 'customWatermark',
defaults: {
text: 'Confidential',
color: 'rgba(0,0,0,0.1)',
font: '14px Arial'
},
beforeDraw: (chart, args, pluginOptions) => {
const { ctx, width, height } = chart;
ctx.save();
ctx.globalAlpha = 0.5;
ctx.fillStyle = pluginOptions.color;
ctx.font = pluginOptions.font;
ctx.textAlign = 'center';
ctx.fillText(pluginOptions.text, width / 2, height / 2);
ctx.restore();
}
};
This example uses the beforeDraw hook to access the canvas context (ctx) and draw semi-transparent text centered on the chart, configurable via plugin options.[41] Similar techniques apply ctx.drawImage for image-based watermarks or fillRect for backgrounds.[41]
Plugins are registered globally using Chart.register(watermarkPlugin), making them available to all charts, or per-chart by including the object in the configuration's plugins array (e.g., new Chart(ctx, { plugins: [watermarkPlugin], ... })).[41] Global registration supports tree-shaking in bundlers like Webpack, as unused plugins are excluded if not referenced.[41] Inline plugins, defined directly in the array, cannot be registered globally but offer isolation for one-off customizations.[41]
Best practices include avoiding direct mutations to Chart.js core objects like scales or datasets to prevent side effects across charts; instead, create copies or use provided arguments.[41] Access options through the pluginOptions parameter or the chart's resolver function (e.g., chart.options.plugins.myPlugin) for handling nested or merged configurations reliably.[41] Plugins should be tested across chart types (e.g., line, bar) and versions, with deprecation checks for hooks like the removed destroy (replaced by afterDestroy since v3.7.0).[41] For TypeScript users, extend the PluginOptionsByType interface to provide type safety.[41]
Advanced usage involves resolver functions for dynamic option resolution, such as chart.getProps(['plugins', 'myPlugin'], true) to retrieve deeply nested values while respecting defaults and overrides.[41] While explicit plugin ordering is managed internally by hook execution sequence, developers can influence flow by returning cancelation values or using event hooks to chain behaviors.[43]