Skip to content

Commit 3fec481

Browse files
committed
Render Map as a schematic region with positioned markers
1 parent 6522717 commit 3fec481

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

  • Demo/swiftui/src/commonMain/kotlin/com/pureswift/swiftui

Demo/swiftui/src/commonMain/kotlin/com/pureswift/swiftui/Render.kt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ private fun RenderResolved(node: ViewNode) {
256256

257257
"LinearGradient" -> RenderGradient(node)
258258

259+
"Map" -> RenderMap(node)
260+
259261
"ProgressView" -> {
260262
val value = node.double("value")
261263
if (value != null) {
@@ -611,6 +613,55 @@ private fun RenderShape(node: ViewNode) {
611613
Box(modifier = node.composeModifiers().background(fill, shape))
612614
}
613615

616+
// A schematic map: the visible region maps linearly onto the box, markers sit
617+
// at their proportional position, and the center coordinate is captioned.
618+
// Real tiles come from a registered composable (maps SDKs need an API key).
619+
@Composable
620+
private fun RenderMap(node: ViewNode) {
621+
val centerLat = node.double("centerLatitude") ?: 0.0
622+
val centerLon = node.double("centerLongitude") ?: 0.0
623+
val spanLat = (node.double("spanLatitude") ?: 1.0).coerceAtLeast(1e-6)
624+
val spanLon = (node.double("spanLongitude") ?: 1.0).coerceAtLeast(1e-6)
625+
Box(
626+
modifier = node.composeModifiers()
627+
.fillMaxWidth()
628+
.height(220.dp)
629+
.clip(RoundedCornerShape(8.dp))
630+
.background(Color(0xFFDCE8DC.toInt()))
631+
.border(1.dp, Color(0xFFB8CCB8.toInt()), RoundedCornerShape(8.dp)),
632+
) {
633+
for (marker in node.children) {
634+
if (marker.type != "MapMarker") continue
635+
val lat = marker.double("latitude") ?: continue
636+
val lon = marker.double("longitude") ?: continue
637+
// normalized region position → alignment bias (north at the top)
638+
val fx = ((lon - (centerLon - spanLon / 2)) / spanLon).coerceIn(0.0, 1.0)
639+
val fy = (((centerLat + spanLat / 2) - lat) / spanLat).coerceIn(0.0, 1.0)
640+
val tint = marker.long("tint")?.let { Color(it.toInt()) } ?: Color(0xFFD32F2F.toInt())
641+
Column(
642+
horizontalAlignment = Alignment.CenterHorizontally,
643+
modifier = Modifier.align(
644+
androidx.compose.ui.BiasAlignment((2 * fx - 1).toFloat(), (2 * fy - 1).toFloat())
645+
),
646+
) {
647+
Box(modifier = Modifier.size(12.dp).clip(CircleShape).background(tint))
648+
Text(marker.string("title") ?: "", fontSize = 11.sp)
649+
}
650+
}
651+
Text(
652+
"${formatCoordinate(centerLat)}, ${formatCoordinate(centerLon)}",
653+
fontSize = 11.sp,
654+
color = Color(0xFF667066.toInt()),
655+
modifier = Modifier.align(Alignment.BottomCenter).padding(4.dp),
656+
)
657+
}
658+
}
659+
660+
private fun formatCoordinate(value: Double): String {
661+
val thousandths = kotlin.math.round(value * 1000) / 1000
662+
return thousandths.toString()
663+
}
664+
614665
// Horizontal/vertical when the endpoints share an axis, else a diagonal linear
615666
// gradient across the frame.
616667
@Composable

0 commit comments

Comments
 (0)