Treemap
Samenstelling
"Welke onderdelen zijn het grootst, en hoeveel daarvan is al gerealiseerd?" Een treemap beantwoordt beide tegelijk: elke tegel is geschaald op zijn totaal, en een optionele tweedelige splitsing vult het solide aandeel binnen elke tegel - zodat je omvang (oppervlakte) en voortgang (de splitsing) in één oogopslag leest. Het klassieke voorbeeld is exportpotentieel: tegeloppervlakte = totaal potentieel, het solide deel = gerealiseerd, het lichtere deel = onbenut. Tegels kunnen onder groepen nestelen, en op een smal scherm vouwt het geheel om tot een leesbare stapel in één kolom.
Liever een platte lijst (één tegel per product, elk zijn eigen kleur - de klassieke exportpotentieel-indeling)? Laat de children-nesting weg en geef de bladeren direct door:
De splitsing is generiek. Benoem de twee delen met
splitLabels-["Realized", "Untapped"],["Used", "Free"],["Done", "Remaining"]- niets in de engine legt een domein hard vast.
Wanneer kies je deze
- Portefeuilleoverzichten. Honderden producten, sectoren of kostenplaatsen op één scherm: oppervlakte is grootte, de splitsing is voortgang, en de hele hiërarchie past zonder scrollen.
- "Waar moeten we ons op focussen?" De grote, grotendeels onbenutte tegels vormen de kansenlijst, zonder dat er gesorteerd hoeft te worden - de klassieke lezing voor exportpotentieel en marktscans.
- Een dozijn platte categorieën of minder? Een staafdiagram of cirkeldiagram leest exacte waarden sneller af dan tegeloppervlaktes; de treemap verdient haar plek pas op schaal.
Veel data op WebGPU Experimenteel
TreemapChart heeft een optionele renderer="webgpu" die de tegels tekent als GPU-instanced rechthoeken, terwijl labels, tooltips en de splitsingsvulling 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.
Speel door de jaren heen
Geef elke tegel op het hoogste niveau een date en zet timeline aan: de momentopname van een jaar bestaat uit de roottegels die die datum delen - kinderen hebben geen eigen datum nodig - en de tegels glijden tussen jaren terwijl ze van formaat veranderen. 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<TreemapChartHandle>(null);
<TreemapChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / stepForward()<TreemapChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" /><div use:treemapChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>applyTreemapChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });<michi-vz-treemap-chart id="c"></michi-vz-treemap-chart>
<script>
const el = document.getElementById("c");
el.timeline = { speedMs: 1000, loop: true };
// el.getTimeline() -> play() / pause() / seek(year)
</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) / stepForward() / stepBack(), plusonStepenformatPeriodin de config voor eigen UI. - Roottegels 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<TreemapChartHandle>(null);
<TreemapChart
ref={ref}
{...props}
progressiveDraw={{ durationMs: 2000 }}
/>;
// ref.current?.replay() speelt de animatie opnieuw af<TreemapChart :options="{ ...props, progressiveDraw: { durationMs: 2000 } }" /><div use:treemapChart={{ ...props, progressiveDraw: { durationMs: 2000 } }}></div>applyTreemapChartProps(this.c.nativeElement, {
...props,
progressiveDraw: { durationMs: 2000 },
});<michi-vz-treemap-chart id="c"></michi-vz-treemap-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 { TreemapChart } from "@michi-vz/react";
export default () => <TreemapChart {...props} />; // props = the chart options<script setup>
import { TreemapChart } from "@michi-vz/vue";
</script>
<template>
<TreemapChart :options="props" />
</template><script>
import { treemapChart } from "@michi-vz/svelte";
</script>
<div use:treemapChart={props}></div>// main.ts - register the elements once
import "@michi-vz/angular";
import { applyTreemapChartProps } from "@michi-vz/angular";
// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-treemap-chart #c></michi-vz-treemap-chart>
applyTreemapChartProps(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-treemap-chart id="c"></michi-vz-treemap-chart>
<script>
Object.assign(document.getElementById("c"), props); // dataSet, splitLabels, …
</script>import { mountTreemapChart } from "@michi-vz/core";
const chart = mountTreemapChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();Datavorm
Elke dataSet-node is een blad (value, optionele partial) of een ouder (children). De waarde van een ouder is de som van zijn bladeren.
const props = {
splitLabels: ["Realized", "Untapped"],
showLegend: true,
layout: "auto", // squarify on desktop, stack on narrow screens
dataSet: [
{ label: "Agri-food", children: [
{ label: "Fruits", value: 100, partial: 34 }, // 34% realized
{ label: "Beverages", value: 50, partial: 35 }, // 70% realized
]},
{ label: "Industry", children: [
{ label: "Machinery", value: 120, partial: 64 },
]},
],
};Responsieve lay-out
layout kiest het tegelalgoritme: "squarify" (de treemap), "stack" (een verticale partitie in één kolom - rijen over de volle breedte, hoogte proportioneel aan de waarde, met dezelfde splitsing per rij), of "auto" (schakelt over naar stack onder stackBreakpoint, standaard 480px). De splitsing, labels, tooltip, getContext() en SVG/canvas-pariteit zijn bij beide lay-outs identiek.
API
Props zijn getypeerd als TreemapChartProps 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: Treemap API.
