Skip to content

MapCameraPositionInterface (posición de cámara)

MapCameraPositionInterface representa la posición de vista de la cámara, su orientación y la región visible en el mapa. Define hacia dónde mira la cámara, qué parte del mapa se muestra y el punto de vista usado para mostrar el mapa.

Interfaz e implementación

Interfaz MapCameraPositionInterface

interface MapCameraPositionInterface {
val position: GeoPointInterface
val zoom: Double
val bearing: Double
val tilt: Double
val paddings: MapPaddingsInterface?
val visibleRegion: VisibleRegion?
}

MapCameraPosition

La implementación principal proporciona datos inmutables de posición de cámara:

data class MapCameraPosition(
override val position: GeoPoint,
override val zoom: Double = 0.0,
override val bearing: Double = 0.0,
override val tilt: Double = 0.0,
override val paddings: MapPaddingsInterface? = MapPaddings.Zeros,
override val visibleRegion: VisibleRegion? = null
) : MapCameraPositionInterface

Propiedades

Posición de cámara

  • position: GeoPointInterface: El punto central geográfico de la vista de la cámara
  • zoom: Double: El nivel de zoom (sigue aproximadamente la escala de Google Maps)
  • bearing: Double: La orientación de brújula en grados (0 = norte, 90 = este)
  • tilt: Double: El ángulo de inclinación de la cámara en grados (0 = vista vertical hacia abajo, 90 = horizontal)

Configuración de vista

  • paddings: MapPaddingsInterface?: Padding del viewport que afecta la región visible
  • visibleRegion: VisibleRegion?: (solo lectura) Los límites geográficos que realmente se muestran en pantalla

Métodos de creación

Posición predeterminada

// Posición de cámara predeterminada en el origen
val defaultPosition = MapCameraPosition.Default

Posición personalizada

// Posición de cámara básica
val sanFrancisco = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
zoom = 15
)
// Cámara con orientación e inclinación
val aerialView = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
zoom = 18,
bearing = 45, // Northeast direction
tilt = 60 // Angled view
)

Niveles de zoom

Los niveles de zoom de MapConductor siguen aproximadamente la escala de Google Maps, aunque pueden variar ligeramente entre SDKs de mapas:

  • 0-2: Vista mundial, se muestran continentes
  • 3-5: Nivel de país
  • 6-9: Nivel de estado/región
  • 10-12: Nivel de ciudad
  • 13-15: Nivel de distrito/barrio
  • 16-18: Nivel de calle
  • 19-21: Nivel de edificio (alto detalle)
// Different zoom levels for different use cases
val worldView = MapCameraPosition(
position = GeoPoint.fromLatLong(0, 0),
zoom = 2 // Mostrar continentes
)
val cityView = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
zoom = 12 // Mostrar toda la ciudad
)
val streetView = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
zoom = 17 // Mostrar calles individuales
)

Orientación e inclinación

Orientación (rotación)

La orientación rota el mapa alrededor del punto central:

// Norte arriba (predeterminado)
val northUp = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
bearing = 0
)
// Este arriba
val eastUp = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
bearing = 90
)
// Seguir la orientación de la ruta
val routeBearing = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
bearing = 135, // Sureste
zoom = 18.0
)

Inclinación (vista 3D)

La inclinación proporciona un ángulo de visualización 3D:

// Vista desde arriba (predeterminada)
val topDown = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
tilt = 0
)
// Inclinación para dar profundidad
val angled = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
tilt = 30,
zoom = 16
)
// Inclinación máxima a nivel de calle
val streetLevel = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
tilt = 80,
bearing = 45,
zoom = 19
)

Valores negativos de tilt - mirar hacia adelante

Cuando tilt se establece en un valor negativo, la cámara usa una vista elevada que mira hacia arriba por encima del horizonte. Un tilt positivo se trata como una vista que mira hacia abajo al suelo, mientras que un tilt negativo se trata como una vista que mira hacia adelante en la dirección de bearing.

// 通常の俯瞰ビュー(従来の動作)
MapCameraPosition(
position = GeoPoint(35.68, 139.76),
zoom = 15.0,
tilt = 60.0, // 地面を60度の角度で見下ろす
)
// 前方(水平線上方)を見る
MapCameraPosition(
position = GeoPoint(35.68, 139.76),
zoom = 15.0,
tilt = -30.0, // 水平線より30度上方を見る
bearing = 45.0,
)
// ArcGIS はネイティブ対応
  • ArcGIS: ArcGIS のカメラ仕様と同じく、負の tilt にネイティブ対応します。
  • Google Maps / Mapbox / MapLibre / HERE: 上向きピッチを直接表現できないため、カメラ位置を固定し、bearing 方向の前方へターゲットを移動してシミュレーションします。ネイティブの仰角ビューと完全に同一にはなりません。

Región visible

La región visible describe el área geográfica real que se muestra en pantalla después de considerar la posición de cámara, el nivel de zoom, la orientación, la inclinación y el padding del viewport.

Clase VisibleRegion

data class VisibleRegion(
val bounds: GeoRectBounds, // Rectángulo delimitador completo
val nearLeft: GeoPointInterface?, // Esquina inferior izquierda (lado cercano a la cámara)
val nearRight: GeoPointInterface?, // Esquina inferior derecha (lado cercano a la cámara)
val farLeft: GeoPointInterface?, // Esquina superior izquierda (lado lejano a la cámara)
val farRight: GeoPointInterface? // Esquina superior derecha (lado lejano a la cámara)
)

Propiedades

  • bounds: GeoRectBounds: Límites geográficos del rectángulo que contiene toda la región visible. Este es el rectángulo delimitador más pequeño que contiene todo el contenido visible.
  • nearLeft: GeoPointInterface?: Coordenadas geográficas de la esquina inferior izquierda de la región visible. “near” se refiere al lado más cercano a la posición de la cámara.
  • nearRight: GeoPointInterface?: Coordenadas geográficas de la esquina inferior derecha de la región visible.
  • farLeft: GeoPointInterface?: Coordenadas geográficas de la esquina superior izquierda de la región visible. “far” se refiere al lado más lejano a la posición de la cámara.
  • farRight: GeoPointInterface?: Coordenadas geográficas de la esquina superior derecha de la región visible.

Uso de VisibleRegion

@Composable
fun VisibleRegionExample() {
val mapViewState = rememberMapboxMapViewState(
cameraPosition = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
zoom = 15.0
),
)
var visibleRegionInfo by remember { mutableStateOf<VisibleRegion?>(null) }
// Reemplaza MapView por el SDK de mapas que elijas, como GoogleMapView o MapboxMapView
MapboxMapView(
state = mapViewState,
modifier = modifier,
onCameraMoveEnd = { cameraPosition ->
cameraPosition.visibleRegion?.let { visibleRegion ->
visibleRegionInfo = visibleRegion
}
},
) {
// Mostrar información de la región visible
visibleRegionInfo?.let { region ->
// Mostrar los límites como un polígono
region.bounds.let { bounds ->
if (!bounds.isEmpty) {
val sw = bounds.southWest!!
val ne = bounds.northEast!!
Polygon(
points = listOf(
sw,
GeoPoint.fromLatLong(sw.latitude, ne.longitude),
ne,
GeoPoint.fromLatLong(ne.latitude, sw.longitude),
sw
),
strokeColor = Color.Blue,
strokeWidth = 2.dp,
fillColor = Color.Blue.copy(alpha = 0.1f)
)
}
}
}
}
}

Animaciones y transiciones

Movimiento suave de cámara

@Composable
fun AnimatedCameraExample() {
val locations = listOf(
GeoPoint.fromLatLong(37.7749, -122.4194), // San Francisco
GeoPoint.fromLatLong(40.7128, -74.0060), // New York
GeoPoint.fromLatLong(51.5074, -0.1278) // London
)
val mapViewState = rememberHereMapViewState(
cameraPosition = MapCameraPosition(
position = locations[0],
zoom = 6.0
),
)
var currentIndex by remember { mutableStateOf(0) }
// Animar a la siguiente ubicación cada 5 segundos
LaunchedEffect(Unit) {
while (true) {
delay(5000)
currentIndex = (currentIndex + 1) % locations.size
val targetPosition = MapCameraPosition(
position = locations[currentIndex],
zoom = 6.0,
bearing = 0.0,
tilt = 0.0
)
mapViewState.moveCameraTo(targetPosition, 1000)
}
}
// Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView
HereMapView(
state = mapViewState,
modifier = modifier,
) {
// Add markers for each location
locations.forEachIndexed { index, location ->
Marker(
position = location,
icon = ColorDefaultIcon(
fillColor = if (index == currentIndex) Color.Red else Color.Gray,
label = when (index) {
0 -> "SF"
1 -> "NYC"
2 -> "LON"
else -> "$index"
}
)
)
}
}
}

Control interactivo de cámara

@Composable
fun CameraControlExample(modifier: Modifier = Modifier) {
val mapViewState = rememberMapLibreMapViewState(
mapDesign = MapLibreDesignType(
id = "debug-tiles",
styleJsonURL = "https://demotiles.maplibre.org/debug-tiles/style.json",
),
cameraPosition = MapCameraPosition(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
zoom = 15.0
),
)
Column(
modifier = modifier,
) {
// Camera controls
Row {
Button(
onClick = {
val newZoom = mapViewState.cameraPosition.copy(
zoom = (mapViewState.cameraPosition.zoom + 1)
.coerceAtMost(21.0),
)
mapViewState.moveCameraTo(newZoom, 500)
}
) {
Text("Zoom In")
}
Button(
onClick = {
val newZoom = mapViewState.cameraPosition.copy(
zoom = (mapViewState.cameraPosition.zoom - 1)
.coerceAtMost(21.0),
)
mapViewState.moveCameraTo(newZoom, 500)
}
) {
Text("Zoom Out")
}
Button(
onClick = {
val newZoom = mapViewState.cameraPosition.copy(
bearing = (mapViewState.cameraPosition.bearing + 45) % 360,
)
mapViewState.moveCameraTo(newZoom, 500)
}
) {
Text("Rotate")
}
}
// Tilt slider
Slider(
value = mapViewState.cameraPosition.tilt.toFloat(),
onValueChange = { tilt ->
val newZoom = mapViewState.cameraPosition.copy(
tilt = tilt.toDouble(),
)
mapViewState.moveCameraTo(newZoom)
},
valueRange = 0f..80f
)
// Reemplaza MapView por el SDK de mapas que elijas, como GoogleMapView o MapboxMapView
MapLibreMapView(
state = mapViewState,
) {
Marker(
position = mapViewState.cameraPosition.position,
icon = ColorDefaultIcon(fillColor = Color.Red)
)
}
}
}

Ajustar a límites

Usa fitBounds para mover y hacer zoom de la cámara de modo que un GeoRectBounds sea completamente visible:

val bounds = GeoRectBounds(
southWest = GeoPoint.fromLatLong(37.7649, -122.4294),
northEast = GeoPoint.fromLatLong(37.7849, -122.4094)
)
mapViewState.fitBounds(bounds, padding = 32)

El parámetro padding agrega un margen en píxeles en todos los lados del espacio de pantalla. Cada proveedor calcula el nivel de zoom resultante de forma nativa.

Mostrar múltiples puntos

Para encuadrar un conjunto de marcadores o puntos de ruta, extiende los límites y luego ajusta:

// Calculate bounds containing all points, then set appropriate zoom
val allPoints = listOf(/* your points */)
val bounds = GeoRectBounds()
allPoints.forEach { bounds.extend(it) }
val centerCamera = MapCameraPosition(
position = bounds.center ?: GeoPoint.fromLatLong(0.0, 0.0),
zoom = calculateZoomForBounds(bounds), // Usa fitBounds en lugar del cálculo manual de zoom
bearing = 0.0,
tilt = 0.0
)

La llamada a fitBounds reemplaza el cálculo manual de zoom mostrado arriba:

val bounds = GeoRectBounds()
allPoints.forEach { bounds.extend(it) }
if (!bounds.isEmpty) {
mapViewState.fitBounds(bounds, padding = 48)
}