Created
August 21, 2023 23:19
-
-
Save imaNNeo/902de71f285fe29f8f0567a4fac0498c to your computer and use it in GitHub Desktop.
Add lines between spots with drag and drop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:fl_chart/fl_chart.dart'; | |
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: ThemeData( | |
brightness: Brightness.dark, | |
scaffoldBackgroundColor: const Color(0xFF282E45), | |
), | |
home: const HomePage(), | |
); | |
} | |
} | |
class HomePage extends StatefulWidget { | |
const HomePage({super.key}); | |
@override | |
State<HomePage> createState() => _HomePageState(); | |
} | |
class _HomePageState extends State<HomePage> { | |
FlSpot? _startSpot; | |
FlSpot? _endSpot; | |
List<LineChartBarData> linesBetweenSpots = []; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: Center( | |
child: AspectRatio( | |
aspectRatio: 2, | |
child: LineChart( | |
LineChartData( | |
lineBarsData: [ | |
LineChartBarData( | |
spots: const [ | |
FlSpot(0, 15), | |
FlSpot(1, 8), | |
FlSpot(2, 0), | |
FlSpot(3, 20), | |
FlSpot(4, 5), | |
FlSpot(5, 12), | |
FlSpot(6, 34), | |
], | |
dotData: FlDotData( | |
show: true, | |
getDotPainter: (spot, percent, barData, index) { | |
final bool selected = | |
spot == _startSpot || spot == _endSpot; | |
return FlDotCirclePainter( | |
radius: 4, | |
color: Colors.blueAccent, | |
strokeWidth: selected ? 3 : 0, | |
strokeColor: Colors.white, | |
); | |
}, | |
), | |
color: Colors.blueAccent, | |
), | |
LineChartBarData( | |
spots: const [ | |
FlSpot(0, 7), | |
FlSpot(1, 1), | |
FlSpot(2, 4), | |
FlSpot(3, 9), | |
FlSpot(4, 1), | |
FlSpot(5, 5), | |
FlSpot(6, 20), | |
], | |
dotData: FlDotData( | |
show: true, | |
getDotPainter: (spot, percent, barData, index) { | |
final bool selected = | |
spot == _startSpot || spot == _endSpot; | |
return FlDotCirclePainter( | |
radius: 4, | |
color: Colors.purpleAccent, | |
strokeWidth: selected ? 3 : 0, | |
strokeColor: Colors.white, | |
); | |
}, | |
), | |
color: Colors.purpleAccent, | |
), | |
...linesBetweenSpots, | |
], | |
lineTouchData: LineTouchData( | |
handleBuiltInTouches: false, | |
touchCallback: _handleTouches, | |
distanceCalculator: | |
(Offset touchPoint, Offset spotPixelCoordinates) => | |
(touchPoint - spotPixelCoordinates).distance, | |
touchSpotThreshold: 40), | |
), | |
), | |
), | |
), | |
); | |
} | |
void _handleTouches(FlTouchEvent event, LineTouchResponse? response) { | |
if (response == null) { | |
if (_startSpot != null && _endSpot != null) { | |
_addLineBetweenSpots(_startSpot!, _endSpot!); | |
} | |
_clearSelections(); | |
return; | |
} | |
if ((event is FlPanDownEvent || | |
event is FlPanStartEvent || | |
event is FlLongPressStart || | |
event is FlTapDownEvent) && | |
response.lineBarSpots != null && | |
response.lineBarSpots!.isNotEmpty && | |
_startSpot == null) { | |
final TouchLineBarSpot touched = response.lineBarSpots!.first; | |
setState(() { | |
_startSpot = touched.bar.spots[touched.spotIndex].clone(); | |
}); | |
} | |
if (event is FlPanUpdateEvent || event is FlLongPressMoveUpdate) { | |
if (response.lineBarSpots != null && response.lineBarSpots!.isNotEmpty) { | |
final TouchLineBarSpot touched = response.lineBarSpots!.first; | |
setState(() { | |
_endSpot = touched.bar.spots[touched.spotIndex].clone(); | |
}); | |
} else { | |
setState(() { | |
_endSpot = null; | |
}); | |
} | |
} | |
if (event is FlPanEndEvent || | |
event is FlPanCancelEvent || | |
event is FlLongPressEnd || | |
event is FlTapUpEvent) { | |
if (response.lineBarSpots != null && | |
response.lineBarSpots!.isNotEmpty && | |
_startSpot != null && | |
_endSpot == null) { | |
final TouchLineBarSpot touched = response.lineBarSpots!.first; | |
_endSpot = touched.bar.spots[touched.spotIndex].clone(); | |
_addLineBetweenSpots(_startSpot!, _endSpot!); | |
setState(() { | |
_startSpot = null; | |
_endSpot = null; | |
}); | |
} else { | |
_clearSelections(); | |
} | |
} | |
} | |
void _clearSelections() { | |
setState(() { | |
_startSpot = null; | |
_endSpot = null; | |
}); | |
} | |
void _addLineBetweenSpots(FlSpot spot1, FlSpot spot2) { | |
if (spot1 == spot2) { | |
return; | |
} | |
setState(() { | |
linesBetweenSpots.add( | |
LineChartBarData( | |
spots: [ | |
spot1, | |
spot2, | |
], | |
color: Colors.redAccent, | |
dashArray: [8, 4], | |
dotData: const FlDotData(show: false), | |
), | |
); | |
}); | |
} | |
} | |
extension on FlSpot { | |
FlSpot clone() => FlSpot(x, y); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
0822.2.mp4