Untitled
unknown
plain_text
8 months ago
5.2 kB
4
Indexable
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Line Chart with Moving Dashed Line')),
body: LineChartSample(),
),
);
}
}
class LineChartSample extends StatefulWidget {
@override
State<LineChartSample> createState() => _LineChartSampleState();
}
class _LineChartSampleState extends State<LineChartSample> {
List<Color> gradientColors = [
Colors.blue,
Colors.purple,
];
double? dashedLineX; // Vị trí X của đường nét đứt (null nếu không hiển thị)
// Dữ liệu các điểm trên biểu đồ
final List<FlSpot> spots = [
FlSpot(0, 3),
FlSpot(2, 2),
FlSpot(3, 5),
FlSpot(4, 3.1),
FlSpot(5, 4),
FlSpot(6, 3),
FlSpot(7, 4),
FlSpot(10, 5),
];
@override
void initState() {
super.initState();
// Đặt vị trí mặc định cho đường nét đứt (ví dụ: ở giữa biểu đồ)
dashedLineX = 5.5; // Giá trị giữa minX (0) và maxX (11)
}
// Tìm FlSpot gần nhất dựa trên vị trí X
FlSpot findNearestSpot(double x) {
if (spots.isEmpty) return FlSpot(x, 0);
FlSpot nearest = spots[0];
double minDistance = (spots[0].x - x).abs();
for (final spot in spots) {
final distance = (spot.x - x).abs();
if (distance < minDistance) {
minDistance = distance;
nearest = spot;
}
}
return nearest;
}
@override
Widget build(BuildContext context) {
return LineChart(
LineChartData(
gridData: FlGridData(show: true),
titlesData: FlTitlesData(show: true),
borderData: FlBorderData(show: true),
minX: 0,
maxX: 11,
minY: 0,
maxY: 6,
lineBarsData: [
// Dữ liệu chính của biểu đồ đường
LineChartBarData(
spots: spots,
isCurved: true,
gradient: LinearGradient(colors: gradientColors),
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(show: false),
belowBarData: BarAreaData(show: true, gradient: LinearGradient(colors: gradientColors.map((color) => color.withOpacity(0.3)).toList())),
),
// Đường nét đứt luôn hiển thị và di chuyển
if (dashedLineX != null)
LineChartBarData(
spots: [
FlSpot(dashedLineX!, 0), // Bắt đầu từ minY
FlSpot(dashedLineX!, 6), // Kết thúc tại maxY
],
isCurved: false,
color: Colors.purple,
barWidth: 2,
dashArray: [5, 5], // Đường nét đứt
dotData: FlDotData(show: false),
belowBarData: BarAreaData(show: false),
),
],
lineTouchData: LineTouchData(
enabled: true,
touchTooltipData: TouchTooltipData(
tooltipBgColor: Colors.blueGrey.withOpacity(0.8),
),
touchCallback: (FlTouchEvent event, response) {
if (event is FlPanStartEvent || event is FlPanUpdateEvent) {
final touchPos = event.localPosition;
if (touchPos != null) {
// Chuyển đổi vị trí chạm trên màn hình thành giá trị X của biểu đồ
final chartWidth = MediaQuery.of(context).size.width;
final x = (touchPos.dx / chartWidth) * 11; // minX = 0, maxX = 11
setState(() {
dashedLineX = x.clamp(0, 11); // Giới hạn trong khoảng minX và maxX
});
}
} else if (event is FlPanEndEvent || event is FlPanCancelEvent) {
// Khi kết thúc vuốt, đặt đường nét đứt tại FlSpot gần nhất
if (dashedLineX != null) {
final nearestSpot = findNearestSpot(dashedLineX!);
setState(() {
dashedLineX = nearestSpot.x; // Dừng tại điểm gần nhất
});
}
}
},
getTouchedSpotIndicator: (barData, spotIndexes) {
return spotIndexes.map((index) {
return TouchedSpotIndicatorData(
FlLine(
color: Colors.purple,
strokeWidth: 2,
dashArray: [5, 5],
),
FlDotData(
show: true,
getDotPainter: (spot, percent, bar, index) => FlDotCirclePainter(
radius: 4,
color: Colors.red,
strokeWidth: 2,
strokeColor: Colors.red,
),
),
);
}).toList();
},
),
),
);
}
}Editor is loading...
Leave a Comment