Skip to main content

PieChartAppi

An interactive pie chart widget for displaying data distributions with customizable styling and animations.

Overview

PieChartAppi is a powerful data visualization component that creates beautiful, interactive pie charts. It supports custom colors, animations, legends, and touch interactions, making it perfect for dashboards, analytics, and data presentation.

Features

  • 📊 Interactive - Touch and hover interactions
  • 🎨 Customizable - Colors, styles, and themes
  • 📱 Responsive - Adapts to different screen sizes
  • 🎬 Animated - Smooth transitions and loading animations
  • 📋 Legend Support - Automatic legend generation
  • Accessible - Screen reader support
  • 🌙 Theme Ready - Light and dark mode support

Basic Usage

PieChartAppi(
data: [
PieChartData(label: 'Mobile', value: 45, color: Colors.blue),
PieChartData(label: 'Desktop', value: 30, color: Colors.green),
PieChartData(label: 'Tablet', value: 25, color: Colors.orange),
],
title: 'Device Usage',
)

Properties

PropertyTypeDefaultDescription
dataList<PieChartData>requiredChart data points
titleString?nullChart title
widthdouble?nullChart width
heightdouble?nullChart height
showLegendbooltrueShow/hide legend
legendPositionLegendPositionLegendPosition.rightLegend position
animationDurationDurationDuration(milliseconds: 1000)Animation duration
strokeWidthdouble2.0Stroke width
showPercentagebooltrueShow percentage labels
centerTextString?nullText in center of chart
onTapFunction(PieChartData)?nullTap callback

Data Model

class PieChartData {
final String label;
final double value;
final Color color;
final String? description;

const PieChartData({
required this.label,
required this.value,
required this.color,
this.description,
});
}

Examples

Basic Pie Chart

PieChartAppi(
data: [
PieChartData(
label: 'Sales',
value: 60,
color: Colors.blue,
),
PieChartData(
label: 'Marketing',
value: 25,
color: Colors.green,
),
PieChartData(
label: 'Support',
value: 15,
color: Colors.orange,
),
],
title: 'Department Budget',
width: 300,
height: 300,
)

Revenue Distribution Chart

PieChartAppi(
data: [
PieChartData(
label: 'Product Sales',
value: 450000,
color: Colors.blue[600]!,
description: 'Revenue from product sales',
),
PieChartData(
label: 'Services',
value: 280000,
color: Colors.green[600]!,
description: 'Revenue from services',
),
PieChartData(
label: 'Subscriptions',
value: 320000,
color: Colors.purple[600]!,
description: 'Revenue from subscriptions',
),
PieChartData(
label: 'Other',
value: 150000,
color: Colors.orange[600]!,
description: 'Other revenue sources',
),
],
title: 'Revenue Distribution 2024',
centerText: '\$1.2M\nTotal',
showPercentage: true,
onTap: (data) {
print('Tapped: ${data.label} - ${data.value}');
},
)

Custom Styled Chart

PieChartAppi(
data: [
PieChartData(label: 'Completed', value: 75, color: Colors.green),
PieChartData(label: 'In Progress', value: 20, color: Colors.blue),
PieChartData(label: 'Pending', value: 5, color: Colors.red),
],
title: 'Project Status',
width: 250,
height: 250,
strokeWidth: 4,
animationDuration: Duration(milliseconds: 1500),
legendPosition: LegendPosition.bottom,
showPercentage: true,
)

Donut Chart Style

PieChartAppi(
data: [
PieChartData(label: 'iOS', value: 40, color: Colors.blue),
PieChartData(label: 'Android', value: 45, color: Colors.green),
PieChartData(label: 'Web', value: 15, color: Colors.orange),
],
title: 'Platform Usage',
centerText: '100%\nCoverage',
strokeWidth: 0, // Creates donut effect
innerRadius: 60, // Custom property for donut
)

Interactive Features

Tap Interactions

class InteractivePieChart extends StatefulWidget {

_InteractivePieChartState createState() => _InteractivePieChartState();
}

class _InteractivePieChartState extends State<InteractivePieChart> {
PieChartData? selectedSegment;


Widget build(BuildContext context) {
return Column(
children: [
PieChartAppi(
data: [
PieChartData(label: 'Q1', value: 25, color: Colors.blue),
PieChartData(label: 'Q2', value: 30, color: Colors.green),
PieChartData(label: 'Q3', value: 28, color: Colors.orange),
PieChartData(label: 'Q4', value: 35, color: Colors.purple),
],
title: 'Quarterly Sales',
onTap: (data) {
setState(() {
selectedSegment = data;
});
},
),
if (selectedSegment != null)
Container(
margin: EdgeInsets.only(top: 16),
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: selectedSegment!.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Text(
'Selected: ${selectedSegment!.label} - ${selectedSegment!.value}%',
style: TextStyle(
fontWeight: FontWeight.bold,
color: selectedSegment!.color,
),
),
),
],
);
}
}

Animated Loading

class AnimatedPieChart extends StatefulWidget {

_AnimatedPieChartState createState() => _AnimatedPieChartState();
}

class _AnimatedPieChartState extends State<AnimatedPieChart>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;


void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 2),
vsync: this,
);
_animation = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
_controller.forward();
}


void dispose() {
_controller.dispose();
super.dispose();
}


Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return PieChartAppi(
data: [
PieChartData(
label: 'Complete',
value: 70 * _animation.value,
color: Colors.green,
),
PieChartData(
label: 'Remaining',
value: 30 * _animation.value,
color: Colors.grey[300]!,
),
],
title: 'Progress',
centerText: '${(70 * _animation.value).toInt()}%',
);
},
);
}
}

Legend Customization

Custom Legend Position

PieChartAppi(
data: chartData,
title: 'Sales by Region',
legendPosition: LegendPosition.bottom,
legendStyle: LegendStyle(
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
spacing: 8,
itemSpacing: 16,
),
)

No Legend

PieChartAppi(
data: chartData,
title: 'Simple Chart',
showLegend: false,
showPercentage: true,
)

Responsive Design

Adaptive Size

LayoutBuilder(
builder: (context, constraints) {
final size = constraints.maxWidth > 600 ? 400.0 : 300.0;
return PieChartAppi(
data: chartData,
width: size,
height: size,
title: 'Responsive Chart',
);
},
)

Mobile Optimized

class ResponsivePieChart extends StatelessWidget {

Widget build(BuildContext context) {
final isMobile = MediaQuery.of(context).size.width < 600;

return PieChartAppi(
data: chartData,
width: isMobile ? 250 : 350,
height: isMobile ? 250 : 350,
legendPosition: isMobile
? LegendPosition.bottom
: LegendPosition.right,
showPercentage: !isMobile,
);
}
}

Theming

Custom Colors

final customColors = [
Color(0xFF6366F1), // Indigo
Color(0xFF8B5CF6), // Violet
Color(0xFF06B6D4), // Cyan
Color(0xFF10B981), // Emerald
Color(0xFFF59E0B), // Amber
Color(0xFFEF4444), // Red
];

PieChartAppi(
data: List.generate(6, (index) => PieChartData(
label: 'Category ${index + 1}',
value: (index + 1) * 10.0,
color: customColors[index],
)),
title: 'Custom Colors',
)

Dark Theme

PieChartAppi(
data: chartData,
title: 'Dark Theme Chart',
backgroundColor: Theme.of(context).brightness == Brightness.dark
? Colors.grey[900]
: Colors.white,
titleStyle: TextStyle(
color: Theme.of(context).textTheme.titleLarge?.color,
fontSize: 18,
fontWeight: FontWeight.bold,
),
)

Advanced Examples

Multi-Level Pie Chart

class MultiLevelPieChart extends StatelessWidget {

Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
// Outer ring
PieChartAppi(
data: [
PieChartData(label: 'Desktop', value: 60, color: Colors.blue),
PieChartData(label: 'Mobile', value: 40, color: Colors.green),
],
width: 300,
height: 300,
showLegend: false,
strokeWidth: 40,
),
// Inner ring
PieChartAppi(
data: [
PieChartData(label: 'Chrome', value: 35, color: Colors.blue[300]!),
PieChartData(label: 'Firefox', value: 25, color: Colors.blue[700]!),
PieChartData(label: 'Safari', value: 25, color: Colors.green[300]!),
PieChartData(label: 'Other', value: 15, color: Colors.green[700]!),
],
width: 200,
height: 200,
showLegend: false,
strokeWidth: 30,
),
],
);
}
}

Dashboard Integration

class DashboardChart extends StatelessWidget {

Widget build(BuildContext context) {
return Card(
elevation: 4,
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Revenue Breakdown',
style: Theme.of(context).textTheme.titleLarge,
),
IconButton(
icon: Icon(Icons.more_vert),
onPressed: () => showChartOptions(),
),
],
),
SizedBox(height: 16),
PieChartAppi(
data: [
PieChartData(
label: 'Products',
value: 450000,
color: Colors.blue,
),
PieChartData(
label: 'Services',
value: 320000,
color: Colors.green,
),
PieChartData(
label: 'Licenses',
value: 180000,
color: Colors.orange,
),
],
height: 250,
centerText: '\$950K\nTotal',
onTap: (data) => showDetailView(data),
),
],
),
),
);
}
}

Best Practices

1. Use Meaningful Colors

// Good: Semantic colors
PieChartData(label: 'Success', value: 80, color: Colors.green),
PieChartData(label: 'Warning', value: 15, color: Colors.orange),
PieChartData(label: 'Error', value: 5, color: Colors.red),

2. Limit Data Points

// Good: 5-7 segments maximum for readability
final data = chartData.take(6).toList();
if (chartData.length > 6) {
final otherValue = chartData.skip(6).fold(0.0, (sum, item) => sum + item.value);
data.add(PieChartData(label: 'Other', value: otherValue, color: Colors.grey));
}

3. Provide Context

// Good: Clear title and descriptions
PieChartAppi(
data: data,
title: 'Q4 2024 Sales Distribution',
centerText: 'Total\n\$2.4M',
)

4. Handle Empty Data

Widget buildChart() {
if (data.isEmpty) {
return Container(
height: 300,
child: Center(
child: Text('No data available'),
),
);
}

return PieChartAppi(data: data);
}

Common Use Cases

1. Analytics Dashboard

PieChartAppi(
data: [
PieChartData(label: 'Organic', value: 45, color: Colors.green),
PieChartData(label: 'Paid', value: 30, color: Colors.blue),
PieChartData(label: 'Social', value: 15, color: Colors.purple),
PieChartData(label: 'Direct', value: 10, color: Colors.orange),
],
title: 'Traffic Sources',
)

2. Budget Allocation

PieChartAppi(
data: [
PieChartData(label: 'Development', value: 40, color: Colors.blue),
PieChartData(label: 'Marketing', value: 25, color: Colors.green),
PieChartData(label: 'Operations', value: 20, color: Colors.orange),
PieChartData(label: 'Research', value: 15, color: Colors.purple),
],
title: 'Budget Allocation',
centerText: '\$500K\nTotal',
)

3. Survey Results

PieChartAppi(
data: [
PieChartData(label: 'Very Satisfied', value: 35, color: Colors.green[600]!),
PieChartData(label: 'Satisfied', value: 40, color: Colors.green[300]!),
PieChartData(label: 'Neutral', value: 15, color: Colors.grey),
PieChartData(label: 'Dissatisfied', value: 10, color: Colors.red),
],
title: 'Customer Satisfaction',
)

Ready to visualize trends? Check out LineChartAppi for time-series data!