BubblePacking
Interactive circle packing visualization with force simulation
Key Features
Circle Packing
Native algorithm packs circles efficiently using force-directed placement
Group Colouring
Automatic colour coding by group with customisable palette
Tooltips
Hover tooltips showing label and value for each bubble
Force Simulation
Smooth animated positioning with collision detection
Area Scaling
Bubble area proportional to value (square root scaling)
Accessible
ARIA labels, keyboard navigation, and screen reader support
Technology Market Overview
Interactive bubble chart showing technology market segments by revenue. Click on any bubble to see details. Hover to view tooltips.
<script>
import BubblePacking from '$lib/components/BubblePacking.svelte';
const bubbleData = [
{ id: 'aws', label: 'AWS', value: 80, group: 'Cloud' },
{ id: 'azure', label: 'Azure', value: 65, group: 'Cloud' },
{ id: 'facebook', label: 'Facebook', value: 115, group: 'Social' },
// ... more data
];
</script>
<BubblePacking
data={bubbleData}
width={700}
height={500}
onBubbleClick={(bubble) => console.log(bubble)}
/>Colour Schemes
Customize the colour palette to match your application's theme. Choose from preset schemes or define your own array of hex colours.
<BubblePacking
data={bubbleData}
colorScheme={['#ef476f', '#ffd166', '#06d6a0', '#118ab2', '#073b4c']}
/>Compact Version
Smaller bubbles without labels for embedding in dashboards and summary views. Labels are hidden when bubble radius is below the threshold.
<BubblePacking
data={bubbleData}
width={400}
height={400}
showLabels={true}
labelThreshold={25}
padding={2}
/>Static Placement
Disable force simulation for faster rendering with fewer iterations. This results in a quicker initial layout but may have slightly more overlap.
<BubblePacking
data={bubbleData}
width={500}
height={400}
useForce={false}
/>Props Reference
| Prop | Type | Default | Description |
|---|---|---|---|
data | BubbleItem[] | required | Array of bubble items with id, label, value, and optional group/color |
width | number | 600 | Container width in pixels |
height | number | 600 | Container height in pixels |
padding | number | 3 | Padding between circles in pixels |
colorScheme | string[] | Tableau10 | Array of hex colours for group colouring |
showLabels | boolean | true | Show text labels on bubbles |
labelThreshold | number | 20 | Minimum radius to show labels |
useForce | boolean | true | Use force simulation for smooth animation |
onBubbleClick | function | - | Click handler: (bubble: BubbleItem) => void |
onBubbleHover | function | - | Hover handler: (bubble: BubbleItem | null) => void |
tooltipFormatter | function | - | Custom tooltip: (bubble: BubbleItem) => string |
class | string | '' | Additional CSS classes |
Data Structure
Each bubble item requires an id, label, and value. Optional properties include group (for colour coding) and color (for explicit bubble colour).
interface BubbleItem {
id: string; // Unique identifier
label: string; // Display text
value: number; // Numeric value (determines size)
color?: string; // Optional: explicit hex colour
group?: string; // Optional: group name for colour coding
children?: BubbleItem[]; // Optional: nested children for hierarchy
}Use Cases
📊 Market Share
Visualise company or product market share with proportional sizing
💰 Portfolio Allocation
Display investment portfolios with asset allocation by value
🏷️ Tag Clouds
Show keyword or tag frequency with size indicating importance
🏢 Organisation Charts
Represent team sizes or departmental budgets visually
📈 Category Analysis
Compare categories or segments with grouped bubble clusters
🔬 Scientific Data
Visualise population sizes, gene expression, or research metrics
Implementation Details
Native Algorithm
Built with pure Svelte 5 and native web technologies. No D3 or external charting libraries required.
Force Simulation
Iterative collision detection pushes overlapping circles apart while attracting them to center.
Area Scaling
Uses square root scaling so bubble area (not radius) is proportional to value.
Responsive SVG
ViewBox-based rendering ensures crisp display on all screen sizes and devices.