Skip to content

Instantly share code, notes, and snippets.

@imaNNeo
Created August 21, 2023 23:19
Show Gist options
  • Save imaNNeo/902de71f285fe29f8f0567a4fac0498c to your computer and use it in GitHub Desktop.
Save imaNNeo/902de71f285fe29f8f0567a4fac0498c to your computer and use it in GitHub Desktop.
Add lines between spots with drag and drop
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);
}
@imaNNeo
Copy link
Author

imaNNeo commented Aug 21, 2023

0822.2.mp4

@imaNNeo
Copy link
Author

imaNNeo commented Aug 21, 2023

Answered here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment