Untitled
unknown
plain_text
2 months ago
5.2 kB
3
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