Skip to content

Commit

Permalink
Move and zoom camera to make points visible (#56)
Browse files Browse the repository at this point in the history
* implement feature

* implement feature

* add example on button click

* reformat

* review

* update README.md and add button for example only on mobile
  • Loading branch information
sbergmair authored Dec 11, 2023
1 parent 8bcefcd commit e52fb73
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 28 deletions.
1 change: 1 addition & 0 deletions arcgis_map_sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Checkout the example app `example/lib/main.dart` for more details.
| addViewPadding ||||
| toggleBaseMap ||||
| moveCamera ||||
| moveCameraToPoints | |||
| zoomIn ||||
| zoomOut ||||
| getZoom ||||
Expand Down
11 changes: 11 additions & 0 deletions arcgis_map_sdk/lib/src/arcgis_map_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,17 @@ class ArcgisMapController {
);
}

Future<void> moveCameraToPoints({
required List<LatLng> points,
double? padding,
}) {
return ArcgisMapPlatform.instance.moveCameraToPoints(
mapId: mapId,
points: points,
padding: padding,
);
}

Future<void> setInteraction({required bool isEnabled}) {
return ArcgisMapPlatform.instance
.setInteraction(mapId, isEnabled: isEnabled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import android.content.Context
import android.view.LayoutInflater
import android.view.View
import com.esri.arcgisruntime.ArcGISRuntimeEnvironment
import com.esri.arcgisruntime.geometry.Geometry
import com.esri.arcgisruntime.geometry.GeometryEngine
import com.esri.arcgisruntime.geometry.Multipoint
import com.esri.arcgisruntime.geometry.Point
import com.esri.arcgisruntime.geometry.PointCollection
import com.esri.arcgisruntime.geometry.Polyline
import com.esri.arcgisruntime.geometry.SpatialReferences
import com.esri.arcgisruntime.layers.ArcGISVectorTiledLayer
import com.esri.arcgisruntime.mapping.ArcGISMap
Expand Down Expand Up @@ -37,10 +41,10 @@ import kotlin.math.roundToInt
* A starting point for documentation can be found here: https://developers.arcgis.com/android/maps-2d/tutorials/display-a-map/
* */
internal class ArcgisMapView(
context: Context,
private val viewId: Int,
private val binaryMessenger: BinaryMessenger,
private val mapOptions: ArcgisMapOptions,
context: Context,
private val viewId: Int,
private val binaryMessenger: BinaryMessenger,
private val mapOptions: ArcgisMapOptions,
) : PlatformView {

private val view: View = LayoutInflater.from(context).inflate(R.layout.vector_map_view, null)
Expand All @@ -52,7 +56,7 @@ internal class ArcgisMapView(
private lateinit var centerPositionStreamHandler: CenterPositionStreamHandler

private val methodChannel =
MethodChannel(binaryMessenger, "dev.fluttercommunity.arcgis_map_sdk/$viewId")
MethodChannel(binaryMessenger, "dev.fluttercommunity.arcgis_map_sdk/$viewId")

override fun getView(): View = view

Expand Down Expand Up @@ -81,18 +85,18 @@ internal class ArcgisMapView(
mapView.addViewpointChangedListener {
val center = mapView.visibleArea.extent.center
val wgs84Center =
GeometryEngine.project(center, SpatialReferences.getWgs84()) as Point
GeometryEngine.project(center, SpatialReferences.getWgs84()) as Point
centerPositionStreamHandler.add(
LatLng(
longitude = wgs84Center.x,
latitude = wgs84Center.y
)
LatLng(
longitude = wgs84Center.x,
latitude = wgs84Center.y
)
)
}

val viewPoint = Viewpoint(
mapOptions.initialCenter.latitude, mapOptions.initialCenter.longitude,
getMapScale(mapOptions.zoom.roundToInt()),
mapOptions.initialCenter.latitude, mapOptions.initialCenter.longitude,
getMapScale(mapOptions.zoom.roundToInt()),
)
mapView.setViewpoint(viewPoint)

Expand All @@ -114,6 +118,7 @@ internal class ArcgisMapView(
"add_view_padding" -> onAddViewPadding(call = call, result = result)
"set_interaction" -> onSetInteraction(call = call, result = result)
"move_camera" -> onMoveCamera(call = call, result = result)
"move_camera_to_points" -> onMoveCameraToPoints(call = call, result = result)
"add_graphic" -> onAddGraphic(call = call, result = result)
"remove_graphic" -> onRemoveGraphic(call = call, result = result)
"toggle_base_map" -> onToggleBaseMap(call = call, result = result)
Expand All @@ -127,10 +132,10 @@ internal class ArcgisMapView(
centerPositionStreamHandler = CenterPositionStreamHandler()

EventChannel(binaryMessenger, "dev.fluttercommunity.arcgis_map_sdk/$viewId/zoom")
.setStreamHandler(zoomStreamHandler)
.setStreamHandler(zoomStreamHandler)

EventChannel(binaryMessenger, "dev.fluttercommunity.arcgis_map_sdk/$viewId/centerPosition")
.setStreamHandler(centerPositionStreamHandler)
.setStreamHandler(centerPositionStreamHandler)
}

private fun onZoomIn(call: MethodCall, result: MethodChannel.Result) {
Expand Down Expand Up @@ -176,10 +181,10 @@ internal class ArcgisMapView(

// https://developers.arcgis.com/android/api-reference/reference/com/esri/arcgisruntime/mapping/view/MapView.html#setViewInsets(double,double,double,double)
mapView.setViewInsets(
viewPadding.left,
viewPadding.top,
viewPadding.right,
viewPadding.bottom
viewPadding.left,
viewPadding.top,
viewPadding.right,
viewPadding.bottom
)

result.success(true)
Expand All @@ -204,7 +209,7 @@ internal class ArcgisMapView(
}

val existingIds =
defaultGraphicsOverlay.graphics.mapNotNull { it.attributes["id"] as? String }
defaultGraphicsOverlay.graphics.mapNotNull { it.attributes["id"] as? String }
val newIds = newGraphic.mapNotNull { it.attributes["id"] as? String }

if (existingIds.any(newIds::contains)) {
Expand Down Expand Up @@ -244,8 +249,8 @@ internal class ArcgisMapView(
val animationOptionMap = (arguments["animationOptions"] as Map<String, Any>?)

val animationOptions =
if (animationOptionMap == null || animationOptionMap.isEmpty()) null
else animationOptionMap.parseToClass<AnimationOptions>()
if (animationOptionMap == null || animationOptionMap.isEmpty()) null
else animationOptionMap.parseToClass<AnimationOptions>()

val scale = if (zoomLevel != null) {
getMapScale(zoomLevel)
Expand All @@ -255,9 +260,9 @@ internal class ArcgisMapView(

val initialViewPort = Viewpoint(point.latitude, point.longitude, scale)
val future = mapView.setViewpointAsync(
initialViewPort,
(animationOptions?.duration?.toFloat() ?: 0F) / 1000,
animationOptions?.animationCurve ?: AnimationCurve.LINEAR,
initialViewPort,
(animationOptions?.duration?.toFloat() ?: 0F) / 1000,
animationOptions?.animationCurve ?: AnimationCurve.LINEAR,
)

future.addDoneListener {
Expand All @@ -269,10 +274,34 @@ internal class ArcgisMapView(
}
}

private fun onMoveCameraToPoints(call: MethodCall, result: MethodChannel.Result) {
val arguments = call.arguments as Map<String, Any>
val latLongs = (arguments["points"] as ArrayList<Map<String, Any>>)
.map { p -> parseToClass<LatLng>(p) }

val padding = arguments["padding"] as Double?

val polyline = Polyline(
PointCollection(latLongs.map { latLng -> Point(latLng.longitude, latLng.latitude) }),
SpatialReferences.getWgs84()
)

val future = if (padding != null) mapView.setViewpointGeometryAsync(polyline.extent, padding)
else mapView.setViewpointGeometryAsync(polyline.extent)

future.addDoneListener {
try {
result.success(future.get())
} catch (e: Exception) {
result.error("Error", e.message, e)
}
}
}

private fun onToggleBaseMap(call: MethodCall, result: MethodChannel.Result) {
val newStyle = gson.fromJson<BasemapStyle>(
call.arguments as String,
object : TypeToken<BasemapStyle>() {}.type
call.arguments as String,
object : TypeToken<BasemapStyle>() {}.type
)
map.basemap = Basemap(newStyle)
result.success(true)
Expand Down
25 changes: 24 additions & 1 deletion arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,12 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
case "add_view_padding": onAddViewPadding(call, result)
case "set_interaction": onSetInteraction(call, result)
case "move_camera": onMoveCamera(call, result)
case "move_camera_to_points": onMoveCameraToPoints(call, result)
case "add_graphic": onAddGraphic(call, result)
case "remove_graphic": onRemoveGraphic(call, result)
case "toggle_base_map" : onToggleBaseMap(call, result)
default:
result(FlutterError(code: "Unimplemented", message: "No method matching the name\(call.method)", details: nil))
result(FlutterError(code: "Unimplemented", message: "No method matching the name \(call.method)", details: nil))
}
})
}
Expand Down Expand Up @@ -190,6 +191,23 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
result(success)
}
}

private func onMoveCameraToPoints(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
let dict = call.arguments as! Dictionary<String, Any>

let payload: MoveToPointsPayload = try! JsonUtil.objectOfJson(dict)
let polyline = AGSPolyline(points: payload.points.map { latLng in AGSPoint(x: latLng.longitude, y:latLng.latitude, spatialReference: .wgs84()) })

if(payload.padding != nil) {
mapView.setViewpointGeometry(polyline.extent, padding: payload.padding!) { success in
result(success)
}
} else {
mapView.setViewpointGeometry(polyline.extent) { success in
result(success)
}
}
}

private func onAddGraphic(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
let parser = GraphicsParser()
Expand Down Expand Up @@ -448,3 +466,8 @@ extension AGSBasemapStyle {
}
}
}

struct MoveToPointsPayload : Codable {
let points : [LatLng]
let padding : Double?
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ class MethodChannelArcgisMapPlugin extends ArcgisMapPlatform {
).then((value) => value!);
}

@override
Future<void> moveCameraToPoints({
required List<LatLng> points,
required int mapId,
double? padding,
}) {
return _methodChannelBuilder(mapId).invokeMethod<bool>(
"move_camera_to_points",
{
"points": points.map((p) => p.toMap()).toList(),
"padding": padding,
},
);
}

@override
Future<bool> zoomIn({
required int lodFactor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ class ArcgisMapPlatform extends PlatformInterface {
throw UnimplementedError('moveCamera() has not been implemented.');
}

Future<void> moveCameraToPoints({
required List<LatLng> points,
required int mapId,
double? padding,
}) {
throw UnimplementedError('moveCameraToPoints() has not been implemented.');
}

Future<bool> zoomIn({
required int lodFactor,
required int mapId,
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b

COCOAPODS: 1.12.1
COCOAPODS: 1.14.2
14 changes: 14 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,13 @@ class _ExampleMapState extends State<ExampleMap> {
_controller?.removeGraphic(layerId: layerId, objectId: objectId);
}

void _makePolylineVisible({required List<LatLng> points}) {
_controller?.moveCameraToPoints(
points: points,
padding: 30,
);
}

void _addPolygon({
required String layerId,
required PolygonGraphic graphic,
Expand Down Expand Up @@ -650,6 +657,13 @@ class _ExampleMapState extends State<ExampleMap> {
],
),
),
if (!kIsWeb)
ElevatedButton(
onPressed: () => _makePolylineVisible(
points: [_firstPinCoordinates, _secondPinCoordinates],
),
child: const Text('Zoom to polyline'),
),
Row(
children: [
const Text(
Expand Down

0 comments on commit e52fb73

Please sign in to comment.