Skip to content

Commit 8de9e7a

Browse files
jbbjarnasonrudi-q
authored andcommitted
release 1.13.0 feat: add optional show titles y axes for legends (#63)
1 parent 625cf42 commit 8de9e7a

File tree

14 files changed

+348
-66
lines changed

14 files changed

+348
-66
lines changed

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
## 1.13.0 - 2025-11-02
2+
3+
#### 🎨 Legend Enhancements
4+
5+
**Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!
6+
7+
**Reviewed and documented by maintainer [@rudi-q](https://github.com/rudi-q)**
8+
9+
**New Features:**
10+
- **Optional Y-Axis Titles in Legends**: Add `showTitles` option to display Y-axis titles alongside legend entries
11+
- Improves chart legend readability when multiple Y-axes are present
12+
- Optional feature - legends work as before by default
13+
- Seamless integration with existing legend styling and layout
14+
15+
**Technical Implementation:**
16+
- Extended `LegendWidget` to support optional Y-axis title rendering
17+
- Enhanced `legend.dart` core logic to handle title display
18+
- Updated chart configuration to expose new option
19+
- Includes comprehensive test coverage
20+
21+
#### 🧪 Quality Assurance
22+
23+
- Zero breaking changes - fully backward compatible
24+
- New feature is opt-in
25+
- All tests passing including new legend test cases
26+
- Production ready
27+
28+
---
29+
130
## 1.12.1 - 2025-11-02
231

332
#### 🐛 Bug Fixes

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,7 @@ chart
11011101

11021102
## 🧪 Development Status
11031103

1104-
**Current Version: 1.12.1** - Production ready with boundary clamping for pan operations, programmatic pan controller, interactive floating legends, and intelligent axis bounds
1104+
**Current Version: 1.13.0** - Production ready with optional Y-axis titles in legends, boundary clamping for pan operations, programmatic pan controller, interactive floating legends, and intelligent axis bounds
11051105

11061106
We're shipping progressively! Each release adds new visualization types while maintaining backward compatibility.
11071107

@@ -1127,6 +1127,7 @@ We're shipping progressively! Each release adds new visualization types while ma
11271127
-**v1.10.0** - **Axis titles & bubble size guide** with optional titles for all axes, visual bubble size legends, smart spacing calculations, and bubble legend validation fixes (by [@davidlrichmond](https://github.com/davidlrichmond))
11281128
-**v1.11.0** - **Programmatic pan controller** for external chart panning control via PanController with panTo() and panReset() methods (by [@jbbjarnason](https://github.com/jbbjarnason))
11291129
-**v1.12.0** - **Boundary clamping for pan operations** with optional boundaryClampingX and boundaryClampingY to prevent infinite panning beyond data boundaries (by [@jbbjarnason](https://github.com/jbbjarnason))
1130+
-**v1.13.0** - **Optional Y-axis titles in legends** for improved multi-axis chart readability (by [@jbbjarnason](https://github.com/jbbjarnason))
11301131

11311132
## Support This Project
11321133

doc/features/legends.mdx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,46 @@ If you were manually creating legends, you can now use the built-in functionalit
642642
</Accordion>
643643
</AccordionGroup>
644644

645+
## Y-Axis Titles in Legends
646+
647+
<Info>
648+
**New in v1.13.0**: Display Y-axis titles alongside legend entries for multi-axis charts!
649+
</Info>
650+
651+
For dual-axis charts, show axis titles in the legend to clarify which data series maps to which Y-axis:
652+
653+
```dart
654+
CristalyseChart()
655+
.data(dualAxisData)
656+
.mapping(x: 'month', y: 'revenue')
657+
.mappingY2('conversion_rate')
658+
.geomBar(yAxis: YAxis.primary)
659+
.geomLine(yAxis: YAxis.secondary)
660+
.scaleYContinuous(title: 'Revenue ($K)')
661+
.scaleY2Continuous(title: 'Conversion Rate (%)')
662+
.legend(
663+
position: LegendPosition.bottom,
664+
showTitles: true, // Show axis titles in legend
665+
)
666+
.build();
667+
```
668+
669+
**Features**:
670+
- Displays Y-axis titles alongside respective data series
671+
- Improves legend readability for multi-axis charts
672+
- Helps users understand which metric uses which axis
673+
- Works with all legend positioning options
674+
675+
### Parameters
676+
677+
| Parameter | Type | Default | Description |
678+
|-----------|------|---------|-------------|
679+
| `showTitles` | `bool` | `false` | Display Y-axis titles in legend entries |
680+
681+
<Tip>
682+
**Pro Tip**: Combine `showYAxisTitles` with descriptive axis titles for maximum clarity in multi-axis charts.
683+
</Tip>
684+
645685
## What's Next?
646686

647687
- Learn about [Custom Themes](/advanced/custom-themes) to create branded chart experiences

doc/installation.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ If you prefer to add the dependency manually, update your `pubspec.yaml`:
2626
dependencies:
2727
flutter:
2828
sdk: flutter
29-
cristalyse: ^1.12.0 # Latest version
29+
cristalyse: ^1.13.0 # Latest version
3030
```
3131
3232
Then run:
@@ -105,6 +105,7 @@ Cristalyse has minimal dependencies to keep your app lightweight:
105105

106106
| Version | Release Date | Key Features |
107107
|---------|-------------|--------------|
108+
| 1.13.0 | November 2025 | Optional Y-axis titles in legends |
108109
| 1.12.1 | November 2025 | Fixed right padding and secondary Y-axis alignment |
109110
| 1.12.0 | November 2025 | Boundary clamping for pan operations |
110111
| 1.11.1 | October 2025 | Fixed Y-axis bounds during X-axis panning |

doc/updates.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,37 @@ seo:
1212

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

15+
<Update label="November 2, 2025" description="v1.13.0">
16+
### 🎨 Legend Enhancements
17+
18+
**Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!
19+
20+
**Optional Y-Axis Titles in Legends!**
21+
22+
**Legend Enhancements:**
23+
- New `showTitles` option to display Y-axis titles alongside legend entries
24+
- Improves chart legend readability when multiple Y-axes are present
25+
- Optional feature - legends work as before by default
26+
- Seamless integration with existing legend styling and layout
27+
28+
**Use Cases:**
29+
- Multi-axis charts with clearer data context
30+
- Better legend readability for complex visualizations
31+
- Maintain visual hierarchy with optional titles
32+
33+
**Technical Implementation:**
34+
- Extended `LegendWidget` to support optional Y-axis title rendering
35+
- Enhanced `legend.dart` core logic to handle title display
36+
- Updated chart configuration to expose new option
37+
- Comprehensive test coverage included
38+
39+
**Quality Assurance:**
40+
- All existing tests continue to pass
41+
- Zero breaking changes - fully backward compatible
42+
- New feature is opt-in
43+
- Production ready
44+
</Update>
45+
1546
<Update label="November 2, 2025" description="v1.12.1">
1647
### 🐛 Right Padding & Secondary Y-Axis Fixes
1748

example/lib/graphs/dual_axis_chart.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ Widget buildDualAxisTab(ChartTheme currentTheme,
2626
height: 400,
2727
child: CristalyseChart()
2828
.data(data)
29-
.mapping(x: 'month', y: 'revenue') // Primary Y-axis (left)
29+
.legend(
30+
position: LegendPosition.right,
31+
interactive: true,
32+
showTitles: true)
33+
.mapping(
34+
x: 'month',
35+
y: 'revenue',
36+
color: 'product') // Primary Y-axis (left)
3037
.mappingY2('conversion_rate') // Secondary Y-axis (right)
3138
.geomBar(
3239
width: sliderValue.clamp(0.1, 1.0),

example/lib/screens/chart_screen.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,21 @@ class _ChartScreenState extends State<ChartScreen>
210210
seasonalConversion +
211211
(math.Random().nextDouble() - 0.5) * 2;
212212

213-
final dataPoint = {
213+
final revenuePoint = {
214214
'month': month,
215215
'revenue': math.max(80.0, revenue), // Ensure positive revenue
216+
'product': 'Product Sales',
217+
};
218+
219+
final conversionPoint = {
220+
'month': month,
216221
'conversion_rate': math.max(10.0,
217222
math.min(30.0, conversionRate)), // Keep conversion rate reasonable
223+
'product': 'Conversion Rate',
218224
};
219225

220-
_dualAxisData.add(dataPoint);
226+
_dualAxisData.add(revenuePoint);
227+
_dualAxisData.add(conversionPoint);
221228
}
222229
}
223230

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ packages:
8787
path: ".."
8888
relative: true
8989
source: path
90-
version: "1.12.1"
90+
version: "1.13.0"
9191
crypto:
9292
dependency: transitive
9393
description:

lib/src/core/chart.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ class CristalyseChart {
828828
///
829829
/// Automatically generates a legend based on the color mapping column.
830830
/// Only works when a `color` mapping is defined in `.mapping()`.
831+
/// Show titles for y and y2 axes titles for the legend group if showTitles is true.
831832
///
832833
/// Basic usage:
833834
/// ```dart
@@ -897,6 +898,7 @@ class CristalyseChart {
897898
bool? interactive,
898899
Set<String>? hiddenCategories,
899900
void Function(String category, bool visible)? onToggle,
901+
bool? showTitles,
900902
}) {
901903
_legendConfig = LegendConfig(
902904
position: position ?? LegendPosition.topRight,
@@ -913,6 +915,7 @@ class CristalyseChart {
913915
interactive: interactive ?? false,
914916
hiddenCategories: hiddenCategories,
915917
onToggle: onToggle,
918+
showTitles: showTitles ?? false,
916919
);
917920
return this;
918921
}

lib/src/core/legend.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class LegendConfig {
7575
final void Function(String category, bool visible)?
7676
onToggle; // Callback when legend item is toggled
7777

78+
/// Whether to show y and y2 axes titles for the legend group
79+
final bool showTitles;
80+
7881
const LegendConfig({
7982
this.position = LegendPosition.topRight,
8083
this.orientation = LegendOrientation.auto,
@@ -90,6 +93,7 @@ class LegendConfig {
9093
this.interactive = false,
9194
this.hiddenCategories,
9295
this.onToggle,
96+
this.showTitles = false,
9397
});
9498

9599
/// Get the effective orientation based on position
@@ -156,7 +160,8 @@ class LegendConfig {
156160
borderRadius == other.borderRadius &&
157161
floatingOffset == other.floatingOffset &&
158162
floatingDraggable == other.floatingDraggable &&
159-
interactive == other.interactive;
163+
interactive == other.interactive &&
164+
showTitles == other.showTitles;
160165
// Note: hiddenCategories and onToggle intentionally excluded from equality
161166

162167
@override
@@ -190,6 +195,7 @@ class LegendConfig {
190195
bool? interactive,
191196
Set<String>? hiddenCategories,
192197
void Function(String, bool)? onToggle,
198+
bool? showTitles,
193199
}) {
194200
return LegendConfig(
195201
position: position ?? this.position,
@@ -206,6 +212,7 @@ class LegendConfig {
206212
interactive: interactive ?? this.interactive,
207213
hiddenCategories: hiddenCategories ?? this.hiddenCategories,
208214
onToggle: onToggle ?? this.onToggle,
215+
showTitles: showTitles ?? this.showTitles,
209216
);
210217
}
211218
}

0 commit comments

Comments
 (0)