GitHub repository

BumpChart

Ranking-over-stages chart that shows who led and who overtook whom.

A token-driven bump chart for tracking finishing rank across an ordered sequence of stages (e.g. the four games of one Friday). Each series is a competitor; its 1-based `ranks` are plotted with rank 1 drawn at the top, connected by lines so crossings reveal overtakes. The x-axis uses a `scalePoint` over `stages`, the y-axis runs integer rank ticks top-down, and `showLabels` puts each series name at its last node (direct labelling). Every node is keyboard-focusable with an accessible tooltip, series absent from a stage (non-finite rank) are skipped while the line still connects present nodes, and empty input shows an em-dash placeholder.

Demo

live · storybook Open in Storybook

Demo loads from https://dssoca-storybook.vercel.app/. Run pnpm storybook for it to render locally.

Usage

svelte
<script>
  import { BumpChart } from 'dssoca';

  const stages = ['G1', 'G2', 'G3', 'G4'];
  const series = [
    { label: 'Ana', ranks: [1, 2, 1, 1] },
    { label: 'Bruno', ranks: [2, 1, 3, 2] },
    { label: 'Caio', ranks: [3, 4, 2, 3] },
  ];
</script>

<BumpChart {series} {stages} />

HTML

CSS only — static markup The exact markup the component renders, generated at build time. Use it with dssoca/vanilla.css — see Plain HTML & CSS.

html
<div class="ss-bump" role="group" aria-label="Bump chart with 2 series over 3 stages (q1, q2, q3).">
  <div class="plot">
    <svg class="canvas" viewBox="0 0 480 280" width="480" height="280" preserveAspectRatio="xMidYMid meet" role="presentation">
      <g transform="translate(32,12)">
        <line class="grid" x1="0" x2="392" y1="0" y2="0">
      </line>
      <text class="tick y" x="-6" y="0" dy="0.32em" text-anchor="end">1</text>
      <line class="grid" x1="0" x2="392" y1="240" y2="240">
    </line>
    <text class="tick y" x="-6" y="240" dy="0.32em" text-anchor="end">2</text>
    <line class="axis" x1="0" x2="0" y1="0" y2="240">
  </line>
  <line class="axis" x1="0" x2="392" y1="240" y2="240">
</line>
<text class="tick x" x="65.33333333333334" y="256" text-anchor="middle">q1</text>
<text class="tick x" x="196" y="256" text-anchor="middle">q2</text>
<text class="tick x" x="326.66666666666663" y="256" text-anchor="middle">q3</text>
<path class="line" d="M65.333,0L196,240L326.667,0" style="stroke:var(--ss-accent)">
</path>
<path class="line" d="M65.333,240L196,0L326.667,240" style="stroke:var(--ss-blue)">
</path>
<circle class="node" cx="65.33333333333334" cy="0" r="5" style="fill:var(--ss-accent)" tabindex="0" role="button" aria-label="api: q1, rank 1">
</circle>
<circle class="node" cx="196" cy="240" r="5" style="fill:var(--ss-accent)" tabindex="0" role="button" aria-label="api: q2, rank 2">
</circle>
<circle class="node" cx="326.66666666666663" cy="0" r="5" style="fill:var(--ss-accent)" tabindex="0" role="button" aria-label="api: q3, rank 1">
</circle>
<circle class="node" cx="65.33333333333334" cy="240" r="5" style="fill:var(--ss-blue)" tabindex="0" role="button" aria-label="db: q1, rank 2">
</circle>
<circle class="node" cx="196" cy="0" r="5" style="fill:var(--ss-blue)" tabindex="0" role="button" aria-label="db: q2, rank 1">
</circle>
<circle class="node" cx="326.66666666666663" cy="240" r="5" style="fill:var(--ss-blue)" tabindex="0" role="button" aria-label="db: q3, rank 2">
</circle>
<text class="series-label" x="334.66666666666663" y="0" dy="0.32em" style="fill:var(--ss-accent)">api</text>
<text class="series-label" x="334.66666666666663" y="240" dy="0.32em" style="fill:var(--ss-blue)">db</text>
</g>
</svg>
</div>
</div>

Charts are rendered geometry: copy the SVG as-is. Hover tooltips are not wired by vanilla.js.

Props

PropTypeDefaultDescription
seriesBumpSeries[]—Required. Each series has a `label`, 1-based `ranks` (length must match `stages`) and optional `color`.
stagesstring[]—Required. Ordered x-axis category labels (e.g. ["G1","G2","G3","G4"]).
showLabelsbooleantrueDraw each series label at its last node (direct labelling).
heightnumber280Intrinsic drawing height in px.
widthnumber480Intrinsic drawing width in px.
fluidbooleanfalseStretch to the container width via the viewBox.
tooltipbooleantrueReveal a tooltip on hover/focus of a node. Each node is keyboard-focusable.
summarystring—Screen-reader summary + accessible name; auto-generated when absent.
size'sm' | 'md' | 'lg'—Per-instance size override; inherits the ancestor `data-size-variant` when unset.
↑↓ navigate · ↵ open · esc close

Keyboard shortcuts

No shortcuts registered

Shortcuts added through the dssoca registry will show up here.

Single-key shortcuts