Polygon editor demo
This commit is contained in:
parent
5a3a4b059e
commit
6278235b51
38
demo/polygon-editor/build.gradle.kts
Normal file
38
demo/polygon-editor/build.gradle.kts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
id("org.jetbrains.compose")
|
||||||
|
}
|
||||||
|
|
||||||
|
val ktorVersion: String by rootProject.extra
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm {
|
||||||
|
compilations.all {
|
||||||
|
kotlinOptions.jvmTarget = "11"
|
||||||
|
}
|
||||||
|
withJava()
|
||||||
|
}
|
||||||
|
sourceSets {
|
||||||
|
val jvmMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(projects.mapsKtScheme)
|
||||||
|
implementation(compose.desktop.currentOs)
|
||||||
|
implementation("ch.qos.logback:logback-classic:1.2.11")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jvmTest by getting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compose.desktop {
|
||||||
|
application {
|
||||||
|
mainClass = "MainKt"
|
||||||
|
nativeDistributions {
|
||||||
|
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
||||||
|
packageName = "polygon-editor-demo"
|
||||||
|
packageVersion = "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
demo/polygon-editor/src/jvmMain/kotlin/Main.kt
Normal file
86
demo/polygon-editor/src/jvmMain/kotlin/Main.kt
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
|
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.CursorDropdownMenu
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
|
import androidx.compose.ui.graphics.PointMode
|
||||||
|
import androidx.compose.ui.input.pointer.isSecondaryPressed
|
||||||
|
import androidx.compose.ui.window.Window
|
||||||
|
import androidx.compose.ui.window.application
|
||||||
|
import center.sciprog.maps.features.*
|
||||||
|
import center.sciprog.maps.scheme.SchemeView
|
||||||
|
import center.sciprog.maps.scheme.XY
|
||||||
|
import center.sciprog.maps.scheme.XYCoordinateSpace
|
||||||
|
import center.sciprog.maps.scheme.XYViewScope
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview
|
||||||
|
fun App() {
|
||||||
|
MaterialTheme {
|
||||||
|
|
||||||
|
var clickPoint by remember { mutableStateOf<XY?>(null) }
|
||||||
|
|
||||||
|
val myPolygon: SnapshotStateList<XY> = remember { mutableStateListOf<XY>() }
|
||||||
|
|
||||||
|
val featureState: FeatureGroup<XY> = FeatureGroup.remember(XYCoordinateSpace) {
|
||||||
|
points(
|
||||||
|
listOf(XY(0f, 0f), XY(0f, 1f), XY(1f, 1f), XY(1f, 0f), XY(0f, 0f)),
|
||||||
|
pointMode = PointMode.Polygon,
|
||||||
|
id = "frame"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(myPolygon.isNotEmpty()) {
|
||||||
|
featureState.group("polygon") {
|
||||||
|
points(
|
||||||
|
myPolygon + myPolygon.first(),
|
||||||
|
pointMode = PointMode.Polygon,
|
||||||
|
)
|
||||||
|
myPolygon.forEachIndexed { index, xy ->
|
||||||
|
circle(xy, id = "point[$index]").draggable { _, to ->
|
||||||
|
myPolygon[index] = to.focus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val mapState: XYViewScope = XYViewScope.remember(
|
||||||
|
config = ViewConfig<XY>(
|
||||||
|
onClick = { event, point ->
|
||||||
|
if (event.buttons.isSecondaryPressed) {
|
||||||
|
clickPoint = point.focus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
initialRectangle = featureState.getBoundingBox(1f),
|
||||||
|
)
|
||||||
|
|
||||||
|
CursorDropdownMenu(clickPoint != null, { clickPoint = null }) {
|
||||||
|
clickPoint?.let { point ->
|
||||||
|
Button({
|
||||||
|
myPolygon.add(point)
|
||||||
|
clickPoint = null
|
||||||
|
}) {
|
||||||
|
Text("Create node")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SchemeView(
|
||||||
|
mapState,
|
||||||
|
featureState,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() = application {
|
||||||
|
Window(title = "Polygon editor demo", onCloseRequest = ::exitApplication) {
|
||||||
|
App()
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,6 @@ import androidx.compose.ui.window.application
|
|||||||
import center.sciprog.maps.features.FeatureGroup
|
import center.sciprog.maps.features.FeatureGroup
|
||||||
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.scheme.*
|
import center.sciprog.maps.scheme.*
|
||||||
import center.sciprog.maps.svg.FeatureStateSnapshot
|
import center.sciprog.maps.svg.FeatureStateSnapshot
|
||||||
import center.sciprog.maps.svg.exportToSvg
|
import center.sciprog.maps.svg.exportToSvg
|
||||||
@ -29,7 +28,7 @@ fun App() {
|
|||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val schemeFeaturesState = FeatureGroup.remember(XYCoordinateSpace) {
|
val schemeFeaturesState: FeatureGroup<XY> = FeatureGroup.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)
|
||||||
@ -53,8 +52,7 @@ fun App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val initialViewPoint: ViewPoint<XY> = remember {
|
val initialViewPoint: ViewPoint<XY> = remember {
|
||||||
schemeFeaturesState.features.computeBoundingBox(XYCoordinateSpace, 1f)?.computeViewPoint()
|
schemeFeaturesState.getBoundingBox(1f)?.computeViewPoint() ?: XYViewPoint(XY(0f, 0f))
|
||||||
?: XYViewPoint(XY(0f, 0f))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewPoint: ViewPoint<XY> by remember { mutableStateOf(initialViewPoint) }
|
var viewPoint: ViewPoint<XY> by remember { mutableStateOf(initialViewPoint) }
|
||||||
@ -81,7 +79,7 @@ fun App() {
|
|||||||
) {
|
) {
|
||||||
val mapState: XYViewScope = XYViewScope.remember(
|
val mapState: XYViewScope = XYViewScope.remember(
|
||||||
ViewConfig(
|
ViewConfig(
|
||||||
onClick = {_, click ->
|
onClick = { _, click ->
|
||||||
println("${click.focus.x}, ${click.focus.y}")
|
println("${click.focus.x}, ${click.focus.y}")
|
||||||
},
|
},
|
||||||
onViewChange = { viewPoint = this }
|
onViewChange = { viewPoint = this }
|
||||||
|
Before Width: | Height: | Size: 469 KiB After Width: | Height: | Size: 469 KiB |
@ -47,7 +47,7 @@ class XYViewScope(
|
|||||||
companion object{
|
companion object{
|
||||||
@Composable
|
@Composable
|
||||||
public fun remember(
|
public fun remember(
|
||||||
config: ViewConfig<XY>,
|
config: ViewConfig<XY> = ViewConfig(),
|
||||||
initialViewPoint: ViewPoint<XY>? = null,
|
initialViewPoint: ViewPoint<XY>? = null,
|
||||||
initialRectangle: Rectangle<XY>? = null,
|
initialRectangle: Rectangle<XY>? = null,
|
||||||
): XYViewScope = remember {
|
): XYViewScope = remember {
|
||||||
|
@ -24,12 +24,12 @@ private val logger = KotlinLogging.logger("SchemeView")
|
|||||||
public fun SchemeView(
|
public fun SchemeView(
|
||||||
state: XYViewScope,
|
state: XYViewScope,
|
||||||
featuresState: FeatureGroup<XY>,
|
featuresState: FeatureGroup<XY>,
|
||||||
modifier: Modifier = Modifier.fillMaxSize(),
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) = key(state, featuresState) {
|
||||||
with(state) {
|
with(state) {
|
||||||
val painterCache: Map<PainterFeature<XY>, Painter> = key(featuresState) {
|
//Can't do that inside canvas
|
||||||
|
val painterCache: Map<PainterFeature<XY>, Painter> =
|
||||||
featuresState.features.filterIsInstance<PainterFeature<XY>>().associateWith { it.getPainter() }
|
featuresState.features.filterIsInstance<PainterFeature<XY>>().associateWith { it.getPainter() }
|
||||||
}
|
|
||||||
|
|
||||||
Canvas(modifier = modifier.mapControls(state, featuresState).fillMaxSize()) {
|
Canvas(modifier = modifier.mapControls(state, featuresState).fillMaxSize()) {
|
||||||
|
|
||||||
@ -41,10 +41,11 @@ public fun SchemeView(
|
|||||||
clipRect {
|
clipRect {
|
||||||
featuresState.featureMap.values.sortedBy { it.z }
|
featuresState.featureMap.values.sortedBy { it.z }
|
||||||
.filter { viewPoint.zoom in it.zoomRange }
|
.filter { viewPoint.zoom in it.zoomRange }
|
||||||
.forEach { background ->
|
.forEach { feature ->
|
||||||
drawFeature(state, painterCache, background)
|
drawFeature(state, painterCache, feature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectRect?.let { dpRect ->
|
selectRect?.let { dpRect ->
|
||||||
val rect = dpRect.toRect()
|
val rect = dpRect.toRect()
|
||||||
drawRect(
|
drawRect(
|
||||||
@ -96,7 +97,10 @@ public fun SchemeView(
|
|||||||
val state = XYViewScope.remember(
|
val state = XYViewScope.remember(
|
||||||
config,
|
config,
|
||||||
initialViewPoint = initialViewPoint,
|
initialViewPoint = initialViewPoint,
|
||||||
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(XYCoordinateSpace, Float.MAX_VALUE),
|
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(
|
||||||
|
XYCoordinateSpace,
|
||||||
|
Float.MAX_VALUE
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
SchemeView(state, featureState, modifier)
|
SchemeView(state, featureState, modifier)
|
||||||
@ -121,7 +125,10 @@ public fun SchemeView(
|
|||||||
val mapState: XYViewScope = XYViewScope.remember(
|
val mapState: XYViewScope = XYViewScope.remember(
|
||||||
config,
|
config,
|
||||||
initialViewPoint = initialViewPoint,
|
initialViewPoint = initialViewPoint,
|
||||||
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(XYCoordinateSpace, Float.MAX_VALUE),
|
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(
|
||||||
|
XYCoordinateSpace,
|
||||||
|
Float.MAX_VALUE
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
SchemeView(mapState, featureState, modifier)
|
SchemeView(mapState, featureState, modifier)
|
||||||
|
@ -49,8 +49,9 @@ include(
|
|||||||
":maps-kt-geojson",
|
":maps-kt-geojson",
|
||||||
":maps-kt-features",
|
":maps-kt-features",
|
||||||
":maps-kt-compose",
|
":maps-kt-compose",
|
||||||
":demo:maps",
|
|
||||||
":maps-kt-scheme",
|
":maps-kt-scheme",
|
||||||
":demo:scheme"
|
":demo:maps",
|
||||||
|
":demo:scheme",
|
||||||
|
":demo:polygon-editor"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user