UNPKG

@aniruddha1806/bubble-chart

Version:

A customizable, responsive bubble chart component for React with TypeScript support

406 lines (349 loc) â€Ē 11.6 kB
# 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> ); }; ```