From 9e43d2c5720914687537e1e7dc18d04c7a7897d6 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 2 Jan 2020 11:23:09 +0300 Subject: [PATCH] Name breadcrumbs in property editor for #10 --- .../hep/dataforge/vis/common/VisualGroup.kt | 1 + .../hep/dataforge/vis/js/editor/jsTree.kt | 28 +++++--- .../dataforge/vis/js/editor/propertyEditor.kt | 70 +++++++++++-------- .../dataforge/vis/spatial/Visual3DPlugin.kt | 1 + .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 6 +- .../ru/mipt/npm/muon/monitor/MMDemoApp.kt | 12 ++-- demo/muon-monitor/src/jsMain/web/index.html | 10 +-- 7 files changed, 73 insertions(+), 55 deletions(-) diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt index a73dfc43..bddfae6f 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt @@ -61,6 +61,7 @@ data class StyleRef(val group: VisualGroup, val styleName: Name) val VisualGroup.isEmpty: Boolean get() = this.children.isEmpty() + interface MutableVisualGroup : VisualGroup { /** diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt index f45727b9..51edd87a 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt @@ -1,6 +1,8 @@ package hep.dataforge.vis.js.editor +import hep.dataforge.names.Name import hep.dataforge.names.NameToken +import hep.dataforge.names.plus import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.isEmpty @@ -15,58 +17,62 @@ import kotlin.dom.clear fun Element.objectTree( token: NameToken, obj: VisualObject, - clickCallback: (VisualObject) -> Unit = {} + clickCallback: (Name, VisualObject) -> Unit = {_,_->} ) { clear() append { card("Object tree") { - subTree(token, obj, clickCallback) + subTree(Name.EMPTY, token, obj, clickCallback) } } } private fun TagConsumer.subTree( + parentName: Name, token: NameToken, obj: VisualObject, - clickCallback: (VisualObject) -> Unit + clickCallback: (Name, VisualObject) -> Unit ) { + val fullName = parentName + token - if (obj is VisualGroup && !obj.isEmpty) { + //display as node if any child is visible + if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) { lateinit var toggle: HTMLSpanElement div("d-inline-block text-truncate") { toggle = span("objTree-caret") label("objTree-label") { +token.toString() - onClickFunction = { clickCallback(obj) } + onClickFunction = { clickCallback(fullName, obj) } } } val subtree = ul("objTree-subtree") toggle.onclick = { toggle.classList.toggle("objTree-caret-down") subtree.apply { + //If expanded, add children dynamically if (toggle.classList.contains("objTree-caret-down")) { obj.children.entries - .filter { !it.key.toString().startsWith("@") } + .filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children .sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true } - .forEach { (token, child) -> + .forEach { (childToken, child) -> append { li().apply { - subTree(token, child, clickCallback) + subTree(fullName, childToken, child, clickCallback) } } } } else { + // if not, clear them to conserve memory on very long lists this.clear() } } - //jQuery(subtree).asDynamic().collapse("toggle") } } else { - div("d-inline-block text-truncate") { + val div = div("d-inline-block text-truncate") { span("objTree-leaf") label("objTree-label") { +token.toString() - onClickFunction = { clickCallback(obj) } + onClickFunction = { clickCallback(fullName, obj) } } } } diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/propertyEditor.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/propertyEditor.kt index e2cdfcaa..59a026c3 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/propertyEditor.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/propertyEditor.kt @@ -5,11 +5,12 @@ import hep.dataforge.js.jsObject import hep.dataforge.meta.DynamicMeta import hep.dataforge.meta.Meta import hep.dataforge.meta.update +import hep.dataforge.names.Name +import hep.dataforge.names.isEmpty import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.findStyle import kotlinx.html.dom.append -import kotlinx.html.js.div -import kotlinx.html.js.h4 +import kotlinx.html.js.* import org.w3c.dom.Element import kotlin.dom.clear @@ -17,40 +18,51 @@ import kotlin.dom.clear fun Meta.toDynamic() = JSON.parse(toJson().toString()) //TODO add node descriptor instead of configuring property selector -fun Element.propertyEditor(item: VisualObject?, propertySelector: (VisualObject) -> Meta = { it.config }) { +fun Element.propertyEditor(name: Name, item: VisualObject, propertySelector: (VisualObject) -> Meta = { it.config }) { clear() - if (item != null) { - append { - card("Properties") { - val dMeta: dynamic = propertySelector(item).toDynamic() - val options: JSONEditorOptions = jsObject { - mode = "form" - onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) } - } - JSONEditor(div(), options, dMeta) - } - val styles = item.styles - if (styles.isNotEmpty()) { - card("Styles") { - item.styles.forEach { style -> - val styleMeta = item.findStyle(style) - h4("container") { +style } - if (styleMeta != null) { - div("container").apply { - val options: JSONEditorOptions = jsObject { - mode = "view" - } - JSONEditor( - this, - options, - styleMeta.toDynamic() - ) + append { + card("Properties") { + if(!name.isEmpty()) { + nav { + attributes["aria-label"] = "breadcrumb" + ol("breadcrumb") { + name.tokens.forEach {token-> + li("breadcrumb-item") { + +token.toString() } } } } } + val dMeta: dynamic = propertySelector(item).toDynamic() + val options: JSONEditorOptions = jsObject { + mode = "form" + onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) } + } + JSONEditor(div(), options, dMeta) + } + + val styles = item.styles + if (styles.isNotEmpty()) { + card("Styles") { + item.styles.forEach { style -> + val styleMeta = item.findStyle(style) + h4("container") { +style } + if (styleMeta != null) { + div("container").apply { + val options: JSONEditorOptions = jsObject { + mode = "view" + } + JSONEditor( + this, + options, + styleMeta.toDynamic() + ) + } + } + } + } } } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt index b09e2ea2..3f4a194d 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt @@ -49,6 +49,7 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) { Box::class with Box.serializer() Convex::class with Convex.serializer() Extruded::class with Extruded.serializer() + addSubclass(PolyLine.serializer()) addSubclass(Label3D.serializer()) } } diff --git a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt index 928fd24a..bc3383f6 100644 --- a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt +++ b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt @@ -2,11 +2,11 @@ package hep.dataforge.vis.spatial.gdml.demo import hep.dataforge.context.Global import hep.dataforge.js.Application -import hep.dataforge.vis.js.editor.objectTree import hep.dataforge.js.startApplication import hep.dataforge.meta.buildMeta import hep.dataforge.meta.withBottom import hep.dataforge.names.NameToken +import hep.dataforge.vis.js.editor.objectTree import hep.dataforge.vis.js.editor.propertyEditor import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY @@ -159,8 +159,8 @@ private class GDMLDemoApp : Application { output.camera.layers.set(0) configElement.threeSettings(output) //tree.visualObjectTree(visual, editor::propertyEditor) - treeElement.objectTree(NameToken("World"), visual) { - editorElement.propertyEditor(it) { item -> + treeElement.objectTree(NameToken("World"), visual) { objName, obj -> + editorElement.propertyEditor(objName, obj) { item -> //val descriptorMeta = Material3D.descriptor val properties = item.allProperties() diff --git a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt index a9fac312..79a4454e 100644 --- a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt +++ b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt @@ -35,7 +35,7 @@ private class GDMLDemoApp : Application { private val model = Model() - private val connection = HttpClient{ + private val connection = HttpClient { install(JsonFeature) { serializer = KotlinxSerializer(Visual3DPlugin.json) } @@ -52,7 +52,6 @@ private class GDMLDemoApp : Application { document.getElementById("settings") ?: error("Element with id 'settings' not found on page") val treeElement = document.getElementById("tree") ?: error("Element with id 'tree' not found on page") val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page") - canvasElement.clear() canvasElement.clear() val visual: VisualObject3D = model.root @@ -63,7 +62,7 @@ private class GDMLDemoApp : Application { output.camera.layers.set(0) output.camera.position.z = -2000.0 output.camera.position.y = 500.0 - settingsElement.threeSettings(output){ + settingsElement.threeSettings(output) { card("Events") { button { +"Next" @@ -83,8 +82,8 @@ private class GDMLDemoApp : Application { } } //tree.visualObjectTree(visual, editor::propertyEditor) - treeElement.objectTree(NameToken("World"), visual) { - editorElement.propertyEditor(it) { item -> + treeElement.objectTree(NameToken("World"), visual) { name, obj -> + editorElement.propertyEditor(name, obj) { item -> //val descriptorMeta = Material3D.descriptor val properties = item.allProperties() @@ -99,10 +98,7 @@ private class GDMLDemoApp : Application { properties.withBottom(bottom) } } - - output.render(visual) - } } diff --git a/demo/muon-monitor/src/jsMain/web/index.html b/demo/muon-monitor/src/jsMain/web/index.html index e4bb83a9..26ae632d 100644 --- a/demo/muon-monitor/src/jsMain/web/index.html +++ b/demo/muon-monitor/src/jsMain/web/index.html @@ -19,13 +19,15 @@
-
-
+
-
+
+
+
+
+
-