Design update for gdml demo
This commit is contained in:
parent
ca2b267fc4
commit
f484d5d1ff
@ -31,21 +31,13 @@ kotlin {
|
||||
jsMain {
|
||||
dependencies {
|
||||
api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
|
||||
|
||||
api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72")
|
||||
api("org.jetbrains:kotlin-react-dom:16.13.1-pre.104-kotlin-1.3.72")
|
||||
api("org.jetbrains.kotlinx:kotlinx-html:0.6.12")
|
||||
|
||||
api("org.jetbrains:kotlin-extensions:1.0.1-pre.104-kotlin-1.3.72")
|
||||
api("org.jetbrains:kotlin-css-js:1.0.0-pre.94-kotlin-1.3.70")
|
||||
//api("org.jetbrains:kotlin-extensions:1.0.1-pre.105-kotlin-1.3.72")
|
||||
//api("org.jetbrains:kotlin-css-js:1.0.0-pre.105-kotlin-1.3.72")
|
||||
api("org.jetbrains:kotlin-styled:1.0.0-pre.104-kotlin-1.3.72")
|
||||
|
||||
api(npm("core-js", "2.6.5"))
|
||||
|
||||
api(npm("react", "16.13.1"))
|
||||
api(npm("react-dom", "16.13.1"))
|
||||
|
||||
api(npm("react-is", "16.13.0"))
|
||||
api(npm("inline-style-prefixer", "5.1.0"))
|
||||
api(npm("styled-components", "4.3.2"))
|
||||
//api(project(":ringui-wrapper"))
|
||||
|
@ -2,9 +2,12 @@ package hep.dataforge.vis
|
||||
|
||||
import hep.dataforge.meta.Laminate
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.values.ValueType
|
||||
import hep.dataforge.values.asValue
|
||||
|
||||
/**
|
||||
* Return nearest selectable parent [Name]
|
||||
@ -32,3 +35,11 @@ fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>?{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified E : Enum<E>> NodeDescriptor.enum(key: Name, default: E?) = value(key) {
|
||||
type(ValueType.STRING)
|
||||
default?.let {
|
||||
default(default)
|
||||
}
|
||||
allowedValues = enumValues<E>().map{it.asValue()}
|
||||
}
|
@ -69,13 +69,13 @@ class Visual3D(meta: Meta) : AbstractPlugin(meta) {
|
||||
|
||||
internal fun VisualObject3D.update(meta: Meta) {
|
||||
fun Meta.toVector(default: Float = 0f) = Point3D(
|
||||
this[VisualObject3D.x].float ?: default,
|
||||
this[VisualObject3D.y].float ?: default,
|
||||
this[VisualObject3D.z].float ?: default
|
||||
this[VisualObject3D.X_KEY].float ?: default,
|
||||
this[VisualObject3D.Y_KEY].float ?: default,
|
||||
this[VisualObject3D.Z_KEY].float ?: default
|
||||
)
|
||||
|
||||
meta[VisualObject3D.position].node?.toVector()?.let { position = it }
|
||||
meta[VisualObject3D.rotation].node?.toVector()?.let { rotation = it }
|
||||
meta[VisualObject3D.scale].node?.toVector(1f)?.let { scale = it }
|
||||
meta[VisualObject3D.POSITION_KEY].node?.toVector()?.let { position = it }
|
||||
meta[VisualObject3D.ROTATION].node?.toVector()?.let { rotation = it }
|
||||
meta[VisualObject3D.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
|
||||
meta["properties"].node?.let { configure(it) }
|
||||
}
|
@ -10,6 +10,7 @@ import hep.dataforge.output.Renderer
|
||||
import hep.dataforge.values.ValueType
|
||||
import hep.dataforge.values.asValue
|
||||
import hep.dataforge.vis.VisualObject
|
||||
import hep.dataforge.vis.enum
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
|
||||
@ -37,29 +38,29 @@ interface VisualObject3D : VisualObject {
|
||||
|
||||
val GEOMETRY_KEY = "geometry".asName()
|
||||
|
||||
val x = "x".asName()
|
||||
val y = "y".asName()
|
||||
val z = "z".asName()
|
||||
val X_KEY = "x".asName()
|
||||
val Y_KEY = "y".asName()
|
||||
val Z_KEY = "z".asName()
|
||||
|
||||
val position = "pos".asName()
|
||||
val POSITION_KEY = "pos".asName()
|
||||
|
||||
val xPos = position + x
|
||||
val yPos = position + y
|
||||
val zPos = position + z
|
||||
val X_POSITION_KEY = POSITION_KEY + X_KEY
|
||||
val Y_POSITION_KEY = POSITION_KEY + Y_KEY
|
||||
val Z_POSITION_KEY = POSITION_KEY + Z_KEY
|
||||
|
||||
val rotation = "rotation".asName()
|
||||
val ROTATION = "rotation".asName()
|
||||
|
||||
val xRotation = rotation + x
|
||||
val yRotation = rotation + y
|
||||
val zRotation = rotation + z
|
||||
val X_ROTATION_KEY = ROTATION + X_KEY
|
||||
val Y_ROTATION_KEY = ROTATION + Y_KEY
|
||||
val Z_ROTATION_KEY = ROTATION + Z_KEY
|
||||
|
||||
val rotationOrder = rotation + "order"
|
||||
val ROTATION_ORDER_KEY = ROTATION + "order"
|
||||
|
||||
val scale = "scale".asName()
|
||||
val SCALE_KEY = "scale".asName()
|
||||
|
||||
val xScale = scale + x
|
||||
val yScale = scale + y
|
||||
val zScale = scale + z
|
||||
val X_SCALE_KEY = SCALE_KEY + X_KEY
|
||||
val Y_SCALE_KEY = SCALE_KEY + Y_KEY
|
||||
val Z_SCALE_KEY = SCALE_KEY + Z_KEY
|
||||
|
||||
val descriptor by lazy {
|
||||
NodeDescriptor {
|
||||
@ -75,6 +76,8 @@ interface VisualObject3D : VisualObject {
|
||||
}
|
||||
|
||||
item(Material3D.MATERIAL_KEY.toString(), Material3D.descriptor)
|
||||
|
||||
enum<RotationOrder>(ROTATION_ORDER_KEY,default = RotationOrder.XYZ)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,8 +110,8 @@ enum class RotationOrder {
|
||||
* Rotation order
|
||||
*/
|
||||
var VisualObject3D.rotationOrder: RotationOrder
|
||||
get() = getProperty(VisualObject3D.rotationOrder).enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||
set(value) = setProperty(VisualObject3D.rotationOrder, value.name.asValue())
|
||||
get() = getProperty(VisualObject3D.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||
set(value) = setProperty(VisualObject3D.ROTATION_ORDER_KEY, value.name.asValue())
|
||||
|
||||
|
||||
/**
|
||||
@ -141,21 +144,21 @@ var VisualObject3D.x: Number
|
||||
get() = position?.x ?: 0f
|
||||
set(value) {
|
||||
position().x = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.xPos)
|
||||
propertyInvalidated(VisualObject3D.X_POSITION_KEY)
|
||||
}
|
||||
|
||||
var VisualObject3D.y: Number
|
||||
get() = position?.y ?: 0f
|
||||
set(value) {
|
||||
position().y = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.yPos)
|
||||
propertyInvalidated(VisualObject3D.Y_POSITION_KEY)
|
||||
}
|
||||
|
||||
var VisualObject3D.z: Number
|
||||
get() = position?.z ?: 0f
|
||||
set(value) {
|
||||
position().z = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.zPos)
|
||||
propertyInvalidated(VisualObject3D.Z_POSITION_KEY)
|
||||
}
|
||||
|
||||
private fun VisualObject3D.rotation(): Point3D =
|
||||
@ -165,21 +168,21 @@ var VisualObject3D.rotationX: Number
|
||||
get() = rotation?.x ?: 0f
|
||||
set(value) {
|
||||
rotation().x = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.xRotation)
|
||||
propertyInvalidated(VisualObject3D.X_ROTATION_KEY)
|
||||
}
|
||||
|
||||
var VisualObject3D.rotationY: Number
|
||||
get() = rotation?.y ?: 0f
|
||||
set(value) {
|
||||
rotation().y = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.yRotation)
|
||||
propertyInvalidated(VisualObject3D.Y_ROTATION_KEY)
|
||||
}
|
||||
|
||||
var VisualObject3D.rotationZ: Number
|
||||
get() = rotation?.z ?: 0f
|
||||
set(value) {
|
||||
rotation().z = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.zRotation)
|
||||
propertyInvalidated(VisualObject3D.Z_ROTATION_KEY)
|
||||
}
|
||||
|
||||
private fun VisualObject3D.scale(): Point3D =
|
||||
@ -189,19 +192,19 @@ var VisualObject3D.scaleX: Number
|
||||
get() = scale?.x ?: 1f
|
||||
set(value) {
|
||||
scale().x = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.xScale)
|
||||
propertyInvalidated(VisualObject3D.X_SCALE_KEY)
|
||||
}
|
||||
|
||||
var VisualObject3D.scaleY: Number
|
||||
get() = scale?.y ?: 1f
|
||||
set(value) {
|
||||
scale().y = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.yScale)
|
||||
propertyInvalidated(VisualObject3D.Y_SCALE_KEY)
|
||||
}
|
||||
|
||||
var VisualObject3D.scaleZ: Number
|
||||
get() = scale?.z ?: 1f
|
||||
set(value) {
|
||||
scale().z = value.toDouble()
|
||||
propertyInvalidated(VisualObject3D.zScale)
|
||||
propertyInvalidated(VisualObject3D.Z_SCALE_KEY)
|
||||
}
|
@ -21,8 +21,8 @@ operator fun Point2D.component1() = x
|
||||
operator fun Point2D.component2() = y
|
||||
|
||||
fun Point2D.toMeta() = Meta {
|
||||
VisualObject3D.x put x
|
||||
VisualObject3D.y put y
|
||||
VisualObject3D.X_KEY put x
|
||||
VisualObject3D.Y_KEY put y
|
||||
}
|
||||
|
||||
fun Meta.point2D() = Point2D(this["x"].number ?: 0, this["y"].number ?: 0)
|
||||
@ -42,7 +42,7 @@ operator fun Point3D.component3() = z
|
||||
fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0)
|
||||
|
||||
fun Point3D.toMeta() = Meta {
|
||||
VisualObject3D.x put x
|
||||
VisualObject3D.y put y
|
||||
VisualObject3D.z put z
|
||||
VisualObject3D.X_KEY put x
|
||||
VisualObject3D.Y_KEY put y
|
||||
VisualObject3D.Z_KEY put z
|
||||
}
|
@ -7,6 +7,7 @@ import hep.dataforge.vis.useStyle
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class PropertyTest {
|
||||
@Test
|
||||
fun testInheritedProperty() {
|
||||
|
@ -60,9 +60,9 @@ fun Object3D.updateProperty(source: VisualObject, propertyName: Name) {
|
||||
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
|
||||
this.material = getMaterial(source)
|
||||
} else if (
|
||||
propertyName.startsWith(VisualObject3D.position)
|
||||
|| propertyName.startsWith(VisualObject3D.rotation)
|
||||
|| propertyName.startsWith(VisualObject3D.scale)
|
||||
propertyName.startsWith(VisualObject3D.POSITION_KEY)
|
||||
|| propertyName.startsWith(VisualObject3D.ROTATION)
|
||||
|| propertyName.startsWith(VisualObject3D.SCALE_KEY)
|
||||
) {
|
||||
//update position of mesh using this object
|
||||
updatePosition(source)
|
||||
|
@ -57,9 +57,9 @@ class ThreePlugin : AbstractPlugin() {
|
||||
|
||||
obj.onPropertyChange(this) { name, _, _ ->
|
||||
if (
|
||||
name.startsWith(VisualObject3D.position) ||
|
||||
name.startsWith(VisualObject3D.rotation) ||
|
||||
name.startsWith(VisualObject3D.scale)
|
||||
name.startsWith(VisualObject3D.POSITION_KEY) ||
|
||||
name.startsWith(VisualObject3D.ROTATION) ||
|
||||
name.startsWith(VisualObject3D.SCALE_KEY)
|
||||
) {
|
||||
//update position of mesh using this object
|
||||
updatePosition(obj)
|
||||
|
@ -19,12 +19,8 @@ import javafx.scene.transform.Rotate
|
||||
import org.fxyz3d.shapes.composites.PolyLine3D
|
||||
import org.fxyz3d.shapes.primitives.CuboidMesh
|
||||
import org.fxyz3d.shapes.primitives.SpheroidMesh
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
import kotlin.collections.find
|
||||
import kotlin.collections.map
|
||||
import kotlin.collections.mapNotNull
|
||||
import kotlin.collections.set
|
||||
import kotlin.math.PI
|
||||
import kotlin.reflect.KClass
|
||||
@ -91,23 +87,23 @@ class FX3DPlugin : AbstractPlugin() {
|
||||
}
|
||||
}
|
||||
}.apply {
|
||||
translateXProperty().bind(binding[VisualObject3D.xPos].float(obj.x.toFloat()))
|
||||
translateYProperty().bind(binding[VisualObject3D.yPos].float(obj.y.toFloat()))
|
||||
translateZProperty().bind(binding[VisualObject3D.zPos].float(obj.z.toFloat()))
|
||||
scaleXProperty().bind(binding[VisualObject3D.xScale].float(obj.scaleX.toFloat()))
|
||||
scaleYProperty().bind(binding[VisualObject3D.yScale].float(obj.scaleY.toFloat()))
|
||||
scaleZProperty().bind(binding[VisualObject3D.zScale].float(obj.scaleZ.toFloat()))
|
||||
translateXProperty().bind(binding[VisualObject3D.X_POSITION_KEY].float(obj.x.toFloat()))
|
||||
translateYProperty().bind(binding[VisualObject3D.Y_POSITION_KEY].float(obj.y.toFloat()))
|
||||
translateZProperty().bind(binding[VisualObject3D.Z_POSITION_KEY].float(obj.z.toFloat()))
|
||||
scaleXProperty().bind(binding[VisualObject3D.X_SCALE_KEY].float(obj.scaleX.toFloat()))
|
||||
scaleYProperty().bind(binding[VisualObject3D.Y_SCALE_KEY].float(obj.scaleY.toFloat()))
|
||||
scaleZProperty().bind(binding[VisualObject3D.Z_SCALE_KEY].float(obj.scaleZ.toFloat()))
|
||||
|
||||
val rotateX = Rotate(0.0, Rotate.X_AXIS).apply {
|
||||
angleProperty().bind(binding[VisualObject3D.xRotation].float(obj.rotationX.toFloat()).multiply(180.0 / PI))
|
||||
angleProperty().bind(binding[VisualObject3D.X_ROTATION_KEY].float(obj.rotationX.toFloat()).multiply(180.0 / PI))
|
||||
}
|
||||
|
||||
val rotateY = Rotate(0.0, Rotate.Y_AXIS).apply {
|
||||
angleProperty().bind(binding[VisualObject3D.yRotation].float(obj.rotationY.toFloat()).multiply(180.0 / PI))
|
||||
angleProperty().bind(binding[VisualObject3D.Y_ROTATION_KEY].float(obj.rotationY.toFloat()).multiply(180.0 / PI))
|
||||
}
|
||||
|
||||
val rotateZ = Rotate(0.0, Rotate.Z_AXIS).apply {
|
||||
angleProperty().bind(binding[VisualObject3D.zRotation].float(obj.rotationZ.toFloat()).multiply(180.0 / PI))
|
||||
angleProperty().bind(binding[VisualObject3D.Z_ROTATION_KEY].float(obj.rotationZ.toFloat()).multiply(180.0 / PI))
|
||||
}
|
||||
|
||||
when (obj.rotationOrder) {
|
||||
|
@ -1,4 +1,6 @@
|
||||
import scientifik.*
|
||||
import scientifik.DependencyConfiguration
|
||||
import scientifik.FXModule
|
||||
import scientifik.useFx
|
||||
|
||||
plugins {
|
||||
id("scientifik.mpp")
|
||||
@ -16,11 +18,6 @@ kotlin {
|
||||
|
||||
js {
|
||||
useCommonJs()
|
||||
browser {
|
||||
webpackTask {
|
||||
//sourceMaps = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
@ -7,6 +7,7 @@ import hep.dataforge.vis.VisualGroup
|
||||
import hep.dataforge.vis.VisualObject
|
||||
import hep.dataforge.vis.bootstrap.*
|
||||
import hep.dataforge.vis.react.component
|
||||
import hep.dataforge.vis.react.configEditor
|
||||
import hep.dataforge.vis.react.flexColumn
|
||||
import hep.dataforge.vis.react.state
|
||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||
@ -80,7 +81,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
|
||||
classes.add("p-1")
|
||||
overflow = Overflow.auto
|
||||
}
|
||||
gridColumn(3) {
|
||||
gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-2 order-xl-1") {
|
||||
card("Load data") {
|
||||
fileDrop("(drag file here)") { files ->
|
||||
val file = files?.get(0)
|
||||
@ -104,7 +105,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
|
||||
}
|
||||
}
|
||||
|
||||
gridColumn(6) {
|
||||
gridColumn(6, maxSize= GridMaxSize.XL, classes = "order-1 order-xl-2") {
|
||||
//canvas
|
||||
(visual as? VisualObject3D)?.let { visual3D ->
|
||||
child(ThreeCanvasComponent::class) {
|
||||
@ -120,7 +121,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
|
||||
}
|
||||
}
|
||||
}
|
||||
gridColumn(3) {
|
||||
gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-3") {
|
||||
container {
|
||||
//settings
|
||||
canvas?.let {
|
||||
|
@ -7,8 +7,10 @@ import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||
import hep.dataforge.vis.spatial.gdml.GDMLTransformer
|
||||
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||
import kotlinx.css.*
|
||||
import react.child
|
||||
import react.dom.render
|
||||
import styled.injectGlobal
|
||||
import kotlin.browser.document
|
||||
|
||||
|
||||
@ -42,6 +44,15 @@ private class GDMLDemoApp : Application {
|
||||
|
||||
override fun start(state: Map<String, Any>) {
|
||||
|
||||
injectGlobal {
|
||||
body {
|
||||
height = 100.pct
|
||||
width = 100.pct
|
||||
margin(0.px)
|
||||
padding(0.px)
|
||||
}
|
||||
}
|
||||
|
||||
val context = Global.context("demo") {}
|
||||
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
|
||||
|
||||
|
@ -6,9 +6,9 @@ import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.vis.VisualObject
|
||||
import hep.dataforge.vis.bootstrap.card
|
||||
import hep.dataforge.vis.bootstrap.configEditor
|
||||
import hep.dataforge.vis.bootstrap.objectTree
|
||||
import hep.dataforge.vis.react.component
|
||||
import hep.dataforge.vis.react.configEditor
|
||||
import hep.dataforge.vis.react.state
|
||||
import hep.dataforge.vis.spatial.specifications.Camera
|
||||
import hep.dataforge.vis.spatial.specifications.Canvas
|
||||
|
@ -11,6 +11,5 @@ kotlin {
|
||||
}
|
||||
|
||||
dependencies{
|
||||
api(project(":dataforge-vis-common"))
|
||||
api(project(":ui:react"))
|
||||
}
|
@ -5,6 +5,7 @@ import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.vis.VisualObject
|
||||
import hep.dataforge.vis.react.configEditor
|
||||
import org.w3c.dom.Element
|
||||
import react.RBuilder
|
||||
import react.dom.li
|
||||
|
@ -11,12 +11,11 @@ kotlin {
|
||||
}
|
||||
|
||||
dependencies{
|
||||
api(project(":dataforge-vis-common"))
|
||||
api(project(":ui:react"))
|
||||
|
||||
api("subroh0508.net.kotlinmaterialui:core:0.3.16")
|
||||
api("subroh0508.net.kotlinmaterialui:lab:0.3.16")
|
||||
api(npm("@material-ui/core","4.9.13"))
|
||||
api(npm("@material-ui/lab","4.0.0-alpha.52"))
|
||||
api("subroh0508.net.kotlinmaterialui:core:0.4.0")
|
||||
api("subroh0508.net.kotlinmaterialui:lab:0.4.0")
|
||||
api(npm("@material-ui/core","4.9.14"))
|
||||
api(npm("@material-ui/lab","4.0.0-alpha.51"))
|
||||
//api(npm("@material-ui/icons","4.9.1"))
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
package hep.dataforge.vis.material
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.descriptors.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.vis.react.component
|
||||
import hep.dataforge.vis.react.state
|
||||
import kotlinx.css.Display
|
||||
import kotlinx.css.display
|
||||
import kotlinx.css.flexGrow
|
||||
import kotlinx.css.flexShrink
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import materialui.components.button.button
|
||||
import materialui.components.grid.enums.GridAlignItems
|
||||
import materialui.components.grid.enums.GridJustify
|
||||
import materialui.components.grid.grid
|
||||
import materialui.components.typography.typographyH6
|
||||
import materialui.lab.components.treeItem.treeItem
|
||||
import materialui.lab.components.treeView.treeView
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.events.Event
|
||||
import react.*
|
||||
import react.dom.render
|
||||
import react.dom.span
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
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?
|
||||
}
|
||||
|
||||
private fun RBuilder.configEditorItem(
|
||||
root: Config,
|
||||
name: Name,
|
||||
descriptor: NodeDescriptor?,
|
||||
default: Meta?
|
||||
) {
|
||||
val item = root[name]
|
||||
val descriptorItem: ItemDescriptor? = descriptor?.get(name)
|
||||
val defaultItem = default?.get(name)
|
||||
val actualItem: MetaItem<Meta>? = item ?: defaultItem ?: descriptorItem?.defaultItem()
|
||||
|
||||
val token = name.last()?.toString() ?: "Properties"
|
||||
|
||||
val removeClick: (Event) -> Unit = {
|
||||
root.remove(name)
|
||||
}
|
||||
|
||||
treeItem {
|
||||
attrs {
|
||||
nodeId = name.toString()
|
||||
label {
|
||||
row {
|
||||
attrs {
|
||||
alignItems = GridAlignItems.stretch
|
||||
justify = GridJustify.spaceBetween
|
||||
spacing(1)
|
||||
}
|
||||
grid {
|
||||
typographyH6 {
|
||||
+token
|
||||
}
|
||||
}
|
||||
if (actualItem is MetaItem.ValueItem) {
|
||||
styledDiv {
|
||||
css {
|
||||
display = Display.flex
|
||||
flexGrow = 1.0
|
||||
}
|
||||
valueChooser(root, name, actualItem.value, descriptorItem as? ValueDescriptor)
|
||||
}
|
||||
}
|
||||
if (!name.isEmpty()) {
|
||||
styledDiv {
|
||||
css {
|
||||
display = Display.flex
|
||||
flexShrink = 1.0
|
||||
}
|
||||
button {
|
||||
+"\u00D7"
|
||||
attrs {
|
||||
if (item == null) {
|
||||
disabled = true
|
||||
} else {
|
||||
onClickFunction = removeClick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (actualItem is MetaItem.NodeItem) {
|
||||
val keys = buildSet<NameToken> {
|
||||
(descriptorItem as? NodeDescriptor)?.items?.keys?.forEach {
|
||||
add(NameToken(it))
|
||||
}
|
||||
item?.node?.items?.keys?.let { addAll(it) }
|
||||
defaultItem?.node?.items?.keys?.let { addAll(it) }
|
||||
}
|
||||
|
||||
keys.forEach { token ->
|
||||
configEditorItem(root, name + token, descriptor, default)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ConfigEditor: FunctionalComponent<ConfigEditorProps> = component { props ->
|
||||
var kostyl by state { false }
|
||||
|
||||
fun update() {
|
||||
kostyl = !kostyl
|
||||
}
|
||||
|
||||
useEffectWithCleanup(listOf(props.root)) {
|
||||
props.root.onChange(this) { name, _, _ ->
|
||||
if (name == props.name) {
|
||||
update()
|
||||
}
|
||||
}
|
||||
return@useEffectWithCleanup { props.root.removeListener(this) }
|
||||
}
|
||||
|
||||
treeView {
|
||||
attrs {
|
||||
defaultCollapseIcon {
|
||||
span {
|
||||
+"-"
|
||||
}
|
||||
//child(ExpandMoreIcon::class) {}
|
||||
}//{<ExpandMoreIcon />}
|
||||
defaultExpandIcon {
|
||||
span {
|
||||
+"+"
|
||||
}
|
||||
//child(ChevronRightIcon::class) {}
|
||||
}//{<ChevronRightIcon />}
|
||||
set("disableSelection", true)
|
||||
}
|
||||
configEditorItem(props.root, props.name, props.descriptor, props.default)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun RBuilder.configEditor(
|
||||
config: Config,
|
||||
name: Name = Name.EMPTY,
|
||||
descriptor: NodeDescriptor? = null,
|
||||
default: Meta? = null
|
||||
) {
|
||||
child(ConfigEditor) {
|
||||
attrs {
|
||||
this.root = config
|
||||
this.name = name
|
||||
this.descriptor = descriptor
|
||||
this.default = default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Element.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null) {
|
||||
render(this) {
|
||||
configEditor(config, Name.EMPTY, descriptor, default)
|
||||
}
|
||||
}
|
||||
|
||||
fun RBuilder.configEditor(obj: Configurable, descriptor: NodeDescriptor? = obj.descriptor, default: Meta? = null) {
|
||||
configEditor(obj.config, Name.EMPTY, descriptor ?: obj.descriptor, default)
|
||||
}
|
@ -8,7 +8,9 @@ import hep.dataforge.vis.VisualObject
|
||||
import hep.dataforge.vis.isEmpty
|
||||
import hep.dataforge.vis.react.component
|
||||
import hep.dataforge.vis.react.state
|
||||
import kotlinx.html.UL
|
||||
import materialui.lab.components.treeItem.treeItem
|
||||
import materialui.lab.components.treeView.SingleSelectTreeViewElementBuilder
|
||||
import materialui.lab.components.treeView.treeView
|
||||
import react.FunctionalComponent
|
||||
import react.RBuilder
|
||||
@ -49,11 +51,11 @@ private fun RBuilder.treeBranch(name: Name, obj: VisualObject): Unit {
|
||||
val ObjectTree: FunctionalComponent<ObjectTreeProps> = component { props ->
|
||||
var selected: String? by state { props.selected.toString() }
|
||||
treeView {
|
||||
this as SingleSelectTreeViewElementBuilder<UL>
|
||||
attrs {
|
||||
this.selected = selected
|
||||
this.onNodeSelect = { _, selectedItem ->
|
||||
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||
selected = (selectedItem as? String)
|
||||
this.onNodeSelect{ _, selectedItem ->
|
||||
selected = selectedItem
|
||||
val itemName = selected?.toName()
|
||||
props.clickCallback(itemName)
|
||||
Unit
|
||||
|
@ -1,114 +0,0 @@
|
||||
package hep.dataforge.vis.material
|
||||
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.number
|
||||
import hep.dataforge.meta.setValue
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.values.*
|
||||
import hep.dataforge.vis.widgetType
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import kotlinx.html.js.onKeyDownFunction
|
||||
import materialui.components.input.input
|
||||
import materialui.components.select.select
|
||||
import materialui.components.slider.slider
|
||||
import materialui.components.switches.switch
|
||||
import materialui.components.textfield.textField
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.HTMLSelectElement
|
||||
import org.w3c.dom.events.Event
|
||||
import org.w3c.dom.events.KeyboardEvent
|
||||
import react.RBuilder
|
||||
import react.dom.option
|
||||
|
||||
internal fun RBuilder.valueChooser(root: Config, name: Name, value: Value, descriptor: ValueDescriptor?) {
|
||||
val onValueChange: (Event) -> Unit = { event ->
|
||||
if (event !is KeyboardEvent || event.key == "Enter") {
|
||||
val res = when (val t = event.target) {
|
||||
// (it.target as HTMLInputElement).value
|
||||
is HTMLInputElement -> if (t.type == "checkbox") {
|
||||
if (t.checked) True else False
|
||||
} else {
|
||||
t.value.asValue()
|
||||
}
|
||||
is HTMLSelectElement -> t.value.asValue()
|
||||
else -> error("Unknown event target: $t")
|
||||
}
|
||||
|
||||
try {
|
||||
root.setValue(name, res)
|
||||
} catch (ex: Exception) {
|
||||
console.error("Can't set config property ${name} to $res")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val type = descriptor?.type?.firstOrNull()
|
||||
when {
|
||||
descriptor?.widgetType == "slider" -> slider {
|
||||
attrs {
|
||||
descriptor.attributes["step"].number?.let {
|
||||
step = it
|
||||
}
|
||||
descriptor.attributes["min"].number?.let {
|
||||
min = it
|
||||
}
|
||||
descriptor.attributes["max"].number?.let {
|
||||
max = it
|
||||
}
|
||||
this.defaultValue = value.number
|
||||
onChangeFunction = onValueChange
|
||||
}
|
||||
}
|
||||
descriptor?.widgetType == "color" -> input {
|
||||
attrs {
|
||||
fullWidth = true
|
||||
this.type = InputType.color
|
||||
this.value = value.string
|
||||
onChangeFunction = onValueChange
|
||||
}
|
||||
}
|
||||
|
||||
type == ValueType.BOOLEAN -> switch {
|
||||
attrs {
|
||||
defaultChecked = value.boolean
|
||||
onChangeFunction = onValueChange
|
||||
}
|
||||
}
|
||||
|
||||
type == ValueType.NUMBER -> textField {
|
||||
attrs {
|
||||
fullWidth = true
|
||||
this.type = InputType.number
|
||||
defaultValue = value.string
|
||||
onChangeFunction = onValueChange
|
||||
//onKeyDownFunction = onValueChange
|
||||
}
|
||||
}
|
||||
descriptor?.allowedValues?.isNotEmpty() ?: false -> select {
|
||||
descriptor!!.allowedValues.forEach {
|
||||
option {
|
||||
+it.string
|
||||
}
|
||||
}
|
||||
attrs {
|
||||
fullWidth = true
|
||||
multiple = false
|
||||
onChangeFunction = onValueChange
|
||||
}
|
||||
}
|
||||
else -> textField {
|
||||
attrs {
|
||||
this.type = InputType.text
|
||||
fullWidth = true
|
||||
this.defaultValue = value.string
|
||||
//onFocusOutFunction = onValueChange
|
||||
onKeyDownFunction = onValueChange
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -10,21 +10,12 @@ kotlin {
|
||||
|
||||
|
||||
dependencies{
|
||||
api(project(":dataforge-vis-common"))
|
||||
|
||||
api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72")
|
||||
//api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72")
|
||||
api("org.jetbrains:kotlin-react-dom:16.13.1-pre.104-kotlin-1.3.72")
|
||||
api("org.jetbrains.kotlinx:kotlinx-html:0.6.12")
|
||||
|
||||
api("org.jetbrains:kotlin-extensions:1.0.1-pre.104-kotlin-1.3.72")
|
||||
api("org.jetbrains:kotlin-css-js:1.0.0-pre.94-kotlin-1.3.70")
|
||||
api("org.jetbrains:kotlin-styled:1.0.0-pre.104-kotlin-1.3.72")
|
||||
|
||||
api(npm("core-js", "2.6.5"))
|
||||
|
||||
api(npm("react", "16.13.1"))
|
||||
api(npm("react-dom", "16.13.1"))
|
||||
|
||||
api(npm("react-is", "16.13.0"))
|
||||
api(npm("inline-style-prefixer", "5.1.0"))
|
||||
api(npm("styled-components", "4.3.2"))
|
||||
api(npm("react-is", "16.13.1"))
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package hep.dataforge.vis.react
|
||||
|
||||
import kotlinx.css.*
|
||||
import kotlinx.css.properties.deg
|
||||
import kotlinx.css.properties.rotate
|
||||
import styled.StyleSheet
|
||||
|
||||
object TreeStyles : StyleSheet("treeStyles", true) {
|
||||
/**
|
||||
* Remove default bullets
|
||||
*/
|
||||
val tree by css {
|
||||
paddingLeft = 8.px
|
||||
marginLeft = 0.px
|
||||
listStyleType = ListStyleType.none
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the caret/arrow
|
||||
*/
|
||||
val treeCaret by css {
|
||||
cursor = Cursor.pointer
|
||||
userSelect = UserSelect.none
|
||||
/* Create the caret/arrow with a unicode, and style it */
|
||||
before {
|
||||
content = "\u25B6".quoted
|
||||
color = Color.black
|
||||
display = Display.inlineBlock
|
||||
marginRight = 6.px
|
||||
}
|
||||
}
|
||||
|
||||
val treeItem by css {
|
||||
alignItems = Align.center
|
||||
paddingLeft = 10.px
|
||||
borderLeftStyle = BorderStyle.dashed
|
||||
borderLeftWidth = 1.px
|
||||
borderLeftColor = Color.lightGray
|
||||
}
|
||||
|
||||
val treeLeaf by css {
|
||||
display = Display.flex
|
||||
flexDirection = FlexDirection.row
|
||||
userSelect = UserSelect.none
|
||||
alignItems = Align.center
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotate the caret/arrow icon when clicked on (using JavaScript)
|
||||
*/
|
||||
val treeCaredDown by css {
|
||||
before {
|
||||
content = "\u25B6".quoted
|
||||
color = Color.black
|
||||
display = Display.inlineBlock
|
||||
marginRight = 6.px
|
||||
transform.rotate(90.deg)
|
||||
}
|
||||
}
|
||||
|
||||
val treeLabel by css {
|
||||
overflow = Overflow.hidden
|
||||
}
|
||||
|
||||
val treeLabelInactive by css {
|
||||
color = Color.lightGray
|
||||
}
|
||||
|
||||
val treeLabelSelected by css {
|
||||
backgroundColor = Color.lightBlue
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package hep.dataforge.vis.bootstrap
|
||||
package hep.dataforge.vis.react
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.descriptors.*
|
||||
@ -6,19 +6,15 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.values.Value
|
||||
import hep.dataforge.vis.react.RFBuilder
|
||||
import hep.dataforge.vis.react.component
|
||||
import hep.dataforge.vis.react.flexRow
|
||||
import hep.dataforge.vis.react.state
|
||||
import kotlinx.css.*
|
||||
import kotlinx.html.classes
|
||||
import kotlinx.css.properties.TextDecoration
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.events.Event
|
||||
import react.*
|
||||
import react.dom.*
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
import react.dom.div
|
||||
import react.dom.render
|
||||
import styled.*
|
||||
|
||||
interface ConfigEditorItemProps : RProps {
|
||||
|
||||
@ -91,25 +87,32 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
when (actualItem) {
|
||||
is MetaItem.NodeItem -> {
|
||||
div {
|
||||
span("tree-caret") {
|
||||
attrs {
|
||||
styledSpan {
|
||||
css {
|
||||
+TreeStyles.treeCaret
|
||||
if (expanded) {
|
||||
classes += "tree-caret-down"
|
||||
+TreeStyles.treeCaredDown
|
||||
}
|
||||
}
|
||||
attrs {
|
||||
onClickFunction = expanderClick
|
||||
}
|
||||
}
|
||||
span("tree-label") {
|
||||
+token
|
||||
attrs {
|
||||
styledSpan {
|
||||
css {
|
||||
+TreeStyles.treeLabel
|
||||
if (item == null) {
|
||||
classes += "tree-label-inactive"
|
||||
+TreeStyles.treeLabelInactive
|
||||
}
|
||||
}
|
||||
+token
|
||||
}
|
||||
}
|
||||
if (expanded) {
|
||||
ul("tree") {
|
||||
styledUl {
|
||||
css {
|
||||
+TreeStyles.tree
|
||||
}
|
||||
val keys = buildSet<NameToken> {
|
||||
(descriptorItem as? NodeDescriptor)?.items?.keys?.forEach {
|
||||
add(NameToken(it))
|
||||
@ -119,7 +122,10 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
}
|
||||
|
||||
keys.forEach { token ->
|
||||
li("tree-item align-middle") {
|
||||
styledLi {
|
||||
css {
|
||||
+TreeStyles.treeItem
|
||||
}
|
||||
child(ConfigEditorItem) {
|
||||
attrs {
|
||||
this.key = props.name.toString()
|
||||
@ -136,22 +142,23 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
}
|
||||
}
|
||||
is MetaItem.ValueItem -> {
|
||||
flexRow {
|
||||
styledDiv {
|
||||
css {
|
||||
alignItems = Align.center
|
||||
+TreeStyles.treeLeaf
|
||||
justifyContent = JustifyContent.flexEnd
|
||||
}
|
||||
styledDiv {
|
||||
css {
|
||||
flexGrow = 1.0
|
||||
}
|
||||
span("tree-label align-self-center") {
|
||||
+token
|
||||
attrs {
|
||||
styledSpan {
|
||||
css {
|
||||
+TreeStyles.treeLabel
|
||||
if (item == null) {
|
||||
classes += "tree-label-inactive"
|
||||
+TreeStyles.treeLabelInactive
|
||||
}
|
||||
}
|
||||
+token
|
||||
}
|
||||
}
|
||||
styledDiv {
|
||||
@ -166,7 +173,23 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
css {
|
||||
flexShrink = 1.0
|
||||
}
|
||||
button(classes = "btn btn-link align-self-center") {
|
||||
styledButton {
|
||||
css {
|
||||
backgroundColor = Color.white
|
||||
borderStyle = BorderStyle.solid
|
||||
borderRadius = 2.px
|
||||
padding(1.px, 5.px)
|
||||
marginLeft = 4.px
|
||||
textAlign = TextAlign.center
|
||||
textDecoration = TextDecoration.none
|
||||
display = Display.inlineBlock
|
||||
cursor = Cursor.pointer
|
||||
disabled {
|
||||
cursor = Cursor.auto
|
||||
borderStyle = BorderStyle.dashed
|
||||
color = Color.lightGray
|
||||
}
|
||||
}
|
||||
+"\u00D7"
|
||||
attrs {
|
||||
if (item == null) {
|
@ -0,0 +1,9 @@
|
||||
package hep.dataforge.vis.react
|
||||
|
||||
import styled.StyleSheet
|
||||
|
||||
|
||||
class MainStyle: StyleSheet("main", true){
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package hep.dataforge.vis.bootstrap
|
||||
package hep.dataforge.vis.react
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||
@ -6,6 +6,8 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.values.*
|
||||
import hep.dataforge.vis.Colors
|
||||
import hep.dataforge.vis.widgetType
|
||||
import kotlinx.css.Align
|
||||
import kotlinx.css.alignSelf
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import kotlinx.html.js.onKeyDownFunction
|
||||
@ -14,7 +16,12 @@ import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.HTMLSelectElement
|
||||
import org.w3c.dom.events.Event
|
||||
import react.*
|
||||
import react.dom.*
|
||||
import react.dom.defaultValue
|
||||
import react.dom.input
|
||||
import react.dom.option
|
||||
import react.dom.select
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
interface ValueChooserProps : RProps {
|
||||
var item: MetaItem<*>?
|
||||
@ -66,9 +73,6 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
}
|
||||
element.indeterminate = props.item == null
|
||||
}
|
||||
// (state.element as? HTMLSelectElement)?.let { element ->
|
||||
// state.value?.let { element.value = it.string }
|
||||
// }
|
||||
}
|
||||
|
||||
private fun RBuilder.stringInput() = input(type = InputType.text) {
|
||||
@ -80,7 +84,10 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
}
|
||||
|
||||
override fun RBuilder.render() {
|
||||
div("align-self-center") {
|
||||
styledDiv {
|
||||
css {
|
||||
alignSelf = Align.center
|
||||
}
|
||||
val descriptor = props.descriptor
|
||||
val type = descriptor?.type?.firstOrNull()
|
||||
when {
|
Loading…
Reference in New Issue
Block a user