Refactored drag processing
This commit is contained in:
parent
26aaac2ecd
commit
5a1d3d701f
@ -7,6 +7,7 @@ import androidx.compose.runtime.*
|
|||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.PointMode
|
import androidx.compose.ui.graphics.PointMode
|
||||||
|
import androidx.compose.ui.input.pointer.isPrimaryPressed
|
||||||
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 center.sciprog.maps.compose.*
|
import center.sciprog.maps.compose.*
|
||||||
@ -58,14 +59,18 @@ fun App() {
|
|||||||
config = MapViewConfig(
|
config = MapViewConfig(
|
||||||
inferViewBoxFromFeatures = true,
|
inferViewBoxFromFeatures = true,
|
||||||
onViewChange = { centerCoordinates = focus },
|
onViewChange = { centerCoordinates = focus },
|
||||||
onDrag = { start, end ->
|
dragHandle = { event, start, end ->
|
||||||
if (start.focus.latitude.degrees.value in (pointTwo.first - 0.05)..(pointTwo.first + 0.05) &&
|
if (!event.buttons.isPrimaryPressed) {
|
||||||
|
true
|
||||||
|
} else if (start.focus.latitude.degrees.value in (pointTwo.first - 0.05)..(pointTwo.first + 0.05) &&
|
||||||
start.focus.longitude.degrees.value in (pointTwo.second - 0.05)..(pointTwo.second + 0.05)
|
start.focus.longitude.degrees.value in (pointTwo.second - 0.05)..(pointTwo.second + 0.05)
|
||||||
) {
|
) {
|
||||||
pointTwo = pointTwo.first + (end.focus.latitude - start.focus.latitude).degrees.value to
|
pointTwo = pointTwo.first + (end.focus.latitude - start.focus.latitude).degrees.value to
|
||||||
pointTwo.second + (end.focus.longitude - start.focus.longitude).degrees.value
|
pointTwo.second + (end.focus.longitude - start.focus.longitude).degrees.value
|
||||||
false// returning false, because when we are dragging circle we don't want to drag map
|
false// returning false, because when we are dragging circle we don't want to drag map
|
||||||
} else true
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@ -3,6 +3,7 @@ package center.sciprog.maps.compose
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.pointer.PointerEvent
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
import center.sciprog.maps.coordinates.*
|
import center.sciprog.maps.coordinates.*
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
@ -10,16 +11,29 @@ import kotlin.math.log2
|
|||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
|
public fun interface DragHandle {
|
||||||
|
/**
|
||||||
|
* @param event - qualifiers of the event used for drag
|
||||||
|
* @param start - is a point where drag begins, end is a point where drag ends
|
||||||
|
* @param end - end point of the drag
|
||||||
|
*
|
||||||
|
* @return true if default event processors should be used after this one
|
||||||
|
*/
|
||||||
|
public fun drag(event: PointerEvent, start: MapViewPoint, end: MapViewPoint): Boolean
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val BYPASS: DragHandle = DragHandle { _, _, _ -> true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//TODO consider replacing by modifier
|
//TODO consider replacing by modifier
|
||||||
/**
|
/**
|
||||||
* @param onDrag - returns true if you want to drag a map and false, if you want to make map stationary.
|
|
||||||
* start - is a point where drag begins, end is a point where drag ends
|
|
||||||
*/
|
*/
|
||||||
public data class MapViewConfig(
|
public data class MapViewConfig(
|
||||||
val zoomSpeed: Double = 1.0 / 3.0,
|
val zoomSpeed: Double = 1.0 / 3.0,
|
||||||
val inferViewBoxFromFeatures: Boolean = false,
|
val inferViewBoxFromFeatures: Boolean = false,
|
||||||
val onClick: MapViewPoint.() -> Unit = {},
|
val onClick: MapViewPoint.(PointerEvent) -> Unit = {},
|
||||||
val onDrag: (start: MapViewPoint, end: MapViewPoint) -> Boolean = { _, _ -> true },
|
val dragHandle: DragHandle = DragHandle.BYPASS,
|
||||||
val onViewChange: MapViewPoint.() -> Unit = {},
|
val onViewChange: MapViewPoint.() -> Unit = {},
|
||||||
val onSelect: (GmcRectangle) -> Unit = {},
|
val onSelect: (GmcRectangle) -> Unit = {},
|
||||||
val zoomOnSelect: Boolean = true,
|
val zoomOnSelect: Boolean = true,
|
||||||
|
@ -80,9 +80,14 @@ public actual fun MapView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val zoom: Int by derivedStateOf { floor(viewPoint.zoom).toInt() }
|
val zoom: Int by derivedStateOf {
|
||||||
|
require(viewPoint.zoom in 1.0..18.0) { "Zoom value of ${viewPoint.zoom} is not valid" }
|
||||||
|
floor(viewPoint.zoom).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
val tileScale: Double by derivedStateOf { 2.0.pow(viewPoint.zoom - zoom) }
|
val tileScale: Double by derivedStateOf {
|
||||||
|
2.0.pow(viewPoint.zoom - zoom)
|
||||||
|
}
|
||||||
|
|
||||||
val mapTiles = remember { mutableStateListOf<MapTile>() }
|
val mapTiles = remember { mutableStateListOf<MapTile>() }
|
||||||
|
|
||||||
@ -109,61 +114,75 @@ public actual fun MapView(
|
|||||||
fun Offset.toDpOffset() = DpOffset(x.toDp(), y.toDp())
|
fun Offset.toDpOffset() = DpOffset(x.toDp(), y.toDp())
|
||||||
|
|
||||||
val event: PointerEvent = awaitPointerEvent()
|
val event: PointerEvent = awaitPointerEvent()
|
||||||
event.changes.forEach { change ->
|
|
||||||
if (event.buttons.isPrimaryPressed) {
|
|
||||||
//Evaluating selection frame
|
|
||||||
if (event.keyboardModifiers.isShiftPressed) {
|
|
||||||
selectRect = Rect(change.position, change.position)
|
|
||||||
drag(change.id) { dragChange ->
|
|
||||||
selectRect?.let { rect ->
|
|
||||||
val offset = dragChange.position
|
|
||||||
selectRect = Rect(
|
|
||||||
min(offset.x, rect.left),
|
|
||||||
min(offset.y, rect.top),
|
|
||||||
max(offset.x, rect.right),
|
|
||||||
max(offset.y, rect.bottom)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selectRect?.let { rect ->
|
|
||||||
//Use selection override if it is defined
|
|
||||||
val gmcBox = GmcRectangle(
|
|
||||||
rect.topLeft.toDpOffset().toGeodetic(),
|
|
||||||
rect.bottomRight.toDpOffset().toGeodetic()
|
|
||||||
)
|
|
||||||
config.onSelect(gmcBox)
|
|
||||||
if (config.zoomOnSelect) {
|
|
||||||
val newViewPoint = gmcBox.computeViewPoint(mapTileProvider).invoke(canvasSize)
|
|
||||||
|
|
||||||
config.onViewChange(newViewPoint)
|
event.changes.forEach { change ->
|
||||||
viewPointInternal = newViewPoint
|
val dragStart = change.position
|
||||||
}
|
val dpPos = DpOffset(dragStart.x.toDp(), dragStart.y.toDp())
|
||||||
selectRect = null
|
|
||||||
}
|
//start selection
|
||||||
} else {
|
if (event.buttons.isPrimaryPressed && event.keyboardModifiers.isShiftPressed) {
|
||||||
val dragStart = change.position
|
selectRect = Rect(change.position, change.position)
|
||||||
val dpPos = DpOffset(dragStart.x.toDp(), dragStart.y.toDp())
|
}
|
||||||
config.onClick(MapViewPoint(dpPos.toGeodetic(), viewPoint.zoom))
|
|
||||||
drag(change.id) { dragChange ->
|
drag(change.id) { dragChange ->
|
||||||
val dragAmount = dragChange.position - dragChange.previousPosition
|
val dragAmount = dragChange.position - dragChange.previousPosition
|
||||||
val dpStart = DpOffset(
|
val dpStart = DpOffset(
|
||||||
dragChange.previousPosition.x.toDp(),
|
dragChange.previousPosition.x.toDp(),
|
||||||
dragChange.previousPosition.y.toDp()
|
dragChange.previousPosition.y.toDp()
|
||||||
)
|
)
|
||||||
val dpEnd = DpOffset(dragChange.position.x.toDp(), dragChange.position.y.toDp())
|
val dpEnd = DpOffset(dragChange.position.x.toDp(), dragChange.position.y.toDp())
|
||||||
if (!config.onDrag(
|
|
||||||
MapViewPoint(dpStart.toGeodetic(), viewPoint.zoom),
|
if (
|
||||||
MapViewPoint(dpEnd.toGeodetic(), viewPoint.zoom)
|
!config.dragHandle.drag(
|
||||||
)
|
event,
|
||||||
) return@drag
|
MapViewPoint(dpStart.toGeodetic(), viewPoint.zoom),
|
||||||
val newViewPoint = viewPoint.move(
|
MapViewPoint(dpEnd.toGeodetic(), viewPoint.zoom)
|
||||||
-dragAmount.x.toDp().value / tileScale,
|
)
|
||||||
+dragAmount.y.toDp().value / tileScale
|
) {
|
||||||
)
|
//clear selection just in case
|
||||||
config.onViewChange(newViewPoint)
|
selectRect = null
|
||||||
viewPointInternal = newViewPoint
|
return@drag
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.buttons.isPrimaryPressed) {
|
||||||
|
//Evaluating selection frame
|
||||||
|
selectRect?.let { rect ->
|
||||||
|
val offset = dragChange.position
|
||||||
|
selectRect = Rect(
|
||||||
|
min(offset.x, rect.left),
|
||||||
|
min(offset.y, rect.top),
|
||||||
|
max(offset.x, rect.right),
|
||||||
|
max(offset.y, rect.bottom)
|
||||||
|
)
|
||||||
|
return@drag
|
||||||
|
}
|
||||||
|
|
||||||
|
config.onClick(MapViewPoint(dpPos.toGeodetic(), viewPoint.zoom), event)
|
||||||
|
|
||||||
|
val newViewPoint = viewPoint.move(
|
||||||
|
-dragAmount.x.toDp().value / tileScale,
|
||||||
|
+dragAmount.y.toDp().value / tileScale
|
||||||
|
)
|
||||||
|
config.onViewChange(newViewPoint)
|
||||||
|
viewPointInternal = newViewPoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate selection
|
||||||
|
selectRect?.let { rect ->
|
||||||
|
//Use selection override if it is defined
|
||||||
|
val gmcBox = GmcRectangle(
|
||||||
|
rect.topLeft.toDpOffset().toGeodetic(),
|
||||||
|
rect.bottomRight.toDpOffset().toGeodetic()
|
||||||
|
)
|
||||||
|
config.onSelect(gmcBox)
|
||||||
|
if (config.zoomOnSelect) {
|
||||||
|
val newViewPoint = gmcBox.computeViewPoint(mapTileProvider).invoke(canvasSize)
|
||||||
|
|
||||||
|
config.onViewChange(newViewPoint)
|
||||||
|
viewPointInternal = newViewPoint
|
||||||
|
}
|
||||||
|
selectRect = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user