circalify
v0.1.8
Published
JavaScript library for creating circular timeline visualizations for annual and cyclical data
Maintainers
Readme
Circalify

A flexible, zero-dependency JavaScript library for creating circular timeline visualizations.
Perfect for annual planning, project timelines, and cyclical data. Built with pure JavaScript and SVG.
🌐 Website | 📺 Live Demo | 📦 npm | ⭐ GitHub
Why Circular Timelines?
Circular layouts excel at showing:
- Cyclical patterns - Annual processes, seasonal data
- Year-at-a-glance - See the entire year in one view
- Multiple layers - Compare different event types side-by-side
- Space efficiency - Fit more information in less screen space
Traditional linear timelines are better for sequences and chronology. Circular timelines are better for cycles and patterns.
Installation
npm install circalifyQuick Start
Minimal Example (3 lines)
import CircularTimeline from 'circalify';
const timeline = new CircularTimeline('#timeline', {
startYear: 2025,
rings: [{ type: 'calendar' }]
});With Events
import CircularTimeline from 'circalify';
const timeline = new CircularTimeline('#timeline', {
startYear: 2025,
rings: [
{ type: 'calendar' },
{ type: 'data', name: 'Events' }
]
});
timeline.setData([
{ label: 'Launch', startDate: '2025-03-15', endDate: '2025-03-15' }
], 'Events');Using CDN (No Build Step)
<!DOCTYPE html>
<html>
<head>
<style>
#timeline { width: 100%; height: 600px; }
</style>
</head>
<body>
<div id="timeline"></div>
<script type="module">
import CircularTimeline from 'https://unpkg.com/circalify@latest/src/index.js';
const timeline = new CircularTimeline('#timeline', {
startYear: 2025,
rings: [
{ type: 'calendar', calendarType: 'month-names' },
{ type: 'data', name: 'Events' }
]
});
timeline.setData([
{ label: 'Project Launch', startDate: '2025-03-15', endDate: '2025-03-15' }
], 'Events');
</script>
</body>
</html>What You Get
Circalify creates SVG-based circular timelines with:
- Flexible rings - Calendar, headers, and data layers
- Full styling control - Colors, fonts, sizes
- Smart date positioning - Automatic geometry calculations
- Interactive - Hover effects and click handlers
- Zero dependencies - Pure JavaScript + SVG
- Tiny footprint - Lightweight and fast
Configuration
General Settings
{
startYear: 2025, // Required: Year to display
startMonth: 0, // Optional: Starting month (0-11, default: 0)
numberOfMonths: 12, // Optional: How many months to show (default: 12)
sameRingHeight: false, // Optional: Equal ring heights (default: false)
backgroundColor: '#fff', // Optional: Background color (default: '#ffffff')
interactive: true // Optional: Enable hover/click (default: true)
}Ring Types
Calendar Ring
Displays time divisions (months, weeks, days, quarters).
{
type: 'calendar',
calendarType: 'month-names', // Options: 'month-names', 'weeks', 'days', 'quarters'
active: true,
color: '#f0f0f0',
height: 18,
fontSize: 11,
fontColor: '#333',
separator: { show: true, color: '#ccc', width: 1 }
}Header Ring
Provides labels and categorical divisions.
{
type: 'header',
headerText: 'Quarter Goals',
active: true,
cells: 4, // Number of divisions
color: '#ffffff',
height: 12,
fontSize: 9,
fontColor: '#666'
}Data Ring
Shows events positioned by their dates.
{
type: 'data',
name: 'Events', // Ring identifier for setData()
active: true,
color: '#4ECDC4',
unit: 'day', // Options: 'day', 'week', 'month', 'quarter'
height: 20,
fontSize: 10,
fontColor: '#fff'
}Event Data Format
Events must include date information in ISO format (YYYY-MM-DD):
{
label: 'Event Name', // Required: Display text
startDate: '2025-03-15', // Required: ISO date string
endDate: '2025-03-15', // Required: ISO date string
color: '#FF6B6B', // Optional: Override ring color
description: 'Details...' // Optional: Shown in detail panel
}API Reference
Constructor
new CircularTimeline(container, config, callbacks)Parameters:
container: CSS selector string or DOM elementconfig: Configuration object (see Configuration section)callbacks: Optional object with interaction handlers
Callbacks:
{
onSegmentClick: (event) => { /* ... */ },
onSegmentHover: (event) => { /* ... */ },
onSegmentLeave: (event) => { /* ... */ }
}Methods
setData(events, ringName)
Add or update events for a specific data ring.
timeline.setData([
{ label: 'Event 1', startDate: '2025-01-15', endDate: '2025-01-15' },
{ label: 'Event 2', startDate: '2025-02-01', endDate: '2025-02-28' }
], 'Events');getRings()
Get all rings in the visualization.
const rings = timeline.getRings();destroy()
Clean up and remove the visualization.
timeline.destroy();Examples
Check out the live demo on CodePen or browse the examples directory.
To run examples locally:
npx serve .
# Then open http://localhost:3000/examples/demo.htmlWhen to Use This
Great for:
- Annual planning and goal tracking
- Project timelines that repeat yearly
- Seasonal business processes
- Multi-year comparisons
- Educational calendars
Not ideal for:
- Long linear sequences (use traditional timelines)
- Non-cyclical data
- Very short time periods (days/weeks only)
Browser Support
Works in all modern browsers that support ES6 modules and SVG:
- Chrome/Edge 61+
- Firefox 60+
- Safari 11+
- Opera 48+
No build step required for development.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Issues and pull requests welcome! Visit the GitHub repository to contribute.
