Fixed multi-drag issue. Added demo for bounded drag.

This commit is contained in:
Alexander Nozik 2022-12-07 18:02:20 +03:00
parent 5561a4188c
commit 5448929d31
5 changed files with 52 additions and 19 deletions

View File

@ -45,8 +45,6 @@ fun App() {
val pointTwo = 55.929444 to 37.518434
val pointThree = 60.929444 to 37.518434
val dragPoint = 55.744 to 37.614
MapView(
mapTileProvider = mapTileProvider,
// initialViewPoint = MapViewPoint(
@ -65,7 +63,27 @@ fun App() {
image(pointOne, Icons.Filled.Home)
rectangle(dragPoint, id = "dragMe", size = DpSize(10.dp, 10.dp)).draggable()
var drag1 = Gmc.ofDegrees(55.744, 37.614)
var drag2 = Gmc.ofDegrees(55.8, 37.5)
fun updateLine() {
line(drag1, drag2, id = "connection", color = Color.Magenta)
}
rectangle(drag1, size = DpSize(10.dp, 10.dp)).draggable { _, _, end ->
drag1 = end.focus
updateLine()
true
}
rectangle(drag2, size = DpSize(10.dp, 10.dp)).draggable { _, _, end ->
drag2 = end.focus
updateLine()
true
}
updateLine()
points(
points = listOf(

View File

@ -18,10 +18,15 @@ import kotlin.math.floor
public interface MapFeature {
public val zoomRange: IntRange
public fun getBoundingBox(zoom: Double): GmcRectangle?
}
public interface DraggableMapFeature : MapFeature {
public interface SelectableMapFeature : MapFeature {
public operator fun contains(point: MapViewPoint): Boolean = getBoundingBox(point.zoom)?.let {
point.focus in it
} ?: false
}
public interface DraggableMapFeature : SelectableMapFeature {
public fun withCoordinates(newCoordinates: GeodeticMapCoordinates): MapFeature
}
@ -118,8 +123,12 @@ public class MapLineFeature(
public val b: GeodeticMapCoordinates,
override val zoomRange: IntRange = defaultZoomRange,
public val color: Color = Color.Red,
) : MapFeature {
) : SelectableMapFeature {
override fun getBoundingBox(zoom: Double): GmcRectangle = GmcRectangle(a, b)
override fun contains(point: MapViewPoint): Boolean {
return super.contains(point)
}
}
/**

View File

@ -18,14 +18,14 @@ public object DraggableAttribute : MapFeaturesState.Attribute<DragHandle>
public class MapFeaturesState internal constructor(
private val features: MutableMap<FeatureId, MapFeature>,
private val attributes: MutableMap<FeatureId, SnapshotStateMap<Attribute<out Any?>, in Any?>>,
@PublishedApi internal val attributes: MutableMap<FeatureId, SnapshotStateMap<Attribute<out Any?>, in Any?>>,
) {
public interface Attribute<T>
//TODO use context receiver for that
public fun FeatureId.draggable(
//TODO add constraints
callback: DragHandle = DragHandle.BYPASS
callback: DragHandle = DragHandle.BYPASS,
) {
val handle = DragHandle.withPrimaryButton { event, start, end ->
val feature = features[this] as? DraggableMapFeature ?: return@withPrimaryButton true
@ -72,7 +72,7 @@ public class MapFeaturesState internal constructor(
// }.keys
// }
public fun <T> forEachWithAttribute(key: Attribute<T>, block: (id: FeatureId, attributeValue: T) -> Unit) {
public inline fun <T> forEachWithAttribute(key: Attribute<T>, block: (id: FeatureId, attributeValue: T) -> Unit) {
attributes.forEach { (id, attributeMap) ->
attributeMap[key]?.let {
@Suppress("UNCHECKED_CAST")
@ -126,6 +126,16 @@ public fun MapFeaturesState.circle(
id, MapCircleFeature(centerCoordinates.toCoordinates(), zoomRange, size, color)
)
public fun MapFeaturesState.rectangle(
centerCoordinates: Gmc,
zoomRange: IntRange = defaultZoomRange,
size: DpSize = DpSize(5.dp, 5.dp),
color: Color = Color.Red,
id: FeatureId? = null,
): FeatureId = addFeature(
id, MapRectangleFeature(centerCoordinates, zoomRange, size, color)
)
public fun MapFeaturesState.rectangle(
centerCoordinates: Pair<Double, Double>,
zoomRange: IntRange = defaultZoomRange,

View File

@ -146,11 +146,10 @@ public fun MapView(
}
val featureDrag: DragHandle = DragHandle.withPrimaryButton { event, start, end ->
var bypass = true
featureState.forEachWithAttribute(DraggableAttribute) { _, handle ->
bypass = bypass and handle.handle(event, start, end)
if(!handle.handle(event, start, end)) return@withPrimaryButton false
}
bypass
true
}

View File

@ -116,20 +116,17 @@ public actual fun MapView(
val dpEnd = dragChange.position.toDpOffset()
//apply drag handle and check if it prohibits the drag even propagation
if (
!config.dragHandle.handle(
if (selectionStart == null && !config.dragHandle.handle(
event,
MapViewPoint(dpStart.toGeodetic(), viewPoint.zoom),
MapViewPoint(dpEnd.toGeodetic(), viewPoint.zoom)
)
) {
//clear selection just in case
selectionStart = null
return@drag
}
if (event.buttons.isPrimaryPressed) {
//Evaluating selection frame
//If selection process is started, modify the frame
selectionStart?.let { start ->
val offset = dragChange.position
selectRect = Rect(
@ -141,8 +138,8 @@ public actual fun MapView(
return@drag
}
config.onClick(MapViewPoint(dpPos.toGeodetic(), viewPoint.zoom), event)
// config.onClick(MapViewPoint(dpPos.toGeodetic(), viewPoint.zoom), event)
//If no selection, drag map
setViewPoint(
viewPoint.move(
-dragAmount.x.toDp().value / tileScale,