Multi-listener drag
This commit is contained in:
parent
572adf041f
commit
7e7cb0a260
@ -64,35 +64,13 @@ fun App() {
|
|||||||
|
|
||||||
image(pointOne, Icons.Filled.Home)
|
image(pointOne, Icons.Filled.Home)
|
||||||
|
|
||||||
var drag1 = Gmc.ofDegrees(55.744, 37.614)
|
val marker1 = rectangle(55.744 to 37.614, size = DpSize(10.dp, 10.dp), color = Color.Magenta)
|
||||||
|
val marker2 = rectangle(55.8 to 37.5, size = DpSize(10.dp, 10.dp), color = Color.Magenta)
|
||||||
|
val marker3 = rectangle(56.0 to 37.5, size = DpSize(10.dp, 10.dp), color = Color.Magenta)
|
||||||
|
|
||||||
var drag2 = Gmc.ofDegrees(55.8, 37.5)
|
draggableLine(marker1, marker2)
|
||||||
|
draggableLine(marker2, marker3)
|
||||||
var drag3 = Gmc.ofDegrees(56.0, 37.5)
|
draggableLine(marker3, marker1)
|
||||||
|
|
||||||
fun updateLine() {
|
|
||||||
line(drag1, drag2, id = "connection1", color = Color.Magenta)
|
|
||||||
line(drag2, drag3, id = "connection2", color = Color.Magenta)
|
|
||||||
line(drag3, drag1, id = "connection3", color = Color.Magenta)
|
|
||||||
}
|
|
||||||
|
|
||||||
rectangle(drag1, size = DpSize(10.dp, 10.dp)).draggable { _, end ->
|
|
||||||
drag1 = end
|
|
||||||
updateLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
rectangle(drag2, size = DpSize(10.dp, 10.dp)).draggable { _, end ->
|
|
||||||
drag2 = end
|
|
||||||
updateLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
rectangle(drag3, size = DpSize(10.dp, 10.dp)).draggable { _, end ->
|
|
||||||
drag3 = end
|
|
||||||
updateLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
updateLine()
|
|
||||||
|
|
||||||
points(
|
points(
|
||||||
points = listOf(
|
points = listOf(
|
||||||
|
@ -8,7 +8,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
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.features.FeaturesState
|
import center.sciprog.maps.features.FeatureCollection
|
||||||
import center.sciprog.maps.features.ViewConfig
|
import center.sciprog.maps.features.ViewConfig
|
||||||
import center.sciprog.maps.features.ViewPoint
|
import center.sciprog.maps.features.ViewPoint
|
||||||
import center.sciprog.maps.features.computeBoundingBox
|
import center.sciprog.maps.features.computeBoundingBox
|
||||||
@ -29,7 +29,7 @@ fun App() {
|
|||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val schemeFeaturesState = FeaturesState.remember(XYCoordinateSpace) {
|
val schemeFeaturesState = FeatureCollection.remember(XYCoordinateSpace) {
|
||||||
background(1600f, 1200f) { painterResource("middle-earth.jpg") }
|
background(1600f, 1200f) { painterResource("middle-earth.jpg") }
|
||||||
circle(410.52737 to 868.7676, color = Color.Blue)
|
circle(410.52737 to 868.7676, color = Color.Blue)
|
||||||
text(410.52737 to 868.7676, "Shire", color = Color.Blue)
|
text(410.52737 to 868.7676, "Shire", color = Color.Blue)
|
||||||
|
@ -18,7 +18,7 @@ import kotlin.math.min
|
|||||||
public expect fun MapView(
|
public expect fun MapView(
|
||||||
mapTileProvider: MapTileProvider,
|
mapTileProvider: MapTileProvider,
|
||||||
initialViewPoint: MapViewPoint,
|
initialViewPoint: MapViewPoint,
|
||||||
featuresState: FeaturesState<Gmc>,
|
featuresState: FeatureCollection<Gmc>,
|
||||||
config: ViewConfig<Gmc> = ViewConfig(),
|
config: ViewConfig<Gmc> = ViewConfig(),
|
||||||
modifier: Modifier = Modifier.fillMaxSize(),
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
)
|
)
|
||||||
@ -51,7 +51,7 @@ public fun MapView(
|
|||||||
modifier: Modifier = Modifier.fillMaxSize(),
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
val featuresState = key(featureMap) {
|
val featuresState = key(featureMap) {
|
||||||
FeaturesState.build(GmcCoordinateSpace) {
|
FeatureCollection.build(GmcCoordinateSpace) {
|
||||||
featureMap.forEach { feature(it.key.id, it.value) }
|
featureMap.forEach { feature(it.key.id, it.value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,9 +80,9 @@ public fun MapView(
|
|||||||
initialRectangle: Rectangle<Gmc>? = null,
|
initialRectangle: Rectangle<Gmc>? = null,
|
||||||
config: ViewConfig<Gmc> = ViewConfig(),
|
config: ViewConfig<Gmc> = ViewConfig(),
|
||||||
modifier: Modifier = Modifier.fillMaxSize(),
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
buildFeatures: FeaturesState<Gmc>.() -> Unit = {},
|
buildFeatures: FeatureCollection<Gmc>.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val featureState = FeaturesState.remember(GmcCoordinateSpace, buildFeatures)
|
val featureState = FeatureCollection.remember(GmcCoordinateSpace, buildFeatures)
|
||||||
|
|
||||||
val viewPointOverride: MapViewPoint = remember(initialViewPoint, initialRectangle) {
|
val viewPointOverride: MapViewPoint = remember(initialViewPoint, initialRectangle) {
|
||||||
initialViewPoint
|
initialViewPoint
|
||||||
|
@ -12,12 +12,12 @@ import center.sciprog.maps.features.*
|
|||||||
import center.sciprog.maps.features.Feature.Companion.defaultZoomRange
|
import center.sciprog.maps.features.Feature.Companion.defaultZoomRange
|
||||||
|
|
||||||
|
|
||||||
internal fun FeaturesState<Gmc>.coordinatesOf(pair: Pair<Number, Number>) =
|
internal fun FeatureCollection<Gmc>.coordinatesOf(pair: Pair<Number, Number>) =
|
||||||
GeodeticMapCoordinates.ofDegrees(pair.first.toDouble(), pair.second.toDouble())
|
GeodeticMapCoordinates.ofDegrees(pair.first.toDouble(), pair.second.toDouble())
|
||||||
|
|
||||||
public typealias MapFeature = Feature<Gmc>
|
public typealias MapFeature = Feature<Gmc>
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.circle(
|
public fun FeatureCollection<Gmc>.circle(
|
||||||
centerCoordinates: Pair<Number, Number>,
|
centerCoordinates: Pair<Number, Number>,
|
||||||
zoomRange: DoubleRange = defaultZoomRange,
|
zoomRange: DoubleRange = defaultZoomRange,
|
||||||
size: Dp = 5.dp,
|
size: Dp = 5.dp,
|
||||||
@ -27,7 +27,7 @@ public fun FeaturesState<Gmc>.circle(
|
|||||||
id, CircleFeature(coordinateSpace, coordinatesOf(centerCoordinates), zoomRange, size, color)
|
id, CircleFeature(coordinateSpace, coordinatesOf(centerCoordinates), zoomRange, size, color)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.rectangle(
|
public fun FeatureCollection<Gmc>.rectangle(
|
||||||
centerCoordinates: Pair<Number, Number>,
|
centerCoordinates: Pair<Number, Number>,
|
||||||
zoomRange: DoubleRange = defaultZoomRange,
|
zoomRange: DoubleRange = defaultZoomRange,
|
||||||
size: DpSize = DpSize(5.dp, 5.dp),
|
size: DpSize = DpSize(5.dp, 5.dp),
|
||||||
@ -38,7 +38,7 @@ public fun FeaturesState<Gmc>.rectangle(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.draw(
|
public fun FeatureCollection<Gmc>.draw(
|
||||||
position: Pair<Number, Number>,
|
position: Pair<Number, Number>,
|
||||||
zoomRange: DoubleRange = defaultZoomRange,
|
zoomRange: DoubleRange = defaultZoomRange,
|
||||||
id: String? = null,
|
id: String? = null,
|
||||||
@ -49,7 +49,7 @@ public fun FeaturesState<Gmc>.draw(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.line(
|
public fun FeatureCollection<Gmc>.line(
|
||||||
curve: GmcCurve,
|
curve: GmcCurve,
|
||||||
zoomRange: DoubleRange = defaultZoomRange,
|
zoomRange: DoubleRange = defaultZoomRange,
|
||||||
color: Color = Color.Red,
|
color: Color = Color.Red,
|
||||||
@ -60,7 +60,7 @@ public fun FeaturesState<Gmc>.line(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.line(
|
public fun FeatureCollection<Gmc>.line(
|
||||||
aCoordinates: Pair<Double, Double>,
|
aCoordinates: Pair<Double, Double>,
|
||||||
bCoordinates: Pair<Double, Double>,
|
bCoordinates: Pair<Double, Double>,
|
||||||
zoomRange: DoubleRange = defaultZoomRange,
|
zoomRange: DoubleRange = defaultZoomRange,
|
||||||
@ -72,7 +72,7 @@ public fun FeaturesState<Gmc>.line(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.arc(
|
public fun FeatureCollection<Gmc>.arc(
|
||||||
center: Pair<Double, Double>,
|
center: Pair<Double, Double>,
|
||||||
radius: Distance,
|
radius: Distance,
|
||||||
startAngle: Angle,
|
startAngle: Angle,
|
||||||
@ -92,7 +92,7 @@ public fun FeaturesState<Gmc>.arc(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.points(
|
public fun FeatureCollection<Gmc>.points(
|
||||||
points: List<Pair<Double, Double>>,
|
points: List<Pair<Double, Double>>,
|
||||||
zoomRange: DoubleRange = defaultZoomRange,
|
zoomRange: DoubleRange = defaultZoomRange,
|
||||||
stroke: Float = 2f,
|
stroke: Float = 2f,
|
||||||
@ -102,7 +102,7 @@ public fun FeaturesState<Gmc>.points(
|
|||||||
): FeatureId<PointsFeature<Gmc>> =
|
): FeatureId<PointsFeature<Gmc>> =
|
||||||
feature(id, PointsFeature(coordinateSpace, points.map(::coordinatesOf), zoomRange, stroke, color, pointMode))
|
feature(id, PointsFeature(coordinateSpace, points.map(::coordinatesOf), zoomRange, stroke, color, pointMode))
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.image(
|
public fun FeatureCollection<Gmc>.image(
|
||||||
position: Pair<Double, Double>,
|
position: Pair<Double, Double>,
|
||||||
image: ImageVector,
|
image: ImageVector,
|
||||||
size: DpSize = DpSize(20.dp, 20.dp),
|
size: DpSize = DpSize(20.dp, 20.dp),
|
||||||
@ -119,7 +119,7 @@ public fun FeaturesState<Gmc>.image(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun FeaturesState<Gmc>.text(
|
public fun FeatureCollection<Gmc>.text(
|
||||||
position: Pair<Double, Double>,
|
position: Pair<Double, Double>,
|
||||||
text: String,
|
text: String,
|
||||||
zoomRange: DoubleRange = defaultZoomRange,
|
zoomRange: DoubleRange = defaultZoomRange,
|
||||||
|
@ -42,7 +42,7 @@ private val logger = KotlinLogging.logger("MapView")
|
|||||||
public actual fun MapView(
|
public actual fun MapView(
|
||||||
mapTileProvider: MapTileProvider,
|
mapTileProvider: MapTileProvider,
|
||||||
initialViewPoint: MapViewPoint,
|
initialViewPoint: MapViewPoint,
|
||||||
featuresState: FeaturesState<Gmc>,
|
featuresState: FeatureCollection<Gmc>,
|
||||||
config: ViewConfig<Gmc>,
|
config: ViewConfig<Gmc>,
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
): Unit = key(initialViewPoint) {
|
): Unit = key(initialViewPoint) {
|
||||||
|
@ -5,8 +5,6 @@ import androidx.compose.ui.graphics.Color
|
|||||||
|
|
||||||
public object ZAttribute : Feature.Attribute<Float>
|
public object ZAttribute : Feature.Attribute<Float>
|
||||||
|
|
||||||
public object DraggableAttribute : Feature.Attribute<DragHandle<Any>>
|
|
||||||
|
|
||||||
public object SelectableAttribute : Feature.Attribute<(FeatureId<*>, SelectableFeature<*>) -> Unit>
|
public object SelectableAttribute : Feature.Attribute<(FeatureId<*>, SelectableFeature<*>) -> Unit>
|
||||||
|
|
||||||
public object VisibleAttribute : Feature.Attribute<Boolean>
|
public object VisibleAttribute : Feature.Attribute<Boolean>
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package center.sciprog.maps.features
|
||||||
|
|
||||||
|
|
||||||
|
public object DraggableAttribute : Feature.Attribute<DragHandle<Any>>
|
||||||
|
|
||||||
|
public object DragListenerAttribute : Feature.Attribute<Set<(begin: Any, end: Any) -> Unit>>
|
@ -49,6 +49,13 @@ public interface DraggableFeature<T : Any> : SelectableFeature<T> {
|
|||||||
public fun withCoordinates(newCoordinates: T): Feature<T>
|
public fun withCoordinates(newCoordinates: T): Feature<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A draggable marker feature. Other features could be bound to this one.
|
||||||
|
*/
|
||||||
|
public interface MarkerFeature<T: Any>: DraggableFeature<T>{
|
||||||
|
public val center: T
|
||||||
|
}
|
||||||
|
|
||||||
public fun <T : Any> Iterable<Feature<T>>.computeBoundingBox(
|
public fun <T : Any> Iterable<Feature<T>>.computeBoundingBox(
|
||||||
space: CoordinateSpace<T>,
|
space: CoordinateSpace<T>,
|
||||||
zoom: Float,
|
zoom: Float,
|
||||||
@ -115,12 +122,12 @@ public class PointsFeature<T : Any>(
|
|||||||
|
|
||||||
public data class CircleFeature<T : Any>(
|
public data class CircleFeature<T : Any>(
|
||||||
override val space: CoordinateSpace<T>,
|
override val space: CoordinateSpace<T>,
|
||||||
public val center: T,
|
override val center: T,
|
||||||
override val zoomRange: FloatRange = defaultZoomRange,
|
override val zoomRange: FloatRange = defaultZoomRange,
|
||||||
public val size: Dp = 5.dp,
|
public val size: Dp = 5.dp,
|
||||||
public val color: Color = Color.Red,
|
public val color: Color = Color.Red,
|
||||||
override var attributes: AttributeMap = AttributeMap(),
|
override var attributes: AttributeMap = AttributeMap(),
|
||||||
) : DraggableFeature<T> {
|
) : MarkerFeature<T> {
|
||||||
override fun getBoundingBox(zoom: Float): Rectangle<T> =
|
override fun getBoundingBox(zoom: Float): Rectangle<T> =
|
||||||
space.Rectangle(center, zoom, DpSize(size, size))
|
space.Rectangle(center, zoom, DpSize(size, size))
|
||||||
|
|
||||||
@ -130,12 +137,12 @@ public data class CircleFeature<T : Any>(
|
|||||||
|
|
||||||
public class RectangleFeature<T : Any>(
|
public class RectangleFeature<T : Any>(
|
||||||
override val space: CoordinateSpace<T>,
|
override val space: CoordinateSpace<T>,
|
||||||
public val center: T,
|
override val center: T,
|
||||||
override val zoomRange: FloatRange = defaultZoomRange,
|
override val zoomRange: FloatRange = defaultZoomRange,
|
||||||
public val size: DpSize = DpSize(5.dp, 5.dp),
|
public val size: DpSize = DpSize(5.dp, 5.dp),
|
||||||
public val color: Color = Color.Red,
|
public val color: Color = Color.Red,
|
||||||
override var attributes: AttributeMap = AttributeMap(),
|
override var attributes: AttributeMap = AttributeMap(),
|
||||||
) : DraggableFeature<T> {
|
) : MarkerFeature<T> {
|
||||||
override fun getBoundingBox(zoom: Float): Rectangle<T> =
|
override fun getBoundingBox(zoom: Float): Rectangle<T> =
|
||||||
space.Rectangle(center, zoom, size)
|
space.Rectangle(center, zoom, size)
|
||||||
|
|
||||||
@ -193,35 +200,35 @@ public data class DrawFeature<T : Any>(
|
|||||||
|
|
||||||
public data class BitmapImageFeature<T : Any>(
|
public data class BitmapImageFeature<T : Any>(
|
||||||
override val space: CoordinateSpace<T>,
|
override val space: CoordinateSpace<T>,
|
||||||
public val position: T,
|
override val center: T,
|
||||||
public val size: DpSize,
|
public val size: DpSize,
|
||||||
public val image: ImageBitmap,
|
public val image: ImageBitmap,
|
||||||
override val zoomRange: FloatRange = defaultZoomRange,
|
override val zoomRange: FloatRange = defaultZoomRange,
|
||||||
override var attributes: AttributeMap = AttributeMap(),
|
override var attributes: AttributeMap = AttributeMap(),
|
||||||
) : DraggableFeature<T> {
|
) : MarkerFeature<T> {
|
||||||
override fun getBoundingBox(zoom: Float): Rectangle<T> = space.Rectangle(position, zoom, size)
|
override fun getBoundingBox(zoom: Float): Rectangle<T> = space.Rectangle(center, zoom, size)
|
||||||
|
|
||||||
override fun withCoordinates(newCoordinates: T): Feature<T> = copy(position = newCoordinates)
|
override fun withCoordinates(newCoordinates: T): Feature<T> = copy(center = newCoordinates)
|
||||||
}
|
}
|
||||||
|
|
||||||
public data class VectorImageFeature<T : Any>(
|
public data class VectorImageFeature<T : Any>(
|
||||||
override val space: CoordinateSpace<T>,
|
override val space: CoordinateSpace<T>,
|
||||||
public val position: T,
|
override val center: T,
|
||||||
public val size: DpSize,
|
public val size: DpSize,
|
||||||
public val image: ImageVector,
|
public val image: ImageVector,
|
||||||
override val zoomRange: FloatRange = defaultZoomRange,
|
override val zoomRange: FloatRange = defaultZoomRange,
|
||||||
override var attributes: AttributeMap = AttributeMap(),
|
override var attributes: AttributeMap = AttributeMap(),
|
||||||
) : DraggableFeature<T>, PainterFeature<T> {
|
) : MarkerFeature<T>, PainterFeature<T> {
|
||||||
override fun getBoundingBox(zoom: Float): Rectangle<T> = space.Rectangle(position, zoom, size)
|
override fun getBoundingBox(zoom: Float): Rectangle<T> = space.Rectangle(center, zoom, size)
|
||||||
|
|
||||||
override fun withCoordinates(newCoordinates: T): Feature<T> = copy(position = newCoordinates)
|
override fun withCoordinates(newCoordinates: T): Feature<T> = copy(center = newCoordinates)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun painter(): VectorPainter = rememberVectorPainter(image)
|
override fun painter(): VectorPainter = rememberVectorPainter(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A background image that is bound to coordinates and is scaled together with them
|
* An image that is bound to coordinates and is scaled together with them
|
||||||
*
|
*
|
||||||
* @param rectangle the size of background in scheme size units. The screen units to scheme units ratio equals scale.
|
* @param rectangle the size of background in scheme size units. The screen units to scheme units ratio equals scale.
|
||||||
*/
|
*/
|
||||||
|
@ -18,10 +18,23 @@ import kotlinx.coroutines.isActive
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class FeatureId<out MapFeature>(public val id: String)
|
public value class FeatureId<out F : Feature<*>>(public val id: String)
|
||||||
|
|
||||||
public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<T>) :
|
public interface FeatureBuilder<T : Any> {
|
||||||
CoordinateSpace<T> by coordinateSpace {
|
|
||||||
|
public val coordinateSpace: CoordinateSpace<T>
|
||||||
|
|
||||||
|
public fun <F : Feature<T>> feature(id: String?, feature: F): FeatureId<F>
|
||||||
|
|
||||||
|
public fun <F : Feature<T>, V> setAttribute(id: FeatureId<F>, key: Feature.Attribute<V>, value: V?)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T : Any, F : Feature<T>> FeatureBuilder<T>.feature(id: FeatureId<F>, feature: F): FeatureId<F> =
|
||||||
|
feature(id.id, feature)
|
||||||
|
|
||||||
|
public class FeatureCollection<T : Any>(
|
||||||
|
override val coordinateSpace: CoordinateSpace<T>,
|
||||||
|
) : CoordinateSpace<T> by coordinateSpace, FeatureBuilder<T> {
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal val featureMap: MutableMap<String, Feature<T>> = mutableStateMapOf()
|
internal val featureMap: MutableMap<String, Feature<T>> = mutableStateMapOf()
|
||||||
@ -30,21 +43,21 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
|||||||
get() = featureMap.mapKeys { FeatureId<Feature<T>>(it.key) }
|
get() = featureMap.mapKeys { FeatureId<Feature<T>>(it.key) }
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public fun <F : Feature<T>> getFeature(id: FeatureId<F>): F = featureMap[id.id] as F
|
public operator fun <F : Feature<T>> get(id: FeatureId<F>): F = featureMap[id.id] as F
|
||||||
|
|
||||||
private fun generateID(feature: Feature<T>): String = "@feature[${feature.hashCode().toUInt()}]"
|
private fun generateID(feature: Feature<T>): String = "@feature[${feature.hashCode().toUInt()}]"
|
||||||
|
|
||||||
public fun <F : Feature<T>> feature(id: String?, feature: F): FeatureId<F> {
|
override fun <F : Feature<T>> feature(id: String?, feature: F): FeatureId<F> {
|
||||||
val safeId = id ?: generateID(feature)
|
val safeId = id ?: generateID(feature)
|
||||||
featureMap[safeId] = feature
|
featureMap[safeId] = feature
|
||||||
return FeatureId(safeId)
|
return FeatureId(safeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun <F : Feature<T>> feature(id: FeatureId<F>?, feature: F): FeatureId<F> = feature(id?.id, feature)
|
public fun <F : Feature<T>> feature(id: FeatureId<F>, feature: F): FeatureId<F> = feature(id.id, feature)
|
||||||
|
|
||||||
|
|
||||||
public fun <F : Feature<T>, V> setAttribute(id: FeatureId<F>, key: Feature.Attribute<V>, value: V?) {
|
override fun <F : Feature<T>, V> setAttribute(id: FeatureId<F>, key: Feature.Attribute<V>, value: V?) {
|
||||||
getFeature(id).attributes[key] = value
|
get(id).attributes[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,26 +67,38 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
|||||||
*
|
*
|
||||||
* TODO use context receiver for that
|
* TODO use context receiver for that
|
||||||
*/
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
public fun FeatureId<DraggableFeature<T>>.draggable(
|
public fun FeatureId<DraggableFeature<T>>.draggable(
|
||||||
constraint: ((T) -> T)? = null,
|
constraint: ((T) -> T)? = null,
|
||||||
callback: ((start: T, end: T) -> Unit) = { _, _ -> },
|
callback: ((start: T, end: T) -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
if (getAttribute(this, DraggableAttribute) == null) {
|
||||||
val handle = DragHandle.withPrimaryButton<Any> { _, start, end ->
|
val handle = DragHandle.withPrimaryButton<Any> { _, start, end ->
|
||||||
val startPosition = start.focus as T
|
val feature = featureMap[id] as? DraggableFeature ?: return@withPrimaryButton DragResult(end)
|
||||||
val endPosition = end.focus as T
|
val startPosition = start.focus as T
|
||||||
val feature = featureMap[id] as? DraggableFeature ?: return@withPrimaryButton DragResult(end)
|
val endPosition = end.focus as T
|
||||||
val boundingBox = feature.getBoundingBox(start.zoom) ?: return@withPrimaryButton DragResult(end)
|
val boundingBox = feature.getBoundingBox(start.zoom) ?: return@withPrimaryButton DragResult(end)
|
||||||
if (startPosition in boundingBox) {
|
if (startPosition in boundingBox) {
|
||||||
val finalPosition = constraint?.invoke(endPosition) ?: endPosition
|
val finalPosition = constraint?.invoke(endPosition) ?: endPosition
|
||||||
feature(id, feature.withCoordinates(finalPosition))
|
feature(id, feature.withCoordinates(finalPosition))
|
||||||
callback(startPosition, finalPosition)
|
feature.attributes[DragListenerAttribute]?.forEach {
|
||||||
DragResult(ViewPoint(finalPosition, end.zoom), false)
|
it.invoke(startPosition, endPosition)
|
||||||
} else {
|
}
|
||||||
DragResult(end, true)
|
DragResult(ViewPoint(finalPosition, end.zoom), false)
|
||||||
|
} else {
|
||||||
|
DragResult(end, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
setAttribute(this, DraggableAttribute, handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply callback
|
||||||
|
if (callback != null) {
|
||||||
|
setAttribute(
|
||||||
|
this, DragListenerAttribute,
|
||||||
|
((getAttribute(this, DragListenerAttribute) ?: emptySet()) + callback) as Set<(Any, Any) -> Unit>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
setAttribute(this, DraggableAttribute, handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,7 +109,7 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
|||||||
update: suspend (F) -> F,
|
update: suspend (F) -> F,
|
||||||
): Job = scope.launch {
|
): Job = scope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
feature(this@updated, update(getFeature(this@updated)))
|
feature(this@updated, update(get(this@updated)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,15 +123,7 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public fun <A> getAttribute(id: FeatureId<Feature<T>>, key: Feature.Attribute<A>): A? =
|
public fun <A> getAttribute(id: FeatureId<Feature<T>>, key: Feature.Attribute<A>): A? =
|
||||||
getFeature(id).attributes[key]
|
get(id).attributes[key]
|
||||||
|
|
||||||
|
|
||||||
// @Suppress("UNCHECKED_CAST")
|
|
||||||
// public fun <T> findAllWithAttribute(key: Attribute<T>, condition: (T) -> Boolean): Set<FeatureId> {
|
|
||||||
// return attributes.filterValues {
|
|
||||||
// condition(it[key] as T)
|
|
||||||
// }.keys
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process all features with a given attribute from the one with highest [z] to lowest
|
* Process all features with a given attribute from the one with highest [z] to lowest
|
||||||
@ -129,8 +146,8 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
|||||||
*/
|
*/
|
||||||
public fun <T : Any> build(
|
public fun <T : Any> build(
|
||||||
coordinateSpace: CoordinateSpace<T>,
|
coordinateSpace: CoordinateSpace<T>,
|
||||||
builder: FeaturesState<T>.() -> Unit = {},
|
builder: FeatureCollection<T>.() -> Unit = {},
|
||||||
): FeaturesState<T> = FeaturesState(coordinateSpace).apply(builder)
|
): FeatureCollection<T> = FeatureCollection(coordinateSpace).apply(builder)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build and remember map feature state
|
* Build and remember map feature state
|
||||||
@ -138,15 +155,15 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
|||||||
@Composable
|
@Composable
|
||||||
public fun <T : Any> remember(
|
public fun <T : Any> remember(
|
||||||
coordinateSpace: CoordinateSpace<T>,
|
coordinateSpace: CoordinateSpace<T>,
|
||||||
builder: FeaturesState<T>.() -> Unit = {},
|
builder: FeatureCollection<T>.() -> Unit = {},
|
||||||
): FeaturesState<T> = remember(builder) {
|
): FeatureCollection<T> = remember(builder) {
|
||||||
build(coordinateSpace, builder)
|
build(coordinateSpace, builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.circle(
|
public fun <T : Any> FeatureBuilder<T>.circle(
|
||||||
center: T,
|
center: T,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
size: Dp = 5.dp,
|
size: Dp = 5.dp,
|
||||||
@ -156,7 +173,7 @@ public fun <T : Any> FeaturesState<T>.circle(
|
|||||||
id, CircleFeature(coordinateSpace, center, zoomRange, size, color)
|
id, CircleFeature(coordinateSpace, center, zoomRange, size, color)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.rectangle(
|
public fun <T : Any> FeatureBuilder<T>.rectangle(
|
||||||
centerCoordinates: T,
|
centerCoordinates: T,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
size: DpSize = DpSize(5.dp, 5.dp),
|
size: DpSize = DpSize(5.dp, 5.dp),
|
||||||
@ -166,7 +183,7 @@ public fun <T : Any> FeaturesState<T>.rectangle(
|
|||||||
id, RectangleFeature(coordinateSpace, centerCoordinates, zoomRange, size, color)
|
id, RectangleFeature(coordinateSpace, centerCoordinates, zoomRange, size, color)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.draw(
|
public fun <T : Any> FeatureBuilder<T>.draw(
|
||||||
position: T,
|
position: T,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
id: String? = null,
|
id: String? = null,
|
||||||
@ -176,7 +193,7 @@ public fun <T : Any> FeaturesState<T>.draw(
|
|||||||
DrawFeature(coordinateSpace, position, zoomRange, drawFeature = draw)
|
DrawFeature(coordinateSpace, position, zoomRange, drawFeature = draw)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.line(
|
public fun <T : Any> FeatureBuilder<T>.line(
|
||||||
aCoordinates: T,
|
aCoordinates: T,
|
||||||
bCoordinates: T,
|
bCoordinates: T,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
@ -187,7 +204,7 @@ public fun <T : Any> FeaturesState<T>.line(
|
|||||||
LineFeature(coordinateSpace, aCoordinates, bCoordinates, zoomRange, color)
|
LineFeature(coordinateSpace, aCoordinates, bCoordinates, zoomRange, color)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.arc(
|
public fun <T : Any> FeatureBuilder<T>.arc(
|
||||||
oval: Rectangle<T>,
|
oval: Rectangle<T>,
|
||||||
startAngle: Float,
|
startAngle: Float,
|
||||||
arcLength: Float,
|
arcLength: Float,
|
||||||
@ -199,7 +216,7 @@ public fun <T : Any> FeaturesState<T>.arc(
|
|||||||
ArcFeature(coordinateSpace, oval, startAngle, arcLength, zoomRange, color)
|
ArcFeature(coordinateSpace, oval, startAngle, arcLength, zoomRange, color)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.points(
|
public fun <T : Any> FeatureBuilder<T>.points(
|
||||||
points: List<T>,
|
points: List<T>,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
stroke: Float = 2f,
|
stroke: Float = 2f,
|
||||||
@ -209,7 +226,7 @@ public fun <T : Any> FeaturesState<T>.points(
|
|||||||
): FeatureId<PointsFeature<T>> =
|
): FeatureId<PointsFeature<T>> =
|
||||||
feature(id, PointsFeature(coordinateSpace, points, zoomRange, stroke, color, pointMode))
|
feature(id, PointsFeature(coordinateSpace, points, zoomRange, stroke, color, pointMode))
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.image(
|
public fun <T : Any> FeatureBuilder<T>.image(
|
||||||
position: T,
|
position: T,
|
||||||
image: ImageVector,
|
image: ImageVector,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
@ -227,17 +244,17 @@ public fun <T : Any> FeaturesState<T>.image(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.group(
|
public fun <T : Any> FeatureBuilder<T>.group(
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
id: String? = null,
|
id: String? = null,
|
||||||
builder: FeaturesState<T>.() -> Unit,
|
builder: FeatureCollection<T>.() -> Unit,
|
||||||
): FeatureId<FeatureGroup<T>> {
|
): FeatureId<FeatureGroup<T>> {
|
||||||
val map = FeaturesState(coordinateSpace).apply(builder).features
|
val map = FeatureCollection(coordinateSpace).apply(builder).features
|
||||||
val feature = FeatureGroup(coordinateSpace, map, zoomRange)
|
val feature = FeatureGroup(coordinateSpace, map, zoomRange)
|
||||||
return feature(id, feature)
|
return feature(id, feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.scalableImage(
|
public fun <T : Any> FeatureBuilder<T>.scalableImage(
|
||||||
box: Rectangle<T>,
|
box: Rectangle<T>,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
||||||
id: String? = null,
|
id: String? = null,
|
||||||
@ -247,7 +264,7 @@ public fun <T : Any> FeaturesState<T>.scalableImage(
|
|||||||
ScalableImageFeature<T>(coordinateSpace, box, zoomRange, painter = painter)
|
ScalableImageFeature<T>(coordinateSpace, box, zoomRange, painter = painter)
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun <T : Any> FeaturesState<T>.text(
|
public fun <T : Any> FeatureBuilder<T>.text(
|
||||||
position: T,
|
position: T,
|
||||||
text: String,
|
text: String,
|
||||||
zoomRange: FloatRange = defaultZoomRange,
|
zoomRange: FloatRange = defaultZoomRange,
|
@ -0,0 +1,34 @@
|
|||||||
|
package center.sciprog.maps.features
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
|
||||||
|
public fun <T : Any> FeatureCollection<T>.draggableLine(
|
||||||
|
aId: FeatureId<MarkerFeature<T>>,
|
||||||
|
bId: FeatureId<MarkerFeature<T>>,
|
||||||
|
zoomRange: FloatRange = Feature.defaultZoomRange,
|
||||||
|
color: Color = Color.Red,
|
||||||
|
id: String? = null,
|
||||||
|
): FeatureId<LineFeature<T>> {
|
||||||
|
var lineId: FeatureId<LineFeature<T>>? = null
|
||||||
|
|
||||||
|
fun drawLine(): FeatureId<LineFeature<T>> = line(
|
||||||
|
get(aId).center,
|
||||||
|
get(bId).center,
|
||||||
|
zoomRange,
|
||||||
|
color,
|
||||||
|
lineId?.id ?: id
|
||||||
|
).also {
|
||||||
|
lineId = it
|
||||||
|
}
|
||||||
|
|
||||||
|
aId.draggable { _, _ ->
|
||||||
|
drawLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
bId.draggable { _, _ ->
|
||||||
|
drawLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
return drawLine()
|
||||||
|
}
|
@ -62,10 +62,10 @@ public fun <T : Any> DrawScope.drawFeature(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is BitmapImageFeature -> drawImage(feature.image, feature.position.toOffset())
|
is BitmapImageFeature -> drawImage(feature.image, feature.center.toOffset())
|
||||||
|
|
||||||
is VectorImageFeature -> {
|
is VectorImageFeature -> {
|
||||||
val offset = feature.position.toOffset()
|
val offset = feature.center.toOffset()
|
||||||
val size = feature.size.toSize()
|
val size = feature.size.toSize()
|
||||||
translate(offset.x - size.width / 2, offset.y - size.height / 2) {
|
translate(offset.x - size.width / 2, offset.y - size.height / 2) {
|
||||||
with(painterCache[feature]!!) {
|
with(painterCache[feature]!!) {
|
||||||
|
@ -12,7 +12,7 @@ import center.sciprog.maps.features.*
|
|||||||
|
|
||||||
internal fun Pair<Number, Number>.toCoordinates(): XY = XY(first.toFloat(), second.toFloat())
|
internal fun Pair<Number, Number>.toCoordinates(): XY = XY(first.toFloat(), second.toFloat())
|
||||||
|
|
||||||
fun FeaturesState<XY>.background(
|
fun FeatureCollection<XY>.background(
|
||||||
width: Float,
|
width: Float,
|
||||||
height: Float,
|
height: Float,
|
||||||
offset: XY = XY(0f, 0f),
|
offset: XY = XY(0f, 0f),
|
||||||
@ -31,7 +31,7 @@ fun FeaturesState<XY>.background(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FeaturesState<XY>.circle(
|
fun FeatureCollection<XY>.circle(
|
||||||
centerCoordinates: Pair<Number, Number>,
|
centerCoordinates: Pair<Number, Number>,
|
||||||
zoomRange: FloatRange = Feature.defaultZoomRange,
|
zoomRange: FloatRange = Feature.defaultZoomRange,
|
||||||
size: Dp = 5.dp,
|
size: Dp = 5.dp,
|
||||||
@ -39,14 +39,14 @@ fun FeaturesState<XY>.circle(
|
|||||||
id: String? = null,
|
id: String? = null,
|
||||||
): FeatureId<CircleFeature<XY>> = circle(centerCoordinates.toCoordinates(), zoomRange, size, color, id = id)
|
): FeatureId<CircleFeature<XY>> = circle(centerCoordinates.toCoordinates(), zoomRange, size, color, id = id)
|
||||||
|
|
||||||
fun FeaturesState<XY>.draw(
|
fun FeatureCollection<XY>.draw(
|
||||||
position: Pair<Number, Number>,
|
position: Pair<Number, Number>,
|
||||||
zoomRange: FloatRange = Feature.defaultZoomRange,
|
zoomRange: FloatRange = Feature.defaultZoomRange,
|
||||||
id: String? = null,
|
id: String? = null,
|
||||||
draw: DrawScope.() -> Unit,
|
draw: DrawScope.() -> Unit,
|
||||||
): FeatureId<DrawFeature<XY>> = draw(position.toCoordinates(), zoomRange = zoomRange, id = id, draw = draw)
|
): FeatureId<DrawFeature<XY>> = draw(position.toCoordinates(), zoomRange = zoomRange, id = id, draw = draw)
|
||||||
|
|
||||||
fun FeaturesState<XY>.line(
|
fun FeatureCollection<XY>.line(
|
||||||
aCoordinates: Pair<Number, Number>,
|
aCoordinates: Pair<Number, Number>,
|
||||||
bCoordinates: Pair<Number, Number>,
|
bCoordinates: Pair<Number, Number>,
|
||||||
scaleRange: FloatRange = Feature.defaultZoomRange,
|
scaleRange: FloatRange = Feature.defaultZoomRange,
|
||||||
@ -55,7 +55,7 @@ fun FeaturesState<XY>.line(
|
|||||||
): FeatureId<LineFeature<XY>> = line(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), scaleRange, color, id)
|
): FeatureId<LineFeature<XY>> = line(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), scaleRange, color, id)
|
||||||
|
|
||||||
|
|
||||||
public fun FeaturesState<XY>.arc(
|
public fun FeatureCollection<XY>.arc(
|
||||||
center: Pair<Double, Double>,
|
center: Pair<Double, Double>,
|
||||||
radius: Float,
|
radius: Float,
|
||||||
startAngle: Float,
|
startAngle: Float,
|
||||||
@ -71,7 +71,7 @@ public fun FeaturesState<XY>.arc(
|
|||||||
color = color
|
color = color
|
||||||
)
|
)
|
||||||
|
|
||||||
fun FeaturesState<XY>.image(
|
fun FeatureCollection<XY>.image(
|
||||||
position: Pair<Number, Number>,
|
position: Pair<Number, Number>,
|
||||||
image: ImageVector,
|
image: ImageVector,
|
||||||
size: DpSize = DpSize(image.defaultWidth, image.defaultHeight),
|
size: DpSize = DpSize(image.defaultWidth, image.defaultHeight),
|
||||||
@ -80,7 +80,7 @@ fun FeaturesState<XY>.image(
|
|||||||
): FeatureId<VectorImageFeature<XY>> =
|
): FeatureId<VectorImageFeature<XY>> =
|
||||||
image(position.toCoordinates(), image, size = size, zoomRange = zoomRange, id = id)
|
image(position.toCoordinates(), image, size = size, zoomRange = zoomRange, id = id)
|
||||||
|
|
||||||
fun FeaturesState<XY>.text(
|
fun FeatureCollection<XY>.text(
|
||||||
position: Pair<Number, Number>,
|
position: Pair<Number, Number>,
|
||||||
text: String,
|
text: String,
|
||||||
zoomRange: FloatRange = Feature.defaultZoomRange,
|
zoomRange: FloatRange = Feature.defaultZoomRange,
|
||||||
|
@ -23,7 +23,7 @@ private val logger = KotlinLogging.logger("SchemeView")
|
|||||||
@Composable
|
@Composable
|
||||||
public fun SchemeView(
|
public fun SchemeView(
|
||||||
initialViewPoint: ViewPoint<XY>,
|
initialViewPoint: ViewPoint<XY>,
|
||||||
featuresState: FeaturesState<XY>,
|
featuresState: FeatureCollection<XY>,
|
||||||
config: ViewConfig<XY>,
|
config: ViewConfig<XY>,
|
||||||
modifier: Modifier = Modifier.fillMaxSize(),
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
) = key(initialViewPoint) {
|
) = key(initialViewPoint) {
|
||||||
@ -96,7 +96,7 @@ public fun SchemeView(
|
|||||||
modifier: Modifier = Modifier.fillMaxSize(),
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
val featuresState = key(featureMap) {
|
val featuresState = key(featureMap) {
|
||||||
FeaturesState.build(XYCoordinateSpace) {
|
FeatureCollection.build(XYCoordinateSpace) {
|
||||||
featureMap.forEach { feature(it.key.id, it.value) }
|
featureMap.forEach { feature(it.key.id, it.value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,9 +124,9 @@ public fun SchemeView(
|
|||||||
initialRectangle: Rectangle<XY>? = null,
|
initialRectangle: Rectangle<XY>? = null,
|
||||||
config: ViewConfig<XY> = ViewConfig(),
|
config: ViewConfig<XY> = ViewConfig(),
|
||||||
modifier: Modifier = Modifier.fillMaxSize(),
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
buildFeatures: FeaturesState<XY>.() -> Unit = {},
|
buildFeatures: FeatureCollection<XY>.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val featureState = FeaturesState.remember(XYCoordinateSpace, buildFeatures)
|
val featureState = FeatureCollection.remember(XYCoordinateSpace, buildFeatures)
|
||||||
|
|
||||||
val viewPointOverride: ViewPoint<XY> = remember(initialViewPoint, initialRectangle) {
|
val viewPointOverride: ViewPoint<XY> = remember(initialViewPoint, initialRectangle) {
|
||||||
initialViewPoint
|
initialViewPoint
|
||||||
|
@ -22,7 +22,7 @@ class FeatureStateSnapshot<T : Any>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun <T: Any> FeaturesState<T>.snapshot(): FeatureStateSnapshot<T> = FeatureStateSnapshot(
|
fun <T: Any> FeatureCollection<T>.snapshot(): FeatureStateSnapshot<T> = FeatureStateSnapshot(
|
||||||
features,
|
features,
|
||||||
features.values.filterIsInstance<PainterFeature<T>>().associateWith { it.painter() }
|
features.values.filterIsInstance<PainterFeature<T>>().associateWith { it.painter() }
|
||||||
)
|
)
|
||||||
@ -83,10 +83,10 @@ fun FeatureStateSnapshot<XY>.generateSvg(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is BitmapImageFeature -> drawImage(feature.image, feature.position.toOffset())
|
is BitmapImageFeature -> drawImage(feature.image, feature.center.toOffset())
|
||||||
|
|
||||||
is VectorImageFeature -> {
|
is VectorImageFeature -> {
|
||||||
val offset = feature.position.toOffset()
|
val offset = feature.center.toOffset()
|
||||||
val imageSize = feature.size.toSize()
|
val imageSize = feature.size.toSize()
|
||||||
translate(offset.x - imageSize.width / 2, offset.y - imageSize.height / 2) {
|
translate(offset.x - imageSize.width / 2, offset.y - imageSize.height / 2) {
|
||||||
with(painterCache[feature]!!) {
|
with(painterCache[feature]!!) {
|
||||||
|
Loading…
Reference in New Issue
Block a user