Bellendiagram
Samenstelling
"Hoe groot is elk onderdeel, en hoeveel ervan is al gerealiseerd?" Een bellenwolk beantwoordt de vraag naar omvang in één oogopslag: elke cirkel heeft een grootte op basis van waarde (oppervlakte, niet straal), en een zwaartekrachtsimulatie trekt ze samen tot een net cluster, zodat de grote bellen duidelijk domineren. Net als bij de treemap kan elke bel een tweedelige splitsing dragen - een volle gerealiseerde kern binnen een lichtere onbenutte ring - zodat je grootte en voortgang samen afleest.
Geen splitsing nodig? Laat partial weg voor een nette proportionele wolk, één kleur per categorie:
Het cluster wordt opgebouwd met d3-force: bellen vallen richting het midden (
gravity) en duwen elkaar uit elkaar zodat ze nooit overlappen (botsing). De simulatie wordt synchroon afgerond, zodat SVG en canvas exact dezelfde, reproduceerbare layout renderen.
Wanneer kies je deze
- Omvang in één oogopslag. Producten, markten, zoekwoorden als een wolk met verschillende groottes - wanneer "welke zijn groot?" meer telt dan een exacte rangschikking, geeft het cluster meteen antwoord.
- Kansenkaarten. Met de splitsing is een grote bel met een dunne gerealiseerde kern geld dat op tafel ligt - de blik waarmee je een portefeuille op onbenut potentieel scant.
- Moet positie iets betekenen (twee numerieke assen, correlatie), dan is een spreidingsdiagram de juiste keuze; de bellenwolk ruilt positie in voor compactheid.
Zware datasets op WebGPU Experimenteel
BubbleChart heeft een optionele renderer="webgpu" die de bellenwolk tekent als GPU-instanced cirkels, terwijl labels en tooltips op de SVG-laag blijven. Dit is capability-gated: in een browser zonder WebGPU schakelt het automatisch terug naar canvas, en getContext().renderer meldt welke renderer daadwerkelijk heeft getekend.
Net als de spreidingsdiagram-pagina leent de demo hieronder van de deeltjesfysica: ~1.500 gereconstrueerde energieclusters uit één gesimuleerd botsingsevent, één bel per cluster, gekleurd per subdetector. Het handjevol harde deposities torent boven duizenden zachte uit, en de zwaartekracht-packing maakt van het hele energiebudget van het event één leesbare wolk.
Speel door de jaren heen
Geef elke bel een date en zet timeline aan: de bellenwolk wordt een verhaal per jaar, met een eigen afspeelknop en scrubber die telkens de groottes 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.
const ref = useRef<BubbleChartHandle>(null);
<BubbleChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / stepForward()<BubbleChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" /><div use:bubbleChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>applyBubbleChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });<michi-vz-bubble-chart id="c"></michi-vz-bubble-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. - Een
filter(top-N, sortering) blijft binnen elke periode gelden, dus blijven per jaar alleen de top 5 bellen over. - Bellen zonder
dateblijven in elke periode zichtbaar.
Gebruik
import { BubbleChart } from "@michi-vz/react";
export default () => <BubbleChart {...props} />; // props = the chart options<script setup>
import { BubbleChart } from "@michi-vz/vue";
</script>
<template>
<BubbleChart :options="props" />
</template><script>
import { bubbleChart } from "@michi-vz/svelte";
</script>
<div use:bubbleChart={props}></div>// main.ts - register the elements once
import "@michi-vz/angular";
import { applyBubbleChartProps } from "@michi-vz/angular";
// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-bubble-chart #c></michi-vz-bubble-chart>
applyBubbleChartProps(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-bubble-chart id="c"></michi-vz-bubble-chart>
<script>
Object.assign(document.getElementById("c"), props); // dataSet, splitLabels, …
</script>import { mountBubbleChart } from "@michi-vz/core";
const chart = mountBubbleChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();Datavorm
Elk dataSet-item is één bel: een label, een value (oppervlakte), een optionele partial (het gerealiseerde subdeel) en een optionele color.
const props = {
splitLabels: ["Realized", "Untapped"],
showLegend: true,
gravity: 0.09, // higher = tighter cluster
dataSet: [
{ label: "Germany", value: 120, partial: 64 }, // 53% realized
{ label: "United States", value: 152, partial: 88 },
{ label: "China", value: 168, partial: 51 },
],
};Zwaartekracht & de splitsing
gravity bepaalt hoe sterk bellen naar het midden worden getrokken (hoger = strakker), padding de ruimte ertussen, en fillRatio hoeveel van het plot de wolk vult. De splitsing werkt hetzelfde als bij de treemap: partial snijdt een areaal-getrouwe gerealiseerde kern uit (straal r·√(partial/value)), en de rest oogt als een lichtere tint van dezelfde kleurtoon - een volle kleur onder een witte sluier, zodat het werkt op zowel lichte als donkere achtergronden. Benoem de onderdelen met splitLabels.
API
Props zijn getypeerd als BubbleChartProps 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. Volledige referentie: Bubble API.
