Skip to content

Commit

Permalink
Add methods to access projection (#380)
Browse files Browse the repository at this point in the history
* remove bitmap; add projection access

* Replace ScreenLocation with Point; expand iOS implementation

* fix iOS with guard let

* iOS: cast to NSObject

* fix typo

* round result of toScreenLocation()

* Revert "round result of toScreenLocation()"

This reverts commit 838726a.

* Docs: document rounding behaviour
  • Loading branch information
m0nac0 authored Sep 8, 2020
1 parent 99b28ce commit 10788a7
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 62 deletions.
16 changes: 16 additions & 0 deletions android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,22 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
result.success(reply);
break;
}
case "map#toScreenLocation": {
Map<String, Object> reply = new HashMap<>();
PointF pointf = mapboxMap.getProjection().toScreenLocation(new LatLng(call.argument("latitude"),call.argument("longitude")));
reply.put("x", pointf.x);
reply.put("y", pointf.y);
result.success(reply);
break;
}
case "map#toLatLng": {
Map<String, Object> reply = new HashMap<>();
LatLng latlng = mapboxMap.getProjection().fromScreenLocation(new PointF( ((Double) call.argument("x")).floatValue(), ((Double) call.argument("y")).floatValue()));
reply.put("latitude", latlng.getLatitude());
reply.put("longitude", latlng.getLongitude());
result.success(reply);
break;
}
case "camera#move": {
final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapboxMap, density);
if (cameraUpdate != null) {
Expand Down
6 changes: 6 additions & 0 deletions example/lib/map_ui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:mapbox_gl/mapbox_gl.dart';

Expand Down Expand Up @@ -266,6 +268,10 @@ class MapUiBodyState extends State<MapUiBody> {
},
onMapLongClick: (point, latLng) async {
print("Map long press: ${point.x},${point.y} ${latLng.latitude}/${latLng.longitude}");
Point convertedPoint = await mapController.toScreenLocation(latLng);
LatLng convertedLatLng = await mapController.toLatLng(point);
print("Map long press converted: ${convertedPoint.x},${convertedPoint.y} ${convertedLatLng.latitude}/${convertedLatLng.longitude}");

List features = await mapController.queryRenderedFeatures(point, [], null);
if (features.length>0) {
print(features[0]);
Expand Down
20 changes: 20 additions & 0 deletions ios/Classes/MapboxMapController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,26 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma
reply["sw"] = [visibleRegion.sw.latitude, visibleRegion.sw.longitude] as NSObject
reply["ne"] = [visibleRegion.ne.latitude, visibleRegion.ne.longitude] as NSObject
result(reply)
case "map#toScreenLocation":
guard let arguments = methodCall.arguments as? [String: Any] else { return }
guard let latitude = arguments["latitude"] as? Double else { return }
guard let longitude = arguments["longitude"] as? Double else { return }
let latlng = CLLocationCoordinate2DMake(latitude, longitude)
let returnVal = mapView.convert(latlng, toPointTo: mapView)
var reply = [String: NSObject]()
reply["x"] = returnVal.x as NSObject
reply["y"] = returnVal.y as NSObject
result(reply)
case "map#toLatLng":
guard let arguments = methodCall.arguments as? [String: Any] else { return }
guard let x = arguments["x"] as? Double else { return }
guard let y = arguments["y"] as? Double else { return }
let screenPoint: CGPoint = CGPoint(x: y, y:y)
let coordinates: CLLocationCoordinate2D = mapView.convert(screenPoint, toCoordinateFrom: mapView)
var reply = [String: NSObject]()
reply["latitude"] = coordinates.latitude as NSObject
reply["longitude"] = coordinates.longitude as NSObject
result(reply)
case "camera#move":
guard let arguments = methodCall.arguments as? [String: Any] else { return }
guard let cameraUpdate = arguments["cameraUpdate"] as? [Any] else { return }
Expand Down
2 changes: 1 addition & 1 deletion lib/mapbox_gl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export 'package:mapbox_gl_platform_interface/mapbox_gl_platform_interface.dart'
Line,
LineOptions;

part 'src/bitmap.dart';

part 'src/controller.dart';
part 'src/mapbox_map.dart';
part 'src/global.dart';
49 changes: 0 additions & 49 deletions lib/src/bitmap.dart

This file was deleted.

17 changes: 17 additions & 0 deletions lib/src/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -670,4 +670,21 @@ class MapboxMapController extends ChangeNotifier {
await MapboxGlPlatform.getInstance(_id)
.setSymbolTextIgnorePlacement(enable);
}

/// Returns the point on the screen that corresponds to a geographical coordinate ([latLng]). The screen location is in screen pixels (not display pixels) relative to the top left of the map (not of the whole screen)
///
/// Note: The resulting x and y coordinates are rounded to [int] on web, on other platforms they may differ very slightly (in the range of about 10^-10) from the actual nearest screen coordinate.
/// You therefore might want to round them appropriately, depending on your use case.
///
/// Returns null if [latLng] is not currently visible on the map.
Future<Point> toScreenLocation(LatLng latLng) async{
return MapboxGlPlatform.getInstance(_id).toScreenLocation(latLng);
}

/// Returns the geographic location (as [LatLng]) that corresponds to a point on the screen. The screen location is specified in screen pixels (not display pixels) relative to the top left of the map (not the top left of the whole screen).
Future<LatLng> toLatLng(Point screenLocation) async{
return MapboxGlPlatform.getInstance(_id).toLatLng(screenLocation);
}


}
1 change: 1 addition & 0 deletions mapbox_gl_platform_interface/lib/src/location.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,4 @@ class LatLngBounds {
@override
int get hashCode => hashValues(southwest, northeast);
}

Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,14 @@ abstract class MapboxGlPlatform {
throw UnimplementedError(
'setSymbolTextIgnorePlacement() has not been implemented.');
}

Future<Point> toScreenLocation(LatLng latLng) async{
throw UnimplementedError(
'toScreenLocation() has not been implemented.');
}

Future<LatLng> toLatLng(Point screenLocation) async{
throw UnimplementedError(
'toLatLng() has not been implemented.');
}
}
51 changes: 39 additions & 12 deletions mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -182,23 +182,22 @@ class MethodChannelMapboxGl extends MapboxGlPlatform {
}

@override
Future<List<Symbol>> addSymbols(List<SymbolOptions> options, [List<Map> data]) async {
Future<List<Symbol>> addSymbols(List<SymbolOptions> options,
[List<Map> data]) async {
final List<dynamic> symbolIds = await _channel.invokeMethod(
'symbols#addAll',
<String, dynamic>{
'options': options.map((o) => o.toJson()).toList(),
},
);
final List<Symbol> symbols = symbolIds.asMap().map(
(i, id) => MapEntry(
final List<Symbol> symbols = symbolIds
.asMap()
.map((i, id) => MapEntry(
i,
Symbol(
id,
options.elementAt(i),
data != null && data.length > i ? data.elementAt(i) : null
)
)
).values.toList();
Symbol(id, options.elementAt(i),
data != null && data.length > i ? data.elementAt(i) : null)))
.values
.toList();

return symbols;
}
Expand All @@ -212,7 +211,7 @@ class MethodChannelMapboxGl extends MapboxGlPlatform {
}

@override
Future<LatLng> getSymbolLatLng(Symbol symbol) async{
Future<LatLng> getSymbolLatLng(Symbol symbol) async {
Map mapLatLng =
await _channel.invokeMethod('symbol#getGeometry', <String, dynamic>{
'symbol': symbol._id,
Expand Down Expand Up @@ -249,7 +248,7 @@ class MethodChannelMapboxGl extends MapboxGlPlatform {
}

@override
Future<List<LatLng>> getLineLatLngs(Line line) async{
Future<List<LatLng>> getLineLatLngs(Line line) async {
List latLngList =
await _channel.invokeMethod('line#getGeometry', <String, dynamic>{
'line': line._id,
Expand Down Expand Up @@ -453,4 +452,32 @@ class MethodChannelMapboxGl extends MapboxGlPlatform {
return new Future.error(e);
}
}

@override
Future<Point> toScreenLocation(LatLng latLng) async {
try {
var screenPosMap = await _channel
.invokeMethod('map#toScreenLocation', <String, dynamic>{
'latitude': latLng.latitude,
'longitude':latLng.longitude,
});
return Point(screenPosMap['x'], screenPosMap['y']);
} on PlatformException catch (e) {
return new Future.error(e);
}
}

@override
Future<LatLng> toLatLng(Point screenLocation) async {
try {
var latLngMap = await _channel
.invokeMethod('map#toLatLng', <String, dynamic>{
'x': screenLocation.x,
'y':screenLocation.y,
});
return LatLng(latLngMap['latitude'], latLngMap['longitude']);
} on PlatformException catch (e) {
return new Future.error(e);
}
}
}
12 changes: 12 additions & 0 deletions mapbox_gl_web/lib/src/mapbox_map_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -615,4 +615,16 @@ class MapboxMapController extends MapboxGlPlatform
_map.keyboard.disable();
}
}

@override
Future<Point> toScreenLocation(LatLng latLng) async {
var screenPosition = _map.project(LngLat(latLng.longitude, latLng.latitude));
return Point(screenPosition.x.round(), screenPosition.y.round());
}

@override
Future<LatLng> toLatLng(Point screenLocation) async {
var lngLat = _map.unproject(mapbox.Point(screenLocation.x, screenLocation.y));
return LatLng(lngLat.lat, lngLat.lng);
}
}

0 comments on commit 10788a7

Please sign in to comment.