Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/scatter chart #120

Merged
merged 13 commits into from
Nov 29, 2019
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.5.0
* 💥 Added ScatterChart ([read about it](https://jbt.github.io/markdown-editor/repo_files/documentations/scatter_chart.md)) 💥
* Added Velocity to in [FlPanEnd](https://github.com/imaNNeoFighT/fl_chart/blob/feature/scatter-chart/repo_files/documentations/base_chart.md#fltouchinput) to determine the Tap event.

## 0.4.3
* fixed a size bug, #100.
* direction support for gradient on the LineChart (added `gradientFrom` and `gradientTo` in the [LineChartBarData](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/line_chart.md#linechartbardata)).
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
| [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/line_chart/line_chart_sample_1.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/line_chart.md#sample-1-source-code) [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/line_chart/line_chart_sample_2.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/line_chart.md#sample-2-source-code) | [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/bar_chart/bar_chart_sample_1.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/bar_chart.md#sample-1-source-code) [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/bar_chart/bar_chart_sample_2.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/bar_chart.md#sample-2-source-code) | [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/pie_chart/pie_chart_sample_1.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/pie_chart.md#sample-1-source-code) [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/pie_chart/pie_chart_sample_2.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/pie_chart.md#sample-2-source-code) |
|[Read More](repo_files/documentations/line_chart.md)|[Read More](repo_files/documentations/bar_chart.md)|[Read More](repo_files/documentations/pie_chart.md)|

|ScatterChart |
|:------------:|
| [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/scatter_chart/scatter_chart_sample_1.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/scatter_chart.md#sample-1-source-code) [![](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/scatter_chart/scatter_chart_sample_2.gif)](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/scatter_chart.md#sample-2-source-code) |
|[Read More](repo_files/documentations/scatter_chart.md)|

Banner designed by [Soheil Saffar](https://www.linkedin.com/in/soheilsaffar), and
samples inspired from
[David Kovalev](https://dribbble.com/shots/5560237-Live-Graphs-XD),
Expand All @@ -36,7 +41,7 @@ Thank you all!

```kotlin
dependencies:
fl_chart: ^0.4.3
fl_chart: ^0.5.0
```


Expand Down
2 changes: 2 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:example/scatter_chart/scatter_chart_page.dart';
import 'package:flutter/material.dart';

import 'bar_chart/bar_chart_page.dart';
Expand Down Expand Up @@ -48,6 +49,7 @@ class _MyHomePageState extends State<MyHomePage> {
LineChartPage2(),
LineChartPage3(),
LineChartPage4(),
ScatterChartPage(),
],
),
),
Expand Down
195 changes: 195 additions & 0 deletions example/lib/scatter_chart/samples/scatter_chart_sample1.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import 'dart:math';

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

class ScatterChartSample1 extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ScatterChartSample1State();
}

class _ScatterChartSample1State extends State {

final maxX = 50.0;
final maxY = 50.0;
final radius = 8.0;

Color blue1 = const Color(0xFF0D47A1);
Color blue2 = const Color(0xFF42A5F5).withOpacity(0.8);

bool showFlutter = true;

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
showFlutter = !showFlutter;
});
},
child: AspectRatio(
aspectRatio: 1,
child: Card(
color: const Color(0xffffffff),
elevation: 6,
child: ScatterChart(
ScatterChartData(
scatterSpots: showFlutter ? flutterLogoData() : randomData(),
minX: 0,
maxX: maxX,
minY: 0,
maxY: maxY,
borderData: FlBorderData(
show: false,
),
gridData: const FlGridData(
show: false,
),
titlesData: const FlTitlesData(
show: false,
),
scatterTouchData: const ScatterTouchData(
enabled: false,
)
),
swapAnimationDuration: Duration(milliseconds: 600),
),
),
),
);
}

List<ScatterSpot> flutterLogoData() {
return [
/// section 1
ScatterSpot(20, 14.5, color: blue1, radius: radius),
ScatterSpot(22, 16.5, color: blue1, radius: radius),
ScatterSpot(24, 18.5, color: blue1, radius: radius),

ScatterSpot(22, 12.5, color: blue1, radius: radius),
ScatterSpot(24, 14.5, color: blue1, radius: radius),
ScatterSpot(26, 16.5, color: blue1, radius: radius),

ScatterSpot(24, 10.5, color: blue1, radius: radius),
ScatterSpot(26, 12.5, color: blue1, radius: radius),
ScatterSpot(28, 14.5, color: blue1, radius: radius),

ScatterSpot(26, 8.5, color: blue1, radius: radius),
ScatterSpot(28, 10.5, color: blue1, radius: radius),
ScatterSpot(30, 12.5, color: blue1, radius: radius),

ScatterSpot(28, 6.5, color: blue1, radius: radius),
ScatterSpot(30, 8.5, color: blue1, radius: radius),
ScatterSpot(32, 10.5, color: blue1, radius: radius),

ScatterSpot(30, 4.5, color: blue1, radius: radius),
ScatterSpot(32, 6.5, color: blue1, radius: radius),
ScatterSpot(34, 8.5, color: blue1, radius: radius),

ScatterSpot(34, 4.5, color: blue1, radius: radius),
ScatterSpot(36, 6.5, color: blue1, radius: radius),

ScatterSpot(38, 4.5, color: blue1, radius: radius),

/// section 2
ScatterSpot(20, 14.5, color: blue2, radius: radius),
ScatterSpot(22, 12.5, color: blue2, radius: radius),
ScatterSpot(24, 10.5, color: blue2, radius: radius),

ScatterSpot(22, 16.5, color: blue2, radius: radius),
ScatterSpot(24, 14.5, color: blue2, radius: radius),
ScatterSpot(26, 12.5, color: blue2, radius: radius),

ScatterSpot(24, 18.5, color: blue2, radius: radius),
ScatterSpot(26, 16.5, color: blue2, radius: radius),
ScatterSpot(28, 14.5, color: blue2, radius: radius),

ScatterSpot(26, 20.5, color: blue2, radius: radius),
ScatterSpot(28, 18.5, color: blue2, radius: radius),
ScatterSpot(30, 16.5, color: blue2, radius: radius),

ScatterSpot(28, 22.5, color: blue2, radius: radius),
ScatterSpot(30, 20.5, color: blue2, radius: radius),
ScatterSpot(32, 18.5, color: blue2, radius: radius),

ScatterSpot(30, 24.5, color: blue2, radius: radius),
ScatterSpot(32, 22.5, color: blue2, radius: radius),
ScatterSpot(34, 20.5, color: blue2, radius: radius),

ScatterSpot(34, 24.5, color: blue2, radius: radius),
ScatterSpot(36, 22.5, color: blue2, radius: radius),

ScatterSpot(38, 24.5, color: blue2, radius: radius),

/// section 3
ScatterSpot(10, 25, color: blue2, radius: radius),
ScatterSpot(12, 23, color: blue2, radius: radius),
ScatterSpot(14, 21, color: blue2, radius: radius),

ScatterSpot(12, 27, color: blue2, radius: radius),
ScatterSpot(14, 25, color: blue2, radius: radius),
ScatterSpot(16, 23, color: blue2, radius: radius),

ScatterSpot(14, 29, color: blue2, radius: radius),
ScatterSpot(16, 27, color: blue2, radius: radius),
ScatterSpot(18, 25, color: blue2, radius: radius),

ScatterSpot(16, 31, color: blue2, radius: radius),
ScatterSpot(18, 29, color: blue2, radius: radius),
ScatterSpot(20, 27, color: blue2, radius: radius),

ScatterSpot(18, 33, color: blue2, radius: radius),
ScatterSpot(20, 31, color: blue2, radius: radius),
ScatterSpot(22, 29, color: blue2, radius: radius),

ScatterSpot(20, 35, color: blue2, radius: radius),
ScatterSpot(22, 33, color: blue2, radius: radius),
ScatterSpot(24, 31, color: blue2, radius: radius),

ScatterSpot(22, 37, color: blue2, radius: radius),
ScatterSpot(24, 35, color: blue2, radius: radius),
ScatterSpot(26, 33, color: blue2, radius: radius),

ScatterSpot(24, 39, color: blue2, radius: radius),
ScatterSpot(26, 37, color: blue2, radius: radius),
ScatterSpot(28, 35, color: blue2, radius: radius),

ScatterSpot(26, 41, color: blue2, radius: radius),
ScatterSpot(28, 39, color: blue2, radius: radius),
ScatterSpot(30, 37, color: blue2, radius: radius),

ScatterSpot(28, 43, color: blue2, radius: radius),
ScatterSpot(30, 41, color: blue2, radius: radius),
ScatterSpot(32, 39, color: blue2, radius: radius),

ScatterSpot(30, 45, color: blue2, radius: radius),
ScatterSpot(32, 43, color: blue2, radius: radius),
ScatterSpot(34, 41, color: blue2, radius: radius),

ScatterSpot(34, 45, color: blue2, radius: radius),
ScatterSpot(36, 43, color: blue2, radius: radius),

ScatterSpot(38, 45, color: blue2, radius: radius),
];
}

List<ScatterSpot> randomData() {
const blue1Count = 21;
const blue2Count = 57;
return List.generate(blue1Count + blue2Count, (i) {
Color color;
if (i < blue1Count) {
color = blue1;
} else {
color = blue2;
}

return ScatterSpot(
(Random().nextDouble() * (maxX - 8)) + 4,
(Random().nextDouble() * (maxY - 8)) + 4,
color: color,
radius: (Random().nextDouble() * 16) + 4,
);
});
}
}
86 changes: 86 additions & 0 deletions example/lib/scatter_chart/samples/scatter_chart_sample2.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

class ScatterChartSample2 extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ScatterChartSample2State();
}

class _ScatterChartSample2State extends State {
int touchedIndex;

Color greyColor = Colors.grey;

List<int> selectedSpots = [];

int lastPanStartOnIndex = -1;

@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Card(
color: Color(0xff222222),
child: ScatterChart(
ScatterChartData(
scatterSpots: [
ScatterSpot(4, 4, color: selectedSpots.contains(0) ? Colors.green : greyColor,),
ScatterSpot(2, 5, color: selectedSpots.contains(1) ? Colors.yellow : greyColor, radius: 12,),
ScatterSpot(4, 5, color: selectedSpots.contains(2) ? Colors.purpleAccent : greyColor, radius: 8,),
ScatterSpot(8, 6, color: selectedSpots.contains(3) ? Colors.orange : greyColor, radius: 20,),
ScatterSpot(5, 7, color: selectedSpots.contains(4) ? Colors.brown : greyColor, radius: 14,),
ScatterSpot(7, 2, color: selectedSpots.contains(5) ? Colors.lightGreenAccent : greyColor, radius: 18,),
ScatterSpot(3, 2, color: selectedSpots.contains(6) ? Colors.red : greyColor, radius: 36,),
ScatterSpot(2, 8, color: selectedSpots.contains(7) ? Colors.tealAccent : greyColor, radius: 22,),
],
minX: 0,
maxX: 10,
minY: 0,
maxY: 10,
borderData: FlBorderData(
show: false,
),
gridData: FlGridData(
show: true,
drawHorizontalGrid: true,
checkToShowHorizontalGrid: (value) => true,
getDrawingHorizontalGridLine: (value) => FlLine(color: Colors.white.withOpacity(0.1)),
drawVerticalGrid: true,
checkToShowVerticalGrid: (value) => true,
getDrawingVerticalGridLine: (value) => FlLine(color: Colors.white.withOpacity(0.1)),
),
titlesData: const FlTitlesData(
show: false,
),
showingTooltipIndicators: selectedSpots,
scatterTouchData: ScatterTouchData(
enabled: true,
handleBuiltInTouches: false,
touchTooltipData: const ScatterTouchTooltipData(
tooltipBgColor: Colors.black,
),
touchCallback: (ScatterTouchResponse touchResponse) {
if (touchResponse.touchInput is FlPanStart) {
lastPanStartOnIndex = touchResponse.touchedSpotIndex;
} else if (touchResponse.touchInput is FlPanEnd) {
final FlPanEnd flPanEnd = touchResponse.touchInput;

if (flPanEnd.velocity.pixelsPerSecond <= const Offset(4, 4)) {
// Tap happened
setState(() {
if (selectedSpots.contains(lastPanStartOnIndex)) {
selectedSpots.remove(lastPanStartOnIndex);
} else {
selectedSpots.add(lastPanStartOnIndex);
}
});
}
}
}
)
),
),
),
);
}
}
45 changes: 45 additions & 0 deletions example/lib/scatter_chart/scatter_chart_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'package:example/scatter_chart/samples/scatter_chart_sample1.dart';
import 'package:example/scatter_chart/samples/scatter_chart_sample2.dart';
import 'package:flutter/material.dart';

class ScatterChartPage extends StatelessWidget {
final Color barColor = Colors.white;
final Color barBackgroundColor = const Color(0xff72d8bf);
final double width = 22;

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xffffffff),
body: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
vertical: 18.0,
horizontal: 22,
),
child: Text(
'Scatter Charts',
style: TextStyle(
color: Colors.black,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(
height: 9,
),
Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18.0, bottom: 18.0),
child: ScatterChartSample1(),
),
Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18.0, bottom: 18.0),
child: ScatterChartSample2(),
)
],
),
);
}
}
4 changes: 3 additions & 1 deletion lib/fl_chart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export 'src/chart/base/base_chart/touch_input.dart';
export 'src/chart/line_chart/line_chart.dart';
export 'src/chart/line_chart/line_chart_data.dart';
export 'src/chart/pie_chart/pie_chart.dart';
export 'src/chart/pie_chart/pie_chart_data.dart';
export 'src/chart/pie_chart/pie_chart_data.dart';
export 'src/chart/scatter_chart/scatter_chart.dart';
export 'src/chart/scatter_chart/scatter_chart_data.dart';
4 changes: 2 additions & 2 deletions lib/src/chart/bar_chart/bar_chart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ class BarChartState extends AnimatedWidgetBaseState<BarChart> {
},
onPanCancel: () async {
final BarTouchResponse response =
_touchHandler?.handleTouch(FlPanEnd(Offset.zero), chartSize);
_touchHandler?.handleTouch(FlPanEnd(Offset.zero, Velocity(pixelsPerSecond: Offset.zero)), chartSize);
if (_canHandleTouch(response, touchData)) {
touchData.touchCallback(response);
}
},
onPanEnd: (DragEndDetails details) async {
final BarTouchResponse response =
_touchHandler?.handleTouch(FlPanEnd(Offset.zero), chartSize);
_touchHandler?.handleTouch(FlPanEnd(Offset.zero, details.velocity), chartSize);
if (_canHandleTouch(response, touchData)) {
touchData.touchCallback(response);
}
Expand Down
Loading