forked from kscience/visionforge
Migration to 1.3.70
This commit is contained in:
parent
150fdb2426
commit
d4dcd32b73
@ -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")
|
||||
}
|
||||
|
@ -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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package hep.dataforge.js
|
||||
|
||||
import react.RComponent
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun <T> RComponent<*, *>.initState(init: () -> T): ReadWriteProperty<RComponent<*, *>, T> =
|
||||
object : ReadWriteProperty<RComponent<*, *>, 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)
|
||||
}
|
||||
}
|
@ -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<ConfigEditorProps, TreeState>() {
|
||||
|
||||
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<NameToken> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -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<MetaViewerProps, TreeState>() {
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<ObjectTreeProps, TreeState>() {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -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<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
|
||||
div("card w-100") {
|
||||
@ -13,6 +17,14 @@ inline fun TagConsumer<HTMLElement>.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<HTMLElement>.accordion(id: String, elements: Map<String, DIV.() -> Unit>) {
|
||||
div("container-fluid") {
|
||||
div("accordion") {
|
||||
|
@ -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<HTMLElement>.subTree(
|
||||
name: Name,
|
||||
obj: VisualObject,
|
||||
|
@ -1,38 +1,88 @@
|
||||
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<dynamic>(toJson().toString())
|
||||
////FIXME something rotten in JS-Meta converter
|
||||
//fun Meta.toDynamic() = JSON.parse<dynamic>(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()) {
|
||||
default: MetaBuilder.() -> Unit = {}
|
||||
): ReactElement = card("Properties") {
|
||||
if (!path.isEmpty()) {
|
||||
nav {
|
||||
attrs {
|
||||
attributes["aria-label"] = "breadcrumb"
|
||||
}
|
||||
ol("breadcrumb") {
|
||||
name.tokens.forEach { token ->
|
||||
path.tokens.forEach { token ->
|
||||
li("breadcrumb-item") {
|
||||
+token.toString()
|
||||
}
|
||||
@ -40,34 +90,13 @@ fun Element.displayPropertyEditor(
|
||||
}
|
||||
}
|
||||
}
|
||||
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()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
configEditor(item.config, item.descriptor, Meta(default))
|
||||
}
|
||||
|
||||
fun Element.visualPropertyEditor(
|
||||
path: Name,
|
||||
item: VisualObject,
|
||||
default: MetaBuilder.() -> Unit = {}
|
||||
) = render(this) {
|
||||
visualPropertyEditor(path, item, default)
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -213,3 +213,7 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
||||
|
||||
fun ThreePlugin.output(element: HTMLElement, spec: Canvas = Canvas.empty()): ThreeCanvas =
|
||||
ThreeCanvas(element, this, spec)
|
||||
|
||||
fun ThreePlugin.render(element: HTMLElement, obj: VisualObject3D, spec: Canvas = Canvas.empty()): Unit =
|
||||
output(element, spec).render(obj)
|
||||
|
||||
|
@ -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<ThreeCanvasProps, RState>() {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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) {
|
||||
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)
|
||||
}
|
||||
|
@ -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<JavaFXOptions> {
|
||||
|
@ -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) {
|
||||
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)
|
||||
}
|
||||
|
@ -16,14 +16,6 @@ kotlin {
|
||||
withJava()
|
||||
}
|
||||
|
||||
js {
|
||||
browser {
|
||||
webpackTask {
|
||||
sourceMaps = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
|
@ -39,7 +39,6 @@ private class ThreeDemoApp : Application {
|
||||
|
||||
}
|
||||
|
||||
override fun dispose() = emptyMap<String, Any>()//mapOf("lines" put presenter.dispose())
|
||||
}
|
||||
|
||||
fun main() {
|
||||
|
27
playground/build.gradle.kts
Normal file
27
playground/build.gradle.kts
Normal file
@ -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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
56
playground/src/jsMain/kotlin/PlayGroundApp.kt
Normal file
56
playground/src/jsMain/kotlin/PlayGroundApp.kt
Normal file
@ -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<String, Any>) {
|
||||
|
||||
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)
|
||||
}
|
40
playground/src/jsMain/resources/css/common.css
Normal file
40
playground/src/jsMain/resources/css/common.css
Normal file
@ -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;
|
||||
}
|
16
playground/src/jsMain/resources/index.html
Normal file
16
playground/src/jsMain/resources/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Playground</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/common.css">
|
||||
<script type="text/javascript" src="playground.js"></script>
|
||||
</head>
|
||||
<body class="testApp">
|
||||
<div class="container">
|
||||
<h1>Playground</h1>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
@ -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()) {
|
||||
|
Loading…
Reference in New Issue
Block a user