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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@gravity-ui/timeline

v1.26.0

Published

Interactive timeline component for React with zoom, pan and custom event rendering capabilities.

Readme

@gravity-ui/timeline npm package Release storybook

A React-based library for building interactive timeline visualizations with canvas rendering.

Documentation

For details see Documentation.

Features

  • Canvas-based rendering for high performance
  • Interactive timeline with zoom and pan capabilities
  • Support for events, markers, sections, axes, and grid
  • Background sections for visual organization and time period highlighting
  • Smart marker grouping with automatic zoom to group - Click on grouped markers to zoom into their individual components
  • Virtualized rendering for improved performance with large datasets (only active when timeline content exceeds the viewport)
  • Customizable appearance and behavior
  • TypeScript support with full type definitions
  • React integration with custom hooks

Installation

npm install @gravity-ui/timeline

Usage

The timeline component can be used in React applications with the following basic setup:

import { TimelineCanvas, useTimeline } from '@gravity-ui/timeline/react';

const MyTimelineComponent = () => {
  const { timeline, api, start, stop } = useTimeline({
    settings: {
      start: Date.now(),
      end: Date.now() + 3600000, // 1 hour from now
      axes: [],
      events: [],
      markers: [],
      sections: []
    },
    viewConfiguration: {
      // Optional view configuration
    }
  });

  // timeline - Timeline instance
  // api - CanvasApi instance (same as timeline.api)
  // start - function to initialize timeline with canvas
  // stop - function to destroy timeline

  return (
    <div style={{ width: '100%', height: '100%' }}>
      <TimelineCanvas timeline={timeline} />
    </div>
  );
};

Section Structure

Each section requires the following structure:

type TimelineSection = {
  id: string;               // Unique section identifier
  from: number;             // Start timestamp
  to?: number;              // Optional end timestamp (defaults to timeline end)
  color: string;            // Background color of the section
  hoverColor?: string;      // Optional color when section is hovered
  renderer?: AbstractSectionRenderer; // Optional custom renderer
};

Sections provide background coloring for time periods and help organize timeline content visually:

const MyTimelineComponent = () => {
  const { timeline } = useTimeline({
    settings: {
      start: Date.now(),
      end: Date.now() + 3600000,
      axes: [],
      events: [],
      markers: [],
      sections: [
        {
          id: 'morning',
          from: Date.now(),
          to: Date.now() + 1800000, // 30 minutes
          color: 'rgba(255, 235, 59, 0.3)', // Semi-transparent yellow
          hoverColor: 'rgba(255, 235, 59, 0.4)'
        },
        {
          id: 'afternoon',
          from: Date.now() + 1800000,
          // No 'to' specified - extends to timeline end
          color: 'rgba(76, 175, 80, 0.2)', // Semi-transparent green
          hoverColor: 'rgba(76, 175, 80, 0.3)'
        }
      ]
    },
    viewConfiguration: {
      sections: {
        hitboxPadding: 2 // Hover detection padding
      }
    }
  });

  return <TimelineCanvas timeline={timeline} />;
};

Marker Structure

Each marker requires the following structure:

type TimelineMarker = {
  time: number;           // Timestamp for the marker position
  color: string;          // Color of the marker line
  activeColor: string;    // Color when marker is selected (required)
  hoverColor: string;     // Color when marker is hovered (required)
  lineWidth?: number;     // Optional width of the marker line
  label?: string;         // Optional label text
  labelColor?: string;    // Optional label color
  renderer?: AbstractMarkerRenderer; // Optional custom renderer
  nonSelectable?: boolean;// Whether marker can be selected
  group?: boolean;        // Whether marker represents a group
};

Marker Grouping and Zoom

The timeline automatically groups markers that are close together and provides zoom functionality:

const MyTimelineComponent = () => {
  const { timeline } = useTimeline({
    settings: {
      start: Date.now(),
      end: Date.now() + 3600000,
      axes: [],
      events: [],
      markers: [
        // These markers will be grouped together
        { time: Date.now(), color: '#ff0000', activeColor: '#ff5252', hoverColor: '#ff1744', label: 'Event 1' },
        { time: Date.now() + 1000, color: '#ff0000', activeColor: '#ff5252', hoverColor: '#ff1744', label: 'Event 2' },
        { time: Date.now() + 2000, color: '#ff0000', activeColor: '#ff5252', hoverColor: '#ff1744', label: 'Event 3' },
      ]
    },
    viewConfiguration: {
      markers: {
        collapseMinDistance: 8,        // Group markers within 8 pixels
        groupZoomEnabled: true,        // Enable zoom on group click
        groupZoomPadding: 0.3,        // 30% padding around group
        groupZoomMaxFactor: 0.3,      // Max zoom factor
      }
    }
  });

  // Listen for group zoom events
  useTimelineEvent(timeline, 'on-group-marker-click', (data) => {
    console.log('Group zoomed:', data);
  });

  return <TimelineCanvas timeline={timeline} />;
};

How It Works

The timeline component is built using React and provides a flexible way to create interactive timeline visualizations. Here's how it works:

Component Architecture

The timeline is implemented as a React component that can be configured through two main objects:

  1. TimelineSettings: Controls the core timeline behavior and appearance
    • start: Start time of the timeline
    • end: End time of the timeline
  • axes: Array of axis configurations
  • events: Array of event configurations
  • markers: Array of marker configurations
  • sections: Array of section configurations
  1. ViewConfiguration: Manages the visual representation and interaction settings
    • Controls appearance, zoom levels, and interaction behavior
    • Can be customized or use default values

Event Handling

The timeline component supports several interactive events:

  • on-click: Triggered when clicking on the timeline
  • on-context-click: Triggered on right-click/context menu
  • on-select-change: Fired when the selection changes
  • on-hover: Triggered when hovering over timeline elements
  • on-leave: Fired when the mouse leaves timeline elements

Example of event handling:

import { useTimelineEvent } from '@gravity-ui/timeline/react';

const MyTimelineComponent = () => {
  const { timeline } = useTimeline({ /* ... */ });

  useTimelineEvent(timeline, 'on-click', (data) => {
    console.log('Timeline clicked:', data);
  });

  useTimelineEvent(timeline, 'on-select-change', (data) => {
    console.log('Selection changed:', data);
  });

  return <TimelineCanvas timeline={timeline} />;
};

React Integration

The component uses custom hooks for timeline management:

  • useTimeline: Manages the timeline instance and its lifecycle

    • Creates and initializes the timeline
    • Handles cleanup on component unmount
    • Provides access to the timeline instance
  • useTimelineEvent: Handles event subscriptions and cleanup

    • Manages event listener lifecycle
    • Automatically cleans up listeners on unmount

The component automatically handles cleanup and destruction of the timeline instance when unmounted.

Event Structure

Events in the timeline follow this structure:

type TimelineEvent = {
  id: string;             // Unique identifier
  from: number;           // Start timestamp
  to?: number;            // End timestamp (optional for point events)
  axisId: string;         // ID of the axis this event belongs to
  trackIndex: number;     // Index in the axis track
  renderer?: AbstractEventRenderer; // Optional custom renderer
  color?: string;         // Optional event color
  selectedColor?: string; // Optional selected state color
};

Direct TypeScript Usage

The Timeline class can be used directly in TypeScript without React. This is useful for integrating with other frameworks or vanilla JavaScript applications:

import { Timeline } from '@gravity-ui/timeline';

const timestamp = Date.now();

// Create a timeline instance
const timeline = new Timeline({
  settings: {
    start: timestamp,
    end: timestamp + 3600000, // 1 hour from now
    axes: [
      {
        id: 'main',
        label: 'Main Axis',
        color: '#000000'
      }
    ],
    events: [
      {
        id: 'event1',
        from: timestamp + 1800000, // 30 minutes from now
        to: timestamp + 2400000,   // 40 minutes from now
        label: 'Sample Event',
        axisId: 'main'
      }
    ],
    markers: [
      {
        id: 'marker1',
        time: timestamp + 1200000, // 20 minutes from now
        label: 'Important Point',
        color: '#ff0000',
        activeColor: '#ff5252',
        hoverColor: '#ff1744'
      }
    ],
    sections: [
      {
        id: 'section1',
        from: timestamp,
        to: timestamp + 1800000, // First 30 minutes
        color: 'rgba(33, 150, 243, 0.2)', // Light blue background
        hoverColor: 'rgba(33, 150, 243, 0.3)'
      }
    ]
  },
  viewConfiguration: {
    // Optional: customize view settings
    zoomLevels: [1, 2, 4, 8, 16],
    hideRuler: false,
    showGrid: true
  }
});

// Initialize with a canvas element
const canvas = document.querySelector('canvas');
if (canvas instanceof HTMLCanvasElement) {
  timeline.init(canvas);
}

// Add event listeners
timeline.on('on-click', (detail) => {
  console.log('Timeline clicked:', detail);
});

timeline.on('on-select-change', (detail) => {
  console.log('Selection changed:', detail);
});

// Clean up when done
timeline.destroy();

The Timeline class provides a rich API for managing the timeline:

  • Event Management:

    // Add event listener
    timeline.on('eventClick', (detail) => {
      console.log('Event clicked:', detail);
    });
    
    // Remove event listener
    const handler = (detail) => console.log(detail);
    timeline.on('eventClick', handler);
    timeline.off('eventClick', handler);
    
    // Emit custom events
    timeline.emit('customEvent', { data: 'custom data' });
  • Timeline Control:

    // Update timeline data
    timeline.api.setEvents([
      {
        id: 'newEvent',
        from: Date.now(),
        to: Date.now() + 3600000,
        label: 'New Event',
        axisId: 'main',
        trackIndex: 0
      }
    ]);
    
    // Update axes
    timeline.api.setAxes([
      {
        id: 'newAxis',
        label: 'New Axis',
        color: '#0000ff'
      }
    ]);
    
    // Update markers
    timeline.api.setMarkers([
      {
        id: 'newMarker',
        time: Date.now(),
        label: 'New Marker',
        color: '#00ff00',
        activeColor: '#4caf50',
        hoverColor: '#2e7d32'
      }
    ]);
    
    // Update sections
    timeline.api.setSections([
      {
        id: 'newSection',
        from: Date.now(),
        to: Date.now() + 1800000,
        color: 'rgba(255, 193, 7, 0.2)', // Light amber background
        hoverColor: 'rgba(255, 193, 7, 0.3)'
      }
    ]);

Live Examples

Explore interactive examples in our Storybook:

Development

Storybook

This project includes Storybook for component development and documentation.

To run Storybook:

npm run storybook

This will start the Storybook development server on port 6006. You can access it at http://localhost:6006.

To build a static version of Storybook for deployment:

npm run build-storybook

License

MIT