Untitled

 avatar
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