AmCharts-style scrollbar zoom controls for Chart.js — draggable handles, pan, and visual scrollbar tracks for both axes.
Unlike chartjs-plugin-zoom (which uses pinch/wheel gestures), this plugin renders visual scrollbar controls directly on the canvas with draggable handles on each end, matching the UX of AmCharts, Highcharts, and other premium charting libraries.
npm install chartjs-plugin-scrollbar-zoom
import { Chart } from 'chart.js';
import ScrollbarZoomPlugin from 'chartjs-plugin-scrollbar-zoom';
// Register globally
Chart.register(ScrollbarZoomPlugin);
// Or per-chart via the plugins array
new Chart(ctx, {
type: 'line',
data: { /* ... */ },
options: {
// Add padding to make room for scrollbars
layout: { padding: { top: 32, right: 28 } },
plugins: {
scrollbarZoom: {
enabled: true,
},
},
},
});
All options are set under options.plugins.scrollbarZoom:
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable or disable the plugin |
axes |
'x' \| 'y' \| 'both' |
'both' |
Which axes get scrollbars |
xPosition |
'top' \| 'bottom' |
'top' |
X scrollbar position |
yPosition |
'left' \| 'right' |
'right' |
Y scrollbar position |
trackSize |
number |
6 |
Track height/width in px |
handleRadius |
number |
10 |
Handle circle radius in px |
xOffset |
number |
20 |
Distance from chart area to X scrollbar center |
yOffset |
number |
16 |
Distance from chart area to Y scrollbar center |
minThumbFraction |
number |
0.08 |
Minimum thumb size (0–1 fraction of track) |
dark |
boolean |
false |
Use dark-mode colors |
colors |
ScrollbarColors |
— | Custom light-mode colors (see below) |
darkColors |
ScrollbarColors |
— | Custom dark-mode colors (see below) |
preserveYTicks |
boolean |
true |
Keep only original Y tick values when zoomed |
onZoomChange |
function |
— | Callback on viewport change |
interface ScrollbarColors {
track?: string; // Track background
thumb?: string; // Thumb (selected range) fill
handleFill?: string; // Handle circle fill
handleStroke?: string; // Handle circle border
grip?: string; // Handle grip-line color
}
Light mode:
| Part | Color |
|—|—|
| Track | rgba(0,0,0,0.08) |
| Thumb | rgba(0,0,0,0.15) |
| Handle fill | #e8e8e8 |
| Handle stroke | rgba(0,0,0,0.25) |
| Grip lines | rgba(0,0,0,0.35) |
Dark mode:
| Part | Color |
|—|—|
| Track | rgba(255,255,255,0.12) |
| Thumb | rgba(255,255,255,0.25) |
| Handle fill | #555 |
| Handle stroke | rgba(255,255,255,0.5) |
| Grip lines | rgba(255,255,255,0.7) |
The scrollbars are drawn outside the chart area, so you need to add layout.padding to reserve space. Typical values:
// Both axes, X on top, Y on right
layout: { padding: { top: 32, right: 28 } }
// X only on top
layout: { padding: { top: 32 } }
// Y only on right
layout: { padding: { right: 28 } }
// X on bottom
layout: { padding: { bottom: 32 } }
new Chart(ctx, {
type: 'line',
data: { labels, datasets },
options: {
layout: { padding: { top: 32, right: 28 } },
plugins: {
scrollbarZoom: { enabled: true },
},
},
});
plugins: {
scrollbarZoom: {
enabled: true,
dark: true,
},
}
options: {
layout: { padding: { top: 32 } },
plugins: {
scrollbarZoom: {
enabled: true,
axes: 'x',
},
},
}
plugins: {
scrollbarZoom: {
enabled: true,
trackSize: 8,
handleRadius: 12,
colors: {
track: 'rgba(139,92,246,0.1)',
thumb: 'rgba(139,92,246,0.25)',
handleFill: '#ede9fe',
handleStroke: 'rgba(139,92,246,0.4)',
grip: 'rgba(139,92,246,0.6)',
},
},
}
plugins: {
scrollbarZoom: {
enabled: true,
onZoomChange: ({ xStart, xEnd, yStart, yEnd }) => {
console.log(`X: ${xStart.toFixed(2)}–${xEnd.toFixed(2)}`);
console.log(`Y: ${yStart.toFixed(2)}–${yEnd.toFixed(2)}`);
},
},
}
| Action | Effect |
|---|---|
| Drag a handle | Zoom in/out from that end |
| Drag the thumb | Pan the visible range |
| Double-click chart | Reset to full view |
Full type definitions are included. Augment Chart.js plugin options:
import type { ScrollbarZoomOptions } from 'chartjs-plugin-scrollbar-zoom';
declare module 'chart.js' {
interface PluginOptionsByType<TType> {
scrollbarZoom?: ScrollbarZoomOptions;
}
}
Open demo/index.html in a browser after building (npm run build) to see live examples with light/dark mode, custom colors, axis configurations, and positioning options.
MIT — OdysseyAB