Back to list
sjnims

chartjs-plugins

by sjnims

Claude Code plugin for Chart.js v4.5.1 with 12 expert skills, interactive code generation, and React/Vue/Angular/Rails integrations

0🍴 0📅 Jan 19, 2026

SKILL.md


name: chartjs-plugins description: This skill should be used when the user asks "Chart.js plugins", "custom Chart.js plugin", "Chart.js plugin hooks", "beforeDraw plugin", "afterDraw plugin", "Chart.js plugin API", "register Chart.js plugin", "Chart.js plugin options", "Chart.js plugin lifecycle", "Chart.js plugin TypeScript", or needs help creating custom plugins for Chart.js v4.5.1.

Chart.js Custom Plugins (v4.5.1)

Complete guide to creating and using custom plugins in Chart.js.

Plugin Basics

Plugins are the most efficient way to customize or change Chart.js default behavior. Plugins provide hooks into the chart lifecycle to execute custom code.

Plugin Types

TypeScopeUse Case
InlineSingle chart instanceOne-off customizations
SharedMultiple chartsReusable across specific charts
GlobalAll chartsSite-wide defaults

Inline Plugins

Define directly in chart config:

const chart = new Chart(ctx, {
  type: 'bar',
  data: data,
  plugins: [{
    id: 'myInlinePlugin',
    beforeDraw: (chart, args, options) => {
      // Custom drawing logic
    }
  }]
});

Limitations: Cannot be registered globally, not reusable.

Shared Plugins

Define once, use in multiple charts:

const myPlugin = {
  id: 'mySharedPlugin',
  beforeDraw: (chart, args, options) => {
    // Custom logic
  }
};

const chart1 = new Chart(ctx1, {
  plugins: [myPlugin]
});

const chart2 = new Chart(ctx2, {
  plugins: [myPlugin]
});

Global Plugins

Register once, apply to all charts:

const myPlugin = {
  id: 'myGlobalPlugin',
  beforeDraw: (chart, args, options) => {
    // Custom logic
  }
};

Chart.register(myPlugin);

// Now all charts use this plugin automatically
const chart = new Chart(ctx, { type: 'bar', data: data });

Plugin Structure

Required Properties

const plugin = {
  id: 'unique-plugin-id',  // Required for configuration

  // Lifecycle hooks (all optional)
  beforeInit: (chart, args, options) => {},
  afterInit: (chart, args, options) => {},
  beforeUpdate: (chart, args, options) => {},
  afterUpdate: (chart, args, options) => {},
  beforeDraw: (chart, args, options) => {},
  afterDraw: (chart, args, options) => {},
  // ... more hooks

  // Default options (optional)
  defaults: {
    color: 'red',
    lineWidth: 2
  }
};

Plugin ID Naming

Follow npm package naming conventions:

  • Lowercase letters, numbers, hyphens only
  • No leading dot or underscore
  • Should be descriptive
  • Prefix with chartjs-plugin- for public packages

Plugin Lifecycle Hooks

Initialization Hooks

HookWhenCancelableUse Case
beforeInitBefore chart initializationNoSet up data structures
afterInitAfter chart initializationNoAccess initialized chart

Update Hooks

HookWhenCancelableUse Case
beforeUpdateBefore chart updateYesModify data before update
afterUpdateAfter chart updateNoReact to data changes
beforeLayoutBefore layout calculationYesModify layout constraints
afterLayoutAfter layout calculationNoAccess calculated layout
beforeDatasetsUpdateBefore datasets updateYesIntercept dataset updates
afterDatasetsUpdateAfter datasets updateNoReact to dataset changes

Render Hooks

HookWhenCancelableUse Case
beforeRenderBefore renderingYesSkip render conditionally
beforeDrawBefore drawing chartYesDraw custom backgrounds
afterDrawAfter drawing chartNoDraw overlays, annotations
afterRenderAfter rendering completeNoPost-render operations

Event Hooks

HookWhenUse Case
beforeEventBefore event processingIntercept/modify events
afterEventAfter event processingReact to user interactions

Destruction Hook

HookWhenUse Case
afterDestroyAfter chart destroyedClean up resources

Plugin Configuration

Defining Options

Configure plugins via options.plugins.{plugin-id}:

const plugin = {
  id: 'backgroundPlugin',
  beforeDraw: (chart, args, options) => {
    const {ctx} = chart;
    ctx.save();
    ctx.fillStyle = options.color || 'white';
    ctx.fillRect(0, 0, chart.width, chart.height);
    ctx.restore();
  },
  defaults: {
    color: 'lightGreen'
  }
};

Chart.register(plugin);

const chart = new Chart(ctx, {
  options: {
    plugins: {
      backgroundPlugin: {
        color: 'lightBlue'  // Override default
      }
    }
  }
});

Disabling Plugins

Disable global plugin for specific chart:

const chart = new Chart(ctx, {
  options: {
    plugins: {
      myPlugin: false  // Disable this plugin
    }
  }
});

Disable all plugins:

const chart = new Chart(ctx, {
  options: {
    plugins: false  // Disable all plugins
  }
});

Common Plugin Patterns

Canvas Background Color

const canvasBackgroundColor = {
  id: 'canvasBackgroundColor',
  beforeDraw: (chart, args, options) => {
    const {ctx, chartArea} = chart;
    ctx.save();
    ctx.globalCompositeOperation = 'destination-over';
    ctx.fillStyle = options.color || 'white';
    ctx.fillRect(0, 0, chart.width, chart.height);
    ctx.restore();
  }
};

Chart Area Border

const chartAreaBorder = {
  id: 'chartAreaBorder',
  beforeDraw(chart, args, options) {
    const {ctx, chartArea: {left, top, width, height}} = chart;
    ctx.save();
    ctx.strokeStyle = options.borderColor;
    ctx.lineWidth = options.borderWidth;
    ctx.setLineDash(options.borderDash || []);
    ctx.strokeRect(left, top, width, height);
    ctx.restore();
  },
  defaults: {
    borderColor: 'black',
    borderWidth: 1,
    borderDash: []
  }
};

Custom Text Overlay

const textOverlay = {
  id: 'textOverlay',
  afterDraw: (chart, args, options) => {
    const {ctx, chartArea: {left, right, top, bottom}} = chart;
    ctx.save();

    const centerX = (left + right) / 2;
    const centerY = (top + bottom) / 2;

    ctx.font = options.font || '20px Arial';
    ctx.fillStyle = options.color || 'black';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(options.text || '', centerX, centerY);

    ctx.restore();
  }
};

Empty State Handler

const emptyStatePlugin = {
  id: 'emptyState',
  afterDraw(chart, args, options) {
    const {datasets} = chart.data;
    let hasData = datasets.some(ds => ds.data.length > 0);

    if (!hasData) {
      const {ctx, chartArea: {left, top, right, bottom}} = chart;
      const centerX = (left + right) / 2;
      const centerY = (top + bottom) / 2;

      ctx.save();
      ctx.font = '16px Arial';
      ctx.fillStyle = 'gray';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillText(options.message || 'No data available', centerX, centerY);
      ctx.restore();
    }
  }
};

Accessing Chart Elements

Chart Object Properties

beforeDraw: (chart, args, options) => {
  const {
    ctx,              // Canvas 2D context
    canvas,           // Canvas element
    width,            // Chart width
    height,           // Chart height
    chartArea,        // {left, top, right, bottom, width, height}
    scales,           // {x, y, r, ...}
    data,             // Chart data
    options,          // Chart options
    config            // Chart configuration
  } = chart;
}

Scales and Coordinates

afterDraw: (chart, args, options) => {
  const {scales: {x, y}} = chart;

  // Convert data value to pixel
  const pixelX = x.getPixelForValue(dataValue);
  const pixelY = y.getPixelForValue(dataValue);

  // Convert pixel to data value
  const dataX = x.getValueForPixel(pixelX);
  const dataY = y.getValueForPixel(pixelY);
}

TypeScript Support

Plugin Type Declaration

import {ChartType, Plugin} from 'chart.js';

declare module 'chart.js' {
  interface PluginOptionsByType<TType extends ChartType> {
    myPlugin?: {
      color?: string;
      width?: number;
      enabled?: boolean;
    }
  }
}

const myPlugin: Plugin = {
  id: 'myPlugin',
  beforeDraw(chart, args, options) {
    // TypeScript now knows about options.color, options.width
    const color = options.color || 'red';
  }
};

Best Practices

Performance

  • Use beforeDraw/afterDraw sparingly - called on every render
  • Cache calculations in afterUpdate hooks
  • Avoid heavy computations in render hooks
  • Use ctx.save() and ctx.restore() to avoid side effects

Error Handling

const safePlugin = {
  id: 'safePlugin',
  afterDraw: (chart, args, options) => {
    try {
      // Plugin logic
    } catch (error) {
      console.error('Plugin error:', error);
    }
  }
};

Conditional Rendering

const conditionalPlugin = {
  id: 'conditionalPlugin',
  beforeDraw: (chart, args, options) => {
    if (!options.enabled) {
      return;  // Skip if disabled
    }
    // Draw logic
  }
};

Additional Resources

  • See references/plugin-api.md for complete hook reference
  • See examples/quadrants-plugin.md for working quadrant background example
  • See examples/empty-state-plugin.md for empty state handler example

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon