3

i am new to flutter, i am currently developing a real estate mobile app and i want to be able to drag and draw lines(polygon, circles) on flutter map and return listings inside the area i draw on just like in redfin app.

i have tried a lot of flutter maps implementations online, but none of the plugins i come across doesn't include drawing of lines on map. This is an example of search result within a drawn lines

hybrid_pro
  • 31
  • 4

2 Answers2

2

Ive come across this example of drawing in Flutter using CustomPaint and added converter from List<Offset> to the List<LatLng> using it for polygon creation on the google maps (google_maps_flutter plugin)

https://medium.com/flutter-community/drawing-in-flutter-using-custompainter-307a9f1c21f8

  buildPolygon(List<Offset> shape) async {
    final List<LatLng> points = <LatLng>[];
    final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
    await Future.forEach(shape, (Offset offset) async {
      LatLng point = await mapController.getLatLng(
        ScreenCoordinate(
          x: (offset.dx  * devicePixelRatio).round() ,
          y: (offset.dy * devicePixelRatio).round()
        )
      );
      points.add(point);
    });

    final PolygonId polygonId = PolygonId("1");
    polygon = Polygon(
      polygonId: polygonId,
      consumeTapEvents: true,
      strokeColor: Colors.blue,
      strokeWidth: 5,
      fillColor: Colors.orange.withOpacity(0.2),
      points: points,
    );
  }

Displaying the polygon

GoogleMap(
  polygons: [polygon].toSet(),
  onMapCreated: (GoogleMapController controller) {
    mapController = controller;
  },
)

For toggling drawing mode on the map you can put it in the Stack like this

 Stack(
   children: <Widget>[
      buildMap(),
      drawingModeOn ? buildMapDraw() : Container(),
   ],
);

final result

kashlo
  • 2,313
  • 1
  • 28
  • 39
0

plugin:

google_maps_flutter: ^1.0.6

code:

import 'dart:async';
import 'dart:collection';
import 'dart:io';
import 'dart:math' as Math;
import 'AddEditPage.dart';
import 'details.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class MapPage extends StatefulWidget {
  MapPage({Key key}) : super(key: key);

  @override
  _MapPageState createState() => _MapPageState();
}

class _MapPageState extends State<MapPage> {
  static final Completer<GoogleMapController> _controller = Completer();

  static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(13.0827, 80.2707),
    zoom: 14.4746,
  );

  final Set<Polygon> _polygons = HashSet<Polygon>();
  final Set<Polyline> _polyLines = HashSet<Polyline>();

  bool _drawPolygonEnabled = false;
  List<LatLng> _userPolyLinesLatLngList = List();
  bool _clearDrawing = false;
  int _lastXCoordinate, _lastYCoordinate;

  List<LatLng> _mapLatLang = List();
  List<LatLng> _latLang = List();

  
  _getlatlan(){
    setState(() => LatLng(13.0827, 80.2707));
  }

  _toggleDrawing() {
    _clearPolygons();
    setState(() => _drawPolygonEnabled = !_drawPolygonEnabled);
  }

  _onPanUpdate(DragUpdateDetails details) async {
    // To start draw new polygon every time.
    if (_clearDrawing) {
      _clearDrawing = false;
      _clearPolygons();
    }

    if (_drawPolygonEnabled) {
      double x, y;
      if (Platform.isAndroid) {
        // It times in 3 without any meaning,
        // We think it's an issue with GoogleMaps package.
        x = details.globalPosition.dx * 3;
        y = details.globalPosition.dy * 3;
      } else if (Platform.isIOS) {
        x = details.globalPosition.dx;
        y = details.globalPosition.dy;
      }

      // Round the x and y.
      int xCoordinate = x.round();
      int yCoordinate = y.round();

      // Check if the distance between last point is not too far.
      // to prevent two fingers drawing.
      if (_lastXCoordinate != null && _lastYCoordinate != null) {
        var distance = Math.sqrt(Math.pow(xCoordinate - _lastXCoordinate, 2) + Math.pow(yCoordinate - _lastYCoordinate, 2));
        
        // Check if the distance of point and point is large.
        if (distance > 80.0) return;
      }

      // Cached the coordinate.
      _lastXCoordinate = xCoordinate;
      _lastYCoordinate = yCoordinate;

      ScreenCoordinate screenCoordinate = ScreenCoordinate(x: xCoordinate, y: yCoordinate);

      final GoogleMapController controller = await _controller.future;
      LatLng latLng = await controller.getLatLng(screenCoordinate);
      
      
      
      try {
        // Add new point to list.
        _userPolyLinesLatLngList.add(latLng);
        _latLang.add(latLng);

        _polyLines.removeWhere((polyline) => polyline.polylineId.value == 'user_polyline');
        _polyLines.add(
          Polyline(
            polylineId: PolylineId('user_polyline'),
            points: _userPolyLinesLatLngList,
            width: 2,
            color: Colors.blue,
          ),
        );
      } catch (e) {
        print(" error painting $e");
      }
      setState(() {});
    }
  }

  _onPanEnd(DragEndDetails details) async {
    // Reset last cached coordinate
    _lastXCoordinate = null;
    _lastYCoordinate = null;

    if (_drawPolygonEnabled) {
      _polygons.removeWhere((polygon) => polygon.polygonId.value == 'user_polygon');
      _polygons.add(
        Polygon(
          polygonId: PolygonId('user_polygon'),
          points: _userPolyLinesLatLngList,
          strokeWidth: 2,
          strokeColor: Colors.blue,
          fillColor: Colors.blue.withOpacity(0.4),
        ),
        
      );
      setState(() {
        _clearDrawing = true;
        _mapLatLang =_userPolyLinesLatLngList;
      });
    }
  }

  _clearPolygons() {
    setState(() {
      _polyLines.clear();
      _polygons.clear();
      _userPolyLinesLatLngList.clear();
    });
  }
var lat = [LatLng(12.82879876203614, 80.12908793985844)];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Farm'),
        iconTheme: IconThemeData(color: Colors.grey.shade800),
        actions: <Widget>[
    FlatButton(
      textColor: Colors.grey.shade800,
      onPressed: () {_drawPolygonEnabled?
        Navigator.push(context, MaterialPageRoute(builder: (context) => AddEditPage(data: new DataLat(_latLang)),),) : null;
      },
      child: _drawPolygonEnabled? Text("Save") : Text("Draw"),
      shape: CircleBorder(side: BorderSide(color: Colors.transparent)),
    ),
  ],
      ),
      body: GestureDetector(
        onPanUpdate: (_drawPolygonEnabled) ? _onPanUpdate : null,
        onPanEnd: (_drawPolygonEnabled) ? _onPanEnd : null,
        child: GoogleMap(
          myLocationEnabled: true,
          mapType: MapType.normal,
          initialCameraPosition: _kGooglePlex,
          polygons: _polygons,
          polylines: _polyLines,
          onMapCreated: (GoogleMapController controller) {
            _controller.complete(controller);
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _toggleDrawing,
        tooltip: 'Drawing',
        child: new IconTheme(
              data: new IconThemeData(
                  color: Colors.grey.shade800), 
              child: new Icon((_drawPolygonEnabled) ? Icons.cancel : Icons.edit),
          ),
      ),
    );
  }

  
}
class DataLat {
  List<LatLng> latLng;

  DataLat(this.latLng);
}
dinesh balan
  • 318
  • 1
  • 14
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 22 '21 at 17:30
  • I apologize to you. I just started my carrier in development so I don't how to write the correct documentation. I will try to give full as soon – dinesh balan Sep 22 '21 at 18:07