A library for rendering interactive timelines from simple Markdown, anywhere. Make time make sense.
Powered by vis.js
- [2020] A year
- [2020-02] A month
- [2020-02-28] A day
- [2020-02-28T12] An hour
- [2020-02-28T12:30] A minute
- [2020-02-28T12:30:09] A second
npm install chronos-timeline-mdimport { ChronosTimeline } from "chronos-timeline-md";<!-- inside <head> -->
<script src="https://unpkg.com/chronos-timeline-md@latest/dist/iife-entry.global.js"></script>import { ChronosTimeline } from "chronos-timeline-md";
const markdownSource = `
- [2020] Event 1
- [2021-06-15] Event 2 | Description
@ [2020~2022] Period 1
* [2021-01-01] Point 1
= [2020-12-31] Marker 1
`;
ChronosTimeline.render(
document.getElementById("timeline-container"),
markdownSource
);import { ChronosTimeline } from "chronos-timeline-md";
const timeline = new ChronosTimeline({
container: document.getElementById("timeline-container"),
});
timeline.render(markdownSource);<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/chronos-timeline-md@latest/dist/iife-entry.global.js"></script>
</head>
<body>
<div id="timeline-container"></div>
<script>
const markdownSource = `
- [2020] Event 1
- [2021-06-15] Event 2 | Description
@ [2020~2022] Period 1
* [2021-01-01] Point 1
= [2020-12-31] Marker 1
`;
ChronosTimeline.render(
document.getElementById("timeline-container"),
markdownSource
);
</script>
</body>
</html>Static Method:
ChronosTimeline.render(container, source, options?)Constructor:
new ChronosTimeline({ container, settings?, callbacks?, cssRootClass? })
// or
new ChronosTimeline(container, settings?)Instance Methods:
render(source: string)- Parse and render markdownon(event: string, handler: Function)- Attach timeline eventsdestroy()- Clean up resources
Static Properties:
ChronosTimeline.version- Library versionChronosTimeline.templates- Built-in templatesChronosTimeline.cheatsheet- Syntax reference
Chronos will exposes a small set of optional callbacks that hosts can provide when constructing a timeline instance. Callbacks are passed either via the callbacks property on ChronosTimeline's constructor object or via CoreParseOptions.callbacks when using the lower-level parse/render functions.
Currently available callbacks:
-
Purpose: Allow the host application to take control of how tooltips are displayed. Chronos calls this for timeline items, custom markers, and UI helper buttons (for example the "Fit all" refit button).
-
When called: Chronos calls this callback with a target DOM element and the formatted tooltip text whenever a tooltip should be shown.
-
Default behaviour: If you don't provide
setTooltip, Chronos falls back to a simple implementation that sets the element'stitleattribute (so native browser tooltips appear). The default is intentionally minimal so the library remains portable across environments. -
Example (basic):
const timeline = new ChronosTimeline({ container: document.getElementById("timeline-container"), settings: { selectedLocale: "en" }, callbacks: { setTooltip: (el, text) => { // Use a custom tooltip library, or set a data attribute // Example using tippy.js: tippy(el, { content: text, placement: "top" }); }, }, });
import {
parseChronos,
renderChronos,
attachChronosStyles,
} from "chronos-timeline-md";
// Parse markdown to timeline data
const result = parseChronos(source, options);
// Render complete timeline
const { timeline, parsed } = renderChronos(container, source, options);
// Inject default styles
attachChronosStyles();Want to add Chronos markdown syntax highlighting to your code editor, IDE, or web application?
Syntax Highlighting Implementation Guide
import { ui } from "chronos-timeline-md";
// Register Chronos language with highlight.js
ui.registerChronosLanguage(hljs);
// Inject CSS styling
ui.injectChronosHighlightCSS();
// Highlight markdown text
const highlighted = ui.highlightChronosText(markdownSource, hljs);For complete syntax documentation, see CHRONOS_SYNTAX_GUIDE.md
# Basic syntax
- [2023] Event
- [2023-06-15] Event with description | Details here
@ [2020~2025] Background period
* [2023-06-15] Point in time
= [2023-01-01] Important marker
# With modifiers
- [2023] #red Colored event
- [2023] {Group} Grouped event
- [2023] #blue {Authors} Combined | Description
# Flags
> ORDERBY start
> DEFAULTVIEW 2020|2025
> NOTODAY
> HEIGHT 400interface CoreParseOptions {
selectedLocale?: string;
roundRanges?: boolean;
settings?: {
align?: "left" | "center" | "right";
clickToUse?: boolean;
useUtc?: boolean;
theme?: {
colorMap?: Record<string, string>;
cssVariables?: Record<string, string>;
};
};
callbacks?: {
setTooltip?: (el: Element, text: string) => void;
};
cssVars?: Record<string, string>;
cssRootClass?: string;
}const timeline = new ChronosTimeline({
container: document.getElementById("timeline"),
cssVars: {
"chronos-accent": "#007acc",
"chronos-bg-primary": "#ffffff",
},
});const timeline = new ChronosTimeline({
container: document.getElementById("timeline-container"),
});
timeline.render(markdownSource);
timeline.on("select", (event) => {
console.log("Selected:", event.items);
});Selection Events:
select- Items are selected/deselecteditemover- Mouse over an itemitemout- Mouse leaves an item
Interaction Events:
click- Mouse click on timelinedoubleClick- Mouse double clickcontextmenu- Right-click context menudrop- Item dropped (drag & drop)
View Events:
rangechange- Visible time range changedrangechanged- Visible time range change completedtimechange- Current time changedtimechanged- Current time change completed
Group Events:
groupDragover- Group drag overgroupDrop- Item dropped on group
Edit Events (if editable):
add- Item addedupdate- Item updatedremove- Item removed
Example Usage:
const timeline = new ChronosTimeline({
container: document.getElementById("timeline-container"),
});
timeline.render(markdownSource);
// Selection
timeline.on("select", (event) => {
console.log("Selected items:", event.items);
});
// Hover effects
timeline.on("itemover", (event) => {
console.log("Hovering over item:", event.item);
});
// View changes
timeline.on("rangechanged", (event) => {
console.log("New time range:", event.start, "to", event.end);
});
// Click handling
timeline.on("click", (event) => {
console.log("Clicked at:", event.time);
console.log("Items at click:", event.item);
});// Use built-in templates
timeline.render(ChronosTimeline.templates.basic);
timeline.render(ChronosTimeline.templates.advanced);:root {
--chronos-bg-primary: var(--background-primary);
--chronos-text-normal: var(--text-normal);
--chronos-accent: var(--interactive-accent);
--chronos-color-red: #ff4444;
--chronos-color-blue: #0066cc;
}function syncTheme() {
const root = document.documentElement;
root.style.setProperty("--chronos-bg-primary", hostThemeColor);
}// Parser utilities
export * as parser from "chronos-timeline-md/parser";
// UI components and styles
export * as ui from "chronos-timeline-md/ui";
// Common utilities and types
export * as utils from "chronos-timeline-md/utils";# Install dependencies
npm install
# Build the package
npm run build
# Development mode with watch
npm run dev
# Run local interactive playground
npm run playground
# Clean build artifacts
npm run cleanIf modifying the underlying chronos-timeline-md locally and want live changes refelcted:
# expose local chronos-timeline-md
cd ~/path/to/local/chronos-timeline-md
npm install
npm link
npm run dev # start watch mode# consume library in plugin
cd ~/path/to/local/obsidian-plugin
npm install
npm link chronos-timeline-md
npm run devTo check which module (npm or local sym link) your plugin is currently using:
readlink node_modules/chronos-timeline-md
# or
npm ls chronos-timeline-md --depth=0
# if linked, npm often shows an arrow or a path. If installed from the registry it shows the version (e.g., chronos-timeline-md@1.0.8)
Unlinking
npm unlink chronos-timeline-md
# then reinstall from registry
npm install(Note to self :P)
# Update version in package.json
npm version patch|minor|major
# Publish to npm
npm publishThis library requires a modern browser environment with ES2020 support. It includes vis-timeline as a bundled dependency.
ISC
