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

react-canvas-timeline

v1.0.1

Published

A high-performance React timeline component built on HTML5 Canvas — designed for rich interactivity, arbitrary time scales, and pixel-perfect rendering at any zoom level.

Readme

react-canvas-timeline

A high-performance React timeline component built on HTML5 Canvas — designed for rich interactivity, arbitrary time scales, and pixel-perfect rendering at any zoom level.

react-canvas-timeline

Why Canvas?

Most timeline and Gantt libraries render rows, bars, and labels as DOM elements. That works fine for small datasets — but it breaks down quickly.

Advantages of the Canvas approach:

  • Performance at scale — 1,000+ task bars render and scroll smoothly because there is no DOM to reflow or repaint. The canvas is redrawn as a single raster operation.
  • Unlimited shapes — Bars, pins, speech bubbles, clouds, stars, curly braces, baselines, circles with center text, and more. CSS cannot express these shapes; Canvas can draw anything.
  • Pixel-precise layout — Every element is positioned and sized to the exact pixel, regardless of browser zoom level, screen DPI, or font scaling.
  • Consistent cross-browser rendering — Canvas output is identical across all modern browsers. No CSS quirks, no layout engine differences.
  • Print layout — A dedicated print mode produces clean, paginated output without additional styling effort.
  • Parallel timelines — Multiple independent timeline instances on the same page work without interference, since each renders to its own canvas.

The common Canvas objection — addressed:

Canvas content is not readable by search engine crawlers or screen readers. react-canvas-timeline solves this by optionally rendering an invisible HTML representation of the timeline data alongside the canvas, making content indexable and accessible without sacrificing rendering performance.


Install

npm install --save react-canvas-timeline

Quick Start

import { ReactCanvasTimeline, Resource, Task, LCal } from 'react-canvas-timeline';

const resources = [
  new Resource(0, 'Alice', 'Developer', false),
  new Resource(1, 'Bob',   'Designer',  false),
];

const now = new LCal().initNow();

const tasks = [
  new Task(0, now.clone(), now.clone().addDay(5),  0, 'Task A', '', null),
  new Task(1, now.clone().addDay(3), now.clone().addDay(10), 1, 'Task B', '', null),
];

export default function App() {
  return (
    <ReactCanvasTimeline
      resources={resources}
      tasks={tasks}
      width={900}
      height={400}
    />
  );
}

Run the Storybook for full working examples:

npm run storybook

LCal — Cosmic Time Range

react-canvas-timeline uses its own calendar system, LCal, instead of JavaScript's Date. This allows representing any point in time from the Big Bang to the far future, internally stored as a Julian day number with minute resolution.

Precision levels

Every LCal value carries a precision that describes how accurately the point in time is known. This is used both for display (labels adapt to the granularity) and for rendering (bars representing geological epochs look different from bars representing a single day).

| Level | Granularity | |------:|-----------------| | 0 | 1 Gigayear | | 1 | 100 Megayears | | 2 | 10 Megayears | | 3 | 1 Megayear | | 4 | 100 Kiloyears | | 5 | 10 Kiloyears | | 6 | 1 Kiloyear | | 7 | 100 years | | 8 | 10 years | | 9 | 1 year | | 10 | 1 month | | 11 | 1 day | | 12 | 1 hour | | 13 | 1 minute |

A single timeline can mix tasks at different precision levels — a geological epoch alongside a modern calendar appointment.


Features

Core

| Story | Feature | |-------|---------| | 01 | 1,000-bar stress test — 100 resources, 1,000 tasks rendered and scrolled without frame drops | | 02 | Hierarchy — Resources and tasks support parent–child nesting with collapse/expand | | 32 | Zoom & fit — Programmatic zoom-to-fit-all and zoom-to-selection |

Visual Customization

| Story | Feature | |-------|---------| | 12 | Bar size — Configurable bar height per timeline | | 13 | Bar groups — Group bars by color and shape within a resource row | | 16 | Shapes & sizes — Full shape catalog: RECT, PIN_INTERVAL, SMALL_PIN_INTERVAL, CLOUD, CURLYBRACE, STAR, CIRCLE, SPEECHBUBBLE, CIRCLE_MIDDLETEXT, BASELINE, TRANSPARENTBACK with transparency and font templates | | 20 | Speech bubbles — Callout shapes with configurable direction | | 21 | Cloud shapes — Organic cloud-style task bars | | 03 | Icons — Per-resource and per-task icon images | | 18 | Short labels — Compact label mode for PIN_INTERVAL and SMALL_PIN_INTERVAL | | 29 | Multiline labels — Text wraps across multiple lines; bar expands vertically to fit | | 35 | Transparent shapes — Background-only shapes without fill | | 37 | Baseline — Render only a baseline marker with no bar body | | 34 | Circle with center text — Circle shape displaying text in the center |

Theming

| Story | Feature | |-------|---------| | 31 | Bright / dark background — Toggle between light and dark themes at runtime | | 09 | Wait overlay styling — Custom loading overlay with full style control |

Interactivity & Events

| Story | Feature | |-------|---------| | 05 | Event callbacksonClick, onPress, onLongPress, onMouseMove, onMousePan with full position and task context | | 06 | Drag & drop — Drag tasks to new times or resources; onDrop callback with position data | | 07 | Highlight & scroll-to — Programmatically highlight a task and scroll it into view | | 08 | Measure intervals — Draggable interval sliders for measuring durations on the canvas | | 24 | Dynamic shape changes — Change task shapes at runtime without full re-render |

Layout & Controls

| Story | Feature | |-------|---------| | 19 | Resource headers — Three modes: default (200 px sidebar), inline (40 px compact row), or no header | | 10 | Additional controls — Inject custom JSX into the vertical and horizontal slider areas | | 27 | No sliders — Render the timeline without any navigation sliders | | 11 | Print layout — Collapse indicators hidden; output optimized for printing | | 14 | Responsive resize — Adapt width and height dynamically as the container resizes | | 15 | Parallel timelines — Multiple independent timeline instances on the same page | | 23 | Config overrides — Fine-grained control over colors, fonts, spacing, and behavior via the config prop |

Advanced

| Story | Feature | |-------|---------| | 39 | Connections — Draw labeled arrows between tasks across resources | | 38 | Resource decorations — Per-resource header colors and background decorations | | 04 | Task backgrounds — Custom painter for the area behind task bars (e.g. agreed-time shading) | | 25 | Embedded diagrams — Paint arbitrary chart data (line, bar, etc.) directly onto the canvas within a resource row | | 26 | Invisible HTML — Render an invisible HTML layer for SEO indexing and screen-reader accessibility | | 33 | Offscreen image rendering — Toggle offscreen canvas pre-rendering for complex scenes | | 30 | Position & bar group features — Combined demo of positioning and grouping capabilities | | 40 | Error handling — Graceful handling of invalid or missing task data |

Precision & Time Scale

| Story | Feature | |-------|---------| | 17 | All precision levels — Visual demonstration of all 14 precision levels on one timeline | | 28 | Precision with images & labels — Precision levels 7–13 combined with icons, labels, and multiple shapes |

Internationalization

| Story | Feature | |-------|---------| | 36 | Language switching — Switch between German, English, and Ukrainian at runtime via languageCode prop | | 41 | Current date indicator callbacks — Custom formatting for the date label shown at the cursor position |


Props Reference

<ReactCanvasTimeline>

Core data

| Prop | Type | Default | Description | |------|------|---------|-------------| | resources | Resource[] | — | Array of resource rows to display | | tasks | Task[] | — | Array of tasks to render on the timeline |

Dimensions

| Prop | Type | Default | Description | |------|------|---------|-------------| | width | number | window.innerWidth × 0.9 | Canvas width in pixels | | height | number | window.innerHeight × 0.9 | Canvas height in pixels | | headerHeight | number | 55 | Height of the time axis header in pixels | | widthOverlap | number | — | Pixel bleed on the left/right edges | | heightOverlap | number | — | Pixel bleed on the top/bottom edges |

Time & locale

| Prop | Type | Default | Description | |------|------|---------|-------------| | start | LCal | auto | Initial visible start time | | end | LCal | auto | Initial visible end time | | timeZone | string | "Europe/Berlin" | IANA timezone identifier | | languageCode | string | — | Locale code for label formatting (e.g. "en", "de", "uk") |

Appearance

| Prop | Type | Default | Description | |------|------|---------|-------------| | barSize | number | 40 | Height of task bars in pixels | | headerType | string | — | Resource header mode: "default" (200 px), "inline" (40 px), or omit for no header | | brightBackground | boolean | — | Optimize contrast for light backgrounds | | paintShadows | boolean | — | Enable drop shadows on task bars | | printLayout | boolean | — | Optimize rendering for print output | | workWithOffscreenImage | boolean | — | Use an offscreen canvas for pre-rendering | | shortLabels | boolean | — | Show short labels on PIN_INTERVAL and SMALL_PIN_INTERVAL shapes | | longlabels | boolean | — | Allow labels to extend beyond the bar to the screen edge |

Event callbacks

| Prop | Type | Description | |------|------|-------------| | onClick | (event: TimelineEvent) => void | Fired on click; event contains time, task, resource, and canvas coordinates | | onPress | (event: TimelineEvent) => void | Fired on pointer down | | onLongPress | (event: TimelineEvent) => void | Fired after a long press gesture | | onMouseMove | (event: TimelineEvent) => void | Fired on pointer move | | onMousePan | (event: TimelineEvent) => void | Fired while panning | | onPanEnd | (timeline) => void | Fired when a pan gesture ends | | onDrop | (timeline, obj, x, y) => void | Fired when an item is dropped onto the timeline | | onZoomChange | (start: LCal, end: LCal) => void | Fired when the visible time window changes | | onOffsetChange | (startTime, endTime, resOffset) => void | Fired when the scroll offset changes | | onToolTip | (event: TimelineEvent) => void | Fired to request a tooltip | | onMeasureIntervalChanged | (interval, isAligning) => void | Fired when the measure sliders move |

Custom rendering

| Prop | Type | Description | |------|------|-------------| | additionalPainter | (ctx, height) => void | Paint additional content on top of the canvas | | resourcePainter | (ctx, resource, x, y, width, height, printLayout, positionCollector) => void | Fully custom resource row painter | | taskBackgroundPainter | (ctx, timeline, task) => void | Paint behind individual task bars | | dateFormatter | (date: LCal) => string | Override the default date label formatter |

Measure sliders

| Prop | Type | Description | |------|------|-------------| | initialMeasureInterval | { start: LCal, end: LCal } | Initial position of the measure sliders | | measureDurationLock | boolean | Keep the interval duration fixed while moving | | sliderValues | SliderValue[] | Predefined zoom level options shown in the slider control |

Configuration

| Prop | Type | Description | |------|------|-------------| | config | object | Partial config object merged with the defaults (see Config Reference below) |


<InstrumentedTimeline> (extended component)

InstrumentedTimeline wraps ReactCanvasTimeline and adds navigation controls (now-button, sliders, zoom buttons). It accepts all props above plus:

| Prop | Type | Description | |------|------|-------------| | instrumentedTimelineCallback | (ref) => void | Receives the component ref for programmatic control | | onNowButtonLongPress | (date: LCal) => void | Long-press on the "now" navigation button | | onNowDialogClose | () => void | Fired when the "now" button dialog is dismissed | | yearPositions | number | Number of year tick positions to display (e.g. 12) | | highlightArrow | JSX | Custom element shown as the scroll-to-task arrow | | measureResult | (interval) => JSX | Render the measure result display | | measureButtons | JSX | Custom buttons shown during measurement mode | | verticalAdditionalControl | JSX | Extra controls in the vertical slider area | | horizontalAdditionalControl | JSX | Extra controls in the horizontal slider area | | nowbuttonChildren | JSX | Content rendered inside the "now" button | | waitOverlay | (width, height) => JSX | Custom loading overlay renderer | | showWaitOverlay | boolean | Show or hide the loading overlay | | dragEnabled | boolean | Enable drag-and-drop of task bars | | currentDateIndicatorLeftCallback | (date: LCal) => string | Format the left side of the cursor date indicator | | currentDateIndicatorRightCallback | (date: LCal) => string | Format the right side (duration) of the cursor date indicator | | children | JSX | Children rendered inside the timeline container |


TimelineEvent object

All pointer callbacks receive a TimelineEvent with these properties:

| Property | Type | Description | |----------|------|-------------| | time | LCal | Time at the cursor position | | task | Task \| null | Task under the cursor, if any | | resource | Resource \| null | Resource row under the cursor, if any | | _x, _y | number | Canvas-relative coordinates | | _absX, _absY | number | Absolute document coordinates | | timeheaderPressed | boolean | Whether the time header was the target | | resourceheaderPressed | boolean | Whether the resource header was the target | | resourceCheckboxPressed | boolean | Whether the resource checkbox was the target | | mouseOverStartMeasureSlider | boolean | Cursor is over the start measure slider | | mouseOverEndMeasureSlider | boolean | Cursor is over the end measure slider |


Config Reference

Pass a partial object to the config prop. Only the keys you provide will override the defaults.

Dimensions & spacing

| Key | Default | Description | |-----|---------|-------------| | ARROWHEADLENGTH | 20 | Arrow head length in pixels | | OVERLAYHEADERWIDTH | 150 | Width of the overlay resource header | | OVERLAYHEADERHEIGHT | 70 | Height of the overlay resource header | | OVERLAY_CHECKBOX_X | 10 | Checkbox x-offset inside the overlay header | | OVERLAY_CHECKBOX_Y | 20 | Checkbox y-offset inside the overlay header | | CHART_INSET | 25 | Padding around chart areas in pixels | | INLINE_RES_HEIGHT | 40 | Row height in inline header mode |

Typography

| Key | Default | Description | |-----|---------|-------------| | resMainFont | "14px Roboto, sans-serif" | Primary font for resource labels | | resSubFont | "12px Roboto, sans-serif" | Secondary font for resource details | | timelineMainFont | "16px Roboto, sans-serif" | Primary font for time axis labels | | timelineSubFont | "12px Roboto, sans-serif" | Secondary font for time axis details | | resourceMainFont | "12px Roboto, sans-serif" | Font for resource element labels | | currentDateOnMousePositionFont | "14px Roboto, sans-serif" | Font for the cursor date indicator | | overlayMessageFont | "16px Roboto, sans-serif" | Font for overlay messages | | positionDecorationFont | "Roboto, sans-serif" | Font for position decorations | | connectionFont | "Roboto, sans-serif" | Font for connection line labels |

Colors

| Key | Default | Description | |-----|---------|-------------| | resMainFontColor | "#000" | Primary resource label color | | resSubFontColor | "#CCC" | Secondary resource label color | | timelineMainFontColor | "#000" | Primary time axis label color | | timelineSubFontColor | "#555" | Secondary time axis label color | | currentDateOnMousePositionColor | "rgba(44,60,80,0.7)" | Background of the cursor date box | | currentDateOnMousePositionBorderColor | "#FFF" | Border of the cursor date box | | timelineHeaderColor | "#F7F7F7" | Time axis header background | | timelineHeaderMainTickColor | "rgba(50,50,50,0.5)" | Major tick marks in the time header | | timelineMainTickColor | "rgba(200,200,200,0.8)" | Major tick lines on the timeline body | | timelineSubTickColor | "rgba(200,200,200,0.5)" | Minor tick lines on the timeline body | | resourceOverlayInlineColor | "rgba(120,120,120,0.8)" | Overlay color in inline header mode | | saturdayColor | "rgba(255,240,240,0.2)" | Saturday column highlight | | sundayColor | "rgba(255,220,220,0.2)" | Sunday column highlight |

Behavior

| Key | Default | Description | |-----|---------|-------------| | hideResourceHeaderIfOnlyOneRes | true | Hide the resource header when only one resource is visible | | getTaskBarInset | function | Returns the pixel inset for a task bar based on its group's collapse state | | getTaskBarInsetByCollapseState | function | Returns 2 if the group is collapsed, 5 if expanded |


Live Examples

GitHub

https://github.com/peterrank/timeline

License

Apache-2.0