npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@odysseyab/chartjs-plugin-scrollbar-zoom

v1.0.1

Published

AmCharts-style scrollbar zoom controls for Chart.js — draggable handles, pan, and visual scrollbar tracks for both axes

Downloads

145

Readme

chartjs-plugin-scrollbar-zoom

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.

Demo screenshot

Features

  • Always-visible scrollbars with track, thumb, and round grip handles
  • Drag handles to zoom from either end of the range
  • Drag thumb to pan the visible viewport
  • Double-click to reset zoom to full view
  • Both axes — independent X and Y scrollbars (or single axis)
  • Preserve tick values — prevents Chart.js from generating decimal ticks when zoomed
  • Dark mode support with separate color sets
  • Fully customizable — colors, sizes, positions, and callbacks
  • Zero dependencies — pure Canvas2D rendering, no DOM elements
  • Works with Chart.js 3.x and 4.x, line and bar charts

Installation

npm install chartjs-plugin-scrollbar-zoom

Quick Start

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,
      },
    },
  },
});

Options

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 |

ScrollbarColors

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
}

Default Colors

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) |

Layout Padding

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 } }

Examples

Both Axes (default)

new Chart(ctx, {
  type: 'line',
  data: { labels, datasets },
  options: {
    layout: { padding: { top: 32, right: 28 } },
    plugins: {
      scrollbarZoom: { enabled: true },
    },
  },
});

Dark Mode

plugins: {
  scrollbarZoom: {
    enabled: true,
    dark: true,
  },
}

X Axis Only

options: {
  layout: { padding: { top: 32 } },
  plugins: {
    scrollbarZoom: {
      enabled: true,
      axes: 'x',
    },
  },
}

Custom Purple Theme

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)',
    },
  },
}

Zoom Change Callback

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)}`);
    },
  },
}

Interaction

| 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 |

TypeScript

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;
  }
}

Testing

The plugin includes a full test suite (25 tests) using Vitest with jsdom. Tests run automatically before every build.

npm test          # Run tests once
npm run test:watch  # Run tests in watch mode
npm run build     # Tests + build (CJS, ESM, IIFE)

Demo

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.

A live demo is available at odysseyab.github.io/chartjs-plugin-scrollbar-zoom.

License

MIT — OdysseyAB