Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

How to convert screen position to LatLng and/or vise versa? #607

Closed
iwishiwasaneagle opened this issue May 4, 2020 · 5 comments
Closed

Comments

@iwishiwasaneagle
Copy link

I'm trying to move a widget relative to the map, and need to be able to either move the map relative to the widget's screen position or vise versa. Any suggestions?

@maRci002
Copy link
Contributor

maRci002 commented May 7, 2020

Check out gestures.dart's _offsetToCrs method.

  LatLng _offsetToCrs(Offset offset) {
    // Get the widget's offset
    var renderObject = context.findRenderObject() as RenderBox;
    var width = renderObject.size.width;
    var height = renderObject.size.height;

    // convert the point to global coordinates
    var localPoint = _offsetToPoint(offset);
    var localPointCenterDistance =
        CustomPoint((width / 2) - localPoint.x, (height / 2) - localPoint.y);
    var mapCenter = map.project(map.center);
    var point = mapCenter - localPointCenterDistance;
    return map.unproject(point);
  }

@iwishiwasaneagle
Copy link
Author

@maRci002 thanks for pointing me towards that. How would I access the function? From what I can tell there's no way other than forking this repo and making it a public function.

@maRci002
Copy link
Contributor

Even if you make it public method you cannot go that deep easily.

Write something like this:

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';

import '../widgets/drawer.dart';

class EsriPage extends StatefulWidget {
  static const String route = 'esri';

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

class _EsriPageState extends State<EsriPage> {
  MapController mapController;

  @override
  void initState() {
    super.initState();

    mapController = MapController();
  }

  LatLng _offsetToCrs(Crs crs, Offset offset, BoxConstraints constraints,
      [LatLng initCenter, double initZoom]) {
    var center = mapController.ready ? mapController.center : initCenter;
    var zoom = mapController.ready ? mapController.zoom : initZoom;

    if (center == null || zoom == null) {
      return null;
    }

    // Get the widget's offset
    var width = constraints.maxWidth;
    var height = constraints.maxHeight;

    // convert the point to global coordinates
    var localPoint = CustomPoint(offset.dx, offset.dy);
    var localPointCenterDistance =
        CustomPoint((width / 2) - localPoint.x, (height / 2) - localPoint.y);
    var mapCenter = crs.latLngToPoint(center, zoom);
    var point = mapCenter - localPointCenterDistance;
    return crs.pointToLatLng(point, zoom);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Esri')),
      drawer: buildDrawer(context, EsriPage.route),
      body: Padding(
        padding: EdgeInsets.all(8.0),
        child: Column(
          children: [
            Padding(
              padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
              child: Text('Esri'),
            ),
            Flexible(
              child: LayoutBuilder(
                builder: (BuildContext context, BoxConstraints constraints) {
                  print(
                    _offsetToCrs(
                      const Epsg3857(),
                      Offset(12.0, 12.0),
                      constraints,
                      // optional center should be same as MapOptions' center
                      // if not provided then _offsetToCrs will return null at very first build because mapController isn't ready
                      LatLng(45.5231, -122.6765),
                      // optional zoom should be same as MapOptions' zoom
                      // if not provided then _offsetToCrs will return null at very first build because mapController isn't ready
                      13.0,
                    ),
                  );

                  return FlutterMap(
                    mapController: mapController,
                    options: MapOptions(
                      crs: const Epsg3857(),
                      center: LatLng(45.5231, -122.6765),
                      zoom: 13.0,
                      onTap: (l) {
                        print(l);

                        print(_offsetToCrs(
                            const Epsg3857(), Offset(12.0, 12.0), constraints));
                      },
                    ),
                    layers: [
                      TileLayerOptions(
                        urlTemplate:
                            'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
                      ),
                    ],
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

@iwishiwasaneagle
Copy link
Author

@maRci002 that's great. Thanks for the help!

@aytunch
Copy link
Contributor

aytunch commented May 17, 2020

@iwishiwasaneagle This was a while ago but can you try this?
#334 (comment)

JaffaKetchup pushed a commit that referenced this issue May 20, 2022
…nt (#1115)

* Added MapController.pointToLatLng() to get LatLng of given screen point

Ref #496, ref #607, ref #981, ref #1010

* Better pointToLatLng example

* dartfmt

* Fix zoom breaking pointToLatLng()

* Updated example to help fix the rotation issue

* Rebased on latest

* Fix pointToLatLng with rotation

* Fix trailing lines (3x attempts)

Co-authored-by: Polo <gitpjp@pm.me> and ibrierley
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants