Temporeum Timelinev1.0.2

Responsive

A responsive timeline is not the same timeline smaller — it is a different projection. Make the frame below narrow and the timeline turns vertical: same items, same code path, a different axis.

Live example: One timeline, two widths

Loading…

Run “One timeline, two widths” on your own machine
  1. 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 class="toolbar" style="display: flex; gap: 8px; align-items: center; padding: 6px 10px; border-bottom: 1px solid #d5d9de">
      <button type="button" data-width="100%">Full width</button>
      <button type="button" data-width="360px">Phone width</button>
      <span id="orientation" aria-live="polite"></span>
    </div>
    <div id="box" style="width: 100%; margin: 0 auto; border-inline: 1px dashed #8a929c">
      <div id="timeline" style="height: 460px"></div>
    </div>
    

    main.js — the code, as it is in the editor now, your edits included:

  2. 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
    npm install --save-dev vite
    npx vite
  3. Open the address it prints, http://localhost:5173/.

const timeline = createTimeline(document.querySelector("#timeline"), {
  items,
  ariaLabel: "Research sprint",
  // Both follow the container, not the window: horizontal from 640 px, vertical below.
  orientation: "auto",
  density: "auto",
});

From the running example example/responsive

What decides

  • Orientation is horizontal from 640 px of container width, vertical below — with a 24 px band on the way back, because the scrollbar an orientation change brings would otherwise flip it forever. breakpoint moves the threshold; "horizontal" and "vertical" pin it.
  • Density (comfortable, compact, dense) is the denser of two answers: the coarsest level at which every lane fits across, and the level the median item's drawn length allows along time.
  • Targets come from the pointer. A hit grows each item by 4 px for a mouse or a pen and 12 px for a finger, and at dense up to the 24 px of WCAG 2.2. An exact hit always wins, the nearest item wins in the slop, and a slop hit never starts a resize.

Each decision is a pure function of a measurement, so a server render, a test and a browser get the same answer. The instance reports a change with orientationChanged and densityChanged, and its snapshot carries both:

timeline.subscribe(() => {
  const { orientation, density } = timeline.getSnapshot();
  // …
});

From the running example example/responsive

Gestures

One finger pans, two pinch, a double tap zooms in, a two-finger tap zooms out, and ctrl + wheel zooms where the cursor is — which is also what a trackpad pinch sends. A plain wheel scrolls the lanes when they have room to scroll and pans time when they do not; shift + wheel always pans time.

A pointer holds an instant, not a delta: every move re-solves the view from what each finger grabbed, so the content stays under the hand, and two fingers pin two instants. Measured over 2 000 generated gestures, the worst anchor error is 2.3e-10 px.

A timeline inside a scrolling article may want to give the page its wheel and its vertical swipe back: touchAction: "cooperative" (or <temporeum-timeline touch-action="cooperative">). A vertical swipe then scrolls the page and a horizontal one pans time; a plain wheel scrolls the page unless the lanes have room to scroll, and ctrl + wheel and shift + wheel stay with the timeline, because they are explicit. The default, "own", claims every gesture — right for a timeline that is the page.

Both are measured in Safari on iOS, in Xcode's iOS Simulator rather than on a device: with the default a drag on the timeline leaves the page where it was, even past the timeline's edge, and with "cooperative" a vertical swipe scrolls the page and the timeline lets go. A long press that picks an item up is not taken over by iOS. Whether a two-finger pinch zooms the timeline rather than the page has been measured in WebKit's emulation only.