Back to Components

Donut Chart

Charts & Rings
about 1 year ago

About

DonutChart Component

A reusable, animated donut chart component for React Native with smooth spring animations and configurable gap spacing.

Features

  • ✨ Smooth Animations - Spring-based animations with configurable delays
  • 📊 Gap Spacing - Configurable gaps between chart segments
  • 🎨 Customizable Colors - Each segment can have its own color
  • 📱 Responsive - Works on all screen sizes
  • 🎯 TypeScript Support - Full type safety with interfaces
  • ⚡ Performance Optimized - Uses React Native Reanimated for 60fps

Usage

Basic Example

typescript
import { DonutChart } from '@/components/donut-chart'; const categories = [ { id: 'category-1', name: 'CATEGORY 1', value: 100, percentage: 50, color: '#FF9500', }, { id: 'category-2', name: 'CATEGORY 2', value: 50, percentage: 25, color: '#FFCC00', }, ]; <DonutChart categories={categories} sizeConfig={{ size: 280, strokeWidth: 20, gapSize: 12, }} animationDelay={200} />

With Custom Sizing

typescript
<DonutChart categories={data} sizeConfig={{ size: 200, // Smaller chart strokeWidth: 15, // Thinner stroke gapSize: 8, // Smaller gaps }} animationDelay={0} // No delay disableAnimation={false} />

Props

DonutChart Props

PropTypeRequiredDefaultDescription
categoriesChartCategory[]✅-Array of data categories
sizeConfigSizeConfig❌{ size: 280, strokeWidth: 20, gapSize: 12 }Chart sizing configuration
animationDelaynumber❌0Delay before animation starts (ms)
disableAnimationboolean❌falseDisable all animations

ChartCategory

PropertyTypeRequiredDescription
idstring✅Unique identifier for the category
namestring✅Display name for the category
valuenumber✅Numerical value for the category
percentagenumber✅Percentage of total (0-100)
colorstring✅Hex color for chart segment
iconkeyof typeof Ionicons.glyphMap❌Ionicons icon name (optional)

SizeConfig

PropertyTypeRequiredDefaultDescription
sizenumber❌280Chart diameter in pixels
strokeWidthnumber❌20Stroke width of chart segments
gapSizenumber❌12Gap size in degrees between segments

Chart Features

Gap Spacing

  • Default Gap: 12 degrees between segments
  • Configurable: Can be adjusted via sizeConfig.gapSize
  • Automatic Adjustment: Segments are proportionally reduced to accommodate gaps

Animation

  • Spring Physics: Uses damping: 15, stiffness: 100 for initial animation
  • Staggered Animation: 100ms delay between each category
  • Smart Updates: Smooth transitions when data changes
  • Disable Option: Can turn off animations completely

Sizing

  • Diameter: Configurable via sizeConfig.size
  • Stroke Width: Configurable via sizeConfig.strokeWidth
  • Responsive: Automatically scales to container

Examples

You can play with gap size and animation delay to get the desired effect. You can also use the disableAnimation prop to turn off animations completely. Gap size is automatically adjusted to accommodate the gap size between segments.

Small Chart

typescript
<DonutChart categories={smallData} sizeConfig={{ size: 150, strokeWidth: 12, gapSize: 8, }} animationDelay={100} />

Large Chart

typescript
<DonutChart categories={largeData} sizeConfig={{ size: 400, strokeWidth: 25, gapSize: 15, }} animationDelay={300} />

Static Chart (No Animation)

typescript
<DonutChart categories={staticData} sizeConfig={{ size: 280, strokeWidth: 20, gapSize: 12, }} disableAnimation={true} />

Complete Demo Example

typescript
import { DonutChart } from '@/components/charts/donut-chart'; const sampleCategories = [ { id: 'claude-4-sonnet', name: 'CLAUDE-4-SONNET', value: 117.89, percentage: 73, color: '#FF9500', }, { id: 'claude-4-opus', name: 'CLAUDE-4-OPUS', value: 35.54, percentage: 22, color: '#FFCC00', }, { id: 'auto', name: 'AUTO', value: 4.93, percentage: 3, color: '#8E8E93', }, ]; export const DonutChartDemo = () => { const totalValue = sampleCategories.reduce((sum, category) => sum + category.value, 0); return ( <View style={styles.chartContainer}> <View style={styles.chartWrapper}> <DonutChart categories={sampleCategories} sizeConfig={{ size: 280, strokeWidth: 20, gapSize: 12, }} animationDelay={1000} disableAnimation={false} /> <View style={styles.chartCenter}> <Text style={styles.totalValue}>{totalValue.toFixed(2)}</Text> <Text style={styles.totalUnit}>USD</Text> </View> </View> </View> ); };

Dependencies

  • react-native-reanimated: For smooth animations
  • react-native-svg: For SVG chart rendering
  • @expo/vector-icons: For optional icon support

Performance

  • 60fps Animations: Uses shared values for optimal performance
  • Efficient Rendering: SVG-based with minimal re-renders
  • Memory Management: Proper cleanup of animated values
  • Optimized Calculations: Pre-calculated values for smooth updates

Customization

Custom Gap Size

To change the gap between segments, use the sizeConfig.gapSize prop:

typescript
<DonutChart categories={data} sizeConfig={{ size: 280, strokeWidth: 20, gapSize: 8, // Smaller gaps }} />

Custom Animation Timing

The spring configuration can be modified in the component:

typescript
// Faster animations const SPRING_CONFIG = { damping: 10, stiffness: 150, }; // Slower animations const SPRING_CONFIG = { damping: 25, stiffness: 80, };

Posted by

E

eren

@eren