Search code examples
flutterdartmapscross-platformpolyline

How to dynamically draw a line from point A to point B in Flutter?


So i have a custom map 4x3 And this is what I want to do: when I tap on two different squares, it shows a line (like a polyline) from square 1 to square 2.

I haven't found a solution to achieve this yet

This is my custom map

And this is it i need it to show after i tap on two squares

Please help me. Do you have any suggestions on how to achieve this? Are there any recommended libraries for accomplishing this task?

Here is the code i handmade custom using custompaint:

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Center(
            child: Image.asset(
              'assets/Sơ đồ mô phỏng.png',
              height: 300,
            ),
          ),
          CustomPaint(
            painter: MyPainter(),
          ),
          Positioned(
            top: 50,
            left: 10,
            child: IconButton(
              onPressed: () {},
              icon: const Icon(
                Icons.map,
                size: 35,
              ),
            ),
          ),
          Positioned(
            top: 100,
            left: 10,
            child: IconButton(
              onPressed: () {},
              icon: const Icon(
                Icons.pattern_sharp,
                size: 35,
              ),
            ),
          ),
          Positioned(
            top: 150,
            left: 10,
            child: IconButton(
              onPressed: () {},
              icon: const Icon(
                Icons.location_on,
                size: 35,
              ),
            ),
          )
        ],
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    const p1 = Offset(165, 100);
    const p2 = Offset(165, 135);
    final paint1 = Paint()
      ..color = Colors.black
      ..strokeJoin
      ..strokeWidth = 3;
    const p3 = Offset(165, 135);
    const p4 = Offset(490, 135);
    final paint2 = Paint()
      ..color = Colors.black
      ..strokeWidth = 3;
    const p5 = Offset(490, 100);
    const p6 = Offset(490, 135);
    final paint3 = Paint()
      ..color = Colors.black
      ..strokeWidth = 3;
    canvas.drawLine(p1, p2, paint1);
    canvas.drawLine(p3, p4, paint2);
    canvas.drawLine(p5, p6, paint3);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

Solution

  • i solve it here is the solution

    class TestDraw2Point extends StatefulWidget {
      @override
      _TestDraw2PointState createState() => _TestDraw2PointState();
    }
    
    class _TestDraw2PointState extends State<TestDraw2Point> {
      List<Offset> _points = [];
    
      void _addPoint(Offset point) {
        setState(() {
          _points.add(point);
          if (_points.length == 2) {
            _points = List.from(_points);
          }
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Draw Line Example'),
          ),
          body: GestureDetector(
            onTapDown: (TapDownDetails details) {
              _addPoint(details.localPosition);
            },
            child: CustomPaint(
              painter: LinePainter(points: _points),
              child: Container(),
            ),
          ),
        );
      }
    }
    
    class LinePainter extends CustomPainter {
      List<Offset> points;
    
      LinePainter({required this.points});
    
      @override
      void paint(Canvas canvas, Size size) {
        if (points.length == 2) {
          final paint = Paint()
            ..color = Colors.black
            ..strokeWidth = 3.0;
    
          canvas.drawLine(points[0], points[1], paint);
        }
      }
    
      @override
      bool shouldRepaint(LinePainter oldDelegate) => true;
    }
    

    Here this another version to draw multiline

    
    class DrawLineScreen extends StatefulWidget {
      const DrawLineScreen({super.key});
    
      @override
      _DrawLineScreenState createState() => _DrawLineScreenState();
    }
    
    class _DrawLineScreenState extends State<DrawLineScreen> {
      final List<Offset> _points = [];
      final List<List<Offset>> _lines = [];
    
      void _addPoint(Offset point) {
        setState(() {
          _points.add(point);
          if (_points.length == 2) {
            _lines.add(List.from(_points));
            _points.clear();
          }
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Draw Line Example'),
          ),
          body: GestureDetector(
            onTapDown: (TapDownDetails details) {
              _addPoint(details.localPosition);
            },
            child: CustomPaint(
              painter: LinePainter(lines: _lines, currentPoints: _points),
              child: Container(),
            ),
          ),
        );
      }
    }
    
    class LinePainter extends CustomPainter {
      List<List<Offset>> lines;
      List<Offset> currentPoints;
    
      LinePainter({required this.lines, required this.currentPoints});
    
      @override
      void paint(Canvas canvas, Size size) {
        final paint = Paint()
          ..color = Colors.black
          ..strokeWidth = 3.0;
    
        for (final line in lines) {
          canvas.drawLine(line[0], line[1], paint);
        }
    
        if (currentPoints.length == 2) {
          canvas.drawLine(currentPoints[0], currentPoints[1], paint);
        }
      }
    
      @override
      bool shouldRepaint(LinePainter oldDelegate) => true;
    }