Skip to content

Commit 1d33e39

Browse files
jbbjarnasonrudi-q
authored andcommitted
release 1.14.0 feat: add tick config for scales (#60)
1 parent 41037e1 commit 1d33e39

File tree

13 files changed

+370
-18
lines changed

13 files changed

+370
-18
lines changed

CHANGELOG.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,58 @@
1+
## 1.14.0 - 2025-11-09
2+
3+
#### 🎯 Tick Configuration for Scales
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+
- **TickConfig Class**: Control tick generation on continuous scales
11+
- `ticks: List<double>?` - Specify explicit tick positions
12+
- `simpleLinear: bool` - Use uniform linear spacing instead of Wilkinson's algorithm
13+
- Optional parameters - scales work as before by default
14+
15+
- **Explicit Tick Specification**: Pass custom tick positions for precise control
16+
- Industry-standard reference points (freezing point, percentiles, etc.)
17+
- Domain-specific intervals for specialized charts
18+
- Consistent tick positions across multiple related charts
19+
20+
- **Simple Linear Ticking**: Generate evenly-spaced ticks
21+
- Predictable, uniform tick intervals
22+
- Ideal for time-series and scientific/technical charts
23+
- Alternative to default Wilkinson's algorithm
24+
25+
**Technical Implementation:**
26+
- Added `TickConfig` class with `ticks` and `simpleLinear` properties
27+
- Extended `LinearScale` to accept and store `TickConfig`
28+
- `scaleXContinuous`, `scaleYContinuous`, `scaleY2Continuous` now accept optional `tickConfig` parameter
29+
- Enhanced Wilkinson labeling algorithm with simple linear fallback
30+
- New example: TimeBasedLineChartWidget demonstrating TickConfig usage
31+
32+
**API Example:**
33+
```dart
34+
CristalyseChart()
35+
.data(data)
36+
.mapping(x: 'time', y: 'value')
37+
.scaleXContinuous(
38+
tickConfig: TickConfig(simpleLinear: true),
39+
)
40+
.scaleYContinuous(
41+
tickConfig: TickConfig(ticks: [0, 25, 50, 75, 100]),
42+
)
43+
.geomLine()
44+
.build()
45+
```
46+
47+
#### 🧪 Quality Assurance
48+
49+
- Zero breaking changes - fully backward compatible
50+
- New feature is opt-in with sensible defaults
51+
- Backward compatible API - all parameters optional
52+
- Production ready
53+
54+
---
55+
156
## 1.13.1 - 2025-11-03
257

358
#### 🐛 Bug Fixes

README.md

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

11021102
## 🧪 Development Status
11031103

1104-
**Current Version: 1.13.1** - Production ready with optional Y-axis titles in legends, boundary clamping for pan operations, programmatic pan controller, interactive floating legends, and intelligent axis bounds
1104+
**Current Version: 1.14.0** - Production ready with tick configuration for continuous scales, 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

@@ -1128,8 +1128,9 @@ We're shipping progressively! Each release adds new visualization types while ma
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))
11301130
-**v1.13.0** - **Optional Y-axis titles in legends** for improved multi-axis chart readability (by [@jbbjarnason](https://github.com/jbbjarnason))
1131+
-**v1.14.0** - **Tick configuration for scales** with explicit tick positions and simple linear spacing options (by [@jbbjarnason](https://github.com/jbbjarnason))
11311132

1132-
## Support This Project
1133+
|## Support This Project
11331134

11341135
**Love Cristalyse?** Your support helps me dedicate more time to building the Flutter charting library you deserve!
11351136

doc/advanced/scales.mdx

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,89 @@ CristalyseChart()
306306
.build()
307307
```
308308

309+
## Tick Configuration
310+
311+
<Info>
312+
**New in v1.14.0:** Control how tick marks and labels are generated on your axes!
313+
</Info>
314+
315+
TickConfig allows you to customize tick generation on continuous scales:
316+
317+
```dart
318+
TickConfig(
319+
ticks: [0, 25, 50, 75, 100], // Optional: specify explicit tick positions
320+
simpleLinear: true, // Optional: use simple linear ticks instead of Wilkinson's algorithm
321+
)
322+
```
323+
324+
### Explicit Tick Specification
325+
326+
Provide your own tick positions for precise control:
327+
328+
```dart
329+
CristalyseChart()
330+
.data(temperatureData)
331+
.mapping(x: 'hour', y: 'temp')
332+
.scaleYContinuous(
333+
tickConfig: TickConfig(
334+
ticks: [-10, 0, 10, 20, 30], // Custom tick positions
335+
),
336+
)
337+
.geomLine()
338+
.build()
339+
```
340+
341+
**Use cases:**
342+
- Industry-standard reference points (e.g., freezing point at 0°C)
343+
- Domain-specific intervals (e.g., percentiles at 25, 50, 75)
344+
- Matching ticks across multiple related charts
345+
346+
### Simple Linear Ticking
347+
348+
Generate evenly-spaced ticks instead of using Wilkinson's algorithm:
349+
350+
```dart
351+
CristalyseChart()
352+
.data(timeSeriesData)
353+
.mapping(x: 'timestamp', y: 'value')
354+
.scaleXContinuous(
355+
tickConfig: TickConfig(simpleLinear: true),
356+
)
357+
.scaleYContinuous(
358+
tickConfig: TickConfig(simpleLinear: true),
359+
)
360+
.geomLine()
361+
.build()
362+
```
363+
364+
**Differences:**
365+
- **Wilkinson's Algorithm** (default): Intelligently chooses "nice" numbers for human-readable labels. Tick intervals vary based on data range (e.g., 10, 25, 50, 100).
366+
- **Simple Linear**: Always generates evenly-spaced ticks. Tick interval is constant based on the scale range divided by number of ticks.
367+
368+
**When to use Simple Linear:**
369+
- Time-based charts where consistent intervals matter (e.g., hourly or daily splits)
370+
- Scientific/technical charts where precision is preferred over "niceness"
371+
- When you need predictable, uniform spacing
372+
373+
### Dual-Axis Example
374+
375+
```dart
376+
CristalyseChart()
377+
.data(businessData)
378+
.mapping(x: 'month', y: 'revenue')
379+
.mappingY2('conversion')
380+
.scaleXOrdinal()
381+
.scaleYContinuous(
382+
tickConfig: TickConfig(ticks: [0, 50000, 100000, 150000]),
383+
)
384+
.scaleY2Continuous(
385+
tickConfig: TickConfig(simpleLinear: true),
386+
)
387+
.geomBar(yAxis: YAxis.primary)
388+
.geomLine(yAxis: YAxis.secondary)
389+
.build()
390+
```
391+
309392
## Scale Customization
310393

311394
Customize scales to fit your data representation needs:

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.13.1 # Latest version
29+
cristalyse: ^1.14.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.14.0 | November 2025 | Tick configuration for continuous scales |
108109
| 1.13.1 | November 2025 | Fixed label size calculation with default font size |
109110
| 1.13.0 | November 2025 | Optional Y-axis titles in legends |
110111
| 1.12.1 | November 2025 | Fixed right padding and secondary Y-axis alignment |

doc/updates.mdx

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

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

15+
<Update label="November 9, 2025" description="v1.14.0">
16+
### 🎯 Tick Configuration for Scales
17+
18+
**Authored by [@jbbjarnason](https://github.com/jbbjarnason)** - Thank you for this contribution!
19+
20+
**Reviewed and documented by maintainer [@rudi-q](https://github.com/rudi-q)**
21+
22+
**Control Tick Generation:**
23+
- New `TickConfig` class for customizing tick marks and labels
24+
- `ticks` parameter: Specify explicit tick positions for precise control
25+
- `simpleLinear` flag: Generate uniform linear spacing instead of Wilkinson's algorithm
26+
27+
**Use Cases:**
28+
- Industry-standard reference points (freezing point, percentiles, etc.)
29+
- Time-series charts with consistent intervals
30+
- Scientific/technical charts requiring uniform spacing
31+
- Matching ticks across multiple related charts
32+
33+
**Example:**
34+
```dart
35+
CristalyseChart()
36+
.data(data)
37+
.mapping(x: 'time', y: 'value')
38+
.scaleXContinuous(
39+
tickConfig: TickConfig(simpleLinear: true), // Uniform spacing
40+
)
41+
.scaleYContinuous(
42+
tickConfig: TickConfig(ticks: [0, 25, 50, 75, 100]), // Custom ticks
43+
)
44+
.geomLine()
45+
.build()
46+
```
47+
48+
**New Example:**
49+
- TimeBasedLineChartWidget demonstrating TickConfig usage
50+
- Toggle between simple linear and Wilkinson's algorithm
51+
- Practical reference for common use cases
52+
53+
**Technical Implementation:**
54+
- Added `TickConfig` class with `ticks` and `simpleLinear` properties
55+
- Extended `LinearScale` to accept and store `TickConfig`
56+
- Enhanced Wilkinson labeling algorithm with simple linear fallback
57+
- All three scale methods (`scaleXContinuous`, `scaleYContinuous`, `scaleY2Continuous`) now support `tickConfig`
58+
59+
**Quality Assurance:**
60+
- Zero breaking changes - fully backward compatible
61+
- New feature is opt-in with sensible defaults
62+
- Production ready
63+
64+
[View tick configuration documentation](/advanced/scales)
65+
</Update>
66+
1567
<Update label="November 3, 2025" description="v1.13.1">
1668
### 🐛 Label Size Calculation Fix
1769

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import 'package:cristalyse/cristalyse.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:intl/intl.dart';
4+
5+
class TimeBasedLineChartWidget extends StatefulWidget {
6+
final ChartTheme currentTheme;
7+
final List<Map<String, dynamic>> data;
8+
final double sliderValue;
9+
10+
const TimeBasedLineChartWidget({
11+
super.key,
12+
required this.currentTheme,
13+
required this.data,
14+
required this.sliderValue,
15+
});
16+
17+
@override
18+
State<TimeBasedLineChartWidget> createState() =>
19+
_TimeBasedLineChartWidgetState();
20+
}
21+
22+
class _TimeBasedLineChartWidgetState extends State<TimeBasedLineChartWidget> {
23+
bool _simpleLinear = false;
24+
25+
@override
26+
Widget build(BuildContext context) {
27+
return SingleChildScrollView(
28+
padding: const EdgeInsets.all(16),
29+
child: Column(
30+
crossAxisAlignment: CrossAxisAlignment.start,
31+
children: [
32+
Text(
33+
'Animated Line Chart',
34+
style: TextStyle(
35+
fontSize: 18,
36+
fontWeight: FontWeight.w600,
37+
color: widget.currentTheme.axisColor,
38+
),
39+
),
40+
const SizedBox(height: 16),
41+
SizedBox(
42+
height: 400,
43+
child: CristalyseChart()
44+
.data(_data)
45+
.mapping(x: 'x', y: 'y')
46+
.geomLine(
47+
strokeWidth: 1.0 + widget.sliderValue * 9.0, alpha: 0.9)
48+
.scaleXContinuous(
49+
title: 'Timestamp',
50+
tickConfig: TickConfig(simpleLinear: _simpleLinear),
51+
labels: (value) {
52+
final date =
53+
DateTime.fromMillisecondsSinceEpoch(value.toInt());
54+
return DateFormat('MM/dd HH:mm:ss').format(date);
55+
})
56+
.scaleYContinuous(
57+
title: 'Value (units)',
58+
tickConfig: TickConfig(simpleLinear: _simpleLinear))
59+
.theme(widget.currentTheme)
60+
.build(),
61+
),
62+
// toggle switch
63+
SwitchListTile(
64+
title: const Text('Use simple linear ticks'),
65+
value: _simpleLinear,
66+
onChanged: (value) {
67+
setState(() {
68+
_simpleLinear = value;
69+
});
70+
},
71+
),
72+
],
73+
),
74+
);
75+
}
76+
}
77+
78+
// Keep the original function for backward compatibility
79+
Widget buildTimeBasedLineChartTab(ChartTheme currentTheme,
80+
List<Map<String, dynamic>> data, double sliderValue) {
81+
return TimeBasedLineChartWidget(
82+
currentTheme: currentTheme,
83+
data: data,
84+
sliderValue: sliderValue,
85+
);
86+
}
87+
88+
const _data = [
89+
{'x': 1761421958320.0, 'y': 4.900000095367432, 's': 'cooler.temp.avg'},
90+
{'x': 1761421959321.0, 'y': 5.0, 's': 'cooler.temp.avg'},
91+
{'x': 1761421960320.0, 'y': 5.0, 's': 'cooler.temp.avg'},
92+
{'x': 1761421961320.0, 'y': 4.900000095367432, 's': 'cooler.temp.avg'}
93+
];

example/lib/router/app_router.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ class AppRouter {
127127
return const ChartScreen(chartIndex: 19);
128128
},
129129
),
130+
GoRoute(
131+
path: '/time-based-line-chart',
132+
builder: (BuildContext context, GoRouterState state) {
133+
return const ChartScreen(chartIndex: 20);
134+
},
135+
),
130136
],
131137
);
132138

@@ -283,6 +289,13 @@ class AppRouter {
283289
isNew: true,
284290
docsUrl: 'https://docs.cristalyse.com/features/legends',
285291
),
292+
RouteInfo(
293+
path: '/time-based-line-chart',
294+
title: 'Time-Based Line Chart',
295+
icon: Icons.timeline,
296+
description: 'Line charts with time-based data',
297+
docsUrl: 'https://docs.cristalyse.com/charts/line-charts',
298+
),
286299
];
287300
}
288301

example/lib/screens/chart_screen.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import '../graphs/pie_chart.dart';
2525
import '../graphs/progress_bars.dart';
2626
import '../graphs/scatter_plot.dart';
2727
import '../graphs/stacked_bar_chart.dart';
28+
import '../graphs/time_based_line_chart.dart';
2829
import '../router/app_router.dart';
2930
import '../utils/chart_feature_list.dart';
3031

@@ -324,6 +325,7 @@ class _ChartScreenState extends State<ChartScreen>
324325
'Gradient Bar Charts',
325326
'Advanced Gradient Effects',
326327
'Legend Examples',
328+
'Time-Based Line Chart',
327329
];
328330
}
329331

@@ -349,6 +351,7 @@ class _ChartScreenState extends State<ChartScreen>
349351
'Beautiful gradient fills for enhanced visual appeal • Linear gradients from light to dark',
350352
'Multiple gradient types: Linear, Radial, Sweep • Works with bars and points',
351353
'Comprehensive legend showcase • 9 positioning options including new floating legends',
354+
'Line chart with time-based data on x-axis • ',
352355
];
353356
}
354357

@@ -571,6 +574,9 @@ class _ChartScreenState extends State<ChartScreen>
571574
case 19:
572575
return buildLegendExampleTab(
573576
currentTheme, _groupedBarData, _sliderValue);
577+
case 20:
578+
return buildTimeBasedLineChartTab(
579+
currentTheme, _lineChartData, _sliderValue);
574580
default:
575581
return Container();
576582
}

0 commit comments

Comments
 (0)