Skip to content

Cirkel / Donut

Samenstelling

"Welk aandeel neemt elk onderdeel van het geheel in?" De oudste vraag in datavisualisatie, en een cirkeldiagram beantwoordt die nog altijd het best wanneer er maar een handvol segmenten zijn. Elk taartpunt is geschaald op waarde en gelabeld met zijn percentage; segmenten worden gesorteerd op waarde zodat het grootste als eerste leest. Liever een donut? Het is dezelfde grafiek - zet innerRadiusRatio boven 0 om het gat uit te snijden (de context rapporteert dan mode: "donut").

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

De donutvariant is één prop verwijderd - hier dezelfde aandelen met innerRadiusRatio: 0.6, een kleine padAngle, en afgeronde hoeken:

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

Houd het aantal segmenten laag (≈ 6 of minder). Voor veel categorieën leest een staafdiagram of treemap preciezer dan een cirkeldiagram.

Wanneer kies je deze

  • Aandelen voor het bestuur. Een handvol taartpunten, elk gelabeld met zijn percentage: nog altijd de snelste manier om "wie neemt welk aandeel van het geheel" op een dia te zetten.
  • Dashboard-donuts. Zet innerRadiusRatio en het uitgesneden midden wordt de beste plek voor het kerngetal dat de cirkel bewijst.

Veel data op WebGPU Experimenteel

PieChart heeft een optionele renderer="webgpu" die de segmenten tekent als GPU-getekende bogen, terwijl labels, legenda en tooltips op de SVG-laag blijven. Dit is capability-gated: in een browser zonder WebGPU wordt automatisch teruggevallen op canvas, en getContext().renderer rapporteert wat daadwerkelijk is getekend.

⚗️ 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 · 40 slices… detecting

Speel door de jaren heen

Geef elk taartpunt een date en zet timeline aan: het cirkeldiagram wordt een verhaal per jaar, met een eigen afspeelknop en scrubber die telkens de aandelen van één periode toont. Standaard uit - zonder opt-in verandert er niets.

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

<PieChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / stepForward()
vue
<PieChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" />
svelte
<div use:pieChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>
ts
applyPieChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });
html
<michi-vz-pie-chart id="c"></michi-vz-pie-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.
  • Een filter (top-N, sortering) blijft binnen elke periode gelden, dus blijven per jaar alleen de top 5 taartpunten over.
  • Taartpunten zonder date blijven in elke periode zichtbaar.

Gebruik

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

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

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

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

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

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

Datavorm

Elk item in dataSet is één segment: een label, een value, en een optionele color.

ts
const props = {
  innerRadiusRatio: 0, // 0 = pie; e.g. 0.6 = donut
  showLabels: true,    // % labels inside large-enough slices
  showLegend: true,
  dataSet: [
    { label: "Industry", value: 281, color: "#005aba" },
    { label: "Agri-food", value: 381, color: "#f0a500" },
    { label: "Materials", value: 132, color: "#2aa39a" },
  ],
};

Cirkel versus donut

Eén engine rendert beide. innerRadiusRatio is het gat als fractie van de buitenradius: 0 is een volle cirkel, 0.6 een donut. padAngle (radialen) voegt een tussenruimte toe tussen segmenten en cornerRadius rondt de hoeken van de boog af. De segmenten, tooltip, getContext() en SVG/canvas-pariteit zijn in beide gevallen identiek.

API

Props zijn getypeerd als PieChartProps 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: Cirkel / Donut API.