@aniruddha1806/bubble-chart
Version:
A customizable, responsive bubble chart component for React with TypeScript support
406 lines (349 loc) âĒ 11.6 kB
Markdown
# React Bubble Chart
A powerful, customizable bubble chart component for React applications with TypeScript support. Perfect for visualizing three-dimensional data relationships with interactive features, smooth animations, and extensive customization options.
## Installation
```bash
npm install @aniruddha1806/bubble-chart
```
## Features
- ðŦ§ Interactive bubble charts with three-dimensional data visualization
- ð Smooth entrance animations with scroll-triggered effects
- ðąïļ Hover tooltips and click handlers
- ð Customizable axes with configurable ticks and labels
- ðĻ Extensive styling options (colors, sizing, formatting)
- ðą Responsive SVG-based rendering
- ð Flexible bubble sizing (relative or absolute)
- ð Real-time data updates with smooth transitions
- ð TypeScript support with full type definitions
- âŋ Accessibility-friendly structure
- ðŠķ Zero dependencies for chart rendering
## Quick Start
### Basic Bubble Chart
```jsx
import { BubbleChart } from '@aniruddha1806/bubble-chart';
function App() {
const data = [
{ x: 10, y: 20, size: 15, label: 'Product A', color: '#3b82f6' },
{ x: 25, y: 35, size: 25, label: 'Product B', color: '#10b981' },
{ x: 40, y: 15, size: 20, label: 'Product C', color: '#f59e0b' },
{ x: 30, y: 45, size: 30, label: 'Product D', color: '#ef4444' },
{ x: 50, y: 30, size: 18, label: 'Product E', color: '#8b5cf6' }
];
return (
<BubbleChart
data={data}
width="100%"
height={400}
xAxisLabel="Revenue (millions)"
yAxisLabel="Growth Rate (%)"
showTooltip={true}
animated={true}
/>
);
}
```
### Advanced Configuration
```jsx
import { BubbleChart } from '@aniruddha1806/bubble-chart';
function AdvancedExample() {
const data = [
// ... your data
];
return (
<BubbleChart
data={data}
width={800}
height={500}
xAxisLabel="Market Share (%)"
yAxisLabel="Customer Satisfaction"
minRadius={8}
maxRadius={60}
xAxisTicks={8}
yAxisTicks={6}
bubbleSizeMultiplier={1.2}
animated={true}
animationDuration={1000}
formatValue={(value) => `$${value}M`}
onBubbleClick={(bubble) => console.log('Clicked:', bubble)}
/>
);
}
```
## Props
### Core Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `data` | `BubbleDataPoint[]` | `required` | Array of bubble data points |
| `width` | `number \| string` | `"100%"` | Chart width |
| `height` | `number \| string` | `400` | Chart height |
### Styling Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `colors` | `string[]` | `default palette` | Color palette for bubbles |
| `backgroundColor` | `string` | `"transparent"` | Chart background color |
| `className` | `string` | `""` | CSS class for container |
| `bubbleClassName` | `string` | `""` | CSS class for bubbles |
| `tooltipClassName` | `string` | `""` | CSS class for tooltips |
### Axis Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `xAxisLabel` | `string` | `"X-Axis"` | X-axis label text |
| `yAxisLabel` | `string` | `"Y-Axis"` | Y-axis label text |
| `xAxisTicks` | `number` | `5` | Number of X-axis tick marks |
| `yAxisTicks` | `number` | `5` | Number of Y-axis tick marks |
### Bubble Sizing Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `minRadius` | `number` | `10` | Minimum bubble radius |
| `maxRadius` | `number` | `50` | Maximum bubble radius |
| `bubbleSizeMultiplier` | `number` | `1` | Size scaling multiplier |
| `absoluteBubbleSize` | `boolean` | `false` | Use absolute sizing instead of relative |
### Formatting Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `formatValue` | `(value: number) => string` | `toString` | General value formatter |
| `formatXAxisValue` | `(value: number) => string` | `formatValue` | X-axis value formatter |
| `formatYAxisValue` | `(value: number) => string` | `formatValue` | Y-axis value formatter |
### Interaction Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `showTooltip` | `boolean` | `true` | Show hover tooltips |
| `onBubbleClick` | `(dataPoint: BubbleDataPoint) => void` | `undefined` | Bubble click handler |
| `tooltipContent` | `(bubble: BubbleDataPoint) => React.ReactNode` | `undefined` | Custom tooltip content |
### Animation Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `animated` | `boolean` | `true` | Enable entrance animations |
| `animationDuration` | `number` | `800` | Animation duration (ms) |
### Data Types
```typescript
type BubbleDataPoint = {
x: number;
y: number;
size: number;
label?: string;
color?: string;
[key: string]: any; // Additional custom properties
};
```
## Examples
### Sales Performance Dashboard
Visualize sales data with revenue, growth, and market size:
```jsx
import { BubbleChart } from '@aniruddha1806/bubble-chart';
function SalesPerformance() {
const salesData = [
{
x: 45, // Revenue (millions)
y: 12, // Growth rate (%)
size: 25, // Market size
label: 'North America',
color: '#3b82f6',
region: 'NA',
customers: 1250
},
{
x: 32,
y: 18,
size: 20,
label: 'Europe',
color: '#10b981',
region: 'EU',
customers: 980
},
{
x: 28,
y: 25,
size: 30,
label: 'Asia Pacific',
color: '#f59e0b',
region: 'APAC',
customers: 1580
},
{
x: 15,
y: 35,
size: 15,
label: 'Latin America',
color: '#ef4444',
region: 'LATAM',
customers: 650
},
{
x: 8,
y: 42,
size: 12,
label: 'Middle East',
color: '#8b5cf6',
region: 'ME',
customers: 420
}
];
const handleBubbleClick = (bubble) => {
alert(`Region: ${bubble.label}\\nRevenue: $${bubble.x}M\\nGrowth: ${bubble.y}%\\nCustomers: ${bubble.customers}`);
};
const customTooltip = (bubble) => (
<div>
<div style={{ fontWeight: 'bold', marginBottom: '4px' }}>{bubble.label}</div>
<div>Revenue: $${bubble.x}M</div>
<div>Growth: \${bubble.y}%</div>
<div>Market Size: \${bubble.size}</div>
<div>Customers: \${bubble.customers?.toLocaleString()}</div>
</div>
);
return (
<div style={{ padding: '20px' }}>
<h2>Regional Sales Performance</h2>
<p>Revenue vs Growth Rate (Bubble size = Market opportunity)</p>
<BubbleChart
data={salesData}
width="100%"
height={500}
xAxisLabel="Revenue ($ millions)"
yAxisLabel="Growth Rate (%)"
minRadius={15}
maxRadius={45}
xAxisTicks={6}
yAxisTicks={8}
animated={true}
animationDuration={1200}
onBubbleClick={handleBubbleClick}
tooltipContent={customTooltip}
formatXAxisValue={(value) => `$${value}M`}
formatYAxisValue={(value) => `${value}%`}
/>
<div style={{
marginTop: '20px',
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
gap: '16px'
}}>
{salesData.map((region, index) => (
<div
key={index}
style={{
padding: '16px',
backgroundColor: 'white',
border: '1px solid #e2e8f0',
borderRadius: '8px',
textAlign: 'center'
}}
>
<div style={{
width: '20px',
height: '20px',
backgroundColor: region.color,
borderRadius: '50%',
margin: '0 auto 8px'
}}></div>
<h4 style={{ margin: '0 0 4px 0' }}>{region.label}</h4>
<p style={{ margin: 0, fontSize: '14px', color: '#666' }}>
$${region.x}M revenue
</p>
</div>
))}
</div>
</div>
);
}
```
## TypeScript Usage
The component provides full TypeScript support:
```typescript
import { BubbleChart, BubbleDataPoint, BubbleChartProps } from '@aniruddha1806/bubble-chart';
import { useState, useCallback } from 'react';
interface AnalyticsData extends BubbleDataPoint {
category: string;
revenue: number;
customers: number;
}
interface ChartConfig {
title: string;
xLabel: string;
yLabel: string;
colors: string[];
}
const AnalyticsDashboard: React.FC = () => {
const [analyticsData, setAnalyticsData] = useState<AnalyticsData[]>([
{
x: 45,
y: 12,
size: 25,
label: 'Product A',
color: '#3b82f6',
category: 'Electronics',
revenue: 2500000,
customers: 1250
},
{
x: 32,
y: 18,
size: 20,
label: 'Product B',
color: '#10b981',
category: 'Software',
revenue: 1800000,
customers: 980
}
]);
const handleBubbleClick = useCallback((dataPoint: BubbleDataPoint): void => {
const analyticsPoint = dataPoint as AnalyticsData;
console.log('Analytics data:', analyticsPoint);
// Handle click logic
}, []);
const formatCurrency = useCallback((value: number): string => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(value);
}, []);
const customTooltip = useCallback((bubble: BubbleDataPoint): React.ReactNode => {
const data = bubble as AnalyticsData;
return (
<div>
<div style={{ fontWeight: 'bold', marginBottom: '4px' }}>{data.label}</div>
<div>Category: {data.category}</div>
<div>Revenue: {formatCurrency(data.revenue)}</div>
<div>Customers: {data.customers.toLocaleString()}</div>
<div>Market Share: \${data.x}%</div>
<div>Growth: \${data.y}%</div>
</div>
);
}, [formatCurrency]);
const chartConfig: ChartConfig = {
title: 'Product Performance Analysis',
xLabel: 'Market Share (%)',
yLabel: 'Growth Rate (%)',
colors: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6']
};
const bubbleChartProps: BubbleChartProps = {
data: analyticsData,
width: '100%',
height: 500,
colors: chartConfig.colors,
xAxisLabel: chartConfig.xLabel,
yAxisLabel: chartConfig.yLabel,
minRadius: 15,
maxRadius: 45,
animated: true,
animationDuration: 1000,
onBubbleClick: handleBubbleClick,
tooltipContent: customTooltip,
formatXAxisValue: (value) => `\${value}%`,
formatYAxisValue: (value) => `\${value}%`
};
return (
<div>
<h2>{chartConfig.title}</h2>
<BubbleChart {...bubbleChartProps} />
<div>
<h3>Summary Statistics:</h3>
<p>Total Products: {analyticsData.length}</p>
<p>Total Revenue: {formatCurrency(analyticsData.reduce((sum, item) => sum + item.revenue, 0))}</p>
<p>Total Customers: {analyticsData.reduce((sum, item) => sum + item.customers, 0).toLocaleString()}</p>
</div>
</div>
);
};
```