Recipe: a chronology
Three thousand years in three regions, with eras behind the events. It opens on antiquity; zoom out (ctrl + wheel, or -) for the whole range, in and the axis steps from centuries to decades to years, without a date library.
Live example: A chronology across three thousand years
Loading…
Run “A chronology across three thousand years” on your own machine
Make an empty folder and put this example’s two files in it:
index.html— the page the code runs in, its markup and styles:<div id="timeline" style="height: 320px"></div>main.js— the code, as it is in the editor now, your edits included:In a terminal in that folder, install the library and Vite (it lets the browser follow the
imports), then start it:npm init -y npm install @temporeum/timeline-element @temporeum/timeline-core npm install --save-dev vite npx viteOpen the address it prints,
http://localhost:5173/.
How it is made
- Regions are lanes, events are items; an event with an
endis a span, one without is an instant. - Years before 1 and before 100. Times are epoch milliseconds, which reach far enough either way.
Date.UTC(50, 0, 1)means 1950, so the recipe sets the year explicitly:
function year(y) {
const date = new Date(0);
date.setUTCFullYear(y, 0, 1);
return date.getTime();
}From the running example example/recipe-chronology
- Known to the year.
granularity: "year"makes an instant cover its whole year, so two events in one year do not overlap, and the accessible name says the year rather than a midnight. - Eras are decorations: named stretches behind the items, which never take part in the packing.
- Limits keep the view between 1500 BC and AD 2100, so a reader cannot get lost in an empty millennium.
What to know
- Labels give way. A label is drawn where it fits — on the item, or after it until the next item in its row — and shortened where it does not: "Rome founded (traditional date)" shows as much as there is room for before "Classical Athens", which is shortened itself; zoom in and they read whole. Past a thousand items in a viewport's width only whole labels are drawn (
labelOverflow). The full text stays in the item's tooltip and accessible name, andtimeline.result.labels.droppedlists what is given up, with the reason. - The axis says BC and AD. The engine's default writes astronomical years —
-0500is 501 BC,0000is 1 BC — because a default that went through the platform's locale data would draw differently on two machines.formatTickwrites any format; this one keeps the default below a year:
const YEARS = new Set(["year", "decade", "century", "millennium"]);
function formatTick(tick, timeZone) {
if (!YEARS.has(tick.granularity)) return defaultTickLabel(tick, timeZone);
// A year label is the whole date: no context label at the start of the axis.
if (tick.context) return "";
const y = new Date(tick.time).getUTCFullYear();
return y <= 0 ? `${String(1 - y)} BC` : `AD ${String(y)}`;
}From the running example example/recipe-chronology
orientation: "vertical"would run time down the page on the same code path; at this width a chronology reads better across.