Add separate builders for feature state
This commit is contained in:
parent
8c79c913e6
commit
2b01b8e316
@ -10,7 +10,7 @@ val ktorVersion by extra("2.0.3")
|
||||
|
||||
allprojects {
|
||||
group = "center.sciprog"
|
||||
version = "0.1.0-dev-5"
|
||||
version = "0.1.0-dev-6"
|
||||
}
|
||||
|
||||
ksciencePublish{
|
||||
|
@ -52,16 +52,29 @@ public class MapFeaturesState internal constructor(
|
||||
condition(it[key] as T)
|
||||
}.keys
|
||||
}
|
||||
}
|
||||
public companion object{
|
||||
|
||||
@Composable
|
||||
public fun rememberMapFeatureState(
|
||||
builder: MapFeaturesState.() -> Unit = {},
|
||||
): MapFeaturesState = remember(builder) {
|
||||
MapFeaturesState(
|
||||
mutableStateMapOf(),
|
||||
mutableStateMapOf()
|
||||
).apply(builder)
|
||||
/**
|
||||
* Build, but do not remember map feature state
|
||||
*/
|
||||
public fun build(
|
||||
builder: MapFeaturesState.() -> Unit = {},
|
||||
): MapFeaturesState = MapFeaturesState(
|
||||
mutableStateMapOf(),
|
||||
mutableStateMapOf()
|
||||
).apply(builder)
|
||||
|
||||
/**
|
||||
* Build and remember map feature state
|
||||
*/
|
||||
@Composable
|
||||
public fun remember(
|
||||
builder: MapFeaturesState.() -> Unit = {},
|
||||
): MapFeaturesState = remember(builder) {
|
||||
build(builder)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public fun MapFeaturesState.circle(
|
||||
|
@ -1,7 +1,9 @@
|
||||
package center.sciprog.maps.compose
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.PointerEvent
|
||||
import androidx.compose.ui.input.pointer.isPrimaryPressed
|
||||
@ -68,15 +70,16 @@ public data class MapViewConfig(
|
||||
public expect fun MapView(
|
||||
mapTileProvider: MapTileProvider,
|
||||
initialViewPoint: MapViewPoint,
|
||||
features: MapFeaturesState,
|
||||
featuresState: MapFeaturesState,
|
||||
config: MapViewConfig = MapViewConfig(),
|
||||
modifier: Modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
internal val defaultCanvasSize = DpSize(512.dp, 512.dp)
|
||||
|
||||
internal fun GmcRectangle.computeViewPoint(
|
||||
public fun GmcRectangle.computeViewPoint(
|
||||
mapTileProvider: MapTileProvider,
|
||||
canvasSize: DpSize,
|
||||
canvasSize: DpSize = defaultCanvasSize,
|
||||
): MapViewPoint {
|
||||
val zoom = log2(
|
||||
min(
|
||||
@ -87,7 +90,33 @@ internal fun GmcRectangle.computeViewPoint(
|
||||
return MapViewPoint(center, zoom)
|
||||
}
|
||||
|
||||
internal val defaultCanvasSize = DpSize(512.dp, 512.dp)
|
||||
/**
|
||||
* A builder for a Map with static features.
|
||||
*/
|
||||
@Composable
|
||||
public fun MapView(
|
||||
mapTileProvider: MapTileProvider,
|
||||
initialViewPoint: MapViewPoint? = null,
|
||||
initialRectangle: GmcRectangle? = null,
|
||||
featureMap: Map<FeatureId, MapFeature>,
|
||||
config: MapViewConfig = MapViewConfig(),
|
||||
modifier: Modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
val featuresState = key(featureMap) {
|
||||
MapFeaturesState.build {
|
||||
featureMap.forEach(::addFeature)
|
||||
}
|
||||
}
|
||||
|
||||
val viewPointOverride: MapViewPoint = remember(initialViewPoint, initialRectangle) {
|
||||
initialViewPoint
|
||||
?: initialRectangle?.computeViewPoint(mapTileProvider)
|
||||
?: featureMap.values.computeBoundingBox(1.0)?.computeViewPoint(mapTileProvider)
|
||||
?: MapViewPoint.globe
|
||||
}
|
||||
|
||||
MapView(mapTileProvider, viewPointOverride, featuresState, config, modifier)
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a map using convenient parameters. If neither [initialViewPoint], noe [initialRectangle] is defined,
|
||||
@ -104,50 +133,40 @@ public fun MapView(
|
||||
config: MapViewConfig = MapViewConfig(),
|
||||
modifier: Modifier = Modifier.fillMaxSize(),
|
||||
buildFeatures: MapFeaturesState.() -> Unit = {},
|
||||
): Unit = key(buildFeatures) {
|
||||
|
||||
val featureState = rememberMapFeatureState(buildFeatures)
|
||||
) {
|
||||
val featureState = MapFeaturesState.remember(buildFeatures)
|
||||
|
||||
val features = featureState.features()
|
||||
|
||||
val viewPointOverride: MapViewPoint = remember(initialViewPoint, initialRectangle) {
|
||||
initialViewPoint
|
||||
?: initialRectangle?.computeViewPoint(mapTileProvider, defaultCanvasSize)
|
||||
?: features.values.computeBoundingBox(1.0)?.computeViewPoint(mapTileProvider, defaultCanvasSize)
|
||||
?: initialRectangle?.computeViewPoint(mapTileProvider)
|
||||
?: features.values.computeBoundingBox(1.0)?.computeViewPoint(mapTileProvider)
|
||||
?: MapViewPoint.globe
|
||||
}
|
||||
|
||||
val featureDrag by remember {
|
||||
derivedStateOf {
|
||||
DragHandle.withPrimaryButton { _, start, end ->
|
||||
val zoom = start.zoom
|
||||
featureState.findAllWithAttribute(DraggableAttribute) { it }.forEach { id ->
|
||||
val feature = features[id] as? DraggableMapFeature ?: return@forEach
|
||||
val boundingBox = feature.getBoundingBox(zoom) ?: return@forEach
|
||||
if (start.focus in boundingBox) {
|
||||
featureState.addFeature(id, feature.withCoordinates(end.focus))
|
||||
return@withPrimaryButton false
|
||||
}
|
||||
}
|
||||
return@withPrimaryButton true
|
||||
val featureDrag = DragHandle.withPrimaryButton { _, start, end ->
|
||||
val zoom = start.zoom
|
||||
featureState.findAllWithAttribute(DraggableAttribute) { it }.forEach { id ->
|
||||
val feature = features[id] as? DraggableMapFeature ?: return@forEach
|
||||
val boundingBox = feature.getBoundingBox(zoom) ?: return@forEach
|
||||
if (start.focus in boundingBox) {
|
||||
featureState.addFeature(id, feature.withCoordinates(end.focus))
|
||||
return@withPrimaryButton false
|
||||
}
|
||||
}
|
||||
return@withPrimaryButton true
|
||||
}
|
||||
|
||||
|
||||
val newConfig by remember {
|
||||
derivedStateOf {
|
||||
config.copy(
|
||||
dragHandle = DragHandle.combine(featureDrag, config.dragHandle)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val newConfig = config.copy(
|
||||
dragHandle = DragHandle.combine(featureDrag, config.dragHandle)
|
||||
)
|
||||
|
||||
MapView(
|
||||
mapTileProvider = mapTileProvider,
|
||||
initialViewPoint = viewPointOverride,
|
||||
features = featureState,
|
||||
featuresState = featureState,
|
||||
config = newConfig,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
@ -49,7 +49,7 @@ private val logger = KotlinLogging.logger("MapView")
|
||||
public actual fun MapView(
|
||||
mapTileProvider: MapTileProvider,
|
||||
initialViewPoint: MapViewPoint,
|
||||
features: MapFeaturesState,
|
||||
featuresState: MapFeaturesState,
|
||||
config: MapViewConfig,
|
||||
modifier: Modifier,
|
||||
): Unit = key(initialViewPoint) {
|
||||
@ -216,8 +216,8 @@ public actual fun MapView(
|
||||
}
|
||||
}
|
||||
|
||||
val painterCache = features.features().values.filterIsInstance<MapVectorImageFeature>().associateWith { it.painter() }
|
||||
|
||||
val painterCache = featuresState.features().values.filterIsInstance<MapVectorImageFeature>()
|
||||
.associateWith { it.painter() }
|
||||
|
||||
Canvas(canvasModifier) {
|
||||
fun WebMercatorCoordinates.toOffset(): Offset = Offset(
|
||||
@ -338,10 +338,12 @@ public actual fun MapView(
|
||||
dstSize = tileSize
|
||||
)
|
||||
}
|
||||
features.features().values.filter { zoom in it.zoomRange }.forEach { feature ->
|
||||
|
||||
featuresState.features().values.filter { zoom in it.zoomRange }.forEach { feature ->
|
||||
drawFeature(zoom, feature)
|
||||
}
|
||||
}
|
||||
|
||||
selectRect?.let { rect ->
|
||||
drawRect(
|
||||
color = Color.Blue,
|
||||
|
Loading…
Reference in New Issue
Block a user