Select to view content in your preferred language

Signal presence of the map markers outside visible area

151
1
03-20-2025 08:24 AM
GabrielDogaru
New Contributor

I have a requirement to signal off the screen markers by showing some icons at the edge of the screen, in the direction of that marker.

Do you have any suggestions what can be the best way to achieve that? 

Should I try to use a map overlay and try to place graphics at the edge of the viewport or use a native compose component on top of the map and place icons on that?

0 Kudos
1 Reply
Shubham_Sharma
Esri Contributor

You can use the locationToScreen to determine the direction-position of your point/graphic relative to the device's display metrics. Using this logic, you could display content on top of your MapView to display your markers. In my opinion, a native overlay would work well. 

 

Here is a direction-position example (without-overlay) using the Toolkit GeoView-Compose:

 

import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.arcgismaps.Color
import com.arcgismaps.geometry.Point
import com.arcgismaps.geometry.SpatialReference
import com.arcgismaps.mapping.ArcGISMap
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbol
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbolStyle
import com.arcgismaps.mapping.view.Graphic
import com.arcgismaps.mapping.view.GraphicsOverlay
import com.arcgismaps.toolkit.geoviewcompose.MapView
import com.arcgismaps.toolkit.geoviewcompose.MapViewProxy

class MainActivity : ComponentActivity() {

    val map = ArcGISMap(BasemapStyle.ArcGISNavigationNight)
    var currentMarkerPosition by mutableStateOf(MarkerPosition.VISIBLE)
    val mapViewProxy = MapViewProxy()
    val point = Point(0.0, 0.0, SpatialReference.wgs84())

    val pointGraphic = Graphic(
        geometry = point,
        symbol = SimpleMarkerSymbol(
            style = SimpleMarkerSymbolStyle.Cross,
            color = Color.fromRgba(255, 255, 0, 255),
            size = 20f
        )
    )

    val graphicsOverlay = GraphicsOverlay(graphics = listOf(pointGraphic))

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.ACCESS_TOKEN)
        setContent {
            MaterialTheme {
                MainScreen()
            }
        }
    }

    @Composable
    fun MainScreen() {
        Scaffold {
            val displayMetrics = LocalContext.current.resources.displayMetrics

            Column(modifier = Modifier.padding(it)) {
                Text("Marker position: ${currentMarkerPosition.name}")
                MapView(
                    modifier = Modifier
                        .fillMaxSize()
                        .weight(1f),
                    arcGISMap = map,
                    mapViewProxy = mapViewProxy,
                    graphicsOverlays = listOf(graphicsOverlay),
                    onVisibleAreaChanged = {
                        updateMarkerPosition(displayMetrics)
                    }
                )
            }
        }
    }

    private fun updateMarkerPosition(displayMetrics: DisplayMetrics) {
        val screenCoordinate = mapViewProxy.locationToScreenOrNull(mapPoint = point) ?: return

        //The origin point for screen coordinate is at the top-left of MapView.
        currentMarkerPosition = when {
            (screenCoordinate.x) > displayMetrics.widthPixels -> MarkerPosition.RIGHT
            (screenCoordinate.y) > displayMetrics.heightPixels -> MarkerPosition.DOWN
            (screenCoordinate.x) <= 0.0 -> MarkerPosition.LEFT
            (screenCoordinate.y) <= 0.0 -> MarkerPosition.TOP
            else -> MarkerPosition.VISIBLE
        }

        Log.e("MARKER", "screenCoordinate: x=${screenCoordinate.x},y=${screenCoordinate.y}")
        Log.e("MARKER", "currentMarkerPosition: ${currentMarkerPosition.name}")
    }

}

enum class MarkerPosition { TOP, DOWN, LEFT, RIGHT, VISIBLE }
​