Added function to draw custom markers with Kotlin DSL Canvas API. FeatureId can be extended to hold info about a feature??? I added unused onFeatureClick, which can be latter implemented with pointer input, where it will check coordinates with offset? Features need to hold info about their coordinates?

This commit is contained in:
a.kalmakhanov 2022-07-16 14:58:56 +06:00
parent 1ebde3a7a6
commit b520d2f93a
5 changed files with 53 additions and 8 deletions

View File

@ -3,9 +3,12 @@ package centre.sciprog.maps.compose
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import centre.sciprog.maps.GmcBox
typealias FeatureId = String typealias FeatureId = String
@ -15,7 +18,7 @@ interface FeatureBuilder {
fun build(): SnapshotStateMap<FeatureId, MapFeature> fun build(): SnapshotStateMap<FeatureId, MapFeature>
} }
internal class MapFeatureBuilder(initialFeatures: Map<FeatureId,MapFeature>) : FeatureBuilder { internal class MapFeatureBuilder(initialFeatures: Map<FeatureId, MapFeature>) : FeatureBuilder {
private val content: SnapshotStateMap<FeatureId, MapFeature> = mutableStateMapOf<FeatureId, MapFeature>().apply { private val content: SnapshotStateMap<FeatureId, MapFeature> = mutableStateMapOf<FeatureId, MapFeature>().apply {
putAll(initialFeatures) putAll(initialFeatures)
@ -41,6 +44,21 @@ fun FeatureBuilder.circle(
id, MapCircleFeature(centerCoordinates.toCoordinates(), zoomRange, size, color) id, MapCircleFeature(centerCoordinates.toCoordinates(), zoomRange, size, color)
) )
fun FeatureBuilder.custom(
position: Pair<Double, Double>,
id: FeatureId? = null,
customFeatureBuilder: DrawScope.(Offset) -> Unit,
) = addFeature(id, object : MapCustomFeature(position = position.toCoordinates()) {
override fun drawFeature(drawScope: DrawScope, offset: Offset) {
customFeatureBuilder(drawScope, offset)
}
override fun getBoundingBox(zoom: Int): GmcBox {
return GmcBox(position.toCoordinates(), position.toCoordinates())
}
})
fun FeatureBuilder.line( fun FeatureBuilder.line(
aCoordinates: Pair<Double, Double>, aCoordinates: Pair<Double, Double>,
bCoordinates: Pair<Double, Double>, bCoordinates: Pair<Double, Double>,

View File

@ -1,9 +1,11 @@
package centre.sciprog.maps.compose package centre.sciprog.maps.compose
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.graphics.vector.rememberVectorPainter
@ -31,6 +33,13 @@ class MapFeatureSelector(val selector: (zoom: Int) -> MapFeature) : MapFeature(d
} }
abstract class MapCustomFeature(
zoomRange: IntRange = defaultZoomRange,
val position: GeodeticMapCoordinates
) : MapFeature(zoomRange) {
abstract fun drawFeature(drawScope: DrawScope, offset: Offset)
}
class MapCircleFeature( class MapCircleFeature(
val center: GeodeticMapCoordinates, val center: GeodeticMapCoordinates,
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
@ -68,7 +77,7 @@ class MapBitmapImageFeature(
} }
class MapVectorImageFeature ( class MapVectorImageFeature(
val position: GeodeticMapCoordinates, val position: GeodeticMapCoordinates,
val painter: Painter, val painter: Painter,
val size: Size, val size: Size,

View File

@ -21,6 +21,7 @@ expect fun MapView(
computeViewPoint: (canvasSize: DpSize) -> MapViewPoint, computeViewPoint: (canvasSize: DpSize) -> MapViewPoint,
features: Map<FeatureId, MapFeature>, features: Map<FeatureId, MapFeature>,
onClick: MapViewPoint.() -> Unit = {}, onClick: MapViewPoint.() -> Unit = {},
onFeatureClick: (FeatureId) -> Unit = {},
//TODO consider replacing by modifier //TODO consider replacing by modifier
config: MapViewConfig = MapViewConfig(), config: MapViewConfig = MapViewConfig(),
modifier: Modifier = Modifier.fillMaxSize(), modifier: Modifier = Modifier.fillMaxSize(),
@ -32,13 +33,14 @@ fun MapView(
initialViewPoint: MapViewPoint, initialViewPoint: MapViewPoint,
features: Map<FeatureId, MapFeature> = emptyMap(), features: Map<FeatureId, MapFeature> = emptyMap(),
onClick: MapViewPoint.() -> Unit = {}, onClick: MapViewPoint.() -> Unit = {},
onFeatureClick: (FeatureId) -> Unit = {},
config: MapViewConfig = MapViewConfig(), config: MapViewConfig = MapViewConfig(),
modifier: Modifier = Modifier.fillMaxSize(), modifier: Modifier = Modifier.fillMaxSize(),
buildFeatures: @Composable (FeatureBuilder.() -> Unit) = {}, buildFeatures: @Composable (FeatureBuilder.() -> Unit) = {},
) { ) {
val featuresBuilder = MapFeatureBuilder(features) val featuresBuilder = MapFeatureBuilder(features)
featuresBuilder.buildFeatures() featuresBuilder.buildFeatures()
MapView(mapTileProvider, { initialViewPoint }, featuresBuilder.build(), onClick, config, modifier) MapView(mapTileProvider, { initialViewPoint }, featuresBuilder.build(), onClick, onFeatureClick, config, modifier)
} }
@Composable @Composable
@ -47,6 +49,7 @@ fun MapView(
box: GmcBox, box: GmcBox,
features: Map<FeatureId, MapFeature> = emptyMap(), features: Map<FeatureId, MapFeature> = emptyMap(),
onClick: MapViewPoint.() -> Unit = {}, onClick: MapViewPoint.() -> Unit = {},
onFeatureClick: (FeatureId) -> Unit = {},
config: MapViewConfig = MapViewConfig(), config: MapViewConfig = MapViewConfig(),
modifier: Modifier = Modifier.fillMaxSize(), modifier: Modifier = Modifier.fillMaxSize(),
buildFeatures: @Composable (FeatureBuilder.() -> Unit) = {}, buildFeatures: @Composable (FeatureBuilder.() -> Unit) = {},
@ -62,5 +65,5 @@ fun MapView(
) )
MapViewPoint(box.center, zoom) MapViewPoint(box.center, zoom)
} }
MapView(mapTileProvider, computeViewPoint, featuresBuilder.build(), onClick, config, modifier) MapView(mapTileProvider, computeViewPoint, featuresBuilder.build(), onClick, onFeatureClick, config, modifier)
} }

View File

@ -6,14 +6,15 @@ import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Home
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.window.Window import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application import androidx.compose.ui.window.application
import centre.sciprog.maps.GeodeticMapCoordinates import centre.sciprog.maps.GeodeticMapCoordinates
import centre.sciprog.maps.MapViewPoint import centre.sciprog.maps.MapViewPoint
import centre.sciprog.maps.compose.* import centre.sciprog.maps.compose.*
import io.ktor.client.HttpClient import io.ktor.client.*
import io.ktor.client.engine.cio.CIO import io.ktor.client.engine.cio.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -44,15 +45,25 @@ fun App() {
mapTileProvider, mapTileProvider,
viewPoint, viewPoint,
onClick = { coordinates = focus }, onClick = { coordinates = focus },
onFeatureClick = {
},
config = MapViewConfig(inferViewBoxFromFeatures = true) config = MapViewConfig(inferViewBoxFromFeatures = true)
) { ) {
val pointOne = 55.568548 to 37.568604 val pointOne = 55.568548 to 37.568604
val pointTwo = 55.929444 to 37.518434 val pointTwo = 55.929444 to 37.518434
val pointThree = 60.929444 to 37.518434
image(pointOne, Icons.Filled.Home) image(pointOne, Icons.Filled.Home)
//remember feature Id //remember feature Id
val circleId: FeatureId = circle(pointTwo) val circleId: FeatureId = custom(position = pointThree) {
drawRect(
color = Color.Red,
topLeft = it,
size = Size(20f, 20f)
)
}
line(pointOne, pointTwo) line(pointOne, pointTwo)
text(pointOne, "Home") text(pointOne, "Home")

View File

@ -41,6 +41,7 @@ actual fun MapView(
computeViewPoint: (canvasSize: DpSize) -> MapViewPoint, computeViewPoint: (canvasSize: DpSize) -> MapViewPoint,
features: Map<FeatureId, MapFeature>, features: Map<FeatureId, MapFeature>,
onClick: MapViewPoint.() -> Unit, onClick: MapViewPoint.() -> Unit,
onFeatureClick: (FeatureId) -> Unit,
config: MapViewConfig, config: MapViewConfig,
modifier: Modifier, modifier: Modifier,
) { ) {
@ -219,7 +220,10 @@ actual fun MapView(
feature.color.toPaint() feature.color.toPaint()
) )
} }
is MapCustomFeature -> drawIntoCanvas { canvas ->
val offset = feature.position.toOffset()
feature.drawFeature(this, offset)
}
} }
} }