# 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>
  );
};
```

