Change state propagation to better support dynamic features. Drag not working for now
This commit is contained in:
parent
fa51fc03db
commit
4c71b8e7bb
@ -28,21 +28,16 @@ public interface MapFeatureBuilder {
|
||||
|
||||
public fun <T> setAttribute(id: FeatureId, key: MapFeatureAttributeKey<T>, value: T)
|
||||
|
||||
public val features: MutableMap<FeatureId, MapFeature>
|
||||
|
||||
public val attributes: Map<FeatureId, MapFeatureAttributeSet>
|
||||
|
||||
//TODO use context receiver for that
|
||||
public fun FeatureId.draggable(enabled: Boolean = true) {
|
||||
setAttribute(this, DraggableAttribute, enabled)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MapFeatureBuilderImpl(
|
||||
override val features: SnapshotStateMap<FeatureId, MapFeature>,
|
||||
) : MapFeatureBuilder {
|
||||
internal class MapFeatureBuilderImpl: MapFeatureBuilder {
|
||||
|
||||
private val _attributes = SnapshotStateMap<FeatureId, SnapshotStateMap<MapFeatureAttributeKey<out Any?>, in Any?>>()
|
||||
internal val features = mutableStateMapOf<FeatureId, MapFeature>()
|
||||
internal val attributes = SnapshotStateMap<FeatureId, SnapshotStateMap<MapFeatureAttributeKey<out Any?>, in Any?>>()
|
||||
|
||||
|
||||
private fun generateID(feature: MapFeature): FeatureId = "@feature[${feature.hashCode().toUInt()}]"
|
||||
@ -54,14 +49,13 @@ internal class MapFeatureBuilderImpl(
|
||||
}
|
||||
|
||||
override fun <T> setAttribute(id: FeatureId, key: MapFeatureAttributeKey<T>, value: T) {
|
||||
_attributes.getOrPut(id) { SnapshotStateMap() }[key] = value
|
||||
attributes.getOrPut(id) { SnapshotStateMap() }[key] = value
|
||||
}
|
||||
|
||||
override val attributes: Map<FeatureId, MapFeatureAttributeSet>
|
||||
get() = _attributes.mapValues { MapFeatureAttributeSet(it.value) }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public fun MapFeatureBuilder.circle(
|
||||
center: GeodeticMapCoordinates,
|
||||
zoomRange: IntRange = defaultZoomRange,
|
||||
@ -195,7 +189,7 @@ public fun MapFeatureBuilder.group(
|
||||
id: FeatureId? = null,
|
||||
builder: MapFeatureBuilder.() -> Unit,
|
||||
): FeatureId {
|
||||
val map = MapFeatureBuilderImpl(mutableStateMapOf()).apply(builder).features
|
||||
val map = MapFeatureBuilderImpl().apply(builder).features
|
||||
val feature = MapFeatureGroup(map, zoomRange)
|
||||
return addFeature(id, feature)
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ package center.sciprog.maps.compose
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.PointerEvent
|
||||
import androidx.compose.ui.input.pointer.isPrimaryPressed
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import center.sciprog.maps.coordinates.*
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.log2
|
||||
@ -87,6 +87,8 @@ internal fun GmcRectangle.computeViewPoint(
|
||||
return MapViewPoint(center, zoom)
|
||||
}
|
||||
|
||||
private val defaultCanvasSize = DpSize(512.dp, 512.dp)
|
||||
|
||||
/**
|
||||
* Draw a map using convenient parameters. If neither [initialViewPoint], noe [initialRectangle] is defined,
|
||||
* use map features to infer view region.
|
||||
@ -102,46 +104,48 @@ public fun MapView(
|
||||
config: MapViewConfig = MapViewConfig(),
|
||||
modifier: Modifier = Modifier.fillMaxSize(),
|
||||
buildFeatures: @Composable (MapFeatureBuilder.() -> Unit) = {},
|
||||
) {
|
||||
): Unit = key(buildFeatures) {
|
||||
|
||||
var viewPointOverride by remember(initialViewPoint, initialRectangle) { mutableStateOf(initialViewPoint ?: MapViewPoint.globe) }
|
||||
val featuresBuilder = MapFeatureBuilderImpl().apply { buildFeatures() }
|
||||
|
||||
val featuresBuilder = MapFeatureBuilderImpl(mutableStateMapOf()).apply { buildFeatures() }
|
||||
val features = featuresBuilder.features
|
||||
val attributes = featuresBuilder.attributes
|
||||
|
||||
val features: SnapshotStateMap<FeatureId, MapFeature> = remember(buildFeatures) { featuresBuilder.features }
|
||||
var cachedCanvasSize: DpSize by remember { mutableStateOf(defaultCanvasSize) }
|
||||
|
||||
val attributes = remember(buildFeatures) { featuresBuilder.attributes }
|
||||
|
||||
val featureDrag by derivedStateOf {
|
||||
DragHandle.withPrimaryButton { _, start, end ->
|
||||
val zoom = start.zoom
|
||||
attributes.filterValues {
|
||||
it[DraggableAttribute] ?: false
|
||||
}.keys.forEach { id ->
|
||||
val feature = features[id] as? DraggableMapFeature ?: return@forEach
|
||||
//val border = WebMercatorProjection.scaleFactor(zoom)
|
||||
val boundingBox = feature.getBoundingBox(zoom) ?: return@forEach
|
||||
if (start.focus in boundingBox) {
|
||||
features[id] = feature.withCoordinates(end.focus)
|
||||
return@withPrimaryButton false
|
||||
}
|
||||
}
|
||||
return@withPrimaryButton true
|
||||
}
|
||||
val viewPointOverride: MapViewPoint = remember(initialViewPoint, initialRectangle, cachedCanvasSize) {
|
||||
initialViewPoint
|
||||
?: initialRectangle?.computeViewPoint(mapTileProvider, cachedCanvasSize)
|
||||
?: features.values.computeBoundingBox(1.0)?.computeViewPoint(mapTileProvider, cachedCanvasSize)
|
||||
?: MapViewPoint.globe
|
||||
}
|
||||
|
||||
val featureDrag = DragHandle.withPrimaryButton { _, start, end ->
|
||||
val zoom = start.zoom
|
||||
attributes.filterValues {
|
||||
it[DraggableAttribute] as? Boolean ?: false
|
||||
}.keys.forEach { id ->
|
||||
val feature = features[id] as? DraggableMapFeature ?: return@forEach
|
||||
//val border = WebMercatorProjection.scaleFactor(zoom)
|
||||
val boundingBox = feature.getBoundingBox(zoom) ?: return@forEach
|
||||
if (start.focus in boundingBox) {
|
||||
features[id] = feature.withCoordinates(end.focus)
|
||||
return@withPrimaryButton false
|
||||
}
|
||||
}
|
||||
return@withPrimaryButton true
|
||||
}
|
||||
|
||||
|
||||
val newConfig = config.copy(
|
||||
dragHandle = DragHandle.combine(featureDrag, config.dragHandle),
|
||||
onCanvasSizeChange = { canvasSize ->
|
||||
viewPointOverride = initialViewPoint
|
||||
?: initialRectangle?.computeViewPoint(mapTileProvider, canvasSize)
|
||||
?: features.values.computeBoundingBox(1.0)?.computeViewPoint(mapTileProvider, canvasSize)
|
||||
?: MapViewPoint.globe
|
||||
|
||||
config.onCanvasSizeChange(canvasSize)
|
||||
cachedCanvasSize = canvasSize
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
MapView(
|
||||
mapTileProvider = mapTileProvider,
|
||||
initialViewPoint = viewPointOverride,
|
||||
|
@ -53,17 +53,11 @@ public actual fun MapView(
|
||||
features: Map<FeatureId, MapFeature>,
|
||||
config: MapViewConfig,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
): Unit = key(initialViewPoint) {
|
||||
var canvasSize by remember { mutableStateOf(DpSize(512.dp, 512.dp)) }
|
||||
|
||||
var viewPointOverride by remember { mutableStateOf(initialViewPoint) }
|
||||
var viewPoint by remember { mutableStateOf(initialViewPoint) }
|
||||
|
||||
if (viewPointOverride != initialViewPoint) {
|
||||
viewPoint = initialViewPoint
|
||||
viewPointOverride = initialViewPoint
|
||||
}
|
||||
|
||||
fun setViewPoint(newViewPoint: MapViewPoint) {
|
||||
config.onViewChange(newViewPoint)
|
||||
viewPoint = newViewPoint
|
||||
@ -78,7 +72,7 @@ public actual fun MapView(
|
||||
2.0.pow(viewPoint.zoom - zoom)
|
||||
}
|
||||
|
||||
val mapTiles = remember { mutableStateListOf<MapTile>() }
|
||||
val mapTiles = remember(mapTileProvider) { mutableStateListOf<MapTile>() }
|
||||
|
||||
val centerCoordinates by derivedStateOf { WebMercatorProjection.toMercator(viewPoint.focus, zoom) }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user