Skip to content

Commit a1ca331

Browse files
Added blog sample
1 parent d0f2980 commit a1ca331

9 files changed

Lines changed: 635 additions & 2 deletions

.gitignore

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
migrate_working_dir/
12+
13+
# IntelliJ related
14+
*.iml
15+
*.ipr
16+
*.iws
17+
.idea/
18+
19+
# The .vscode folder contains launch configuration and tasks you configure in
20+
# VS Code which you may wish to be included in version control, so this line
21+
# is commented out by default.
22+
#.vscode/
23+
24+
# Flutter/Dart/Pub related
25+
**/doc/api/
26+
**/ios/Flutter/.last_build_id
27+
.dart_tool/
28+
.flutter-plugins
29+
.flutter-plugins-dependencies
30+
.pub-cache/
31+
.pub/
32+
/build/
33+
34+
# Symbolication related
35+
app.*.symbols
36+
37+
# Obfuscation related
38+
app.*.map.json
39+
40+
# Android Studio will place build artifacts here
41+
/android/app/debug
42+
/android/app/profile
43+
/android/app/release

.metadata

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3"
8+
channel: "stable"
9+
10+
project_type: app
11+
12+
# Tracks metadata for the flutter migrate command
13+
migration:
14+
platforms:
15+
- platform: root
16+
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
17+
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
18+
- platform: android
19+
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
20+
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
21+
- platform: ios
22+
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
23+
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
24+
- platform: linux
25+
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
26+
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
27+
- platform: macos
28+
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
29+
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
30+
- platform: web
31+
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
32+
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
33+
- platform: windows
34+
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
35+
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
36+
37+
# User provided section
38+
39+
# List of Local paths (relative to this file) that should be
40+
# ignored by the migrate tool.
41+
#
42+
# Files that are not part of the templates will be ignored by default.
43+
unmanaged_files:
44+
- 'lib/main.dart'
45+
- 'ios/Runner.xcodeproj/project.pbxproj'

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,29 @@
1-
# flutter_scrollbar_chart
2-
flutter_scrollbar_chart
1+
# Flutter scrollbar Chart
2+
3+
This repository contains a sample that demonstrates how to create a scrollbar chart in Flutter using the Syncfusion Flutter Charts and Sliders packages.
4+
5+
## Syncfusion controls:
6+
7+
This project used the following Syncfusion widget(s):
8+
* [Charts](https://www.syncfusion.com/flutter-widgets/flutter-charts)
9+
* [Range Slider](https://www.syncfusion.com/flutter-widgets/flutter-range-slider)
10+
* [Range Selector](https://www.syncfusion.com/flutter-widgets/flutter-range-selector)
11+
12+
## Supported platforms
13+
14+
Refer to the following link to know about the supported platform - [Platforms](https://help.syncfusion.com/flutter/system-requirements#supported-platforms)
15+
16+
## Requirements to run the sample
17+
18+
Refer to the following link to know about system requirements - [System Requirements](https://help.syncfusion.com/flutter/system-requirements)
19+
20+
## How to run the sample
21+
22+
1. Clone the sample and open it in preferred IDE.
23+
2. Run the application.
24+
25+
*Note: If you download the sample using the "Download ZIP" option, right-click it, select Properties, and then select Unblock.*
26+
27+
## License
28+
29+
Syncfusion has no liability for any damage or consequence that may arise by using or viewing the samples. The samples are for demonstrative purposes, and if you choose to use or access the samples, you agree to not hold Syncfusion liable, in any form, for any damage that is related to use, for accessing, or viewing the samples. By accessing, viewing, or seeing the samples, you acknowledge and agree Syncfusion’s samples will not allow you seek injunctive relief in any form for any claim related to the sample. If you do not agree to this, do not view, access, utilize, or otherwise do anything with Syncfusion’s samples.

analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include: package:flutter_lints/flutter.yaml

lib/axes_scrollbar_chart.dart

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
import 'dart:math';
2+
import 'dart:ui';
3+
4+
import 'package:flutter/material.dart';
5+
import 'package:flutter/scheduler.dart';
6+
import 'package:syncfusion_flutter_charts/charts.dart' hide LabelPlacement;
7+
import 'package:syncfusion_flutter_core/core.dart';
8+
import 'package:syncfusion_flutter_core/theme.dart';
9+
import 'package:syncfusion_flutter_sliders/sliders.dart'
10+
hide EdgeLabelPlacement;
11+
12+
import 'chart_data.dart';
13+
14+
class ScrollbarAxesChart extends StatefulWidget {
15+
const ScrollbarAxesChart({super.key});
16+
17+
@override
18+
State<ScrollbarAxesChart> createState() => _ScrollbarAxesChartState();
19+
}
20+
21+
class _ScrollbarAxesChartState extends State<ScrollbarAxesChart> {
22+
late List<ChartData> _chartData;
23+
late DateTime _xScrollbarStartRange;
24+
late DateTime _xScrollbarEndRange;
25+
late NumericAxisController _yAxisController;
26+
late num _yAxisActualMin;
27+
late num _yAxisActualMax;
28+
final ValueNotifier<SfRangeValues> _yScrollbarSelectedValues =
29+
ValueNotifier(const SfRangeValues(0, 1));
30+
31+
final Random _random = Random();
32+
final int _dataCount = daysInYear(2020);
33+
final ZoomPanBehavior _zoomPanBehavior = ZoomPanBehavior(
34+
enablePanning: true,
35+
enablePinching: true,
36+
enableMouseWheelZooming: true,
37+
enableSelectionZooming: true,
38+
);
39+
40+
RangeController? _xScrollbarController;
41+
double _baseValue = 75;
42+
Size _scrollbarSize = Size.zero;
43+
44+
Offset _horizontalScrollbarStart = Offset.zero;
45+
Offset _verticalScrollbarStart = Offset.zero;
46+
47+
void _updateScrollBarSize(Size size) {
48+
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
49+
if (size != _scrollbarSize) {
50+
setState(() {
51+
_scrollbarSize = size;
52+
_horizontalScrollbarStart = Offset(0, size.height);
53+
_verticalScrollbarStart = Offset(size.width, size.height);
54+
});
55+
}
56+
});
57+
}
58+
59+
static int daysInYear(int year) {
60+
if (isLeapYear(year)) {
61+
return 366;
62+
} else {
63+
return 365;
64+
}
65+
}
66+
67+
static bool isLeapYear(int year) {
68+
if (year % 4 == 0) {
69+
if (year % 100 == 0) {
70+
return year % 400 == 0;
71+
} else {
72+
return true;
73+
}
74+
} else {
75+
return false;
76+
}
77+
}
78+
79+
num _yValue() {
80+
if (_random.nextDouble() > 0.5) {
81+
_baseValue += _random.nextDouble();
82+
return _baseValue;
83+
} else {
84+
_baseValue -= _random.nextDouble();
85+
return _baseValue;
86+
}
87+
}
88+
89+
@override
90+
void initState() {
91+
DateTime date = DateTime(2020);
92+
_chartData = List.generate(_dataCount + 1, (int index) {
93+
final List<num> values = [_yValue(), _yValue(), _yValue(), _yValue()];
94+
values.sort();
95+
return ChartData(
96+
x: date.add(Duration(days: index)),
97+
high: values[0],
98+
low: values[3],
99+
open: values[1],
100+
close: values[2],
101+
);
102+
});
103+
_xScrollbarStartRange = _chartData[0].x;
104+
_xScrollbarEndRange = _chartData[_dataCount].x;
105+
_xScrollbarController = RangeController(
106+
start: _xScrollbarStartRange,
107+
end: _xScrollbarEndRange,
108+
);
109+
super.initState();
110+
}
111+
112+
@override
113+
void dispose() {
114+
_yScrollbarSelectedValues.dispose();
115+
super.dispose();
116+
}
117+
118+
@override
119+
Widget build(BuildContext context) {
120+
return Scaffold(
121+
backgroundColor: Theme.of(context).colorScheme.onPrimary,
122+
appBar: AppBar(title: const Text('Scrollbar On Chart Axes')),
123+
body: Padding(
124+
padding: const EdgeInsets.all(15.0),
125+
child: SfCartesianChart(
126+
margin: EdgeInsets.zero,
127+
primaryXAxis: DateTimeAxis(
128+
rangeController: _xScrollbarController,
129+
edgeLabelPlacement: EdgeLabelPlacement.shift,
130+
),
131+
primaryYAxis: NumericAxis(
132+
opposedPosition: true,
133+
rangePadding: ChartRangePadding.round,
134+
onRendererCreated: (NumericAxisController controller) {
135+
_yAxisController = controller;
136+
},
137+
),
138+
series: <CartesianSeries<ChartData, DateTime>>[
139+
HiloOpenCloseSeries(
140+
dataSource: _chartData,
141+
xValueMapper: (ChartData data, int index) => data.x,
142+
highValueMapper: (ChartData data, int index) => data.high,
143+
lowValueMapper: (ChartData data, int index) => data.low,
144+
openValueMapper: (ChartData data, int index) => data.open,
145+
closeValueMapper: (ChartData data, int index) => data.close,
146+
onCreateRenderer: (ChartSeries<ChartData, DateTime> series) {
147+
return _HiloOpenCloseSeriesRenderer(this);
148+
},
149+
),
150+
],
151+
zoomPanBehavior: _zoomPanBehavior,
152+
onActualRangeChanged: (ActualRangeChangedArgs args) {
153+
if (args.axisName == 'primaryYAxis') {
154+
_yAxisActualMin = args.actualMin;
155+
_yAxisActualMax = args.actualMax;
156+
SchedulerBinding.instance
157+
.addPostFrameCallback((Duration timeStamp) {
158+
final num actualRange = args.actualMax - args.actualMin;
159+
double visibleMinNormalized =
160+
(args.visibleMin - args.actualMin) / actualRange;
161+
double visibleMaxNormalized =
162+
(args.visibleMax - args.actualMin) / actualRange;
163+
_yScrollbarSelectedValues.value =
164+
SfRangeValues(visibleMinNormalized, visibleMaxNormalized);
165+
});
166+
}
167+
},
168+
annotations: [
169+
CartesianChartAnnotation(
170+
x: _horizontalScrollbarStart.dx,
171+
y: _horizontalScrollbarStart.dy,
172+
coordinateUnit: CoordinateUnit.logicalPixel,
173+
horizontalAlignment: ChartAlignment.near,
174+
widget: SizedBox(
175+
width: _scrollbarSize.width,
176+
child: SfRangeSelectorTheme(
177+
data: const SfRangeSelectorThemeData(
178+
thumbRadius: 0,
179+
overlayRadius: 0,
180+
),
181+
child: SfRangeSelector(
182+
min: _xScrollbarStartRange,
183+
max: _xScrollbarEndRange,
184+
controller: _xScrollbarController,
185+
child: const SizedBox(height: 0),
186+
),
187+
),
188+
),
189+
),
190+
CartesianChartAnnotation(
191+
x: _verticalScrollbarStart.dx,
192+
y: _verticalScrollbarStart.dy,
193+
coordinateUnit: CoordinateUnit.logicalPixel,
194+
verticalAlignment: ChartAlignment.far,
195+
widget: SizedBox(
196+
width: 6,
197+
height: _scrollbarSize.height,
198+
child: ValueListenableBuilder<SfRangeValues>(
199+
valueListenable: _yScrollbarSelectedValues,
200+
builder: (BuildContext context, SfRangeValues values,
201+
Widget? child) {
202+
return SfRangeSliderTheme(
203+
data: const SfRangeSliderThemeData(
204+
thumbRadius: 0,
205+
overlayRadius: 0,
206+
),
207+
child: SfRangeSlider.vertical(
208+
min: 0,
209+
max: 1,
210+
values: values,
211+
onChanged: (SfRangeValues newValues) {
212+
_yAxisController.visibleMinimum = lerpDouble(
213+
_yAxisActualMin,
214+
_yAxisActualMax,
215+
newValues.start);
216+
_yAxisController.visibleMaximum = lerpDouble(
217+
_yAxisActualMin, _yAxisActualMax, newValues.end);
218+
},
219+
),
220+
);
221+
},
222+
),
223+
),
224+
),
225+
],
226+
),
227+
),
228+
);
229+
}
230+
}
231+
232+
class _HiloOpenCloseSeriesRenderer
233+
extends HiloOpenCloseSeriesRenderer<ChartData, DateTime> {
234+
_HiloOpenCloseSeriesRenderer(this._state);
235+
236+
final _ScrollbarAxesChartState _state;
237+
238+
@override
239+
void performLayout() {
240+
super.performLayout();
241+
_state._updateScrollBarSize(size);
242+
}
243+
}

lib/chart_data.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class ChartData {
2+
ChartData({
3+
required this.x,
4+
required this.high,
5+
required this.low,
6+
required this.open,
7+
required this.close,
8+
});
9+
10+
final DateTime x;
11+
final num high;
12+
final num low;
13+
final num open;
14+
final num close;
15+
}

0 commit comments

Comments
 (0)