Select to view content in your preferred language

View rotation (setViewpointRotationAsync)

952
2
Jump to solution
01-18-2021 05:51 AM
JohnCartse
Emerging Contributor

Hello!

I have loaded a map like this:

 

 

MapView mapView = new MapView();
ArcGISMap map = new ArcGISMap(SpatialReferences.getWebMercator());
map.setBasemap(Basemap.createImagery());
map.setMaxScale(...);
mapView.setMap(map);

 

Now, with this mapView object, I would like to rotate the map using the mouse (dragging the mouse).

(note: I don't want to rotate the map itself, just the 'view' or camera, if you will).


I managed to achieve it by doing this when I drag the mouse:

 

 mapView.setViewpointRotationAsync(mousePosDiffX);

 

(note: this method returns a ListenableFuture<Boolean> to tell when it is done.)


However, it is very laggy.

map_rotate3.gif

My first solution would be to avoid calling to much setViewpointRotationAsync by checking the CompletableFuture and call it only when the rotation is it complete using some kind of mutex/lock.. but it is not very successful.

Any help appreciated!

Thanks!

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
MarkBaird
Esri Regular Contributor

I can see how this would not be very pleasing to the user.  I tried it myself and it feels pretty bad.

You'll be glad to hear there is a better way and it's not that complicated.

The laggy experience you have here is happening because you are calling an animated change of viewpoint over and over again.  The approach here is to change the viewpoint without animation.

I've written a method to show how this is done:

  private void rotateMapView(double angle) {
    Viewpoint v = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
    if (angle < 0) {
      angle += 360.0f;
    }
    v = new Viewpoint((Point) v.getTargetGeometry(), v.getTargetScale(), angle);
    mapView.setViewpoint(v);
  }

 

The next step is to wire this up to the custom interaction you are creating.  The best approach is to make your own InteractionListener which you can conveniently create by overriding the DefaultInteractionListener.

I started to put one together here to show how it works, but it needs more work as it is not that robust yet.  It was created as a class within the application class:

  private class rotationInteractionListener extends MapView.DefaultInteractionListener {

    private double initialX;

    protected rotationInteractionListener(MapView mapView) {
      super(mapView);
    }

    @Override
    public void onMousePressed(MouseEvent e) {
      initialX = e.getX();
      System.out.println("custom pressed");
      super.onMousePressed(e);
    }

    @Override
    public void onMouseDragged(MouseEvent e) {

      double xDiff = initialX - e.getX();
      rotateMapView(xDiff);
      System.out.println("custom pan " + xDiff);

      e.consume();
      //super.onMouseDragged(e);
    }
  }

 

To attach the new listener to your mapview you need to add this:

// create a map view and set its map
mapView = new MapView();
mapView.setMap(map);

//Instantiate custom interaction listener and assign it to the mapview
InteractionListener interactionListener = new rotationInteractionListener(mapView);
mapView.setInteractionListener(interactionListener);

You should this solution much less laggy.

Does this help?

View solution in original post

2 Replies
MarkBaird
Esri Regular Contributor

I can see how this would not be very pleasing to the user.  I tried it myself and it feels pretty bad.

You'll be glad to hear there is a better way and it's not that complicated.

The laggy experience you have here is happening because you are calling an animated change of viewpoint over and over again.  The approach here is to change the viewpoint without animation.

I've written a method to show how this is done:

  private void rotateMapView(double angle) {
    Viewpoint v = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
    if (angle < 0) {
      angle += 360.0f;
    }
    v = new Viewpoint((Point) v.getTargetGeometry(), v.getTargetScale(), angle);
    mapView.setViewpoint(v);
  }

 

The next step is to wire this up to the custom interaction you are creating.  The best approach is to make your own InteractionListener which you can conveniently create by overriding the DefaultInteractionListener.

I started to put one together here to show how it works, but it needs more work as it is not that robust yet.  It was created as a class within the application class:

  private class rotationInteractionListener extends MapView.DefaultInteractionListener {

    private double initialX;

    protected rotationInteractionListener(MapView mapView) {
      super(mapView);
    }

    @Override
    public void onMousePressed(MouseEvent e) {
      initialX = e.getX();
      System.out.println("custom pressed");
      super.onMousePressed(e);
    }

    @Override
    public void onMouseDragged(MouseEvent e) {

      double xDiff = initialX - e.getX();
      rotateMapView(xDiff);
      System.out.println("custom pan " + xDiff);

      e.consume();
      //super.onMouseDragged(e);
    }
  }

 

To attach the new listener to your mapview you need to add this:

// create a map view and set its map
mapView = new MapView();
mapView.setMap(map);

//Instantiate custom interaction listener and assign it to the mapview
InteractionListener interactionListener = new rotationInteractionListener(mapView);
mapView.setInteractionListener(interactionListener);

You should this solution much less laggy.

Does this help?

JohnCartse
Emerging Contributor

Thank you Mark! That works like a charm!

0 Kudos