Claude-skill-registry chartjs-advanced
This skill should be used when the user asks "Chart.js gradients", "Chart.js linear gradient", "Chart.js radial gradient", "custom Chart.js chart type", "extend Chart.js", "derived chart type", "custom Chart.js scale", "Chart.js programmatic events", "Chart.js setActiveElements", "Chart.js custom controller", or needs help with advanced Chart.js v4.5.1 techniques.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/chartjs-advanced" ~/.claude/skills/majiayu000-claude-skill-registry-chartjs-advanced && rm -rf "$T"
manifest:
skills/data/chartjs-advanced/SKILL.mdsource content
Chart.js Advanced Techniques (v4.5.1)
Guide to advanced Chart.js customization including gradients, custom chart types, and programmatic control.
Gradients
Create visual depth with linear and radial gradients.
Linear Gradients
const ctx = document.getElementById('myChart').getContext('2d'); // Create gradient const gradient = ctx.createLinearGradient(0, 0, 0, 400); gradient.addColorStop(0, 'rgba(75, 192, 192, 1)'); gradient.addColorStop(0.5, 'rgba(75, 192, 192, 0.5)'); gradient.addColorStop(1, 'rgba(75, 192, 192, 0.1)'); const chart = new Chart(ctx, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'], datasets: [{ label: 'Sales', data: [12, 19, 3, 5, 2], backgroundColor: gradient, borderColor: 'rgb(75, 192, 192)', fill: true }] } });
Dynamic Gradients (Responsive)
function createGradient(ctx, chartArea) { const gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top); gradient.addColorStop(0, 'rgba(54, 162, 235, 0)'); gradient.addColorStop(1, 'rgba(54, 162, 235, 1)'); return gradient; } const chart = new Chart(ctx, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar'], datasets: [{ label: 'Revenue', data: [10, 20, 30], backgroundColor: function(context) { const chart = context.chart; const {ctx, chartArea} = chart; if (!chartArea) { return null; // Chart not initialized yet } return createGradient(ctx, chartArea); } }] } });
Radial Gradients
function createRadialGradient(ctx, chartArea) { const width = chartArea.right - chartArea.left; const height = chartArea.bottom - chartArea.top; const centerX = (chartArea.left + chartArea.right) / 2; const centerY = (chartArea.top + chartArea.bottom) / 2; const r = Math.min(width, height) / 2; const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, r); gradient.addColorStop(0, 'rgba(255, 99, 132, 1)'); gradient.addColorStop(0.5, 'rgba(255, 99, 132, 0.5)'); gradient.addColorStop(1, 'rgba(255, 99, 132, 0)'); return gradient; } // Use with pie/doughnut charts datasets: [{ data: [300, 50, 100], backgroundColor: function(context) { const chart = context.chart; const {ctx, chartArea} = chart; if (!chartArea) return null; return createRadialGradient(ctx, chartArea); } }]
Multi-Dataset Gradients
const gradients = [ { start: 'rgba(255, 99, 132, 1)', end: 'rgba(255, 99, 132, 0.1)' }, { start: 'rgba(54, 162, 235, 1)', end: 'rgba(54, 162, 235, 0.1)' }, { start: 'rgba(255, 206, 86, 1)', end: 'rgba(255, 206, 86, 0.1)' } ]; datasets: gradients.map((colors, i) => ({ label: `Dataset ${i + 1}`, data: data[i], backgroundColor: function(context) { const chart = context.chart; const {ctx, chartArea} = chart; if (!chartArea) return null; const gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top); gradient.addColorStop(0, colors.end); gradient.addColorStop(1, colors.start); return gradient; } }))
Custom Chart Types
Extend existing chart types or create new ones.
Extending Bar Controller
import {Chart, BarController} from 'chart.js'; class CustomBarController extends BarController { // Override draw method draw() { super.draw(); // Add custom drawing const meta = this.getMeta(); const ctx = this.chart.ctx; meta.data.forEach(bar => { const {x, y, base, width} = bar.getProps(['x', 'y', 'base', 'width']); // Draw custom element ctx.save(); ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; ctx.fillRect(x - width/2, y - 5, width, 5); ctx.restore(); }); } // Override update method update(mode) { const meta = this.getMeta(); // Custom update logic this.updateElements(meta.data, 0, meta.data.length, mode); } } CustomBarController.id = 'customBar'; CustomBarController.defaults = { ...BarController.defaults, // Add custom default options customOption: true }; Chart.register(CustomBarController); // Use custom chart type const chart = new Chart(ctx, { type: 'customBar', data: data });
Creating Derived Bubble Chart
import {Chart, BubbleController} from 'chart.js'; class DerivedBubble extends BubbleController { draw() { // Call parent draw super.draw(); // Add custom decoration const meta = this.getMeta(); const firstPoint = meta.data[0]; const {x, y} = firstPoint.getProps(['x', 'y']); const {radius} = firstPoint.options; const ctx = this.chart.ctx; ctx.save(); ctx.strokeStyle = this.options.boxStrokeStyle; ctx.lineWidth = 2; ctx.strokeRect(x - radius, y - radius, 2 * radius, 2 * radius); ctx.restore(); } } DerivedBubble.id = 'derivedBubble'; DerivedBubble.defaults = { boxStrokeStyle: 'red' }; Chart.register(DerivedBubble);
Custom Scales
Create custom axis types.
Logarithmic Base-2 Scale
import {Chart, Scale} from 'chart.js'; class Log2Axis extends Scale { constructor(cfg) { super(cfg); this.start = undefined; this.end = undefined; } parse(raw, index) { const value = +raw; return isFinite(value) ? value : null; } determineDataLimits() { const {min, max} = this.getMinMax(true); this.min = min; this.max = max; } buildTicks() { const ticks = []; let power = Math.floor(Math.log2(this.min)); let value = Math.pow(2, power); while (value < this.max) { ticks.push({value}); power++; value = Math.pow(2, power); } return ticks; } getPixelForValue(value) { if (value === undefined || value === 0) { value = this.min; } const decimal = (Math.log2(value) - Math.log2(this.min)) / (Math.log2(this.max) - Math.log2(this.min)); return this.getPixelForDecimal(decimal); } getValueForPixel(pixel) { const decimal = this.getDecimalForPixel(pixel); return Math.pow(2, Math.log2(this.min) + decimal * (Math.log2(this.max) - Math.log2(this.min))); } } Log2Axis.id = 'log2'; Log2Axis.defaults = {}; Chart.register(Log2Axis); // Use custom scale const chart = new Chart(ctx, { type: 'line', data: data, options: { scales: { y: { type: 'log2' } } } });
Programmatic Interactions
Control chart interactions via API.
Trigger Hover Programmatically
function triggerHover(chart, datasetIndex, index) { if (chart.getActiveElements().length > 0) { // Clear active elements chart.setActiveElements([]); } else { // Set active elements chart.setActiveElements([ {datasetIndex: 0, index: 0}, {datasetIndex: 1, index: 0} ]); } chart.update(); } // Usage triggerHover(chart, 0, 2); // Highlight first dataset, third point
Trigger Tooltip Programmatically
function triggerTooltip(chart, datasetIndex, index) { const tooltip = chart.tooltip; if (tooltip.getActiveElements().length > 0) { // Hide tooltip tooltip.setActiveElements([], {x: 0, y: 0}); } else { // Show tooltip const chartArea = chart.chartArea; tooltip.setActiveElements([ {datasetIndex, index} ], { x: (chartArea.left + chartArea.right) / 2, y: (chartArea.top + chartArea.bottom) / 2 }); } chart.update(); } // Usage triggerTooltip(chart, 0, 3); // Show tooltip for first dataset, fourth point
Simulate Click Event
function simulateClick(chart, x, y) { const event = { type: 'click', x: x, y: y, native: { clientX: x, clientY: y } }; chart.handleEvent(event); } // Click center of chart const chartArea = chart.chartArea; const centerX = (chartArea.left + chartArea.right) / 2; const centerY = (chartArea.top + chartArea.bottom) / 2; simulateClick(chart, centerX, centerY);
Dynamic Updates
Advanced data update patterns.
Smooth Data Streaming
function addDataPoint(chart, label, data) { chart.data.labels.push(label); chart.data.datasets.forEach((dataset, i) => { dataset.data.push(data[i]); }); // Keep last 20 points if (chart.data.labels.length > 20) { chart.data.labels.shift(); chart.data.datasets.forEach(dataset => { dataset.data.shift(); }); } chart.update('active'); // Use active transition for smooth updates } // Stream data every second setInterval(() => { addDataPoint(chart, new Date().toLocaleTimeString(), [ Math.random() * 100, Math.random() * 100 ]); }, 1000);
Update Without Animation
// No animation chart.data.datasets[0].data = [10, 20, 30, 40]; chart.update('none'); // Or disable for single update chart.update({duration: 0});
Performance Optimization
Data Decimation
options: { plugins: { decimation: { enabled: true, algorithm: 'lttb', // Largest Triangle Three Buckets samples: 500 // Target number of samples } } }
Disable Animations for Large Datasets
const dataPoints = data.datasets[0].data.length; options: { animation: dataPoints > 1000 ? false : { duration: 1000, easing: 'easeOutQuart' } }
Additional Resources
Examples
- Gradient pattern library (vertical, horizontal, radial, diagonal)examples/gradient-backgrounds.html
- Complete custom controller example (DerivedBubble)examples/custom-chart-type.html
References
- Chart controller API and TypeScript declarationsreferences/controller-api.md
- Scale API for custom axis typesreferences/scale-api.md
- Comprehensive performance tuning guidereferences/performance-optimization.md