Overview

Bar charts are ideal for comparing categorical data. Cristalyse supports vertical, horizontal, grouped, and stacked bar charts with smooth animations and customizable styling.


Basic Bar Chart

Create a simple vertical bar chart:

final data = [
  {'quarter': 'Q1', 'revenue': 120},
  {'quarter': 'Q2', 'revenue': 150},
  {'quarter': 'Q3', 'revenue': 110},
  {'quarter': 'Q4', 'revenue': 180},
];

CristalyseChart()
  .data(data)
  .mapping(x: 'quarter', y: 'revenue')
  .geomBar(
    width: 0.8,
    alpha: 0.9,
    borderRadius: BorderRadius.circular(4),
  )
  .scaleXOrdinal()
  .scaleYContinuous(min: 0)
  .theme(ChartTheme.defaultTheme())
  .build()

Grouped Bar Charts

Compare multiple series side-by-side:


final productData = [
  {'quarter': 'Q1', 'revenue': 120, 'product': 'Widget A'},
  {'quarter': 'Q2', 'revenue': 150, 'product': 'Widget A'},
  {'quarter': 'Q1', 'revenue': 80, 'product': 'Widget B'},
  {'quarter': 'Q2', 'revenue': 110, 'product': 'Widget B'},
];

CristalyseChart()
  .data(productData)
  .mapping(x: 'quarter', y: 'revenue', color: 'product')
  .geomBar(
    style: BarStyle.grouped,
    width: 0.8,
    alpha: 0.9,
  )
  .scaleXOrdinal()
  .scaleYContinuous(min: 0)
  .theme(ChartTheme.defaultTheme())
  .build()

Stacked Bar Charts

Show composition and totals:


final budgetData = [
  {'department': 'Marketing', 'amount': 50, 'category': 'Personnel'},
  {'department': 'Marketing', 'amount': 30, 'category': 'Technology'},
  {'department': 'Marketing', 'amount': 20, 'category': 'Travel'},
  {'department': 'Sales', 'amount': 80, 'category': 'Personnel'},
  {'department': 'Sales', 'amount': 25, 'category': 'Technology'},
];

CristalyseChart()
  .data(budgetData)
  .mapping(x: 'department', y: 'amount', color: 'category')
  .geomBar(
    style: BarStyle.stacked,
    width: 0.8,
    alpha: 0.9,
  )
  .scaleXOrdinal()
  .scaleYContinuous(min: 0)
  .theme(ChartTheme.defaultTheme())
  .build()

Horizontal Bar Charts

Perfect for long category names or ranking data:

final departmentData = [
  {'department': 'Engineering', 'headcount': 45},
  {'department': 'Product', 'headcount': 25},
  {'department': 'Sales', 'headcount': 35},
  {'department': 'Marketing', 'headcount': 20},
  {'department': 'Customer Success', 'headcount': 15},
];

CristalyseChart()
  .data(departmentData)
  .mapping(x: 'department', y: 'headcount')
  .geomBar(
    borderRadius: BorderRadius.circular(4),
    borderWidth: 1.0,
  )
  .coordFlip() // Makes it horizontal
  .scaleXOrdinal()
  .scaleYContinuous(min: 0)
  .theme(ChartTheme.defaultTheme())
  .build()

Styling Options

Rounded Corners

Add modern styling with border radius:

CristalyseChart()
  .data(data)
  .mapping(x: 'category', y: 'value')
  .geomBar(
    borderRadius: BorderRadius.circular(8),
    alpha: 0.8,
  )
  .build()

Borders

Add definition with borders:

CristalyseChart()
  .data(data)
  .mapping(x: 'category', y: 'value')
  .geomBar(
    borderWidth: 2.0,
    alpha: 0.7,
  )
  .build()

Custom Colors

Override default color mapping:

CristalyseChart()
  .data(data)
  .mapping(x: 'category', y: 'value')
  .geomBar(
    color: Colors.deepPurple,
    alpha: 0.8,
  )
  .build()

Animation Types

Progressive Bar Growth

Bars animate from bottom to top:

CristalyseChart()
  .data(data)
  .mapping(x: 'category', y: 'value')
  .geomBar()
  .animate(
    duration: Duration(milliseconds: 1200),
    curve: Curves.easeInOutCubic,
  )
  .build()

Staggered Animation

Each bar animates with a slight delay:

CristalyseChart()
  .data(data)
  .mapping(x: 'category', y: 'value')
  .geomBar()
  .animate(
    duration: Duration(milliseconds: 1400),
    curve: Curves.elasticOut,
  )
  .build()

Dual Y-Axis Bar Charts

Combine bars with different scales:

final mixedData = [
  {'quarter': 'Q1', 'revenue': 120, 'efficiency': 85},
  {'quarter': 'Q2', 'revenue': 150, 'efficiency': 92},
  {'quarter': 'Q3', 'revenue': 110, 'efficiency': 78},
];

CristalyseChart()
  .data(mixedData)
  .mapping(x: 'quarter', y: 'revenue')
  .mappingY2('efficiency')
  .geomBar(yAxis: YAxis.primary)  // Revenue bars
  .geomLine(
    yAxis: YAxis.secondary,        // Efficiency line
    strokeWidth: 3.0,
    color: Colors.orange,
  )
  .scaleXOrdinal()
  .scaleYContinuous(min: 0)
  .scaleY2Continuous(min: 0, max: 100)
  .build()

Interactive Bar Charts

Hover Effects

Add rich tooltips on hover:

CristalyseChart()
  .data(data)
  .mapping(x: 'quarter', y: 'revenue')
  .geomBar()
  .interaction(
    tooltip: TooltipConfig(
      builder: (point) {
        return Container(
          padding: EdgeInsets.all(8),
          decoration: BoxDecoration(
            color: Colors.black.withOpacity(0.8),
            borderRadius: BorderRadius.circular(4),
          ),
          child: Text(
            '${point.getDisplayValue('quarter')}: \$${point.getDisplayValue('revenue')}k',
            style: TextStyle(color: Colors.white),
          ),
        );
      },
    ),
  )
  .build()

Click Handlers

React to bar selection:

CristalyseChart()
  .data(data)
  .mapping(x: 'quarter', y: 'revenue')
  .geomBar()
  .interaction(
    click: ClickConfig(
      onTap: (point) {
        print('Clicked: ${point.data}');
        // Navigate to detail view
        showQuarterDetails(point.data);
      },
    ),
  )
  .build()

Best Practices

Common Use Cases

Sales Comparison

Compare performance across regions or time periods

Budget Analysis

Show spending breakdown with stacked bars

Survey Results

Display categorical survey responses

Performance Metrics

Rank teams or products by metrics

Next Steps