Fast scroll bug fix
This commit is contained in:
parent
18b7b91b6f
commit
6258e25669
@ -1,24 +1,25 @@
|
||||
package centre.sciprog.maps.compose
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
|
||||
//TODO replace zoom range with zoom-based representation change
|
||||
sealed class MapFeature(val zoomRange: ClosedFloatingPointRange<Double>)
|
||||
|
||||
private val defaultRange = 0.0..18.0
|
||||
private val defaultZoomRange = 1.0..18.0
|
||||
|
||||
private fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second)
|
||||
|
||||
class MapCircleFeature(
|
||||
val center: GeodeticMapCoordinates,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultRange,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
|
||||
val size: Float = 5f,
|
||||
val color: Color = Color.Red,
|
||||
) : MapFeature(zoomRange)
|
||||
|
||||
fun MapCircleFeature(
|
||||
centerCoordinates: Pair<Double, Double>,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultRange,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
|
||||
size: Float = 5f,
|
||||
color: Color = Color.Red,
|
||||
) = MapCircleFeature(
|
||||
@ -28,17 +29,30 @@ fun MapCircleFeature(
|
||||
color
|
||||
)
|
||||
|
||||
|
||||
class MapLineFeature(
|
||||
val a: GeodeticMapCoordinates,
|
||||
val b: GeodeticMapCoordinates,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultRange,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
|
||||
val color: Color = Color.Red,
|
||||
) : MapFeature(zoomRange)
|
||||
|
||||
fun MapLineFeature(
|
||||
aCoordinates: Pair<Double, Double>,
|
||||
bCoordinates: Pair<Double, Double>,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultRange,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
|
||||
color: Color = Color.Red,
|
||||
) = MapLineFeature(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), zoomRange, color)
|
||||
|
||||
class MapTextFeature(
|
||||
val position: GeodeticMapCoordinates,
|
||||
val text: String,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
|
||||
val color: Color = Color.Red,
|
||||
): MapFeature(zoomRange)
|
||||
|
||||
class MapImageFeature(
|
||||
val position: GeodeticMapCoordinates,
|
||||
val image: ImageBitmap,
|
||||
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
|
||||
val color: Color = Color.Red,
|
||||
): MapFeature(zoomRange)
|
@ -9,8 +9,11 @@ import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.drawscope.clipRect
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||
import androidx.compose.ui.input.pointer.PointerEventType
|
||||
import androidx.compose.ui.input.pointer.PointerInputChange
|
||||
@ -30,6 +33,7 @@ import java.net.URL
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
private const val TILE_SIZE = 256
|
||||
@ -89,6 +93,14 @@ private class OsMapCache(val scope: CoroutineScope, val client: HttpClient, priv
|
||||
}
|
||||
}
|
||||
|
||||
private fun Color.toPaint(): org.jetbrains.skia.Paint = org.jetbrains.skia.Paint().setARGB(
|
||||
(alpha * 256).toInt(),
|
||||
(red * 256).toInt(),
|
||||
(green * 256).toInt(),
|
||||
(blue * 256).toInt()
|
||||
)
|
||||
|
||||
|
||||
private fun Double.toIndex(): Int = floor(this / TILE_SIZE).toInt()
|
||||
private fun Int.toCoordinate(): Double = (this * TILE_SIZE).toDouble()
|
||||
|
||||
@ -115,6 +127,7 @@ fun MapView(
|
||||
val centerCoordinates by derivedStateOf { viewPoint.toMercator() }
|
||||
|
||||
LaunchedEffect(viewPoint, canvasSize) {
|
||||
val z = viewPoint.zoom.toInt()
|
||||
val left = centerCoordinates.x - canvasSize.width / 2
|
||||
val right = centerCoordinates.x + canvasSize.width / 2
|
||||
val horizontalIndices = left.toIndex()..right.toIndex()
|
||||
@ -125,11 +138,15 @@ fun MapView(
|
||||
|
||||
mapTiles.clear()
|
||||
|
||||
val indexRange = 0 until 2.0.pow(z).toInt()
|
||||
|
||||
for (j in verticalIndices) {
|
||||
for (i in horizontalIndices) {
|
||||
val tileId = OsMapTileId(viewPoint.zoom.toInt(), i, j)
|
||||
val tile = mapCache.loadTile(tileId)
|
||||
mapTiles.add(tile)
|
||||
if(z == viewPoint.zoom.toInt() && i in indexRange && j in indexRange) {
|
||||
val tileId = OsMapTileId(z, i, j)
|
||||
val tile = mapCache.loadTile(tileId)
|
||||
mapTiles.add(tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,10 +203,20 @@ fun MapView(
|
||||
topLeft = offset
|
||||
)
|
||||
}
|
||||
features.filter { viewPoint.zoom in it.zoomRange }.forEach {
|
||||
when (it) {
|
||||
is MapCircleFeature -> drawCircle(it.color, it.size, center = it.center.toOffset())
|
||||
is MapLineFeature -> drawLine(it.color, it.a.toOffset(), it.b.toOffset())
|
||||
features.filter { viewPoint.zoom in it.zoomRange }.forEach { feature ->
|
||||
when (feature) {
|
||||
is MapCircleFeature -> drawCircle(
|
||||
feature.color,
|
||||
feature.size,
|
||||
center = feature.center.toOffset()
|
||||
)
|
||||
is MapLineFeature -> drawLine(feature.color, feature.a.toOffset(), feature.b.toOffset())
|
||||
is MapImageFeature -> drawImage(feature.image, feature.position.toOffset())
|
||||
is MapTextFeature -> drawIntoCanvas {
|
||||
val offset = feature.position.toOffset()
|
||||
it.nativeCanvas.drawString(feature.text, offset.x, offset.y, null, feature.color.toPaint())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ fun MapViewPoint.move(delta: GeodeticMapCoordinates): MapViewPoint {
|
||||
}
|
||||
|
||||
fun MapViewPoint.zoom(zoomDelta: Double): MapViewPoint {
|
||||
return copy(zoom = (zoom + zoomDelta).coerceIn(1.0, 18.0))
|
||||
return copy(zoom = (zoom + zoomDelta).coerceIn(2.0, 18.0))
|
||||
}
|
||||
|
||||
fun MapViewPoint.toMercator() = WebMercatorProjection.toMercator(focus, zoom)
|
Loading…
Reference in New Issue
Block a user