Graphique à bulles
Composition
« Quelle est la taille de chacun, et quelle part en est déjà réalisée ? » Un nuage de bulles répond à la question de l'ampleur d'un coup d'œil : chaque cercle est dimensionné par sa valeur (aire, pas rayon), et une simulation de gravité les rassemble en une grappe ordonnée pour que les plus grands dominent évidemment. Comme le treemap, chaque bulle peut porter une division en deux parties - un noyau réalisé plein à l'intérieur d'un anneau inexploité plus clair - pour lire taille et progression ensemble.
Pas besoin de division ? Retirez partial pour un nuage proportionnel épuré, une couleur par catégorie :
La grappe est disposée avec d3-force : les bulles tombent vers le centre (
gravity) et se repoussent pour ne jamais se chevaucher (collision). La simulation est stabilisée de manière synchrone, pour que le SVG et le canvas affichent la même disposition identique et reproductible.
Quand le choisir
- L'ampleur en un coup d'œil. Produits, marchés, mots-clés sous forme de nuage dimensionné - quand « lesquels sont grands ? » compte plus qu'un classement exact, la grappe répond instantanément.
- Cartes d'opportunités. Avec la division, une grosse bulle au noyau réalisé fin est de l'argent laissé sur la table - la vue de repérage du potentiel pour les revues de portefeuille.
- Si la position doit signifier quelque chose (deux axes numériques, une corrélation), c'est un nuage de points qu'il vous faut ; le nuage de bulles échange la position contre la compacité.
Données volumineuses sur WebGPU Expérimental
BubbleChart dispose d'un renderer="webgpu" optionnel qui peint le nuage de bulles comme des cercles instanciés sur le GPU tandis que les étiquettes et infobulles restent sur la couche SVG. C'est conditionné par les capacités du navigateur : sur un navigateur sans WebGPU, il rétrograde automatiquement vers canvas, et getContext().renderer indique lequel a effectivement peint.
Comme la page du nuage de points, la démo ci-dessous emprunte à la physique des particules : ~1 500 amas d'énergie reconstruits d'un événement de collision simulé, une bulle par amas, colorée par sous-détecteur. La poignée de dépôts durs domine des milliers de dépôts mous, et le tassement par gravité transforme tout le budget d'énergie de l'événement en un seul nuage lisible.
Faire defiler les annees
Donnez un date à chaque bulle et activez timeline : le nuage de bulles devient un récit année par année, avec son propre bouton lecture et son curseur, un instantané des tailles à la fois. Désactivé par défaut - sans opt-in, rien ne change.
Appuyez sur le bouton lecture sous le graphique : les données défilent année après année, un instantané à la fois. Faites glisser le curseur pour sauter à une année.
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>speedMsrègle le rythme,loopreboucle,autoplay: truedémarre au montage,showControl: falsemasque la barre intégrée.- Les valeurs glissent d'une période à l'autre par défaut (
interpolate) ; ajustez le mouvement avectweenMseteasing, ou passezinterpolate: falsepour des coupes nettes. Avec reduced motion, la coupe est toujours nette. - Le contrôleur headless reste disponible :
chart.timeline()exposeplay() / pause() / toggle() / seek(period) / stepForward() / stepBack(), plusonStepetformatPerioddans la config pour une UI maison. - Un
filter(top-N, tri) s'applique toujours à l'intérieur de chaque période : seules les 5 meilleures bulles de l'année passent le filtre. - Les bulles sans
daterestent visibles à chaque période.
Usage
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();Forme des données
Chaque élément de dataSet est une bulle : une label, une value (aire), un partial optionnel (la sous-partie réalisée), et une color optionnelle.
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 },
],
};Gravité et la division
gravity définit avec quelle force les bulles sont attirées vers le centre (plus élevé = grappe plus serrée), padding l'écart entre elles, et fillRatio quelle part de la zone de tracé le nuage occupe. La division reflète le treemap : partial découpe un noyau réalisé fidèle à l'aire (rayon r·√(partial/value)), et le reste se lit comme une teinte plus claire de la même couleur - une couleur pleine sous un voile blanc, pour fonctionner sur fond clair et sombre. Nommez les parties avec splitLabels.
API
Les props sont typées comme BubbleChartProps dans @michi-vz/core. Communes à tous les graphiques : width, height, margin, colors / colorsMapping, renderer ("svg", "canvas", ou expérimentalement "webgpu"), highlightItems, disabledItems, et les callbacks on*. onChartDataProcessed / getContext() renvoient le ChartContext agnostique du moteur de rendu. Référence complète : API Bubble.
