Skip to content

Vlakdiagram ​

Samenstelling

Het totaal groeit, maar welk deel is daarvan de drijvende kracht? Stapel je categorieën en bekijk hoe het aandeel van elk ervan in het geheel in de tijd groeit of krimpt, zodat een stijgend totaal en een verschuivende mix tegelijk hun verhaal vertellen.

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

De grafiek hierboven gebruikt in elk framework dezelfde engine - alleen de integratiecode hieronder verschilt.

Wanneer kies je deze ​

  • Samenstelling in de tijd, wanneer het totaal ook telt. De gestapelde banden tonen het aandeel van elke categorie terwijl de bovenrand de som traceert - een stijgend totaal en een verschuivende mix in één beeld.
  • "De mix verandert"-verhalen. Een segment dat dunner wordt terwijl het totaal groeit, is een boodschap die geen spreadsheet zo snel overbrengt - ideaal voor overzichten van omzet per product of verkeer per kanaal.
  • Wisselen de rangordes, wissel dan van grafiek. Als het verhaal is wie wie inhaalde, maakt het lintdiagram die wissels expliciet; voor één enkel moment in de tijd volstaat een cirkeldiagram.
  • Aandelen, percentages of indices die niet optellen. Houd de vlakken, maar laat ze overlappen in plaats van te stapelen: stacked: false, hieronder uitgelegd.

Overlappende vlakken ​

Stapelen heeft alleen zin als de reeksen samen een betekenisvol geheel vormen. Aandelen, percentages en indices doen dat niet: een huishouden kan een laptop en een smartphone hebben, dus de bezitsaandelen tellen op tot boven de 100% en een gestapelde bovenrand zou een totaal tekenen dat niemand kan lezen. Met stacked: false loopt elk vlak in plaats daarvan van nul tot zijn eigen waarde, als doorschijnende vulling met een lijn langs de bovenrand.

Example
canvas · responsive
Ga dieper: Insights-gids·DevTools-gids
tsx
<AreaChart {...props} stacked={false} />
vue
<AreaChart :options="{ ...props, stacked: false }" />
svelte
<div use:areaChart={{ ...props, stacked: false }}></div>
ts
applyAreaChartProps(this.c.nativeElement, { ...props, stacked: false });
html
<michi-vz-area-chart id="c"></michi-vz-area-chart>
<script>
  // een HTML-attribuut kan stapelen alleen aanzetten: gebruik de property om het uit te zetten
  document.getElementById("c").stacked = false;
</script>
  • De y-as loopt tot de grootste afzonderlijke waarde (afgerond op een mooie tick), niet tot de som van een rij, en heeft geen ondergrens van 100, zodat aandelen van slechts 0,9 hun hoogte houden. Een expliciete yAxisDomain of forcePercentageScale wint nog steeds.
  • Grotere vlakken worden eerst getekend, zodat de kleinere er zichtbaar bovenop liggen. De volgorde van de legenda en de kleuren veranderen niet.
  • Elk vlak bedekt de onderkant van de grafiek, dus hover kiest de reeks waarvan de bovenrand het dichtst bij de aanwijzer ligt.
  • De bovenlijn krijgt de kleur van het vlak, ook een kleur die je CSS op .area[data-label-safe] zet, in alle drie de renderers.
  • stackOffset: "expand" normaliseert een stapel en heeft hier dus niets te doen: het wordt genegeerd, met een datawaarschuwing ignored-option.

Zware datasets op WebGPU Experimenteel ​

AreaChart heeft een optionele renderer="webgpu" die de gestapelde banden op de GPU tekent, terwijl assen, labels en tooltips op de SVG-laag blijven. Dit is capability-gated: in een browser zonder WebGPU schakelt het automatisch terug 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 · ~7,500 points… detecting

Doorlopende tijdlijn & ontbrekende-data-ticks ​

De x-as behoudt altijd de eerste en laatste periode en kantelt/verdunt overvolle labels tot ~5. Schakel fillPeriodTicks in om voor elke maand in het bereik een tick te tekenen; maanden zonder data worden vervaagd weergegeven met een "geen data"-tooltip bij hover. Schakel het in of uit:

Toggle it on: the empty months appear as faded ticks. Hover one to see its "no data" tooltip. First and last periods are always kept, either way.

Pas dit aan via noDataTickTooltip(epochMs) (tooltiptekst) en noDataTickColor (of de CSS-variabele --michi-vz-tick-nodata).

tsx
<AreaChart
  {...props}
  xAxisDataType="date_monthly"
  fillPeriodTicks
  noDataTickTooltip={() => "No data reported for this month"}
  noDataTickColor="#c0392b"
/>
vue
<AreaChart :options="{ ...props, fillPeriodTicks: true, noDataTickTooltip: () => 'No data' }" />
svelte
<div use:areaChart={{ ...props, fillPeriodTicks: true, noDataTickTooltip: () => 'No data' }}></div>
ts
applyAreaChartProps(this.c.nativeElement, {
  ...props,
  fillPeriodTicks: true,
  noDataTickTooltip: () => "No data",
});
html
<michi-vz-area-chart id="c" fill-period-ticks no-data-tick-color="#c0392b"></michi-vz-area-chart>
<script>
  document.getElementById("c").noDataTickTooltip = () => "No data reported";
</script>

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<AreaChartHandle>(null);

<AreaChart
  ref={ref}
  {...props}
  progressiveDraw={{ durationMs: 2000 }}
/>;
// ref.current?.replay() speelt de animatie opnieuw af
vue
<AreaChart :options="{ ...props, progressiveDraw: { durationMs: 2000 } }" />
svelte
<div use:areaChart={{ ...props, progressiveDraw: { durationMs: 2000 } }}></div>
ts
applyAreaChartProps(this.c.nativeElement, {
  ...props,
  progressiveDraw: { durationMs: 2000 },
});
html
<michi-vz-area-chart id="c"></michi-vz-area-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.

Speel door de jaren heen ​

De data beslaat al meerdere jaren, dus er is niets te taggen. Zet timeline aan: de eigen afspeelknop en scrubber van de grafiek stappen door die jaren - bij elke stap tekenen de gestapelde banden zich alleen tot het actieve jaar, en tijdens het afspelen lopen ze vloeiend verder door. Scrub je terug, dan trekken de banden zich weer terug. Hoveren toont alleen wat al echt getekend is. Standaard uit - zonder opt-in verandert er niets.

Druk op de afspeelknop onder de grafiek: de grafiek tekent zich verder door tot elk jaar terwijl hij speelt. Sleep de scrubber om naar een jaar te springen.

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

<AreaChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / seekIndex(i) / stepForward()
vue
<AreaChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" />
svelte
<div use:areaChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>
ts
applyAreaChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });
html
<michi-vz-area-chart id="c"></michi-vz-area-chart>
<script>
  const el = document.getElementById("c");
  el.timeline = { speedMs: 1000, loop: true };
  // el.getTimeline() -> play() / pause() / seek(year) / seekIndex(i)
</script>
  • speedMs bepaalt het tempo, loop begint opnieuw, autoplay: true start bij mounten, showControl: false verbergt de ingebouwde balk.
  • De headless controller is altijd beschikbaar: chart.timeline() biedt play() / pause() / toggle() / seek(period) / seekIndex(i) / stepForward() / stepBack(), plus onStep en formatPeriod in de config voor eigen UI.
  • seek(period) zoekt eerst de periode en vergelijkt als tekst, dus seek(2021) en seek("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.
  • Waarden glijden standaard tussen jaren (interpolate); zet interpolate: false voor harde overgangen. Met reduced motion is de overgang altijd hard.
  • timeline wint het van progressiveDraw wanneer beide op dezelfde grafiek staan.

Gebruik ​

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

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

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

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

// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-area-chart #c></michi-vz-area-chart>
applyAreaChartProps(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-area-chart id="c"></michi-vz-area-chart>
<script>
  Object.assign(document.getElementById("c"), props); // dataSet/series, title, …
</script>
ts
import { mountAreaChart } from "@michi-vz/core";

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

API ​

Props zijn getypeerd als AreaChartProps 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() geven de renderer-onafhankelijke ChartContext terug.