Skip to content

Sankey

Stroom

"Waar gaat het allemaal naartoe?" Een Sankey-diagram brengt de stroom door een systeem in kaart: knopen worden ingedeeld in kolommen, en de dikte van elke band is de stroomwaarde. Het is het juiste beeld voor handel tussen exporteurs en markten, budget van bronnen naar bestemmingen, verkeer van verwijzers naar pagina's - overal waar een hoeveelheid onderweg opsplitst en weer samenkomt.

Example
canvas · responsive
Ga dieper: Insights-gids·DevTools-gids

De lay-out wordt berekend met d3-sankey: knopen worden op basis van de grafiektopologie aan kolommen toegewezen, verticaal gepakt, en verbindingen worden getekend als vloeiende horizontale banden. Hover over een knoop of een stroom voor de bijbehorende cijfers.

Wanneer kies je deze

  • Stromen met structuur. Handel tussen exporteurs en markten, budget van bronnen naar bestemmingen, gebruikers door een trechter: waar hoeveelheden vandaan komen, waar ze naartoe gaan, wat opsplitst en weer samenkomt.
  • Het dominante pad en de lekken vinden. Banddikte is de waarde, dus de dikke routes en de dunne verliezen lees je meteen af - het auditoverzicht van elk systeem.
  • Slechts één fase? Als er niets doorheen stroomt, rangschikt een staafdiagram bronnen overzichtelijker dan een Sankey met twee kolommen.

Veel data op WebGPU Experimenteel

De optionele renderer="webgpu" van deze grafiek tekent de marks op de GPU, terwijl assen/labels/tooltips op SVG blijven; capability-gated met automatische terugval naar canvas.

⚗️ Experimental - not yet stable. WebGPU rendering is an opt-in preview. It needs a WebGPU-capable browser (Chrome / Edge, or Safari 26+); everywhere else it falls back to canvas automatically. Axes, labels and tooltips stay on the SVG layer - only the data marks are painted on the GPU.
Heavy-data demo · ~150 links… detecting

Speel door de jaren heen

Geef elke link een date en zet timeline aan: de momentopname van een jaar bestaat uit de links die die datum delen - knopen worden gedeeld over de jaren heen, alleen de stromen komen en gaan - en de banddikte glijdt tussen jaren. Standaard uit - zonder opt-in verandert er niets. Dit is interactief jaar-voor-jaar stappen, niet de eenmalige intro verderop.

Druk op de afspeelknop onder de grafiek: de data stapt door de jaren, één momentopname per keer. Sleep de scrubber om naar een jaar te springen.

tsx
const ref = useRef<SankeyChartHandle>(null);

<SankeyChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / stepForward()
vue
<SankeyChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" />
svelte
<div use:sankeyChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>
ts
applySankeyChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });
html
<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  const el = document.getElementById("c");
  el.timeline = { speedMs: 1000, loop: true };
  // el.getTimeline() -> play() / pause() / seek(year)
</script>
  • speedMs bepaalt het tempo, loop begint opnieuw, autoplay: true start bij mounten, showControl: false verbergt de ingebouwde balk.
  • Waarden glijden standaard tussen periodes (interpolate); stem de beweging af met tweenMs en easing, of zet interpolate: false voor harde overgangen. Met reduced motion is de overgang altijd hard.
  • De headless controller is altijd beschikbaar: chart.timeline() biedt play() / pause() / toggle() / seek(period) / stepForward() / stepBack(), plus onStep en formatPeriod in de config voor eigen UI.
  • Links zonder date blijven in elke periode zichtbaar.
  • timeline wint het van progressiveDraw als beide zijn ingesteld - de onthulanimatie verderop blijft uit zolang de timeline de regie heeft.

Onthulanimatie

De grafiek tekent zichzelf van links naar rechts bij het mounten, waarbij de elementen na elkaar verschijnen voordat ze op hun plek vallen. Standaard uit - een grafiek kiest ervoor met de progressiveDraw-prop.

Elke lijn groeit van het eerste naar het laatste jaar; het label volgt de punt en komt tot stilstand bij het lijneinde. Met reduced motion ingeschakeld verschijnt de grafiek meteen volledig getekend.

progressiveDraw: true gebruikt de standaardinstellingen (1200 ms, easeInOutCubic). Een configuratieobject verfijnt het gedrag:

tsx
const ref = useRef<SankeyChartHandle>(null);

<SankeyChart
  ref={ref}
  {...props}
  progressiveDraw={{ durationMs: 2000 }}
/>;
// ref.current?.replay() speelt de animatie opnieuw af
vue
<SankeyChart :options="{ ...props, progressiveDraw: { durationMs: 2000 } }" />
svelte
<div use:sankeyChart={{ ...props, progressiveDraw: { durationMs: 2000 } }}></div>
ts
applySankeyChartProps(this.c.nativeElement, {
  ...props,
  progressiveDraw: { durationMs: 2000 },
});
html
<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  const el = document.getElementById("c");
  el.progressiveDraw = { durationMs: 2000 };
  // el.replay() speelt de animatie opnieuw af
</script>
  • durationMs en easing ("linear", "easeOutQuad", "easeInOutCubic", of een eigen (t) => t-functie) bepalen het tempo.
  • autoplay: false rendert de grafiek volledig getekend; roep replay() aan (React-ref-handle, webcomponent-methode of de core-instantie) om de animatie op aanvraag te starten. replayOnUpdate: true herhaalt de animatie bij elke datawijziging.
  • Respecteert prefers-reduced-motion: de grafiek verschijnt dan meteen volledig getekend.
  • Onthulanimatie is een eenmalige animatie bij mounten; speel door de jaren hierboven stapt in plaats daarvan jaar voor jaar door de data.

Gebruik

tsx
import { SankeyChart } from "@michi-vz/react";

export default () => <SankeyChart {...props} />; // props = the chart options
vue
<script setup>
import { SankeyChart } from "@michi-vz/vue";
</script>

<template>
  <SankeyChart :options="props" />
</template>
svelte
<script>
  import { sankeyChart } from "@michi-vz/svelte";
</script>

<div use:sankeyChart={props}></div>
ts
// main.ts - register the elements once
import "@michi-vz/angular";
import { applySankeyChartProps } from "@michi-vz/angular";

// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-sankey-chart #c></michi-vz-sankey-chart>
applySankeyChartProps(this.c.nativeElement, props);
html
<script type="module" src="https://cdn.jsdelivr.net/npm/@michi-vz/wc/dist/michi-vz-wc.bundle.js"></script>

<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  Object.assign(document.getElementById("c"), props); // nodes, links, …
</script>
ts
import { mountSankeyChart } from "@michi-vz/core";

const chart = mountSankeyChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();

Datavorm

In tegenstelling tot de andere grafieken neemt een Sankey twee arrays aan: nodes (elk met een unieke id, een optionele label en color) en links (sourcetarget op basis van id, met een value).

ts
const props = {
  linkColorMode: "source", // colour links by their source (or "target")
  nodes: [
    { id: "France" }, { id: "Germany" },
    { id: "EU" }, { id: "Asia" },
  ],
  links: [
    { source: "France", target: "EU", value: 40 },
    { source: "France", target: "Asia", value: 22 },
    { source: "Germany", target: "EU", value: 55 },
    { source: "Germany", target: "Asia", value: 35 },
  ],
};

Een link naar een onbekende knoop-id (of een knoop in disabledItems) wordt met een datawarning weggelaten; het uitschakelen van een knoop laat ook de bijbehorende links vervallen.

Lay-outinstellingen

nodeWidth bepaalt de breedte van het knooprechthoek, nodePadding de verticale tussenruimte tussen knopen in een kolom, en linkOpacity hoe doorschijnend de banden zijn. linkColorMode kleurt elke band naar zijn source-knoop (standaard) of target-knoop. De a11y-spiegel en getContext() presenteren de links als een leesbare "Bron → Doel: waarde"-tabel.

Afgeronde knopen. nodeRadius (px, standaard 2) rondt de hoeken van het knooprechthoek af - verhoog de waarde voor het pilvormige uiterlijk, of zet hem op 0 voor rechte hoeken. Deze wordt begrensd tot de helft van de kortste zijde van de knoop, zodat een dunne knoop nooit vervormt.

Afgeronde stromen. De stromen worden getekend als gevulde linten; linkRadius (px, standaard 2) rondt hun hoeken af waar ze de knopen raken, voor een zachtere verbinding (begrensd tot de helft van de banddikte; 0 = scherp). linkColorMode kleurt elke stroom naar zijn source- of target-knoop, op linkOpacity:

ts
const props = { nodeRadius: 4, linkRadius: 4, /* …nodes, links */ };

API

Props zijn getypeerd als SankeyChartProps in @michi-vz/core. Gedeeld door alle grafieken: width, height, margin, colors / colorsMapping, renderer ("svg", "canvas", of experimenteel "webgpu"), highlightItems, disabledItems, en de on*-callbacks. onChartDataProcessed / getContext() retourneren de renderer-agnostische ChartContext. Volledige referentie: Sankey API.