Skip to content
New issue

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

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

Already on GitHub? Sign in 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants