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