Skip to content

Commit 19858cf

Browse files
committed
fix: fixed dp/px calculation in ScaleBar
1 parent eb277e2 commit 19858cf

File tree

1 file changed

+25
-29
lines changed
  • maps-compose-widgets/src/main/java/com/google/maps/android/compose/widgets

1 file changed

+25
-29
lines changed

maps-compose-widgets/src/main/java/com/google/maps/android/compose/widgets/ScaleBar.kt

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,36 @@ import androidx.compose.ui.geometry.Offset
4040
import androidx.compose.ui.graphics.Color
4141
import androidx.compose.ui.graphics.Shadow
4242
import androidx.compose.ui.graphics.StrokeCap
43+
import androidx.compose.ui.platform.LocalDensity
4344
import androidx.compose.ui.text.style.TextAlign
45+
import androidx.compose.ui.unit.Density
4446
import androidx.compose.ui.unit.Dp
4547
import androidx.compose.ui.unit.dp
4648
import androidx.compose.ui.unit.em
4749
import androidx.compose.ui.unit.sp
50+
import com.google.android.gms.maps.Projection
4851
import com.google.maps.android.compose.CameraPositionState
4952
import com.google.maps.android.ktx.utils.sphericalDistance
5053
import kotlinx.coroutines.delay
5154

55+
internal fun calculateDistance(
56+
projection: Projection,
57+
width: Dp,
58+
density: Density
59+
): Int {
60+
val widthInPixels = with(density) {
61+
width.toPx().toInt()
62+
}
63+
64+
val upperLeftLatLng = projection.fromScreenLocation(Point(0, 0))
65+
val upperRightLatLng =
66+
projection.fromScreenLocation(Point(widthInPixels, 0))
67+
68+
val canvasWidthMeters = upperLeftLatLng.sphericalDistance(upperRightLatLng)
69+
70+
return (canvasWidthMeters * 8 / 9).toInt()
71+
}
72+
5273
public val DarkGray: Color = Color(0xFF3a3c3b)
5374
private val defaultWidth: Dp = 65.dp
5475
private val defaultHeight: Dp = 50.dp
@@ -75,37 +96,12 @@ public fun ScaleBar(
7596
lineColor: Color = DarkGray,
7697
shadowColor: Color = Color.White,
7798
) {
78-
// This is the core logic for calculating the scale of the map.
79-
//
80-
// `remember` with a key (`cameraPositionState.position.zoom`) is used for performance.
81-
// It ensures that the calculation inside is only re-executed when the zoom level changes.
82-
// This is important because we don't need to recalculate the scale every time the map pans,
83-
// only when the zoom level changes.
84-
//
85-
// `derivedStateOf` is a Compose state function that creates a new state object that is
86-
// derived from other state objects. The calculation inside `derivedStateOf` is only
87-
// re-executed when one of the state objects it reads from changes. In this case, it's
88-
// `cameraPositionState.projection`. This is another performance optimization that
89-
// prevents unnecessary recalculations.
99+
val density = LocalDensity.current
90100
val horizontalLineWidthMeters by remember(cameraPositionState.position.zoom) {
91101
derivedStateOf {
92-
// The projection is used to convert between screen coordinates (pixels) and
93-
// geographical coordinates (LatLng). It can be null if the map is not ready yet.
94-
val projection = cameraPositionState.projection ?: return@derivedStateOf 0
95-
96-
// We get the geographical coordinates of two points on the screen: the top-left
97-
// corner (0, 0) and a point to the right of it, at the width of the scale bar.
98-
val upperLeftLatLng = projection.fromScreenLocation(Point(0, 0))
99-
val upperRightLatLng =
100-
projection.fromScreenLocation(Point(0, width.value.toInt()))
101-
102-
// We then calculate the spherical distance between these two points in meters.
103-
// This gives us the distance that the scale bar represents on the map.
104-
val canvasWidthMeters = upperLeftLatLng.sphericalDistance(upperRightLatLng)
105-
106-
// We take 8/9th of the canvas width to provide some padding on the right side
107-
// of the scale bar.
108-
(canvasWidthMeters * 8 / 9).toInt()
102+
cameraPositionState.projection?.let {
103+
calculateDistance(it, width, density)
104+
} ?: 0
109105
}
110106
}
111107

0 commit comments

Comments
 (0)