From d4dcd32b73fa62c159e5fa97ffacdc83fabadde2 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 23 Mar 2020 22:19:52 +0300 Subject: [PATCH] Migration to 1.3.70 --- build.gradle.kts | 1 + dataforge-vis-common/build.gradle.kts | 35 ++-- .../hep/dataforge/vis/AbstractVisualObject.kt | 2 +- .../kotlin/hep/dataforge/vis/valueWidget.kt | 13 +- .../jsMain/kotlin/hep/dataforge/js/react.kt | 17 ++ .../vis/editor/ConfigEditorComponent.kt | 178 ++++++++++++++++++ .../vis/editor/MetaViewerComponent.kt | 81 ++++++++ .../vis/editor/ObjectTreeComponent.kt | 108 +++++++++++ .../hep/dataforge/vis/editor/bootstrap.kt | 12 ++ .../kotlin/hep/dataforge/vis/editor/jsTree.kt | 24 +-- .../dataforge/vis/editor/propertyEditor.kt | 139 ++++++++------ .../src/jsMain/resources/css/common.css | 17 ++ .../hep/dataforge/vis/editor/ValueChooser.kt | 3 +- dataforge-vis-spatial-gdml/build.gradle.kts | 2 +- .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 1 - .../vis/spatial/three/ThreeCanvas.kt | 6 +- .../vis/spatial/three/ThreeCanvasComponent.kt | 56 ++++++ .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 37 ++-- demo/muon-monitor/build.gradle.kts | 17 +- .../ru/mipt/npm/muon/monitor/MMDemoApp.kt | 43 +++-- demo/spatial-showcase/build.gradle.kts | 8 - .../vis/spatial/demo/ThreeDemoApp.kt | 1 - playground/build.gradle.kts | 27 +++ playground/src/jsMain/kotlin/PlayGroundApp.kt | 56 ++++++ .../src/jsMain/resources/css/common.css | 40 ++++ playground/src/jsMain/resources/index.html | 16 ++ settings.gradle.kts | 3 +- 27 files changed, 803 insertions(+), 140 deletions(-) create mode 100644 dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt create mode 100644 dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt create mode 100644 dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/MetaViewerComponent.kt create mode 100644 dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTreeComponent.kt create mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvasComponent.kt create mode 100644 playground/build.gradle.kts create mode 100644 playground/src/jsMain/kotlin/PlayGroundApp.kt create mode 100644 playground/src/jsMain/resources/css/common.css create mode 100644 playground/src/jsMain/resources/index.html diff --git a/build.gradle.kts b/build.gradle.kts index 82f0e8d5..8d9f1e05 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,6 +18,7 @@ allprojects { maven("https://dl.bintray.com/pdvrieze/maven") maven("http://maven.jzy3d.org/releases") maven("https://kotlin.bintray.com/js-externals") + maven("https://kotlin.bintray.com/kotlin-js-wrappers/") // maven("https://dl.bintray.com/gbaldeck/kotlin") // maven("https://dl.bintray.com/rjaros/kotlin") } diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index f673dde2..cf2d60c8 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -1,5 +1,3 @@ -import scientifik.serialization - plugins { id("scientifik.mpp") } @@ -7,35 +5,44 @@ plugins { val dataforgeVersion: String by rootProject.extra //val kvisionVersion: String by rootProject.extra("2.0.0-M1") -serialization() -val fxVersion: String by rootProject.extra - kotlin { sourceSets { - commonMain{ + commonMain { dependencies { api("hep.dataforge:dataforge-output:$dataforgeVersion") } } - jvmMain{ + jvmMain { dependencies { api("no.tornado:tornadofx:1.7.20") //api("no.tornado:tornadofx-controlsfx:0.1.1") - api("de.jensd:fontawesomefx-fontawesome:4.7.0-11"){ + api("de.jensd:fontawesomefx-fontawesome:4.7.0-11") { exclude(group = "org.openjfx") } - api("de.jensd:fontawesomefx-commons:11.0"){ + api("de.jensd:fontawesomefx-commons:11.0") { exclude(group = "org.openjfx") } } } - jsMain{ + jsMain { dependencies { api("hep.dataforge:dataforge-output-html:$dataforgeVersion") - //api(npm("bootstrap","4.4.1")) - implementation(npm("uri-js","4.2.2")) - implementation(npm("jsoneditor","8.6.1")) - implementation(npm("file-saver")) + + //React, React DOM + Wrappers (chapter 3) + api("org.jetbrains:kotlin-react:16.13.0-pre.94-kotlin-1.3.70") + api("org.jetbrains:kotlin-react-dom:16.13.0-pre.94-kotlin-1.3.70") + api(npm("react", "16.13.0")) + api(npm("react-dom", "16.13.0")) + + //Kotlin Styled (chapter 3) + api("org.jetbrains:kotlin-styled:1.0.0-pre.94-kotlin-1.3.70") + api(npm("styled-components")) + api(npm("inline-style-prefixer")) + + + api(npm("bootstrap","4.3.1")) + //api(npm("jsoneditor", "8.6.1")) + api(npm("file-saver","2.0.2")) } } } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt index e13f6253..47d002d5 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt @@ -68,7 +68,7 @@ abstract class AbstractVisualObject : VisualObject { private var styleCache: Meta? = null /** - * Collect all styles for this object in a laminate + * Collect all styles for this object in a single cached meta */ protected val mergedStyles: Meta get() = styleCache ?: findAllStyles().merge().also { diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/valueWidget.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/valueWidget.kt index 809ad4ed..fd0f598d 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/valueWidget.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/valueWidget.kt @@ -1,16 +1,21 @@ package hep.dataforge.vis -import hep.dataforge.meta.* +import hep.dataforge.meta.EmptyMeta +import hep.dataforge.meta.Meta import hep.dataforge.meta.descriptors.ValueDescriptor +import hep.dataforge.meta.node import hep.dataforge.meta.scheme.getProperty +import hep.dataforge.meta.scheme.setProperty +import hep.dataforge.meta.string +import hep.dataforge.values.asValue /** * Extension property to access the "widget" key of [ValueDescriptor] */ var ValueDescriptor.widget: Meta - get() = this.config["widget"].node?: EmptyMeta + get() = getProperty("widget").node ?: EmptyMeta set(value) { - config["widget"] = value + setProperty("widget", value) } /** @@ -19,5 +24,5 @@ var ValueDescriptor.widget: Meta var ValueDescriptor.widgetType: String? get() = getProperty("widget.type").string set(value) { - config["widget.type"] = value + setProperty("widget.type", value?.asValue()) } \ No newline at end of file diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt new file mode 100644 index 00000000..2611e7db --- /dev/null +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt @@ -0,0 +1,17 @@ +package hep.dataforge.js + +import react.RComponent +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +fun RComponent<*, *>.initState(init: () -> T): ReadWriteProperty, T> = + object : ReadWriteProperty, T> { + val pair = react.useState(init) + override fun getValue(thisRef: RComponent<*, *>, property: KProperty<*>): T { + return pair.first + } + + override fun setValue(thisRef: RComponent<*, *>, property: KProperty<*>, value: T) { + pair.second(value) + } + } \ No newline at end of file diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt new file mode 100644 index 00000000..800e8090 --- /dev/null +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt @@ -0,0 +1,178 @@ +package hep.dataforge.vis.editor + +import hep.dataforge.js.initState +import hep.dataforge.meta.* +import hep.dataforge.meta.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.defaultItem +import hep.dataforge.meta.descriptors.get +import hep.dataforge.names.Name +import hep.dataforge.names.NameToken +import hep.dataforge.names.plus +import hep.dataforge.values.asValue +import kotlinx.html.InputType +import kotlinx.html.classes +import kotlinx.html.js.onChangeFunction +import kotlinx.html.js.onClickFunction +import org.w3c.dom.Element +import react.* +import react.dom.* + +interface ConfigEditorProps : RProps { + /** + * Root config object - always non null + */ + var root: Config + + /** + * Full path to the displayed node in [root]. Could be empty + */ + var name: Name + + /** + * Root default + */ + var default: Meta? + + /** + * Root descriptor + */ + var descriptor: NodeDescriptor? + + var listen: Boolean +} + +class ConfigEditorComponent : RComponent() { + + override fun TreeState.init() { + expanded = false + } + + override fun componentDidMount() { + if (props.listen) { + props.root.onChange(this) { name, _, _ -> + if (name == props.name) { + forceUpdate() + } + } + } + } + + override fun componentWillUnmount() { + props.root.removeListener(this) + } + + override fun RBuilder.render() { + val item = props.root[props.name] + val descriptorItem = props.descriptor?.get(props.name) + val defaultItem = props.default?.get(props.name) + val actualItem = item ?: defaultItem ?: descriptorItem?.defaultItem() + val token = props.name.last() + + div("d-inline-block text-truncate") { + when (actualItem) { + null -> { + } + is MetaItem.ValueItem -> { + i("tree-caret") { } + } + is MetaItem.NodeItem -> { + i("tree-caret fa fa-caret-right") { + attrs { + if (state.expanded) { + classes += "rotate" + } + onClickFunction = { + setState { + expanded = !expanded + } + } + } + } + } + } + label("tree-label") { + +token.toString() + attrs { + if (item == null) { + classes += "tree-label-inactive" + } + } + } + + if (actualItem is MetaItem.NodeItem && state.expanded) { + ul("tree") { + val keys = buildList { + item?.node?.items?.keys?.let { addAll(it) } + defaultItem?.node?.items?.keys?.let { addAll(it) } + (descriptorItem as? NodeDescriptor)?.items?.keys?.forEach { + add(NameToken(it)) + } + } + keys.forEach { token -> + li("tree-item") { + child(ConfigEditorComponent::class) { + attrs { + root = props.root + name = props.name + token + this.default = props.default + this.descriptor = props.descriptor + listen = false + } + } + } + } + } + } else if (actualItem is MetaItem.ValueItem) { + div("row") { + div("col") { + label("tree-label") { + +token.toString() + } + } + div("col") { + input(type = InputType.text) { + attrs { + value = actualItem.value.toString() + onChangeFunction = { + try { + props.root.setValue(props.name, value.asValue()) + } catch (ex: Exception) { + console.error("Can't set config property $name to $value") + } + } + } + } + //+actualItem.value.toString() + } + } + } + } + } + +} + +fun Element.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null) { + render(this) { + child(ConfigEditorComponent::class) { + attrs { + root = config + name = Name.EMPTY + this.descriptor = descriptor + this.default = default + listen = true + } + } + } +} + +fun RBuilder.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null) { + child(ConfigEditorComponent::class) { + attrs { + root = config + name = Name.EMPTY + this.descriptor = descriptor + this.default = default + listen = true + } + } +} diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/MetaViewerComponent.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/MetaViewerComponent.kt new file mode 100644 index 00000000..871d81d1 --- /dev/null +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/MetaViewerComponent.kt @@ -0,0 +1,81 @@ +package hep.dataforge.vis.editor + +import hep.dataforge.js.initState +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaItem +import hep.dataforge.meta.descriptors.NodeDescriptor +import hep.dataforge.names.NameToken +import kotlinx.html.classes +import kotlinx.html.js.onClickFunction +import react.* +import react.dom.* + +interface MetaViewerProps : RProps { + var name: NameToken + var meta: Meta + var descriptor: NodeDescriptor? +} + +class MetaViewerComponent : RComponent() { + + override fun TreeState.init() { + expanded = false + } + + override fun RBuilder.render() { + div("d-inline-block text-truncate") { + if (props.meta.items.isNotEmpty()) { + span("objTree-caret") { + attrs { + classes = if (state.expanded) { + setOf("objTree-caret", "objTree-caret-down") + } else { + setOf("objTree-caret") + } + onClickFunction = { + setState { + expanded = !expanded + } + } + } + } + } + label("tree-label") { + +props.name.toString() + } + ul("tree") { + props.meta.items.forEach { (token, item) -> + //val descriptor = props. + li { + when (item) { + is MetaItem.NodeItem -> { + child(MetaViewerComponent::class) { + attrs { + name = token + meta = item.node + descriptor = props.descriptor?.nodes?.get(token.body) + } + } + } + is MetaItem.ValueItem -> { + div("row") { + div("col") { + label("tree-label") { + +token.toString() + } + } + div("col") { + label { + +item.value.toString() + } + } + } + } + } + } + } + } + } + } + +} \ No newline at end of file diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTreeComponent.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTreeComponent.kt new file mode 100644 index 00000000..102af649 --- /dev/null +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTreeComponent.kt @@ -0,0 +1,108 @@ +package hep.dataforge.vis.editor + +import hep.dataforge.names.Name +import hep.dataforge.names.plus +import hep.dataforge.vis.VisualGroup +import hep.dataforge.vis.VisualObject +import hep.dataforge.vis.isEmpty +import kotlinx.html.classes +import kotlinx.html.js.onClickFunction +import org.w3c.dom.Element +import react.* +import react.dom.* + +interface ObjectTreeProps : RProps { + var name: Name + var obj: VisualObject + var clickCallback: (Name) -> Unit +} + +interface TreeState : RState { + var expanded: Boolean +} + +class ObjectTreeComponent : RComponent() { + + override fun TreeState.init() { + expanded = false + } + + override fun RBuilder.render() { + val token = props.name.last()?.toString() ?: "World" + val obj = props.obj + + //display as node if any child is visible + if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) { + div("d-inline-block text-truncate") { + span("objTree-caret") { + attrs { + classes = if (state.expanded) { + setOf("objTree-caret", "objTree-caret-down") + } else { + setOf("objTree-caret") + } + onClickFunction = { + setState { + expanded = !expanded + } + } + } + } + label("objTree-label") { + +token + attrs { + onClickFunction = { props.clickCallback(props.name) } + } + } + } + if (state.expanded) { + ul("objTree-subtree") { + obj.children.entries + .filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children + .sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true } + .forEach { (childToken, child) -> + li { + child(ObjectTreeComponent::class) { + attrs { + name = props.name + childToken + this.obj = child + clickCallback = props.clickCallback + } + } + } + } + } + } + } else { + div("d-inline-block text-truncate") { + span("objTree-leaf") {} + label("objTree-label") { + +token + attrs { + onClickFunction = { props.clickCallback(props.name) } + } + } + } + } + } +} + +fun RBuilder.objectTree( + obj: VisualObject, + clickCallback: (Name) -> Unit = {} +) = child(ObjectTreeComponent::class) { + attrs { + name = Name.EMPTY + this.obj = obj + this.clickCallback = clickCallback + } +} + +fun Element.objectTree( + obj: VisualObject, + clickCallback: (Name) -> Unit = {} +) { + render(this) { + objectTree(obj, clickCallback) + } +} \ No newline at end of file diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/bootstrap.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/bootstrap.kt index f002e29c..02149034 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/bootstrap.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/bootstrap.kt @@ -3,6 +3,10 @@ package hep.dataforge.vis.editor import kotlinx.html.* import kotlinx.html.js.div import org.w3c.dom.HTMLElement +import react.RBuilder +import react.ReactElement +import react.dom.div +import react.dom.h3 inline fun TagConsumer.card(title: String, crossinline block: TagConsumer.() -> Unit) { div("card w-100") { @@ -13,6 +17,14 @@ inline fun TagConsumer.card(title: String, crossinline block: TagCo } } +inline fun RBuilder.card(title: String, crossinline block: RBuilder.() -> Unit): ReactElement = div("card w-100") { + div("card-body") { + h3(classes = "card-title") { +title } + block() + } +} + + fun TagConsumer.accordion(id: String, elements: Map Unit>) { div("container-fluid") { div("accordion") { diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/jsTree.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/jsTree.kt index 393f1f58..a9c876ae 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/jsTree.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/jsTree.kt @@ -13,18 +13,18 @@ import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLSpanElement import kotlin.dom.clear -fun Element.displayObjectTree( - obj: VisualObject, - clickCallback: (Name) -> Unit = {} -) { - clear() - append { - card("Object tree") { - subTree(Name.EMPTY, obj, clickCallback) - } - } -} - +//fun Element.displayObjectTree( +// obj: VisualObject, +// clickCallback: (Name) -> Unit = {} +//) { +// clear() +// append { +// card("Object tree") { +// subTree(Name.EMPTY, obj, clickCallback) +// } +// } +//} +// private fun TagConsumer.subTree( name: Name, obj: VisualObject, diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/propertyEditor.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/propertyEditor.kt index 3af199cf..f3876e58 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/propertyEditor.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/propertyEditor.kt @@ -1,73 +1,102 @@ package hep.dataforge.vis.editor -import hep.dataforge.js.jsObject -import hep.dataforge.meta.DynamicMeta import hep.dataforge.meta.Meta -import hep.dataforge.meta.toJson -import hep.dataforge.meta.update +import hep.dataforge.meta.MetaBuilder import hep.dataforge.names.Name import hep.dataforge.names.isEmpty import hep.dataforge.vis.VisualObject -import hep.dataforge.vis.findStyle -import kotlinx.html.dom.append -import kotlinx.html.js.* import org.w3c.dom.Element +import react.RBuilder +import react.ReactElement +import react.dom.li +import react.dom.nav +import react.dom.ol +import react.dom.render import kotlin.collections.set -import kotlin.dom.clear -//FIXME something rotten in JS-Meta converter -fun Meta.toDynamic() = JSON.parse(toJson().toString()) +////FIXME something rotten in JS-Meta converter +//fun Meta.toDynamic() = JSON.parse(toJson().toString()) +// +////TODO add node descriptor instead of configuring property selector +//fun Element.displayPropertyEditor( +// name: Name, +// item: VisualObject, +// propertySelector: (VisualObject) -> Meta = { it.config } +//) { +// clear() +// +// 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() +// ) +// } +// } +// } +// } +// } +// } +//} -//TODO add node descriptor instead of configuring property selector -fun Element.displayPropertyEditor( - name: Name, +fun RBuilder.visualPropertyEditor( + path: Name, item: VisualObject, - propertySelector: (VisualObject) -> Meta = { it.config } -) { - clear() - - append { - card("Properties") { - if (!name.isEmpty()) { - nav { - attributes["aria-label"] = "breadcrumb" - ol("breadcrumb") { - name.tokens.forEach { token -> - li("breadcrumb-item") { - +token.toString() - } - } - } - } + default: MetaBuilder.() -> Unit = {} +): ReactElement = card("Properties") { + if (!path.isEmpty()) { + nav { + attrs { + attributes["aria-label"] = "breadcrumb" } - 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() - ) - } + ol("breadcrumb") { + path.tokens.forEach { token -> + li("breadcrumb-item") { + +token.toString() } } } } } + configEditor(item.config, item.descriptor, Meta(default)) +} + +fun Element.visualPropertyEditor( + path: Name, + item: VisualObject, + default: MetaBuilder.() -> Unit = {} +) = render(this) { + visualPropertyEditor(path, item, default) } \ No newline at end of file diff --git a/dataforge-vis-common/src/jsMain/resources/css/common.css b/dataforge-vis-common/src/jsMain/resources/css/common.css index c5efcd40..4d1bac9d 100644 --- a/dataforge-vis-common/src/jsMain/resources/css/common.css +++ b/dataforge-vis-common/src/jsMain/resources/css/common.css @@ -21,3 +21,20 @@ ul, .objTree-subtree { .objTree-caret-down::before { transform: rotate(90deg); } + +ul, .tree { + list-style-type: none; +} + +i, .tree-caret{ + display: inline-block; + margin-right: 6px; +} + +.rotate { + transform: rotate(90deg); +} + +.tree-label-inactive { + color: gray; +} diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt index 596c3b29..7c5a0d1e 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt @@ -108,8 +108,7 @@ interface ValueChooser { descriptor: ValueDescriptor? = null, setter: (Value) -> Unit ): ValueChooser { - val chooser = - build(context, descriptor) + val chooser = build(context, descriptor) chooser.setDisplayValue(value.value ?: Null) value.onChange { chooser.setDisplayValue(it ?: Null) diff --git a/dataforge-vis-spatial-gdml/build.gradle.kts b/dataforge-vis-spatial-gdml/build.gradle.kts index c13e2e3f..a2a0bce8 100644 --- a/dataforge-vis-spatial-gdml/build.gradle.kts +++ b/dataforge-vis-spatial-gdml/build.gradle.kts @@ -7,7 +7,7 @@ kotlin { val commonMain by getting { dependencies { api(project(":dataforge-vis-spatial")) - api("scientifik:gdml:0.1.6") + api("scientifik:gdml:0.1.7") } } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index 0e962b72..4514a559 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -11,7 +11,6 @@ import hep.dataforge.names.NameToken import hep.dataforge.names.asName import hep.dataforge.names.plus import hep.dataforge.vis.* -import hep.dataforge.vis.common.* import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt index 6e3a9603..4de96ab5 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt @@ -212,4 +212,8 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv } fun ThreePlugin.output(element: HTMLElement, spec: Canvas = Canvas.empty()): ThreeCanvas = - ThreeCanvas(element, this, spec) \ No newline at end of file + ThreeCanvas(element, this, spec) + +fun ThreePlugin.render(element: HTMLElement, obj: VisualObject3D, spec: Canvas = Canvas.empty()): Unit = + output(element, spec).render(obj) + diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvasComponent.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvasComponent.kt new file mode 100644 index 00000000..01f0a30f --- /dev/null +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvasComponent.kt @@ -0,0 +1,56 @@ +package hep.dataforge.vis.spatial.three + +import hep.dataforge.context.Global +import hep.dataforge.vis.spatial.VisualObject3D +import hep.dataforge.vis.spatial.specifications.Canvas +import kotlinx.html.id +import org.w3c.dom.HTMLElement +import react.RBuilder +import react.RComponent +import react.RProps +import react.RState +import react.dom.div +import kotlin.browser.document +import kotlin.dom.clear + +interface ThreeCanvasProps : RProps { + var obj: VisualObject3D + var canvasId: String + var options: Canvas +} + +class ThreeCanvasComponent : RComponent() { + + private val three: ThreePlugin = Global.plugins.fetch(ThreePlugin) + + override fun componentDidMount() { + val element = document.getElementById(props.canvasId) as? HTMLElement + ?: error("Element with id 'canvas' not found on page") + val output = three.output(element, props.options) + output.render(props.obj) + } + + override fun componentWillUnmount() { + val element = document.getElementById(props.canvasId) as? HTMLElement + ?: error("Element with id 'canvas' not found on page") + element.clear() + } + + override fun RBuilder.render() { + div { + attrs { + id = props.canvasId + } + } + } +} + +fun RBuilder.threeCanvas(object3D: VisualObject3D, id: String = "threeCanvas", options: Canvas.() -> Unit = {}) { + child(ThreeCanvasComponent::class) { + attrs { + this.obj = object3D + this.canvasId = id + this.options = Canvas.invoke(options) + } + } +} \ No newline at end of file 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 c950bdca..913c5583 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 @@ -9,8 +9,8 @@ import hep.dataforge.names.Name import hep.dataforge.names.isEmpty import hep.dataforge.vis.VisualGroup import hep.dataforge.vis.VisualObject -import hep.dataforge.vis.editor.displayObjectTree -import hep.dataforge.vis.editor.displayPropertyEditor +import hep.dataforge.vis.editor.objectTree +import hep.dataforge.vis.editor.visualPropertyEditor import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY @@ -163,26 +163,35 @@ private class GDMLDemoApp : Application { visual is VisualGroup -> visual[name] ?: return else -> return } - editorElement.displayPropertyEditor(name, child) { item -> - //val descriptorMeta = Material3D.descriptor - val properties = item.allProperties() - val bottom = Meta { - VISIBLE_KEY put (item.visible ?: true) - if (item is VisualObject3D) { - MATERIAL_COLOR_KEY put "#ffffff" - MATERIAL_OPACITY_KEY put 1.0 - MATERIAL_WIREFRAME_KEY put false - } + editorElement.visualPropertyEditor(name, child) { + VISIBLE_KEY put true + if (child is VisualObject3D) { + MATERIAL_COLOR_KEY put "#ffffff" + MATERIAL_OPACITY_KEY put 1.0 + MATERIAL_WIREFRAME_KEY put false } - properties.withBottom(bottom) } +// editorElement.displayPropertyEditor(name, child) { item -> +// //val descriptorMeta = Material3D.descriptor +// +// val properties = item.allProperties() +// val bottom = Meta { +// VISIBLE_KEY put (item.visible ?: true) +// if (item is VisualObject3D) { +// MATERIAL_COLOR_KEY put "#ffffff" +// MATERIAL_OPACITY_KEY put 1.0 +// MATERIAL_WIREFRAME_KEY put false +// } +// } +// properties.withBottom(bottom) +// } } // canvas.clickListener = ::selectElement //tree.visualObjectTree(visual, editor::propertyEditor) - treeElement.displayObjectTree(visual) { treeName -> + treeElement.objectTree(visual) { treeName -> selectElement(treeName) canvas.highlight(treeName) } diff --git a/demo/muon-monitor/build.gradle.kts b/demo/muon-monitor/build.gradle.kts index b1f3126b..55f913ce 100644 --- a/demo/muon-monitor/build.gradle.kts +++ b/demo/muon-monitor/build.gradle.kts @@ -7,7 +7,7 @@ plugins { group = "ru.mipt.npm" -val ktor_version = "1.3.2" +val ktorVersion = "1.3.2" kotlin { @@ -34,23 +34,28 @@ kotlin { jvmMain { dependencies { implementation("org.apache.commons:commons-math3:3.6.1") - implementation("io.ktor:ktor-server-cio:$ktor_version") - implementation("io.ktor:ktor-serialization:$ktor_version") + implementation("io.ktor:ktor-server-cio:$ktorVersion") + implementation("io.ktor:ktor-serialization:$ktorVersion") } } jsMain { dependencies { - implementation("io.ktor:ktor-client-js:$ktor_version") - implementation("io.ktor:ktor-client-serialization-js:$ktor_version") + implementation("io.ktor:ktor-client-js:$ktorVersion") + implementation("io.ktor:ktor-client-serialization-js:$ktorVersion") implementation(npm("text-encoding")) implementation(npm("abort-controller")) + implementation(npm("bufferutil")) + implementation(npm("utf-8-validate")) +// implementation(npm("jquery")) +// implementation(npm("popper.js")) +// implementation(npm("react-is")) } } } } application { - mainClassName = "ru.mipt.npm.muon.monitor.server/MMServerKt" + mainClassName = "ru.mipt.npm.muon.monitor.server.MMServerKt" } //configure { 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 19d08623..5a8ef3e6 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 @@ -3,15 +3,13 @@ package ru.mipt.npm.muon.monitor import hep.dataforge.context.Global import hep.dataforge.js.Application import hep.dataforge.js.startApplication -import hep.dataforge.meta.Meta -import hep.dataforge.meta.withBottom import hep.dataforge.names.Name import hep.dataforge.names.isEmpty import hep.dataforge.vis.VisualGroup import hep.dataforge.vis.VisualObject import hep.dataforge.vis.editor.card -import hep.dataforge.vis.editor.displayObjectTree -import hep.dataforge.vis.editor.displayPropertyEditor +import hep.dataforge.vis.editor.objectTree +import hep.dataforge.vis.editor.visualPropertyEditor import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY @@ -21,7 +19,6 @@ import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.displayCanvasControls import hep.dataforge.vis.spatial.three.output -import hep.dataforge.vis.spatial.visible import info.laht.threekt.math.Vector3 import io.ktor.client.HttpClient import io.ktor.client.features.json.JsonFeature @@ -66,7 +63,7 @@ private class MMDemoApp : Application { canvas.camera.layers.set(0) canvas.camera.position.z = -2000.0 canvas.camera.position.y = 500.0 - canvas.camera.lookAt(Vector3(0,0,0)) + canvas.camera.lookAt(Vector3(0, 0, 0)) settingsElement.displayCanvasControls(canvas) { card("Events") { button { @@ -94,26 +91,34 @@ private class MMDemoApp : Application { visual is VisualGroup -> visual[name] ?: return else -> return } - editorElement.displayPropertyEditor(name, child) { item -> - //val descriptorMeta = Material3D.descriptor - - val properties = item.allProperties() - val bottom = Meta { - VISIBLE_KEY put (item.visible ?: true) - if (item is VisualObject3D) { - MATERIAL_COLOR_KEY put "#ffffff" - MATERIAL_OPACITY_KEY put 1.0 - MATERIAL_WIREFRAME_KEY put false - } + editorElement.visualPropertyEditor(name, child) { + VISIBLE_KEY put true + if (child is VisualObject3D) { + MATERIAL_COLOR_KEY put "#ffffff" + MATERIAL_OPACITY_KEY put 1.0 + MATERIAL_WIREFRAME_KEY put false } - properties.withBottom(bottom) } +// editorElement.displayPropertyEditor(name, child) { item -> +// //val descriptorMeta = Material3D.descriptor +// +// val properties = item.allProperties() +// val bottom = Meta { +// VISIBLE_KEY put (item.visible ?: true) +// if (item is VisualObject3D) { +// MATERIAL_COLOR_KEY put "#ffffff" +// MATERIAL_OPACITY_KEY put 1.0 +// MATERIAL_WIREFRAME_KEY put false +// } +// } +// properties.withBottom(bottom) +// } } // canvas.clickListener = ::selectElement //tree.visualObjectTree(visual, editor::propertyEditor) - treeElement.displayObjectTree(visual) { name -> + treeElement.objectTree(visual) { name -> selectElement(name) canvas.highlight(name) } diff --git a/demo/spatial-showcase/build.gradle.kts b/demo/spatial-showcase/build.gradle.kts index fef9057c..064f207d 100644 --- a/demo/spatial-showcase/build.gradle.kts +++ b/demo/spatial-showcase/build.gradle.kts @@ -16,14 +16,6 @@ kotlin { withJava() } - js { - browser { - webpackTask { - sourceMaps = false - } - } - } - sourceSets { commonMain { dependencies { diff --git a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt index 984a3bcf..c773f7f7 100644 --- a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt +++ b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt @@ -39,7 +39,6 @@ private class ThreeDemoApp : Application { } - override fun dispose() = emptyMap()//mapOf("lines" put presenter.dispose()) } fun main() { diff --git a/playground/build.gradle.kts b/playground/build.gradle.kts new file mode 100644 index 00000000..3ad5ff15 --- /dev/null +++ b/playground/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + kotlin("multiplatform") +} + +repositories{ + jcenter() + maven("https://kotlin.bintray.com/kotlinx") + maven("https://dl.bintray.com/kotlin/kotlin-eap") + maven("https://dl.bintray.com/mipt-npm/dataforge") + maven("https://dl.bintray.com/mipt-npm/scientifik") + maven("https://dl.bintray.com/mipt-npm/dev") +} + +kotlin { + js { + browser {} + } + + sourceSets { + commonMain { + dependencies { + api(project(":dataforge-vis-spatial")) + api(project(":dataforge-vis-spatial-gdml")) + } + } + } +} diff --git a/playground/src/jsMain/kotlin/PlayGroundApp.kt b/playground/src/jsMain/kotlin/PlayGroundApp.kt new file mode 100644 index 00000000..aa0b03d8 --- /dev/null +++ b/playground/src/jsMain/kotlin/PlayGroundApp.kt @@ -0,0 +1,56 @@ +import hep.dataforge.context.Global +import hep.dataforge.js.Application +import hep.dataforge.js.startApplication +import hep.dataforge.names.Name +import hep.dataforge.vis.editor.objectTree +import hep.dataforge.vis.editor.visualPropertyEditor +import hep.dataforge.vis.spatial.Point3D +import hep.dataforge.vis.spatial.VisualGroup3D +import hep.dataforge.vis.spatial.box +import hep.dataforge.vis.spatial.group +import hep.dataforge.vis.spatial.three.ThreePlugin +import hep.dataforge.vis.spatial.three.threeCanvas +import org.w3c.dom.HTMLElement +import react.dom.div +import react.dom.render +import kotlin.browser.document + +private class PlayGroundApp : Application { + + private val three = Global.plugins.fetch(ThreePlugin) + + override fun start(state: Map) { + + val element = + document.getElementById("app") as? HTMLElement ?: error("Element with id 'canvas' not found on page") + + val obj = VisualGroup3D().apply { + box(100, 100, 100) + group { + position = Point3D(120, 0, 0) + box(100, 100, 100) + } + } + + render(element) { + div("row") { + div("col-3") { + objectTree(obj) + } + div("col-6") { + threeCanvas(obj) + } + div("col-3") { + visualPropertyEditor(Name.EMPTY, obj) + } + } + } + + + } + +} + +fun main() { + startApplication(::PlayGroundApp) +} \ No newline at end of file diff --git a/playground/src/jsMain/resources/css/common.css b/playground/src/jsMain/resources/css/common.css new file mode 100644 index 00000000..4d1bac9d --- /dev/null +++ b/playground/src/jsMain/resources/css/common.css @@ -0,0 +1,40 @@ +/* Remove default bullets */ +ul, .objTree-subtree { + list-style-type: none; +} + +/* Style the caret/arrow */ +.objTree-caret { + cursor: pointer; + user-select: none; /* Prevent text selection */ +} + +/* Create the caret/arrow with a unicode, and style it */ +.objTree-caret::before { + content: "\25B6"; + color: black; + display: inline-block; + margin-right: 6px; +} + +/* Rotate the caret/arrow icon when clicked on (using JavaScript) */ +.objTree-caret-down::before { + transform: rotate(90deg); +} + +ul, .tree { + list-style-type: none; +} + +i, .tree-caret{ + display: inline-block; + margin-right: 6px; +} + +.rotate { + transform: rotate(90deg); +} + +.tree-label-inactive { + color: gray; +} diff --git a/playground/src/jsMain/resources/index.html b/playground/src/jsMain/resources/index.html new file mode 100644 index 00000000..c022a175 --- /dev/null +++ b/playground/src/jsMain/resources/index.html @@ -0,0 +1,16 @@ + + + + + Playground + + + + + +
+

Playground

+
+
+ + \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 891155fd..b6673c37 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,7 +30,8 @@ include( ":dataforge-vis-spatial-gdml", ":demo:spatial-showcase", ":demo:gdml", - ":demo:muon-monitor" + ":demo:muon-monitor", + ":playground" ) //if(file("../dataforge-core").exists()) {