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.
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.
Nadruk bij hover
Hover toont altijd een tooltip. Met hoverHighlight: true zet de grafiek ook naar voren waar je naar wijst: hover over een knoop en die knoop, elke stroom die erin of eruit gaat en de knopen aan de andere uiteinden blijven op volle sterkte terwijl de rest vervaagt; hover over een stroom en alleen die stroom en zijn twee eindknopen blijven opgelicht. Standaard uit.
<SankeyChart {...props} hoverHighlight /><SankeyChart :options="{ ...props, hoverHighlight: true }" /><div use:sankeyChart={{ ...props, hoverHighlight: true }}></div>applySankeyChartProps(this.c.nativeElement, { ...props, hoverHighlight: true });<michi-vz-sankey-chart hover-highlight></michi-vz-sankey-chart>- De nadruk wordt ter plekke toegepast: svg past de dekking aan van de markeringen die al getekend zijn, canvas en webgpu tekenen opnieuw. Hoveren rendert de grafiek nooit opnieuw, dus je hoeft
onHighlightItemniet terug te voeren inhighlightItemsvoor dit effect.onHighlightItemvuurt nog steeds zoals voorheen, voor je eigen UI. - Het dimt tot dezelfde niveaus als
highlightItems(stromen op een kwart vanlinkOpacity, knopen op 0,25). Tijdens het hoveren wint het vanhighlightItems; wie wegbeweegt krijgt dehighlightItems-toestand terug. - Klik om de tooltip vast te zetten; de nadruk blijft erbij tot de tooltip wordt losgemaakt (klik op de tooltip, of ergens buiten de grafiek).
- Op de svg-renderer volgt het vervagen
enableTransitions; canvas en webgpu schakelen meteen om.
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.
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.
const ref = useRef<SankeyChartHandle>(null);
<SankeyChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / seekIndex(i) / stepForward()<SankeyChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" /><div use:sankeyChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>applySankeyChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });<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) / seekIndex(i)
</script>speedMsbepaalt het tempo,loopbegint opnieuw,autoplay: truestart bij mounten,showControl: falseverbergt de ingebouwde balk.- Waarden glijden standaard tussen periodes (
interpolate); stem de beweging af mettweenMseneasing, of zetinterpolate: falsevoor harde overgangen. Met reduced motion is de overgang altijd hard. - De headless controller is altijd beschikbaar:
chart.timeline()biedtplay() / pause() / toggle() / seek(period) / seekIndex(i) / stepForward() / stepBack(), plusonStepenformatPeriodin de config voor eigen UI. seek(period)zoekt eerst de periode en vergelijkt als tekst, dusseek(2021)enseek("2021")komen allebei op 2021 uit, of je datums nu getallen of strings zijn. Een getal telt alleen als positie (0 = de eerste) als geen periode past, en een string die nergens bij past doet niets.seekIndex(i)gaat altijd op positie, net als de ingebouwde scrubber.- Links zonder
dateblijven in elke periode zichtbaar. timelinewint het vanprogressiveDrawals 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:
const ref = useRef<SankeyChartHandle>(null);
<SankeyChart
ref={ref}
{...props}
progressiveDraw={{ durationMs: 2000 }}
/>;
// ref.current?.replay() speelt de animatie opnieuw af<SankeyChart :options="{ ...props, progressiveDraw: { durationMs: 2000 } }" /><div use:sankeyChart={{ ...props, progressiveDraw: { durationMs: 2000 } }}></div>applySankeyChartProps(this.c.nativeElement, {
...props,
progressiveDraw: { durationMs: 2000 },
});<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>durationMseneasing("linear", "easeOutQuad", "easeInOutCubic", of een eigen(t) => t-functie) bepalen het tempo.autoplay: falserendert de grafiek volledig getekend; roepreplay()aan (React-ref-handle, webcomponent-methode of de core-instantie) om de animatie op aanvraag te starten.replayOnUpdate: trueherhaalt 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
import { SankeyChart } from "@michi-vz/react";
export default () => <SankeyChart {...props} />; // props = the chart options<script setup>
import { SankeyChart } from "@michi-vz/vue";
</script>
<template>
<SankeyChart :options="props" />
</template><script>
import { sankeyChart } from "@michi-vz/svelte";
</script>
<div use:sankeyChart={props}></div>// 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);<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>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 (source → target op basis van id, met een value).
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:
const props = { nodeRadius: 4, linkRadius: 4, /* …nodes, links */ };Volgorde van knopen. Standaard ordent d3-sankey de knopen in een kolom om kruisingen te beperken. nodeSort: "input" houdt de volgorde van je nodes-array aan (en de volgorde van links voor de banden die een knoop verlaten), zodat een knoop "Rest van de wereld" of "Overige" blijft staan waar je hem hebt gezet, meestal onderaan.
Dunne stromen. Een straaltje naast een grote stroom kan een band van één pixel zijn, onmogelijk te hoveren. minLinkValue (in waarde-eenheden) legt zulke links uit alsof ze minstens die waarde hadden; alleen de geometrie verandert, de tooltip, de context en de totalen houden de echte waarden. Kies hem uit je data, bijvoorbeeld 15% van de grootste link.
Klikken. onNodeClick(node, event) en onLinkClick(link, event) vuren bij een klik op een knoop of een stroom, in svg en via de canvas-hittest, met dezelfde context die de tooltip-formatter krijgt. De klik pint de tooltip nog steeds; gebruik de callbacks om vanaf de markering zelf te navigeren of te selecteren.
const props = { nodeSort: "input", minLinkValue: 0.15 * maxLinkValue, onNodeClick: (n) => go(n.id) };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.
