Fix for TAVRIDA-T-5
This commit is contained in:
parent
6f6c4b117b
commit
bebd33f859
@ -1,23 +1,20 @@
|
|||||||
package centre.sciprog.maps.compose
|
package centre.sciprog.maps.compose
|
||||||
|
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.gestures.detectDragGestures
|
import androidx.compose.foundation.gestures.drag
|
||||||
|
import androidx.compose.foundation.gestures.forEachGesture
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
import androidx.compose.ui.graphics.PathEffect
|
||||||
import androidx.compose.ui.graphics.drawscope.clipRect
|
import androidx.compose.ui.graphics.drawscope.*
|
||||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
|
||||||
import androidx.compose.ui.graphics.drawscope.translate
|
|
||||||
import androidx.compose.ui.graphics.nativeCanvas
|
import androidx.compose.ui.graphics.nativeCanvas
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.input.pointer.PointerEventType
|
import androidx.compose.ui.input.pointer.*
|
||||||
import androidx.compose.ui.input.pointer.PointerInputChange
|
|
||||||
import androidx.compose.ui.input.pointer.onPointerEvent
|
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
|
||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
import centre.sciprog.maps.*
|
import centre.sciprog.maps.*
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
@ -25,8 +22,8 @@ import org.jetbrains.skia.Font
|
|||||||
import org.jetbrains.skia.Paint
|
import org.jetbrains.skia.Paint
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
import kotlin.math.log2
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
|
|
||||||
private fun Color.toPaint(): Paint = Paint().apply {
|
private fun Color.toPaint(): Paint = Paint().apply {
|
||||||
@ -39,6 +36,7 @@ private val logger = KotlinLogging.logger("MapView")
|
|||||||
/**
|
/**
|
||||||
* A component that renders map and provides basic map manipulation capabilities
|
* A component that renders map and provides basic map manipulation capabilities
|
||||||
*/
|
*/
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
actual fun MapView(
|
actual fun MapView(
|
||||||
initialViewPoint: MapViewPoint,
|
initialViewPoint: MapViewPoint,
|
||||||
@ -73,20 +71,62 @@ actual fun MapView(
|
|||||||
*/
|
*/
|
||||||
fun DpOffset.toGeodetic() = WebMercatorProjection.toGeodetic(toMercator())
|
fun DpOffset.toGeodetic() = WebMercatorProjection.toGeodetic(toMercator())
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeUiApi::class)
|
// Selection rectangle. If null - no selection
|
||||||
val canvasModifier = modifier.onPointerEvent(PointerEventType.Press) {
|
var selectRect by remember { mutableStateOf<Rect?>(null) }
|
||||||
val (xPos, yPos) = it.changes.first().position
|
|
||||||
onClick(DpOffset(xPos.toDp(), yPos.toDp()).toGeodetic())
|
val canvasModifier = modifier.pointerInput(Unit) {
|
||||||
|
forEachGesture {
|
||||||
|
awaitPointerEventScope {
|
||||||
|
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(
|
||||||
|
kotlin.math.min(offset.x, rect.left),
|
||||||
|
kotlin.math.min(offset.y, rect.top),
|
||||||
|
kotlin.math.max(offset.x, rect.right),
|
||||||
|
kotlin.math.max(offset.y, rect.bottom)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectRect?.let { rect ->
|
||||||
|
val (centerX, centerY) = rect.center
|
||||||
|
val centerGmc = DpOffset(centerX.toDp(), centerY.toDp()).toGeodetic()
|
||||||
|
|
||||||
|
val horizontalZoom: Float = log2(canvasSize.width.toPx() / rect.width)
|
||||||
|
val verticalZoom: Float = log2(canvasSize.height.toPx() / rect.height)
|
||||||
|
|
||||||
|
|
||||||
|
viewPoint = MapViewPoint(centerGmc, viewPoint.zoom + kotlin.math.min(verticalZoom, horizontalZoom))
|
||||||
|
selectRect = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val dragStart = change.position
|
||||||
|
val dpPos = DpOffset(dragStart.x.toDp(), dragStart.y.toDp())
|
||||||
|
onClick(dpPos.toGeodetic())
|
||||||
|
drag(change.id) { dragChange ->
|
||||||
|
val dragAmount = dragChange.position - dragChange.previousPosition
|
||||||
|
viewPoint = viewPoint.move(
|
||||||
|
-dragAmount.x.toDp().value / tileScale,
|
||||||
|
+dragAmount.y.toDp().value / tileScale
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}.onPointerEvent(PointerEventType.Scroll) {
|
}.onPointerEvent(PointerEventType.Scroll) {
|
||||||
val change = it.changes.first()
|
val change = it.changes.first()
|
||||||
val (xPos, yPos) = change.position
|
val (xPos, yPos) = change.position
|
||||||
//compute invariant point of translation
|
//compute invariant point of translation
|
||||||
val invariant = DpOffset(xPos.toDp(), yPos.toDp()).toGeodetic()
|
val invariant = DpOffset(xPos.toDp(), yPos.toDp()).toGeodetic()
|
||||||
viewPoint = viewPoint.zoom(-change.scrollDelta.y.toDouble() * config.zoomSpeed, invariant)
|
viewPoint = viewPoint.zoom(-change.scrollDelta.y.toDouble() * config.zoomSpeed, invariant)
|
||||||
}.pointerInput(Unit) {
|
|
||||||
detectDragGestures { _: PointerInputChange, dragAmount: Offset ->
|
|
||||||
viewPoint = viewPoint.move(-dragAmount.x.toDp().value / tileScale, +dragAmount.y.toDp().value / tileScale)
|
|
||||||
}
|
|
||||||
}.fillMaxSize()
|
}.fillMaxSize()
|
||||||
|
|
||||||
|
|
||||||
@ -189,5 +229,17 @@ actual fun MapView(
|
|||||||
drawFeature(zoom, feature)
|
drawFeature(zoom, feature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
selectRect?.let { rect ->
|
||||||
|
drawRect(
|
||||||
|
color = Color.Blue,
|
||||||
|
topLeft = rect.topLeft,
|
||||||
|
size = rect.size,
|
||||||
|
alpha = 0.5f,
|
||||||
|
style = Stroke(
|
||||||
|
width = 2f,
|
||||||
|
pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user