> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cristalyse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Updates

> Latest features, improvements, and fixes in Cristalyse

# Updates & Changelog

Stay informed about the latest features, improvements, and fixes in Cristalyse.

<Update label="April 4, 2026" description="v1.17.6">
  ### 🐛 Tooltip Flickering Fix

  **Smooth tooltips, no more jitter!**

  **What was fixed:**

  * **Eliminated tooltip flicker:** Tooltips no longer close and reopen when the mouse moves slightly while hovering over the same data point.
  * **Smart Point Detection:** The chart now intelligently detects when the hovered data point hasn't changed. If the tooltip content would be identical, the existing tooltip is preserved instead of being recreated.
  * **Comparison Logic:** Points are identified by `dataIndex + seriesName`, ensuring the fix works seamlessly with both single-series and multi-series charts.

  **Why this matters:**

  * Users can now hover naturally over data points without experiencing visual jitter.
  * Tooltips feel stable and responsive across all chart types.
  * No performance impact — the optimization actually reduces unnecessary DOM updates.

  **Quality Assurance:**

  * 297 tests pass — zero breaking changes.
  * Fully backward compatible.
  * Safe upgrade for all existing projects.
</Update>

<Update label="February 22, 2026" description="v1.17.5">
  ### 🐛 Layout Optimizations & Bug Fixes

  **Crisper layouts, less wasted space, and perfect combo charts!**

  **What was fixed:**

  * **Dynamic Left Padding:** Removed the hardcoded 80px left padding fallback. The chart now dynamically calculates the exact width needed for Y-axis labels and heatmaps.
  * **Memory & Clipping:** Fixed heatmap Y-axis layout clipping and resolved a `TextPainter` memory leak.
  * **Geometry Color Priorities:** Fixed a bug where explicit `geomLine(color: ...)` overrides were ignored if the data had categorical color mappings. You can now cleanly mix and match color logic in combo charts!
  * **Theme Adjustments:** Default `ChartTheme` padding has been tightened for a much cleaner out-of-the-box appearance.

  **Quality Assurance:**

  * 100% backward compatible API.
  * Fixes apply automatically to existing setups.
</Update>

<Update label="February 17, 2026" description="v1.17.4">
  ### 🎨 Example App UI Overhaul & Fixes

  **Major visual upgrade for the example app!**

  * **Dark Mode Support**: Example app now automatically adapts to system brightness.
  * **Theme & Palette Expansion**: Added **13 new color palettes** (Ocean, Warm, Neon, etc.) and High Contrast / Solarized themes.
  * **Gesture Fixes**: Replaced `SelectableText` with `Text` across interactive widgets to resolve touch conflicts.
  * **Code Quality**: Refactored theme management for better type safety and maintainability.

  **Quality Assurance:**

  * Zero changes to library code (safe upgrade).
</Update>

<Update label="February 9, 2026" description="v1.17.3">
  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!

  **Reviewed and documented by maintainer [@rudi-q](https://github.com/rudi-q)**

  ### 🐛 OrdinalScale Inversion Fix

  **Fixed coordinate inversion at scale boundaries!**

  **What was fixed:**

  * `OrdinalScale.invert()` now correctly maps screen coordinates back to domain categories even at the very edges of the range.
  * Previously, a calculation mismatch could cause index overflows or incorrect category selection.
  * The fix ensures mathematical consistency between forward scaling and inverse mapping.

  ### 📊 Enhanced Bar Chart Examples

  **Better multi-series demonstration!**

  * Added grouped bar series to the example app data.
  * Demonstrated color mapping for categorical data in standard bar charts.
  * Improved data visualization examples for developers.

  **Quality Assurance:**

  * Zero breaking changes.
  * Fully backward compatible.
</Update>

<Update label="December 15, 2025" description="v1.17.2">
  ### 🐛 Tooltip Offset Fix

  **Fixed tooltip positioning when panning!**

  **What was fixed:**

  * Tooltips now correctly align with data points even after panning the chart.
  * Previously, a mismatch between the estimated and actual plot area caused offsets.
  * The fix ensures the interaction detector uses the exact geometry calculated by the painter.

  **Quality Assurance:**

  * Zero breaking changes.
  * Fully backward compatible.
</Update>

<Update label="December 10, 2025" description="v1.17.1">
  ### 🐛 Interactive Legend Tooltip Fix

  **Tooltips now work correctly with interactive legends!**

  **What was fixed:**

  * Tooltips now appear when hovering over charts with `interactive: true` legends
  * Previously, enabling interactive legends caused tooltips to stop working
  * Affected chart types: line charts, area charts, bar charts, and all other geometries

  **Root Cause:**

  * When interactive legends filter data, the chart creates a new widget for filtered data
  * This filtered chart was missing the `ChartTooltipOverlay` wrapper
  * Fix ensures tooltip overlay is properly applied to filtered charts

  **Example:**

  ```dart theme={null}
  // Now works perfectly together!
  CristalyseChart()
    .data(salesData)
    .mapping(x: 'quarter', y: 'revenue', color: 'product')
    .geomBar(style: BarStyle.grouped)
    .legend(interactive: true)  // ✅ Click to toggle categories
    .interaction(
      tooltip: TooltipConfig(
        builder: (point) => Text(
          '${point.getDisplayValue('product')}: \$${point.getDisplayValue('revenue')}k',
        ),
      ),
    )
    .build()
  ```

  **Quality Assurance:**

  * All 297 tests passing
  * Zero breaking changes
  * Example app updated with demonstration

  [View legend documentation](/features/legends)
</Update>

<Update label="December 8, 2025" description="v1.17.0">
  ### 📊 Bar Chart Positive/Negative Value Styling

  **Smart rounded corners and conditional colors for financial charts!**

  **Smart Rounded Corners (`roundOutwardEdges`):**

  * Positive bars: Rounded top (vertical) or right (horizontal)
  * Negative bars: Rounded bottom (vertical) or left (horizontal)
  * Sharp edge at zero baseline for clean alignment
  * Works seamlessly with existing `borderRadius` parameter

  **Conditional Bar Colors:**

  * New `positiveColor` parameter for values >= 0
  * New `negativeColor` parameter for values \< 0
  * Smart fallback: positiveColor/negativeColor → color → colorScale → theme
  * Perfect for profit/loss, variance analysis, financial dashboards

  **Use Cases:**

  * Financial dashboards showing gains and losses
  * Variance charts highlighting positive and negative deviations
  * Performance metrics with above/below target visualization
  * Budget analysis with overspending and savings

  ```dart theme={null}
  // Financial Dashboard Example
  final profitLossData = [
    {'month': 'Jan', 'pnl': 45000.0},
    {'month': 'Feb', 'pnl': -12000.0},
    {'month': 'Mar', 'pnl': 67000.0},
    {'month': 'Apr', 'pnl': -8000.0},
  ];

  CristalyseChart()
    .data(profitLossData)
    .mapping(x: 'month', y: 'pnl')
    .geomBar(
      borderRadius: BorderRadius.circular(12),
      roundOutwardEdges: true,        // Smart rounding
      positiveColor: Colors.green,    // Gains
      negativeColor: Colors.red,      // Losses
    )
    .scaleXOrdinal()
    .scaleYContinuous()
    .build()
  ```

  **Enhanced Example App:**

  * Updated bar chart demo with positive/negative value showcase
  * Live demonstration at `#/bar-chart` route
  * Visual comparison of standard vs. smart-rounded bars

  **Bug Fixes:**

  * Fixed negative bar rendering (bars extending below zero)
  * Corrected bar rect calculation for negative heights

  **Code Quality:**

  * Extracted `_computeOutwardRRect()` helper to eliminate code duplication
  * Optimized example with const widgets and top-level data

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * All new parameters optional (default to `false`/`null`)
  * `flutter analyze` passes with no issues

  [View bar chart documentation](/charts/bar-charts#positivenegative-value-styling)
</Update>

<Update label="November 27, 2025" description="v1.16.0">
  ### 📏 Integer-Only Ticks

  **Force axis ticks to be integers!**

  **Integer-Only Ticks:**

  * New `integersOnly` parameter in `TickConfig`
  * Automatically clamps ticks to integer values
  * Ensures step size is at least 1
  * Ideal for count data (people, items, events) where fractional values don't make sense

  **Use Cases:**

  * Count data (e.g., number of users, items sold)
  * Discrete events
  * Avoiding "1.5 people" in charts

  ```dart theme={null}
  CristalyseChart()
    .scaleYContinuous(
      tickConfig: TickConfig(
        integersOnly: true,
      ),
    )
  ```

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * Production ready
</Update>

<Update label="November 11, 2025" description="v1.15.0">
  ### 🔍 Zoom & Pan Interactions

  **Pinch, scroll wheel, and button-based zooming!**

  **Zoom Interaction Modes:**

  * Pinch gestures for multi-touch zooming
  * Scroll wheel support for precise zoom control
  * Floating +/- buttons for touch-friendly interfaces
  * Independent X-axis, Y-axis, or dual-axis zooming

  **Zoom Configuration:**

  * New `ZoomConfig` class with extensive customization
  * `axes` parameter: Choose `ZoomAxis.x`, `ZoomAxis.y`, or `ZoomAxis.both`
  * `wheelSensitivity`: Fine-tune scroll wheel responsiveness (0.0005-0.0035)
  * `buttonStep`: Control zoom increment for +/- buttons (default 1.4x)
  * `maxScale` / `minScale`: Set zoom boundaries (default 16x / 1x)
  * `showButtons`: Toggle floating control buttons
  * `buttonAlignment` & `buttonPadding`: Customize button placement

  **Zoom Event Callbacks:**

  * `onZoomStart`, `onZoomUpdate`, `onZoomEnd` for lifecycle events
  * `ZoomInfo` provides real-time zoom metrics:
    * Current visible range: `visibleMinX`, `visibleMaxX`, `visibleMinY`, `visibleMaxY`
    * Scale factors: `scaleX`, `scaleY` (e.g., 4.0 = 4x zoom)
    * State: `ZoomState.start` / `update` / `end`

  **Quick Setup:**

  ```dart theme={null}
  CristalyseChart()
    .data(data)
    .mapping(x: 'day', y: 'revenue')
    .geomLine()
    .onZoom((info) {
      print('Zoom scale: ${info.scaleX}x');
    })
    .build()
  ```

  **Advanced Configuration:**

  ```dart theme={null}
  CristalyseChart()
    .data(data)
    .mapping(x: 'time', y: 'value')
    .geomLine()
    .interaction(
      zoom: ZoomConfig(
        enabled: true,
        axes: ZoomAxis.both,                    // Zoom both axes
        maxScale: 16.0,                         // Up to 16x zoom
        wheelSensitivity: 0.0015,               // Scroll sensitivity
        buttonStep: 1.4,                        // 40% step per button press
        showButtons: true,                      // Show +/- buttons
        onZoomUpdate: (info) {
          setState(() {
            zoomLevel = '${info.scaleX?.toStringAsFixed(1)}x';
          });
        },
      ),
    )
    .build()
  ```

  **New Example:**

  * Full zoom demo in example app showing all interaction methods
  * Live zoom state display with visible ranges and scale factors
  * Interactive controls to adjust sensitivity and zoom modes
  * Demonstrates combined zoom + pan workflows

  **Use Cases:**

  * Time-series exploration: Zoom into specific date ranges
  * Scientific visualizations: Independent X/Y axis zoom control
  * Mobile dashboards: Touch-friendly zoom buttons for accessibility
  * Financial charts: Precise zoom with scroll wheel support

  **Seamless Integration:**

  * Works alongside existing pan interactions
  * Respects domain boundaries and scale configuration
  * Responsive gesture handling (pinch, scroll, single-touch pan)
  * Full touch and mouse support across all platforms

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * All new parameters optional with sensible defaults

  [View zoom documentation](/features/interactions)
</Update>

<Update label="November 9, 2025" description="v1.14.0">
  ### 🎯 Tick Configuration for Scales

  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!

  **Reviewed and documented by maintainer [@rudi-q](https://github.com/rudi-q)**

  **Control Tick Generation:**

  * New `TickConfig` class for customizing tick marks and labels
  * `ticks` parameter: Specify explicit tick positions for precise control
  * `simpleLinear` flag: Generate uniform linear spacing instead of Wilkinson's algorithm

  **Use Cases:**

  * Industry-standard reference points (freezing point, percentiles, etc.)
  * Time-series charts with consistent intervals
  * Scientific/technical charts requiring uniform spacing
  * Matching ticks across multiple related charts

  **Example:**

  ```dart theme={null}
  CristalyseChart()
    .data(data)
    .mapping(x: 'time', y: 'value')
    .scaleXContinuous(
      tickConfig: TickConfig(simpleLinear: true),  // Uniform spacing
    )
    .scaleYContinuous(
      tickConfig: TickConfig(ticks: [0, 25, 50, 75, 100]),  // Custom ticks
    )
    .geomLine()
    .build()
  ```

  **New Example:**

  * TimeBasedLineChartWidget demonstrating TickConfig usage
  * Toggle between simple linear and Wilkinson's algorithm
  * Practical reference for common use cases

  **Technical Implementation:**

  * Added `TickConfig` class with `ticks` and `simpleLinear` properties
  * Extended `LinearScale` to accept and store `TickConfig`
  * Enhanced Wilkinson labeling algorithm with simple linear fallback
  * All three scale methods (`scaleXContinuous`, `scaleYContinuous`, `scaleY2Continuous`) now support `tickConfig`

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * New feature is opt-in with sensible defaults
  * Production ready

  [View tick configuration documentation](/advanced/scales)
</Update>

<Update label="November 3, 2025" description="v1.13.1">
  ### 🐛 Label Size Calculation Fix

  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this fix!

  **Fixed label size deduction based on formatter**

  * Label size now calculated based on actual text width with default font size
  * Ensures consistent and accurate label spacing in charts
  * Improves readability with properly-sized axis labels

  **Technical Improvements:**

  * Added `_calculatePixelsPerLabel()` method to measure text dimensions
  * Uses TextPainter with default TextStyle (fontSize: 12) for accurate measurement
  * Includes proper padding calculation (10px)
  * Applied to both LinearScale and OrdinalScale
  * Made `optimalPixelsPerLabel` private

  **Benefits:**

  * More accurate label sizing across all chart types
  * Better space utilization for axis labels
  * Consistent behavior regardless of label content

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * Focused single-file bug fix
  * Production ready
</Update>

<Update label="November 2, 2025" description="v1.13.0">
  ### 🎨 Legend Enhancements

  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!

  **Optional Y-Axis Titles in Legends!**

  **Legend Enhancements:**

  * New `showTitles` option to display Y-axis titles alongside legend entries
  * Improves chart legend readability when multiple Y-axes are present
  * Optional feature - legends work as before by default
  * Seamless integration with existing legend styling and layout

  **Use Cases:**

  * Multi-axis charts with clearer data context
  * Better legend readability for complex visualizations
  * Maintain visual hierarchy with optional titles

  **Technical Implementation:**

  * Extended `LegendWidget` to support optional Y-axis title rendering
  * Enhanced `legend.dart` core logic to handle title display
  * Updated chart configuration to expose new option
  * Comprehensive test coverage included

  **Quality Assurance:**

  * All existing tests continue to pass
  * Zero breaking changes - fully backward compatible
  * New feature is opt-in
  * Production ready
</Update>

<Update label="November 2, 2025" description="v1.12.1">
  ### 🐛 Right Padding & Secondary Y-Axis Fixes

  **Fixed excessive right padding and layout misalignment**

  * Removed hardcoded 80px padding applied unconditionally for secondary y-axis
  * Charts without secondary y-axis now use only theme padding (no waste)
  * Widget layout uses conservative estimate only when y2Scale exists
  * Painter performs precise calculation at paint time with full scale information
  * Eliminates divergence between layout and rendering phases
  * Added proper null checking for `y2Scale` to prevent unnecessary padding

  **Benefits:**

  * Better space utilization on single-axis charts
  * Proper secondary y-axis spacing based on actual label widths
  * Ensures hit-testing alignment for interactions (hover, click, pan)
  * Consistent plot area between layout and render phases

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * Improved interaction reliability with secondary y-axis charts
  * Maintains consistent dimensions during pan/zoom operations
</Update>

<Update label="November 1, 2025" description="v1.12.0">
  ### 🏔️ Boundary Clamping for Pan Operations

  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!

  **Control infinite panning with boundary clamping!**

  **Boundary Clamping:**

  * New `boundaryClampingX` and `boundaryClampingY` options in `PanConfig`
  * Prevents panning beyond data boundaries when enabled
  * Maintains intuitive pan behavior within configured domain limits
  * Perfect for constrained data exploration and guided navigation

  **Use Cases:**

  * Prevent users from panning too far from relevant data
  * Create bounded exploration areas for large datasets
  * Maintain data context during navigation
  * Improve UX for time-series and scientific visualizations

  ```dart theme={null}
  CristalyseChart()
    .data(timeSeriesData)
    .mapping(x: 'time', y: 'value')
    .geomLine()
    .interaction(
      pan: PanConfig(
        enabled: true,
        boundaryClampingX: true,  // Clamp X-axis panning
        boundaryClampingY: true,  // Clamp Y-axis panning
      ),
    )
    .build()
  ```

  **Technical Implementation:**

  * Scale boundaries tracked via `valuesBoundaries` in `LinearScale`
  * Pan domain clamping applied during interaction handling
  * Seamless integration with existing pan callbacks and pan controller
  * No changes to default behavior - opt-in feature

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * Default clamping disabled (infinite panning by default)
  * Tested with pan controller and manual pan interactions
  * Production ready
</Update>

<Update label="October 24, 2025" description="v1.11.1">
  ### 🐛 Y-axis Bounds Fix During Panning

  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this fix!

  **Fixed Y-axis getting stuck during X-axis pan operations**

  * Y-axis bounds now correctly update when configured with `updateYDomain: false`
  * Previously remained locked to original `panYDomain` bounds during X-axis panning
  * Enables proper dynamic Y-axis scaling while panning horizontally

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * Patch bump release
</Update>

<Update label="October 24, 2025" description="v1.11.0">
  ### 🎯 Programmatic Pan Controller

  **Code authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!

  **New PanController Class:**

  * External control of chart panning via new `PanController` class
  * `panTo(PanInfo)` method for programmatic pan operations
  * `panReset()` method to restore original chart view
  * ChangeNotifier-based architecture for reactive updates
  * Optional `controller` parameter in `PanConfig`

  **Enhanced Pan Configuration:**

  * Widget lifecycle management (initState, didUpdateWidget, dispose)
  * Automatic listener registration and cleanup
  * Full integration with existing pan callbacks

  ```dart theme={null}
  final panController = PanController();

  CristalyseChart()
    .data(data)
    .mapping(x: 'x', y: 'y')
    .geomLine()
    .interaction(
      pan: PanConfig(
        enabled: true,
        controller: panController,
      ),
    )
    .build();

  // Pan to specific range
  panController.panTo(PanInfo(
    visibleMinX: 500,
    visibleMaxX: 1500,
    state: PanState.update,
  ));

  // Reset to original view
  panController.panReset();
  ```

  **Use Cases:**

  * Programmatic zoom controls with buttons/sliders
  * Reset to original view functionality
  * Coordinated panning across multiple charts
  * External UI controls for chart navigation
  * Jump to specific data ranges programmatically

  **Quality Assurance:**

  * Zero breaking changes - fully backward compatible
  * Optional controller parameter (defaults to null)
  * Proper lifecycle management with listener cleanup
  * Example integration in pan\_example.dart
</Update>

<Update label="October 23, 2025" description="v1.10.3">
  ### 🐛 Scale Padding Fix

  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this fix!

  **Fixed chart shrinking when panning**

  * Scale padding now initialized before painting charts
  * Prevents setupYScale from changing padding during panning
  * Chart maintains consistent size during all pan operations
  * Smooth user experience without unintended resize behavior

  **Quality Assurance:**

  * All existing tests continue to pass
  * Zero breaking changes - fully backward compatible
</Update>

<Update label="October 21, 2025" description="v1.10.2">
  ### 🎨 Heat Map Unification & Bounds Validation

  **Authored by [@davidlrichmond](https://github.com/davidlrichmond)** - Thank you for this contribution!

  **Heat Map Color System Unification:**

  * Unified heat maps to use `GradientColorScale` for consistent color handling
  * Eliminates duplicate color logic between heat maps and other chart types
  * Improves code maintainability and reduces technical debt
  * Heat map colors now follow the same scaling principles as other geometries

  **Bounds Edge Cases & Validation:**

  * Fixed guard condition for corner case where `min > max` in bounds calculations
  * Prevents invalid scale configurations that could crash rendering
  * Added comprehensive test coverage for edge cases
  * Improved documentation for bounds behavior with notes on invalid configurations

  **Code Quality:**

  * Addressed code review feedback on refactored code
  * Fixed deprecated `int` RGB getters for Flutter compatibility
  * Applied code formatting linter fixes

  **Quality Assurance:**

  * Added 34 new test cases for bounds edge cases
  * Added 106 lines of tests for GradientColorScale functionality
  * All existing tests continue to pass
  * Zero breaking changes - fully backward compatible
</Update>

<Update label="October 21, 2025" description="v1.10.1">
  ### 🐛 Wilkinson Labeling Precision

  **Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this fix!

  **Fixed floating-point rounding in epoch millisecond label calculations**

  * Replaced `round()` with `roundToDouble()` for proper double precision handling
  * Resolves issues with large number labeling (e.g., epoch timestamps)
  * Added comprehensive test case for epoch millisecond labeling
  * Test validates correct tick generation: \[1760527000000.0, 1760528000000.0, 1760529000000.0, 1760530000000.0]

  **Technical Details:**

  * `_cleanNumber()` method in `WilkinsonLabeling` class now uses `roundToDouble()` instead of `round()`
  * Fixes edge case with very large timestamp values (>1.7 trillion milliseconds)
  * Maintains precision in float arithmetic for astronomical numbers

  **Quality Assurance:**

  * All 286 tests passing (285 existing + 1 new test)
  * Zero breaking changes - fully backward compatible
</Update>

<Update label="October 7, 2025" description="v1.10.0">
  ### 🎨 Axis Titles & Bubble Size Guide

  **Descriptive axis titles and visual bubble size legends!**

  **Axis Titles:**

  * Add titles to X, Y, and Y2 axes with optional `title` parameter
  * Smart positioning with automatic spacing calculations
  * Vertical axes display rotated titles (-90° for Y, +90° for Y2)
  * Theme-aware styling with customizable fonts

  **Bubble Size Guide:**

  * Visual legend shows min, mid, and max bubble sizes
  * Automatically appears when `title` provided on `geomBubble()`
  * Horizontal and vertical layout support
  * Seamlessly integrates with existing legend system

  ```dart theme={null}
  // Axis titles for clearer data context
  CristalyseChart()
    .data(timeSeriesData)
    .mapping(x: 'time', y: 'value')
    .geomLine()
    .scaleXContinuous(title: 'Time (seconds)')
    .scaleYContinuous(title: 'Temperature (°C)')
    .build()

  // Dual axis with titles
  CristalyseChart()
    .data(businessData)
    .mapping(x: 'month', y: 'revenue')
    .mappingY2('conversion')
    .geomBar(yAxis: YAxis.primary)
    .geomLine(yAxis: YAxis.secondary)
    .scaleXOrdinal(title: 'Month')
    .scaleYContinuous(title: 'Revenue ($K)')
    .scaleY2Continuous(title: 'Conversion Rate (%)')
    .build()

  // Bubble size guide in legend
  CristalyseChart()
    .data(companyData)
    .mapping(x: 'revenue', y: 'customers', size: 'marketShare')
    .geomBubble(
      title: 'Market Share (%)',  // Enables size guide
      minSize: 8.0,
      maxSize: 25.0,
    )
    .legend()  // Shows both category colors and size guide
    .build()
  ```

  **Bug Fixes:**

  * Fixed edge case where zero/negative bubble sizes could cause rendering errors
  * Added validation to ensure bubble legend sizes are always positive
  * Clamps invalid values to safe minimum (1.0px radius)
  * Prevents Container dimension errors with edge-case data

  **Technical Improvements:**

  * Precise spacing calculations for axis labels and titles
  * Pre-calculated label dimensions for optimal layout
  * Consistent spacing constants across all axes
  * Validated bubble sizes in legend rendering
  * 8 new edge case tests for bubble validation

  **Quality Assurance:**

  * All 285 tests passing (20 new tests added)
  * Zero breaking changes - fully backward compatible
  * Titles optional and render only when provided
  * Production ready
</Update>

<Update label="October 6, 2025" description="v1.9.0">
  ### 🎯 Interactive & Floating Legends

  **Authored by [@davidlrichmond](https://github.com/davidlrichmond)** - Valuable contribution!

  **Transform your charts with interactive legend controls and advanced positioning!**

  **Interactive Legend Toggle:**

  * Click-to-hide/show data points with visual feedback
  * Simple `.legend(interactive: true)` to enable
  * Toggled items show reduced opacity + strikethrough styling
  * Smooth chart updates with preserved color consistency
  * Both auto-managed and external state control

  **Floating Legend Positioning:**

  * New `LegendPosition.floating` with custom offsets
  * Negative offsets supported (legends outside chart bounds!)
  * `clipBehavior: Clip.none` enables overflow rendering
  * Full creative control over placement

  ```dart theme={null}
  // Interactive Legend (Auto-Managed)
  CristalyseChart()
    .data(salesData)
    .mapping(x: 'quarter', y: 'revenue', color: 'product')
    .geomBar(style: BarStyle.grouped)
    .legend(interactive: true) // Click to toggle!
    .build()

  // Floating Legend with Custom Position
  CristalyseChart()
    .data(data)
    .mapping(x: 'x', y: 'y', color: 'category')
    .geomPoint()
    .legend(
      position: LegendPosition.floating,
      floatingOffset: Offset(20, 20), // Custom position
    )
    .build()

  // Interactive + Floating + External State
  CristalyseChart()
    .data(data)
    .mapping(x: 'x', y: 'y', color: 'category')
    .geomLine()
    .legend(
      interactive: true,
      position: LegendPosition.floating,
      floatingOffset: Offset(-10, 30), // Can overflow!
      hiddenCategories: myHiddenSet,
      onToggle: (category, visible) => handleToggle(category, visible),
    )
    .build()
  ```

  **Enhanced API:**

  * `interactive`: Enable click-to-toggle functionality
  * `hiddenCategories`: External state management
  * `onToggle`: Custom toggle callbacks
  * `floatingOffset`: Precise Offset positioning

  **Color Consistency Fixed:**

  * Original ColorScale preserved when filtering
  * No color shifting when toggling categories
  * Chart painter respects provided ColorScale

  **Theme-Aware Backgrounds:**

  * Legend backgrounds adapt to theme colors
  * Automatic contrast for light/dark modes
  * No hardcoded white backgrounds

  **Quality Assurance:**

  * All 268 tests passing
  * Zero breaking changes
  * Production ready

  [View legend documentation](/features/legends)
</Update>

<Update label="October 4, 2025" description="v1.8.1">
  ### 🔗 Enhanced Developer Experience

  **Seamless navigation between documentation and live examples!**

  * **Bidirectional Links**: Jump between docs and example app instantly
  * **View Docs Button**: All 19 example app screens link to documentation
  * **View Live Example Cards**: 9 chart docs pages link to interactive examples
  * **Better Learning Flow**: Quickly switch from reading to seeing live code

  **Documentation Navigation:**

  * Scatter plots, line charts, bar charts, area charts
  * Bubble charts, pie charts, dual-axis charts
  * Heat maps, progress bars
  * Opens in appropriate context (external browser for app, new tab for docs)

  **Technical Improvements:**

  * Clean architecture with single source of truth for URL mappings
  * Type-safe implementation with proper null checks
  * Consistent UI patterns across both navigation methods
  * Added `url_launcher` package for external link handling

  ```dart theme={null}
  // Example app now has "View Docs" button on each chart
  // Documentation now has "View Live Example" cards
  // Perfect for learning and exploring!
  ```

  **Quality Assurance:**

  * All Flutter analyze checks passing
  * Zero breaking changes
  * Backward compatible
</Update>

<Update label="October 1, 2025" description="v1.8.0">
  ### 🎯 Intelligent Axis Bounds & Labeling

  **Authored by [@davidlrichmond](https://github.com/davidlrichmond)** - Exceptional contribution!

  **Wilkinson Extended Algorithm for professional axis labels:**

  * Based on IEEE paper by Talbot, Lin, and Hanrahan (2010)
  * Generates "nice" round numbers: 0, 5, 10, 50, 100
  * Optimizes simplicity, coverage, density, and legibility
  * Smart pruning for performance

  **Geometry-Aware Bounds:**

  * Bar/area charts: Zero baseline for quantity comparison
  * Line/scatter charts: Data-driven bounds for trend analysis
  * Automatic appropriate defaults based on chart type

  ```dart theme={null}
  // Prettier axis labels automatically!
  // Before: 0.47, 5.23, 10.88, 15.91, 21.07
  // After:  0, 5, 10, 15, 20

  CristalyseChart()
    .data(data)
    .mapping(x: 'time', y: 'value')
    .geomLine()
    .scaleYContinuous()  // Smart bounds automatically!
    .build()

  // New bubble size limits
  chart.geomBubble(
    minSize: 8.0,
    maxSize: 25.0,
    limits: (1000, 50000),  // Scale domain control
  )
  ```

  **Testing & Quality:**

  * 803 lines of new tests added
  * All 263 tests passing
  * Zero breaking changes
  * Production ready

  [View axis bounds documentation](/advanced/scales)
</Update>

<Update label="September 30, 2025" description="v1.7.0">
  ### 📊 Progress Bar Charts

  **Professional progress visualization with multiple styles!**

  * **Multiple Orientations**: Horizontal, vertical, and circular progress bars
  * **Advanced Styles**: Stacked, grouped, gauge, and concentric layouts
  * **Theme-Responsive**: Full dark mode and custom palette support
  * **Robust Validation**: Comprehensive input validation and error handling

  ```dart theme={null}
  // Stacked Progress Bar
  CristalyseChart()
    .data([
      {'project': 'App', 'stage': 'Design', 'progress': 30.0},
      {'project': 'App', 'stage': 'Development', 'progress': 50.0},
      {'project': 'App', 'stage': 'Testing', 'progress': 20.0},
    ])
    .mappingProgress(category: 'project', value: 'progress', group: 'stage')
    .geomProgress(
      style: ProgressStyle.stacked,
      orientation: ProgressOrientation.horizontal,
    )
    .build()
  ```

  **Documentation Improvements:**

  * Enhanced SEO with comprehensive metadata
  * Custom 404 page with helpful navigation
  * Subscribable RSS feed for updates
  * Fixed all broken links
  * Improved contextual menu copy
</Update>

<Update label="September 8, 2025" description="v1.6.1">
  ### 🤖 MCP Server Integration

  **Cristalyse now integrates with AI coding assistants!**

  * New documentation guide for connecting Cristalyse docs to AI coding assistants (Cursor, Windsurf, Warp, Claude)
  * Enable AI assistants to access complete documentation, examples, and best practices directly in your IDE
  * Setup instructions: Add `"cristalyse_docs": {"url": "https://docs.cristalyse.com/mcp"}` to MCP settings

  [Learn more about MCP Server](/cristalyse-mcp-server)
</Update>

<Update label="September 7, 2025" description="v1.6.0">
  ### 🌈 Gradient Color Support (Experimental)

  **Transform your charts with stunning gradient effects!**

  * Category-specific gradients with `categoryGradients` property
  * Support for Linear, Radial, and Sweep gradients
  * Advanced alpha blending that respects animation transparency
  * Works with bar charts and scatter plots

  ```dart theme={null}
  CristalyseChart()
    .data(data)
    .mapping(x: 'quarter', y: 'revenue', color: 'quarter')
    .geomBar()
    .customPalette(categoryGradients: {
      'Q1': LinearGradient(colors: [Colors.blue, Colors.cyan]),
      'Q2': RadialGradient(colors: [Colors.red, Colors.orange]),
    })
    .build()
  ```

  ⚠️ **Note:** Not advisable for production use as of v1.6.0
</Update>

<Update label="September 5, 2025" description="v1.5.0">
  ### 🔥 Built-In Legend Support

  **Professional legends with zero configuration!**

  * Simple `.legend()` method with smart defaults
  * 8 flexible positioning options (topLeft, topRight, bottom, etc.)
  * Automatic symbol generation based on chart type
  * Full dark mode support with theme-aware text colors

  ```dart theme={null}
  CristalyseChart()
    .data(salesData)
    .mapping(x: 'quarter', y: 'revenue', color: 'product')
    .geomBar(style: BarStyle.grouped)
    .legend() // That's it! ✨
    .build()
  ```

  [View legend documentation](/features/legends)
</Update>

<Update label="September 3, 2025" description="v1.4.0">
  ### 🎨 Custom Category Colors

  **Brand-consistent charts with custom color palettes!**

  * New `customPalette()` method for category-specific colors
  * Smart fallback system for unmapped categories
  * Perfect for corporate dashboards and brand consistency

  ```dart theme={null}
  final platformColors = {
    'iOS': const Color(0xFF007ACC),      // Apple Blue
    'Android': const Color(0xFF3DDC84),  // Android Green
    'Web': const Color(0xFFFF6B35),      // Web Orange
  };

  CristalyseChart()
    .customPalette(categoryColors: platformColors)
    .build()
  ```
</Update>

<Update label="September 3, 2025" description="v1.3.1">
  ### 🐛 Multi-Series Line Chart Fixes

  * Fixed critical rendering issues with multi-series line charts
  * Resolved missing data points on multi-series visualizations
  * Fixed overlapping series lines for better visual separation
</Update>

<Update label="September 2, 2025" description="v1.3.0">
  ### 🫧 Bubble Chart Support

  **Three-dimensional data visualization is here!**

  * Full bubble chart implementation with size mapping
  * Advanced `SizeScale` class for proportional bubble sizing
  * Interactive tooltips with rich hover information
  * New `geomBubble()` API following grammar of graphics

  ```dart theme={null}
  CristalyseChart()
    .data(companyData)
    .mapping(
      x: 'revenue',
      y: 'customers',
      size: 'marketShare',
      color: 'category',
    )
    .geomBubble(
      minSize: 8.0,
      maxSize: 25.0,
      alpha: 0.75,
    )
    .build()
  ```

  [View bubble chart documentation](/charts/bubble-charts)
</Update>

<Update label="August 30, 2025" description="v1.2.4">
  ### Bug Fixes & Improvements

  * Fixed heatmap cell ordering to match axis labels
  * Fixed horizontal grouped bar charts crash
  * Fixed heatmap alpha calculation overflow
  * Improved code quality with comprehensive docstrings
</Update>

<Update label="August 24, 2025" description="v1.2.2">
  ### 🎨 Enhanced HeatMap Text Readability

  * Improved text visibility for low-value cells
  * Values \< 15% now display with black text for guaranteed readability
  * Values ≥ 15% use smart brightness-based contrast
  * Zero breaking changes - fully backward compatible
</Update>

<Update label="August 18, 2025" description="v1.2.0">
  ### 🔥 Heat Map Chart Support

  **Visualize 2D data patterns with professional heat maps!**

  * Comprehensive heat map implementation with customizable styling
  * Advanced color mapping with smooth gradients
  * Wave-effect animations with staggered cell appearance
  * Smart value visualization with automatic contrast detection

  ```dart theme={null}
  CristalyseChart()
    .data(salesData)
    .mappingHeatMap(x: 'month', y: 'region', value: 'revenue')
    .geomHeatMap(
      cellSpacing: 2.0,
      colorGradient: [Colors.red, Colors.yellow, Colors.green],
      showValues: true,
    )
    .build()
  ```

  [View heat map documentation](/charts/heat-map-charts)
</Update>

<Update label="August 5, 2025" description="v1.1.0">
  ### 🎯 Advanced Label Formatting

  **Professional data visualization with NumberFormat integration!**

  * Full callback-based label formatting system
  * Seamless integration with Flutter's `intl` package
  * Currency, percentages, compact notation support

  ```dart theme={null}
  CristalyseChart()
    .scaleYContinuous(
      labels: NumberFormat.simpleCurrency().format  // $1,234.56
    )
    .build()
  ```

  🙏 **Feature authored by [@davidlrichmond](https://github.com/davidlrichmond)**
</Update>

<Update label="July 31, 2025" description="v1.0.1">
  ### Fixed

  * **Grouped Bar Chart Alignment**: Fixed positioning of grouped bars on ordinal scales
  * Bars now center properly on tick marks
  * Thanks [@davidlrichmond](https://github.com/davidlrichmond)!
</Update>

<Update label="July 10, 2025" description="v1.0.0">
  ### 🥧 Pie & Donut Charts

  **Major v1.0 release with comprehensive pie chart support!**

  * Full pie chart and donut chart implementation
  * Smooth slice animations with staggered timing
  * Smart label positioning with percentage display
  * Exploded slice functionality for emphasis
  * New `.mappingPie()` and `.geomPie()` API

  ```dart theme={null}
  CristalyseChart()
    .mappingPie(value: 'revenue', category: 'department')
    .geomPie(
      outerRadius: 120.0,
      innerRadius: 60.0,  // Creates donut
      showLabels: true,
    )
    .build()
  ```

  [View pie chart documentation](/charts/pie-charts)
</Update>

<Update label="July 4, 2025" description="v0.9.4 - v0.9.3">
  ### 📖 Documentation Site Launch

  * **[docs.cristalyse.com](https://docs.cristalyse.com)** is now live!
  * Comprehensive guides, examples, and API reference
  * Improved web WASM compatibility
</Update>

<Update label="July 3, 2025" description="v0.9.2">
  ### Advanced Pan Control System

  * Fixed chart position reset bug
  * Infinite panning capability in any direction
  * Visual clipping implementation for clean boundaries
  * Selective axis panning with `updateXDomain` and `updateYDomain`

  Perfect for exploring large datasets!
</Update>

<Update label="July 2, 2025" description="v0.9.0">
  ### Enhanced SVG Export

  * Professional-quality vector graphics output
  * Support for all chart types
  * Perfect for presentations and reports
  * Editable in Figma, Adobe Illustrator, etc.
</Update>

<Update label="July 2, 2025" description="v0.8.0">
  ### 🎨 Area Chart Support

  **Visualize volume and trends with area charts!**

  * Comprehensive `AreaGeometry` with customizable styling
  * Progressive area animations
  * Multi-series support with transparency
  * Dual Y-axis compatibility

  ```dart theme={null}
  CristalyseChart()
    .geomArea(
      strokeWidth: 2.0,
      alpha: 0.3,
      fillArea: true,
    )
    .build()
  ```

  [View area chart documentation](/charts/area-charts)
</Update>

<Update label="June 30, 2025" description="v0.7.0">
  ### Interactive Panning System

  * Persistent pan state across gestures
  * Real-time visible range synchronization
  * Comprehensive `PanConfig` API with callbacks
  * Perfect for time series data exploration
</Update>

<Update label="June 21, 2025" description="v0.6.0">
  ### 🎯 Interactive Chart Layer

  **Tooltips, hover, and click interactions!**

  * New interaction system for user engagement
  * Flexible tooltip system with `TooltipConfig`
  * `onHover`, `onExit`, and `onTap` callbacks

  ```dart theme={null}
  CristalyseChart()
    .interaction(
      tooltip: TooltipConfig(
        builder: (point) => MyCustomTooltip(point: point),
      ),
      click: ClickConfig(
        onTap: (point) => showDetails(point),
      ),
    )
    .build()
  ```

  [View interaction documentation](/features/interactions)
</Update>

<Update label="June 14, 2025" description="v0.5.0">
  ### 🚀 Dual Y-Axis Support

  **Professional business dashboards unlocked!**

  * Independent left and right Y-axes
  * New `.mappingY2()` and `.scaleY2Continuous()` methods
  * Perfect for Revenue vs Conversion Rate charts
  * Fixed ordinal scale support for lines and points

  ```dart theme={null}
  CristalyseChart()
    .mapping(x: 'month', y: 'revenue')
    .mappingY2('conversion_rate')
    .geomBar(yAxis: YAxis.primary)
    .geomLine(yAxis: YAxis.secondary)
    .scaleY2Continuous(min: 0, max: 100)
    .build()
  ```

  [View dual axis documentation](/charts/dual-axis)
</Update>

<Update label="June 12, 2025" description="v0.4.4 - v0.4.0">
  ### Bar Charts & Theming

  * **Stacked Bar Charts**: Full support with progressive animations
  * **Enhanced Theming**: Solarized Light/Dark themes
  * **Color Palettes**: Warm, cool, and pastel options
  * **Horizontal Bars**: Via `coordFlip()` method
</Update>

<Update label="June 8, 2025" description="v0.2.0">
  ### Line Charts & Animations

  * Line chart support with `geomLine()`
  * Configurable animations with curves
  * Multi-series support with color grouping
  * Progressive line drawing animations
  * Dark theme support
</Update>

<Update label="June 8, 2025" description="v0.1.0">
  ### 🎉 Initial Release

  **Cristalyse is born!**

  * Basic scatter plot support
  * Grammar of graphics API
  * Linear scales for continuous data
  * Light and dark themes
  * Cross-platform Flutter support
</Update>
