Skip to content
View on GitHubSample viewer app

This sample demonstrates how to keep the viewpoints of two GeoViews (a 2D MapView and a 3D SceneView) synchronized with each other.

Screenshot of match viewpoint of geo views

Use case

You might need to synchronize GeoView viewpoints if you had two map views in one application - a main map and an inset. An inset map view could display all the layers at their full extent and contain a hollow rectangular graphic that represents the visible extent of the main map view. As you zoom or pan in the main map view, the extent graphic in the inset map would adjust accordingly.

How to use the sample

Interact with the MapView or SceneView by zooming or panning. The other MapView or SceneView will automatically focus on the same viewpoint.

How it works

  1. The ViewModel creates two containers: an ArcGISMap and an ArcGISScene. Both are initialized with the same initial Viewpoint (center coordinate and scale).
  2. The ViewModel also exposes a MapViewProxy and a SceneViewProxy. These proxies provide convenience functions to set viewpoints on the map/scene from the ViewModel without needing direct MapView/SceneView references.
  3. Each GeoView composable registers two callbacks:
    • onNavigationChanged: notifies when the user is actively navigating (panning/zooming/rotating).
    • onViewpointChangedForCenterAndScale: notifies about center-and-scale viewpoint updates.
  4. When the MapView viewpoint changes and the SceneView is not currently navigating, the ViewModel sets the SceneViewProxy to the new viewpoint. Symmetrically, when the SceneView viewpoint changes and the MapView is not navigating, the ViewModel sets the MapViewProxy to that viewpoint.

Relevant API

  • GeoView
  • MapView
  • SceneView
  • Viewpoint

About the data

This application provides two different perspectives of the arcGISImagery basemap, A 2D MapView as well as a 3D SceneView, displayed side by side.

Tags

3D, automatic refresh, event, event handler, events, extent, interaction, interactions, pan, zoom

Sample Code

MatchViewpointOfGeoViewsViewModel.ktMatchViewpointOfGeoViewsViewModel.ktMainActivity.ktMatchViewpointOfGeoViewsScreen.kt
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.esri.arcgismaps.sample.matchviewpointofgeoviews.screens

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import com.arcgismaps.geometry.Point
import com.arcgismaps.geometry.SpatialReference
import com.arcgismaps.mapping.ArcGISMap
import com.arcgismaps.mapping.ArcGISScene
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.Viewpoint
import com.arcgismaps.toolkit.geoviewcompose.MapViewProxy
import com.arcgismaps.toolkit.geoviewcompose.SceneViewProxy

class MatchViewpointOfGeoViewsViewModel : ViewModel() {
    val arcGISMap = ArcGISMap(BasemapStyle.ArcGISImagery)
    val arcGISScene = ArcGISScene(BasemapStyle.ArcGISImagery)
    val mapViewProxy = MapViewProxy()
    val sceneViewProxy = SceneViewProxy()

    // Initial viewpoint
    private val initialViewpoint = Viewpoint(
        center = Point(-13637000.0, 4550000.0, SpatialReference.webMercator()),
        scale = 100_000.0
    )

    // Track navigation state
    var isMapNavigating by mutableStateOf(false)
    var isSceneNavigating by mutableStateOf(false)

    init {
        arcGISMap.initialViewpoint = initialViewpoint
        arcGISScene.initialViewpoint = initialViewpoint
    }

    fun updateMapIsNavigating(navigating: Boolean) {
        isMapNavigating = navigating
    }

    fun updateSceneIsNavigating(navigating: Boolean) {
        isSceneNavigating = navigating
    }

    fun onMapViewpointChanged(newViewpoint: Viewpoint) {
        if (!isSceneNavigating) {
            sceneViewProxy.setViewpoint(newViewpoint)
        }
    }

    fun onSceneViewpointChanged(newViewpoint: Viewpoint) {
        if (!isMapNavigating) {
            mapViewProxy.setViewpoint(newViewpoint)
        }
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.