Working tree navigation
This commit is contained in:
parent
66caebb090
commit
4fa2e50777
@ -2,6 +2,7 @@ package hep.dataforge.vis.common
|
|||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
@ -59,3 +60,6 @@ interface VisualObject : MetaRepr, Configurable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun VisualObject.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = getProperty(key.toName(), inherit)
|
||||||
|
fun VisualObject.setProperty(key: String, value: Any?) = setProperty(key.toName(), value)
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ kotlin {
|
|||||||
val jsMain by getting {
|
val jsMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-vis-spatial"))
|
api(project(":dataforge-vis-spatial"))
|
||||||
|
api("kotlin.js.externals:kotlin-js-jquery:3.2.0-0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml.demo
|
package hep.dataforge.vis.spatial.gdml.demo
|
||||||
|
|
||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.string
|
||||||
|
import hep.dataforge.vis.common.VisualGroup
|
||||||
|
import hep.dataforge.vis.common.VisualObject
|
||||||
import hep.dataforge.vis.hmr.ApplicationBase
|
import hep.dataforge.vis.hmr.ApplicationBase
|
||||||
import hep.dataforge.vis.hmr.startApplication
|
import hep.dataforge.vis.hmr.startApplication
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
@ -10,16 +14,14 @@ import hep.dataforge.vis.spatial.gdml.toVisual
|
|||||||
import hep.dataforge.vis.spatial.three.ThreeOutput
|
import hep.dataforge.vis.spatial.three.ThreeOutput
|
||||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||||
import hep.dataforge.vis.spatial.three.output
|
import hep.dataforge.vis.spatial.three.output
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import hep.dataforge.vis.spatial.tree.render
|
||||||
import kotlinx.coroutines.GlobalScope
|
import hep.dataforge.vis.spatial.tree.toTree
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.InputType
|
||||||
import kotlinx.html.dom.append
|
import kotlinx.html.dom.append
|
||||||
import kotlinx.html.js.input
|
import kotlinx.html.js.*
|
||||||
import kotlinx.html.js.li
|
|
||||||
import kotlinx.html.js.ul
|
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.HTMLDivElement
|
import org.w3c.dom.HTMLDivElement
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import org.w3c.files.FileList
|
import org.w3c.files.FileList
|
||||||
import org.w3c.files.FileReader
|
import org.w3c.files.FileReader
|
||||||
@ -42,7 +44,7 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
/**
|
/**
|
||||||
* Load data from text file
|
* Load data from text file
|
||||||
*/
|
*/
|
||||||
private fun loadData(event: Event, block: suspend CoroutineScope.(name: String, data: String) -> Unit) {
|
private fun loadData(event: Event, block: (name: String, data: String) -> Unit) {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
@ -53,34 +55,46 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
FileReader().apply {
|
FileReader().apply {
|
||||||
onload = {
|
onload = {
|
||||||
val string = result as String
|
val string = result as String
|
||||||
GlobalScope.launch {
|
|
||||||
|
try {
|
||||||
block(file.name, string)
|
block(file.name, string)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
console.error(ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
readAsText(file)
|
readAsText(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun spinner(show: Boolean) {
|
private fun spinner(show: Boolean) {
|
||||||
val style = if (show) {
|
// if( show){
|
||||||
"display:block;"
|
//
|
||||||
} else {
|
// val style = if (show) {
|
||||||
"display:none;"
|
// "display:block;"
|
||||||
}
|
// } else {
|
||||||
document.getElementById("loader")?.setAttribute("style", style)
|
// "display:none;"
|
||||||
|
// }
|
||||||
|
// document.getElementById("canvas")?.append {
|
||||||
|
//
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun message(message: String?) {
|
private fun message(message: String?) {
|
||||||
val element = document.getElementById("message")
|
document.getElementById("messages")?.let { element ->
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
element?.setAttribute("style", "display:none;")
|
element.clear()
|
||||||
} else {
|
} else {
|
||||||
element?.textContent = message
|
element.append {
|
||||||
element?.setAttribute("style", "display:block;")
|
p {
|
||||||
|
+message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setupSidebar(element: Element, output: ThreeOutput, root: VisualObject3D) {
|
fun setupLayers(element: Element, output: ThreeOutput) {
|
||||||
element.clear()
|
element.clear()
|
||||||
element.append {
|
element.append {
|
||||||
ul("list-group") {
|
ul("list-group") {
|
||||||
@ -103,7 +117,6 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
element.appendFancyTree(root)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val gdmlConfiguration: GDMLTransformer.() -> Unit = {
|
private val gdmlConfiguration: GDMLTransformer.() -> Unit = {
|
||||||
@ -137,6 +150,43 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun showEditor(item: VisualObject?, name: String?) {
|
||||||
|
val element = document.getElementById("editor") ?: error("Element with id 'canvas' not found on page")
|
||||||
|
element.clear()
|
||||||
|
if (item != null) {
|
||||||
|
element.append {
|
||||||
|
div("card") {
|
||||||
|
div("card-body") {
|
||||||
|
h3(classes = "card-title") { +(name ?: "") }
|
||||||
|
form {
|
||||||
|
div("form-group") {
|
||||||
|
label {
|
||||||
|
+"Color: "
|
||||||
|
}
|
||||||
|
input(InputType.color, classes = "form-control").apply {
|
||||||
|
onchange = { event ->
|
||||||
|
item.color(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("form-group form-check") {
|
||||||
|
input(InputType.checkBox, classes = "form-check-input").apply {
|
||||||
|
this.value = item.material?.get("color").string ?: ""
|
||||||
|
onchange = { event ->
|
||||||
|
item.visible = checked
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label("form-check-label") { +"Visible" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun start(state: Map<String, Any>) {
|
override fun start(state: Map<String, Any>) {
|
||||||
|
|
||||||
val context = Global.context("demo") {}
|
val context = Global.context("demo") {}
|
||||||
@ -144,15 +194,16 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||||
|
|
||||||
val canvas = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
|
val canvas = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
|
||||||
val sidebar = document.getElementById("sidebar") ?: error("Element with id 'sidebar' not found on page")
|
val layers = document.getElementById("layers") ?: error("Element with id 'layers' not found on page")
|
||||||
|
val tree = document.getElementById("tree") ?: error("Element with id 'tree' not found on page")
|
||||||
canvas.clear()
|
canvas.clear()
|
||||||
|
|
||||||
val action: suspend CoroutineScope.(name: String, data: String) -> Unit = { name, data ->
|
val action: (name: String, data: String) -> Unit = { name, data ->
|
||||||
canvas.clear()
|
canvas.clear()
|
||||||
launch { spinner(true) }
|
spinner(true)
|
||||||
launch { message("Loading GDML") }
|
message("Loading GDML")
|
||||||
val gdml = GDML.format.parse(GDML.serializer(), data)
|
val gdml = GDML.format.parse(GDML.serializer(), data)
|
||||||
launch { message("Converting GDML into DF-VIS format") }
|
message("Converting GDML into DF-VIS format")
|
||||||
|
|
||||||
val visual: VisualObject3D = when {
|
val visual: VisualObject3D = when {
|
||||||
name.endsWith(".gdml") || name.endsWith(".xml") -> gdml.toVisual(gdmlConfiguration)
|
name.endsWith(".gdml") || name.endsWith(".xml") -> gdml.toVisual(gdmlConfiguration)
|
||||||
@ -165,19 +216,22 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
launch { message("Rendering") }
|
message("Rendering")
|
||||||
val output = three.output(canvas)
|
val output = three.output(canvas as HTMLElement)
|
||||||
|
|
||||||
|
|
||||||
//output.camera.layers.enable(1)
|
//output.camera.layers.enable(1)
|
||||||
output.camera.layers.set(0)
|
output.camera.layers.set(0)
|
||||||
setupSidebar(sidebar, output, visual)
|
setupLayers(layers, output)
|
||||||
|
|
||||||
|
if (visual is VisualGroup) {
|
||||||
|
visual.toTree(::showEditor).render(tree as HTMLElement) {
|
||||||
|
showCheckboxes = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output.render(visual)
|
output.render(visual)
|
||||||
launch {
|
message(null)
|
||||||
message(null)
|
spinner(false)
|
||||||
spinner(false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
|
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
|
||||||
@ -187,6 +241,9 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun dispose(): Map<String, Any> {
|
||||||
|
return super.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml.demo
|
|
||||||
|
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
|
||||||
import hep.dataforge.vis.spatial.tree.JSVisualTree
|
|
||||||
import nl.adaptivity.js.util.asElement
|
|
||||||
import org.w3c.dom.Element
|
|
||||||
|
|
||||||
fun Element.appendFancyTree(root: VisualObject3D){
|
|
||||||
val visualTree = JSVisualTree("world", root) {}
|
|
||||||
val treeNode = visualTree.root
|
|
||||||
treeNode.asElement()!!.id = "fancytree"
|
|
||||||
appendChild(treeNode)
|
|
||||||
}
|
|
1
dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-dark.min.css
vendored
Normal file
1
dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-dark.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-light.min.css
vendored
Normal file
1
dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-light.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -4,11 +4,13 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
|
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
|
||||||
<title>Three js demo for particle physics</title>
|
<title>Three js demo for particle physics</title>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
|
||||||
|
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.32.0/dist/modules/jquery.fancytree.min.js"></script>
|
<link rel="stylesheet" href="css/main.css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery.fancytree@2.32.0/dist/skin-bootstrap/ui.fancytree.min.css">
|
<link rel="stylesheet" href="css/inspire-tree-light.min.css">
|
||||||
<link rel="stylesheet" href="main.css">
|
|
||||||
<script type="text/javascript" src="main.bundle.js"></script>
|
<script type="text/javascript" src="main.bundle.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="testApp">
|
<body class="testApp">
|
||||||
@ -21,18 +23,53 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>GDML demo</h1>
|
<h1>GDML demo</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="container loader" id="loader" style="display:none;"></div>
|
<!--<div class="container loader" id="loader" style="display:none;"></div>-->
|
||||||
<div class="container animate-bottom" id="message" style="display:none;"></div>
|
<div class="container animate-bottom" id="messages"></div>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-9" id="canvas"></div>
|
<div class="col-9" id="canvas"></div>
|
||||||
<div class="col-3" id="sidebar"></div>
|
<div class="col-3">
|
||||||
|
|
||||||
|
<div id="editor"></div>
|
||||||
|
<div class="accordion" id="accordion">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header" id="layers-header">
|
||||||
|
<h2 class="mb-0">
|
||||||
|
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#layers-body"
|
||||||
|
aria-expanded="true" aria-controls="layers-body">
|
||||||
|
Layers
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="layers-body" class="collapse show" aria-labelledby="layers-header"
|
||||||
|
data-parent="#accordion">
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="layers"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header" id="tree-header">
|
||||||
|
<h2 class="mb-0">
|
||||||
|
<button class="btn btn-link collapsed" type="button" data-toggle="collapse"
|
||||||
|
data-target="#tree-body" aria-expanded="false" aria-controls="tree-body">
|
||||||
|
Object tree
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div id="tree-body" class="collapse" aria-labelledby="tree-header" data-parent="#accordion">
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="tree"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
|
|
||||||
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
|
||||||
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
|
@ -5,12 +5,12 @@ plugins {
|
|||||||
id("org.openjfx.javafxplugin")
|
id("org.openjfx.javafxplugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
scientifik{
|
scientifik {
|
||||||
withSerialization()
|
withSerialization()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvm{
|
jvm {
|
||||||
withJava()
|
withJava()
|
||||||
}
|
}
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@ -19,20 +19,20 @@ kotlin {
|
|||||||
api(project(":dataforge-vis-common"))
|
api(project(":dataforge-vis-common"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jvmMain{
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":dataforge-vis-fx"))
|
implementation(project(":dataforge-vis-fx"))
|
||||||
implementation("org.fxyz3d:fxyz3d:0.4.0")
|
implementation("org.fxyz3d:fxyz3d:0.4.0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsMain{
|
jsMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(npm("three", "0.106.2"))
|
implementation(npm("three", "0.106.2"))
|
||||||
implementation(npm("@hi-level/three-csg", "1.0.6"))
|
implementation(npm("@hi-level/three-csg", "1.0.6"))
|
||||||
implementation(npm("style-loader"))
|
implementation(npm("style-loader"))
|
||||||
implementation(npm("element-resize-event"))
|
implementation(npm("element-resize-event"))
|
||||||
// api("kotlin.js.externals:kotlin-js-jquery:3.2.0-0")
|
implementation(npm("inspire-tree","6.0.1"))
|
||||||
// implementation(npm("jquery.fancytree","2.32.0"))
|
implementation(npm("inspire-tree-dom","4.0.6"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import hep.dataforge.vis.common.asName
|
|||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.MATERIAL_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.MATERIAL_KEY
|
||||||
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.SELECTED_KEY
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ interface VisualObject3D : VisualObject {
|
|||||||
companion object {
|
companion object {
|
||||||
val MATERIAL_KEY = "material".asName()
|
val MATERIAL_KEY = "material".asName()
|
||||||
val VISIBLE_KEY = "visible".asName()
|
val VISIBLE_KEY = "visible".asName()
|
||||||
|
val SELECTED_KEY = "selected".asName()
|
||||||
val DETAIL_KEY = "detail".asName()
|
val DETAIL_KEY = "detail".asName()
|
||||||
val LAYER_KEY = "layer".asName()
|
val LAYER_KEY = "layer".asName()
|
||||||
|
|
||||||
@ -117,10 +119,18 @@ var VisualObject.visible: Boolean?
|
|||||||
get() = getProperty(VISIBLE_KEY).boolean
|
get() = getProperty(VISIBLE_KEY).boolean
|
||||||
set(value) = setProperty(VISIBLE_KEY, value)
|
set(value) = setProperty(VISIBLE_KEY, value)
|
||||||
|
|
||||||
|
var VisualObject.selected: Boolean?
|
||||||
|
get() = getProperty(SELECTED_KEY).boolean
|
||||||
|
set(value) = setProperty(SELECTED_KEY, value)
|
||||||
|
|
||||||
fun VisualObject.color(rgb: Int) {
|
fun VisualObject.color(rgb: Int) {
|
||||||
material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgb }
|
material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgb }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun VisualObject.color(rgb: String) {
|
||||||
|
material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgb }
|
||||||
|
}
|
||||||
|
|
||||||
fun VisualObject3D.material(builder: MetaBuilder.() -> Unit) {
|
fun VisualObject3D.material(builder: MetaBuilder.() -> Unit) {
|
||||||
material = buildMeta(builder)
|
material = buildMeta(builder)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial.tree
|
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
|
|
||||||
interface VisualTree<out T: VisualObject> {
|
|
||||||
val item: T?
|
|
||||||
val children: Collection<VisualTree<T>>
|
|
||||||
}
|
|
@ -10,8 +10,9 @@ import info.laht.threekt.WebGLRenderer
|
|||||||
import info.laht.threekt.helpers.AxesHelper
|
import info.laht.threekt.helpers.AxesHelper
|
||||||
import info.laht.threekt.lights.AmbientLight
|
import info.laht.threekt.lights.AmbientLight
|
||||||
import info.laht.threekt.scenes.Scene
|
import info.laht.threekt.scenes.Scene
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.HTMLElement
|
||||||
import kotlin.browser.window
|
import kotlin.browser.window
|
||||||
|
import kotlin.dom.clear
|
||||||
|
|
||||||
private val elementResizeEvent = require("element-resize-event")
|
private val elementResizeEvent = require("element-resize-event")
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
|
|||||||
|
|
||||||
val scene: Scene = Scene().apply {
|
val scene: Scene = Scene().apply {
|
||||||
add(AmbientLight())
|
add(AmbientLight())
|
||||||
if(meta["axes.visible"].boolean == true){
|
if (meta["axes.visible"].boolean == true) {
|
||||||
axes.visible = true
|
axes.visible = true
|
||||||
}
|
}
|
||||||
add(axes)
|
add(axes)
|
||||||
@ -31,7 +32,8 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
|
|||||||
|
|
||||||
val camera = three.buildCamera(meta["camera"].node ?: EmptyMeta)
|
val camera = three.buildCamera(meta["camera"].node ?: EmptyMeta)
|
||||||
|
|
||||||
fun attach(element: Element, computeWidth: Element.() -> Int = { element.clientWidth }) {
|
fun attach(element: HTMLElement, computeWidth: HTMLElement.() -> Int = { this.offsetWidth }) {
|
||||||
|
element.clear()
|
||||||
val width by meta.number(computeWidth(element)).int
|
val width by meta.number(computeWidth(element)).int
|
||||||
|
|
||||||
val height: Int = (width / camera.aspect).toInt()
|
val height: Int = (width / camera.aspect).toInt()
|
||||||
@ -56,7 +58,7 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
|
|||||||
renderer.setSize(newWidth, (newWidth / camera.aspect).toInt())
|
renderer.setSize(newWidth, (newWidth / camera.aspect).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
element.replaceWith(renderer.domElement)
|
element.appendChild(renderer.domElement)
|
||||||
animate()
|
animate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +67,7 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ThreePlugin.output(element: Element? = null, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) =
|
fun ThreePlugin.output(element: HTMLElement? = null, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) =
|
||||||
ThreeOutput(this, buildMeta(meta, override)).apply {
|
ThreeOutput(this, buildMeta(meta, override)).apply {
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
attach(element)
|
attach(element)
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial.tree
|
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.spatial.visible
|
|
||||||
import kotlinx.html.InputType
|
|
||||||
import kotlinx.html.dom.append
|
|
||||||
import kotlinx.html.js.*
|
|
||||||
import org.w3c.dom.HTMLDivElement
|
|
||||||
import org.w3c.dom.Node
|
|
||||||
import kotlin.browser.document
|
|
||||||
|
|
||||||
class JSVisualTree(
|
|
||||||
val title: String,
|
|
||||||
override val item: VisualObject,
|
|
||||||
val callback: VisualObject.() -> Unit
|
|
||||||
) : VisualTree<VisualObject> {
|
|
||||||
|
|
||||||
override val children: Collection<JSVisualTree> by lazy {
|
|
||||||
if (item is VisualGroup) {
|
|
||||||
item.children.mapNotNull {(key,value)->
|
|
||||||
val str = key.toString()
|
|
||||||
if(!str.startsWith("@")) {
|
|
||||||
JSVisualTree(str, value, callback)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var visible: Boolean
|
|
||||||
get() = item.visible ?: true
|
|
||||||
set(value) {
|
|
||||||
item.visible = value
|
|
||||||
}
|
|
||||||
|
|
||||||
val root: Node by lazy {
|
|
||||||
(document.createElement("div") as HTMLDivElement).apply {
|
|
||||||
append {
|
|
||||||
div(TREE_ITEM_HEADER_CLASS) {
|
|
||||||
input(type = InputType.checkBox).apply {
|
|
||||||
checked = visible
|
|
||||||
onChangeFunction = {
|
|
||||||
visible = checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
+this@JSVisualTree.title
|
|
||||||
+"[${item::class}]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (item is VisualGroup) {
|
|
||||||
ul {
|
|
||||||
this@JSVisualTree.children.forEach { value ->
|
|
||||||
li(TREE_NODE_CLASS).apply {
|
|
||||||
appendChild(value.root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TREE_NODE_CLASS = "tree-node"
|
|
||||||
const val TREE_LEAF_CLASS = "tree-leaf"
|
|
||||||
const val TREE_ITEM_HEADER_CLASS = "tree-header"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,65 @@
|
|||||||
|
@file:Suppress(
|
||||||
|
"INTERFACE_WITH_SUPERCLASS",
|
||||||
|
"OVERRIDING_FINAL_MEMBER",
|
||||||
|
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
||||||
|
"CONFLICTING_OVERLOADS",
|
||||||
|
"EXTERNAL_DELEGATION"
|
||||||
|
)
|
||||||
|
@file:JsModule("eventemitter2")
|
||||||
|
@file: JsNonModule
|
||||||
|
|
||||||
|
package hep.dataforge.vis.spatial.tree
|
||||||
|
|
||||||
|
import kotlin.js.Promise
|
||||||
|
|
||||||
|
//typealias eventNS = Array<String>
|
||||||
|
|
||||||
|
external interface ConstructorOptions {
|
||||||
|
var wildcard: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var delimiter: String? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var newListener: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var maxListeners: Number? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var verboseMemoryLeak: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface EventAndListener {
|
||||||
|
@nativeInvoke
|
||||||
|
operator fun invoke(event: String, vararg values: Any)
|
||||||
|
|
||||||
|
@nativeInvoke
|
||||||
|
operator fun invoke(event: Array<String>, vararg values: Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
external open class EventEmitter2(options: ConstructorOptions? = definedExternally /* null */) {
|
||||||
|
open fun emit(event: String, vararg values: Any): Boolean
|
||||||
|
open fun emit(event: Array<String>, vararg values: Any): Boolean
|
||||||
|
open fun emitAsync(event: String, vararg values: Any): Promise<Array<Any>>
|
||||||
|
open fun emitAsync(event: Array<String>, vararg values: Any): Promise<Array<Any>>
|
||||||
|
open fun addListener(event: String, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun on(event: String, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun on(event: Array<String>, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun prependListener(event: String, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun prependListener(event: Array<String>, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun once(event: String, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun once(event: Array<String>, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun prependOnceListener(event: String, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun prependOnceListener(event: Array<String>, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun many(event: String, timesToListen: Number, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun many(event: Array<String>, timesToListen: Number, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun prependMany(event: String, timesToListen: Number, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun prependMany(event: Array<String>, timesToListen: Number, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun onAny(listener: EventAndListener): EventEmitter2 /* this */
|
||||||
|
open fun prependAny(listener: EventAndListener): EventEmitter2 /* this */
|
||||||
|
open fun offAny(listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun removeListener(event: String, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun removeListener(event: Array<String>, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun off(event: String, listener: Function<*>): EventEmitter2 /* this */
|
||||||
|
open fun removeAllListeners(event: String? = definedExternally /* null */): EventEmitter2 /* this */
|
||||||
|
open fun removeAllListeners(event: Array<String>? = definedExternally /* null */): EventEmitter2 /* this */
|
||||||
|
open fun setMaxListeners(n: Number)
|
||||||
|
open fun eventNames(): Array<String>
|
||||||
|
open fun listeners(event: String): Array<Function<*>>
|
||||||
|
open fun listeners(event: Array<String>): Array<Function<*>>
|
||||||
|
open fun listenersAny(): Array<Function<*>>
|
||||||
|
open fun removeAllListeners(): EventEmitter2 /* this */
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
@file:Suppress(
|
||||||
|
"INTERFACE_WITH_SUPERCLASS",
|
||||||
|
"OVERRIDING_FINAL_MEMBER",
|
||||||
|
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
||||||
|
"CONFLICTING_OVERLOADS",
|
||||||
|
"EXTERNAL_DELEGATION"
|
||||||
|
)
|
||||||
|
|
||||||
|
package hep.dataforge.vis.spatial.tree
|
||||||
|
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
|
||||||
|
external interface DropTargetValidator {
|
||||||
|
@nativeInvoke
|
||||||
|
operator fun invoke(dragNode: TreeNode, targetNode: TreeNode): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface DragAndDrop {
|
||||||
|
var enabled: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var validateOn: String? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var validate: DropTargetValidator
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface DomConfig {
|
||||||
|
var autoLoadMore: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var deferredRendering: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var dragAndDrop: DragAndDrop? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var nodeHeight: Number? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var showCheckboxes: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var dragTargets: Array<String>? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var tabindex: Number? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var target: HTMLElement
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@JsModule("inspire-tree-dom")
|
||||||
|
@JsNonModule
|
||||||
|
open external class InspireTreeDOM(tree: Any, opts: DomConfig)
|
@ -0,0 +1,417 @@
|
|||||||
|
@file:Suppress(
|
||||||
|
"INTERFACE_WITH_SUPERCLASS",
|
||||||
|
"OVERRIDING_FINAL_MEMBER",
|
||||||
|
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
||||||
|
"CONFLICTING_OVERLOADS",
|
||||||
|
"EXTERNAL_DELEGATION",
|
||||||
|
"unused"
|
||||||
|
)
|
||||||
|
|
||||||
|
package hep.dataforge.vis.spatial.tree
|
||||||
|
|
||||||
|
import kotlin.js.Promise
|
||||||
|
import kotlin.js.RegExp
|
||||||
|
|
||||||
|
external interface NodeIteratee {
|
||||||
|
@nativeInvoke
|
||||||
|
operator fun invoke(node: TreeNode): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface MatchProcessor {
|
||||||
|
@nativeInvoke
|
||||||
|
operator fun invoke(matches: TreeNodes): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface SearchMatcher {
|
||||||
|
@nativeInvoke
|
||||||
|
operator fun invoke(query: String, resolve: Any, reject: Any): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface `T$0` {
|
||||||
|
var add: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var edit: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var remove: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface `T$1` {
|
||||||
|
var resetStateOnRestore: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface `T$2` {
|
||||||
|
var limit: Number? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface `T$3` {
|
||||||
|
var matcher: SearchMatcher
|
||||||
|
var matchProcess: MatchProcessor
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface Selection {
|
||||||
|
var allow: NodeIteratee? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var autoDeselect: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var autoSelectChildren: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var disableDirectDeselection: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var mode: String? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var multiple: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var require: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface Config {
|
||||||
|
var allowLoadEvents: Array<String>? get() = definedExternally; set(value) = definedExternally
|
||||||
|
// var checkbox: dynamic get() = definedExternally; set(value) = definedExternally
|
||||||
|
var contextMenu: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
val data: ((node: TreeNode, resolve: (nodes: Array<NodeConfig>) -> Any, reject: (err: Error) -> Any) -> dynamic)? get() = definedExternally
|
||||||
|
var deferredLoading: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var editable: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var editing: `T$0`? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var nodes: `T$1`? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var pagination: `T$2`? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var renderer: Any? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var search: `T$3`? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var selection: Selection? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var sort: String? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var multiselect: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface State {
|
||||||
|
var checked: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var collapsed: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var draggable: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
//var `drop-target`: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var editable: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var focused: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var hidden: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var indeterminate: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var loading: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var matched: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var removed: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var rendered: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var selectable: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var selected: Boolean? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface InspireTag {
|
||||||
|
var attributes: Any? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface ITree {
|
||||||
|
var a: InspireTag? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var icon: String? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var li: InspireTag? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var state: State? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface NodeConfig {
|
||||||
|
var children: dynamic /* Array<NodeConfig> | true */
|
||||||
|
var id: String? get() = definedExternally; set(value) = definedExternally
|
||||||
|
var text: String
|
||||||
|
@JsName("itree")
|
||||||
|
var itree: ITree? get() = definedExternally; set(value) = definedExternally
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface Pagination {
|
||||||
|
var limit: Number
|
||||||
|
var total: Number
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsModule("inspire-tree")
|
||||||
|
@JsNonModule
|
||||||
|
open external class InspireTree(opts: Config) : EventEmitter2 {
|
||||||
|
constructor(tree: InspireTree)
|
||||||
|
constructor(tree: InspireTree, array: Array<Any>)
|
||||||
|
constructor(tree: InspireTree, array: TreeNodes)
|
||||||
|
|
||||||
|
open fun addNode(node: NodeConfig): TreeNode
|
||||||
|
open fun addNodes(node: Array<NodeConfig>): TreeNodes
|
||||||
|
open fun available(): TreeNodes
|
||||||
|
open fun blur(): TreeNodes
|
||||||
|
open fun blurDeep(): TreeNodes
|
||||||
|
open fun boundingNodes(): Array<TreeNode>
|
||||||
|
open fun canAutoDeselect(): Boolean
|
||||||
|
open fun checked(): TreeNodes
|
||||||
|
open fun clean(): TreeNodes
|
||||||
|
open fun clearSearch(): InspireTree
|
||||||
|
open fun clone(): TreeNodes
|
||||||
|
open fun collapse(): TreeNodes
|
||||||
|
open fun collapsed(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun collapseDeep(): TreeNodes
|
||||||
|
open fun context(): TreeNode
|
||||||
|
open fun copy(
|
||||||
|
dest: InspireTree,
|
||||||
|
hierarchy: Boolean? = definedExternally /* null */,
|
||||||
|
includeState: Boolean? = definedExternally /* null */
|
||||||
|
): TreeNodes
|
||||||
|
|
||||||
|
open fun createNode(obj: Any): TreeNode
|
||||||
|
open fun deepest(): TreeNodes
|
||||||
|
open fun deselect(): TreeNodes
|
||||||
|
open fun deselectDeep(): TreeNodes
|
||||||
|
open fun disableDeselection(): InspireTree
|
||||||
|
open fun each(iteratee: NodeIteratee): TreeNodes
|
||||||
|
open fun editable(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun editing(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun enableDeselection(): InspireTree
|
||||||
|
open fun expand(): Promise<TreeNodes>
|
||||||
|
open fun expandDeep(): TreeNodes
|
||||||
|
open fun expanded(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun expandParents(): TreeNodes
|
||||||
|
open fun extract(predicate: String): TreeNodes
|
||||||
|
open fun extract(predicate: NodeIteratee): TreeNodes
|
||||||
|
open fun filterBy(predicate: String): TreeNodes
|
||||||
|
open fun filterBy(predicate: NodeIteratee): TreeNodes
|
||||||
|
open fun find(
|
||||||
|
predicate: (node: TreeNode, index: Number? /* = null */, obj: Array<TreeNode>? /* = null */) -> Boolean,
|
||||||
|
thisArg: Any? = definedExternally /* null */
|
||||||
|
): TreeNode
|
||||||
|
|
||||||
|
open fun first(predicate: (node: TreeNode) -> Boolean): TreeNode
|
||||||
|
open fun flatten(predicate: String): TreeNodes
|
||||||
|
open fun flatten(predicate: NodeIteratee): TreeNodes
|
||||||
|
open fun focused(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun get(index: Number): TreeNode
|
||||||
|
open fun hidden(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun hide(): TreeNodes
|
||||||
|
open fun hideDeep(): TreeNodes
|
||||||
|
open var id: dynamic /* String | Number */
|
||||||
|
open var config: Config
|
||||||
|
open var preventDeselection: Boolean
|
||||||
|
open fun indeterminate(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun insertAt(index: Number, `object`: Any): TreeNode
|
||||||
|
open fun invoke(methods: String): TreeNodes
|
||||||
|
open fun invoke(methods: Array<String>): TreeNodes
|
||||||
|
open fun invokeDeep(methods: String): TreeNodes
|
||||||
|
open fun invokeDeep(methods: Array<String>): TreeNodes
|
||||||
|
open fun isEventMuted(eventName: String): Boolean
|
||||||
|
open fun last(predicate: (node: TreeNode) -> Boolean): TreeNode
|
||||||
|
open fun lastSelectedNode(): TreeNode
|
||||||
|
open fun load(loader: Promise<TreeNodes>): Promise<TreeNodes>
|
||||||
|
open fun loading(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun matched(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun move(index: Number, newIndex: Number, target: TreeNodes): TreeNode
|
||||||
|
open fun mute(events: Array<String>): InspireTree
|
||||||
|
open fun muted(): Boolean
|
||||||
|
open fun node(id: String): TreeNode
|
||||||
|
open fun node(id: Number): TreeNode
|
||||||
|
open fun nodes(ids: Array<String>? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun nodes(ids: Array<Number>? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun pagination(): Pagination
|
||||||
|
open fun recurseDown(iteratee: NodeIteratee): TreeNodes
|
||||||
|
open fun reload(): Promise<TreeNodes>
|
||||||
|
open fun removeAll(): InspireTree
|
||||||
|
open fun removed(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun restore(): TreeNodes
|
||||||
|
open fun restoreDeep(): TreeNodes
|
||||||
|
open fun search(query: String): Promise<TreeNodes>
|
||||||
|
open fun search(query: RegExp): Promise<TreeNodes>
|
||||||
|
open fun search(query: NodeIteratee): Promise<TreeNodes>
|
||||||
|
open fun select(): TreeNodes
|
||||||
|
open fun selectable(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun selectBetween(start: TreeNode, end: TreeNode): InspireTree
|
||||||
|
open fun selectDeep(): TreeNodes
|
||||||
|
open fun selected(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun selectFirstAvailableNode(): TreeNode
|
||||||
|
open fun show(): TreeNodes
|
||||||
|
open fun showDeep(): TreeNodes
|
||||||
|
open fun softRemove(): TreeNodes
|
||||||
|
open fun sortBy(sorter: String): TreeNodes
|
||||||
|
open fun sortBy(sorter: NodeIteratee): TreeNodes
|
||||||
|
open fun state(key: String, `val`: Boolean): TreeNodes
|
||||||
|
open fun stateDeep(key: String, `val`: Boolean): TreeNodes
|
||||||
|
open fun swap(node1: TreeNode, node2: TreeNode): TreeNodes
|
||||||
|
open fun toArray(): Array<Any>
|
||||||
|
open fun toArray(): Array<Any>
|
||||||
|
open fun tree(): InspireTree
|
||||||
|
open fun unmute(events: Array<String>): InspireTree
|
||||||
|
open fun visible(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun nodes(): TreeNodes
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun isTreeNode(`object`: Any): Boolean
|
||||||
|
fun isTreeNodes(`object`: Any): Boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open external class TreeNodes(tree: InspireTree) {
|
||||||
|
constructor(tree: InspireTree, array: Array<Any>)
|
||||||
|
constructor(tree: InspireTree, array: TreeNodes)
|
||||||
|
|
||||||
|
open fun addNode(node: NodeConfig): TreeNode
|
||||||
|
open fun available(): TreeNodes
|
||||||
|
open fun blur(): TreeNodes
|
||||||
|
open fun blurDeep(): TreeNodes
|
||||||
|
open fun checked(): TreeNodes
|
||||||
|
open fun clean(): TreeNodes
|
||||||
|
open fun clone(): TreeNodes
|
||||||
|
open fun collapse(): TreeNodes
|
||||||
|
open fun collapsed(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun collapseDeep(): TreeNodes
|
||||||
|
open fun context(): TreeNode
|
||||||
|
open fun copy(
|
||||||
|
dest: InspireTree,
|
||||||
|
hierarchy: Boolean? = definedExternally /* null */,
|
||||||
|
includeState: Boolean? = definedExternally /* null */
|
||||||
|
): TreeNodes
|
||||||
|
|
||||||
|
open fun deepest(): TreeNodes
|
||||||
|
open fun deselect(): TreeNodes
|
||||||
|
open fun deselectDeep(): TreeNodes
|
||||||
|
open fun each(iteratee: NodeIteratee): TreeNodes
|
||||||
|
open fun editable(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun editing(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun expand(): TreeNodes
|
||||||
|
open fun expandDeep(): Promise<TreeNodes>
|
||||||
|
open fun expanded(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun expandParents(): TreeNodes
|
||||||
|
open fun extract(predicate: String): TreeNodes
|
||||||
|
open fun extract(predicate: NodeIteratee): TreeNodes
|
||||||
|
open fun filterBy(predicate: String): TreeNodes
|
||||||
|
open fun filterBy(predicate: NodeIteratee): TreeNodes
|
||||||
|
open fun find(
|
||||||
|
predicate: (node: TreeNode, index: Number? /* = null */, obj: Array<TreeNode>? /* = null */) -> Boolean,
|
||||||
|
thisArg: Any? = definedExternally /* null */
|
||||||
|
): TreeNode
|
||||||
|
|
||||||
|
open fun flatten(predicate: String): TreeNodes
|
||||||
|
open fun flatten(predicate: NodeIteratee): TreeNodes
|
||||||
|
open fun focused(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
operator fun get(index: Number): TreeNode
|
||||||
|
open fun hidden(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun hide(): TreeNodes
|
||||||
|
open fun hideDeep(): TreeNodes
|
||||||
|
open fun indeterminate(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun insertAt(index: Number, `object`: Any): TreeNode
|
||||||
|
open fun invoke(methods: String): TreeNodes
|
||||||
|
open fun invoke(methods: Array<String>): TreeNodes
|
||||||
|
open fun invokeDeep(methods: String): TreeNodes
|
||||||
|
open fun invokeDeep(methods: Array<String>): TreeNodes
|
||||||
|
open fun loading(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun matched(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun move(index: Number, newIndex: Number, target: TreeNodes): TreeNode
|
||||||
|
open fun node(id: String): TreeNode
|
||||||
|
open fun node(id: Number): TreeNode
|
||||||
|
open fun nodes(ids: Array<String>? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun nodes(ids: Array<Number>? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun pagination(): Pagination
|
||||||
|
open fun recurseDown(iteratee: NodeIteratee): TreeNodes
|
||||||
|
open fun removed(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun restore(): TreeNodes
|
||||||
|
open fun restoreDeep(): TreeNodes
|
||||||
|
open fun select(): TreeNodes
|
||||||
|
open fun selectable(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun selectBetween(start: TreeNode, end: TreeNode): InspireTree
|
||||||
|
open fun selectDeep(): TreeNodes
|
||||||
|
open fun selected(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun show(): TreeNodes
|
||||||
|
open fun showDeep(): TreeNodes
|
||||||
|
open fun softRemove(): TreeNodes
|
||||||
|
open fun sortBy(sorter: String): TreeNodes
|
||||||
|
open fun sortBy(sorter: NodeIteratee): TreeNodes
|
||||||
|
open fun state(key: String, `val`: Boolean): TreeNodes
|
||||||
|
open fun stateDeep(key: String, `val`: Boolean): TreeNodes
|
||||||
|
open fun swap(node1: TreeNode, node2: TreeNode): TreeNodes
|
||||||
|
open fun toArray(): Array<Any>
|
||||||
|
open fun tree(): InspireTree
|
||||||
|
open fun visible(full: Boolean? = definedExternally /* null */): TreeNodes
|
||||||
|
open fun nodes(): TreeNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
open external class TreeNode(tree: InspireTree) {
|
||||||
|
constructor(tree: InspireTree, source: Any, excludeKeys: Array<String>)
|
||||||
|
constructor(tree: InspireTree, source: TreeNode, excludeKeys: Array<String>)
|
||||||
|
constructor(tree: InspireTree, source: Any)
|
||||||
|
constructor(tree: InspireTree, source: TreeNode)
|
||||||
|
|
||||||
|
open fun addChild(node: NodeConfig): TreeNode
|
||||||
|
open fun addChildren(nodes: Array<NodeConfig>): TreeNodes
|
||||||
|
open fun assign(vararg sources: Any?): TreeNode
|
||||||
|
open fun available(): Boolean
|
||||||
|
open fun blur(): TreeNode
|
||||||
|
open fun check(shallow: Boolean? = definedExternally /* null */): TreeNode
|
||||||
|
open fun checked(): Boolean
|
||||||
|
open fun clean(): TreeNode
|
||||||
|
open fun clone(excludeKeys: Array<String>? = definedExternally /* null */): TreeNode
|
||||||
|
open fun collapse(): TreeNode
|
||||||
|
open fun collapsed(): Boolean
|
||||||
|
open var text: String
|
||||||
|
open var id: String
|
||||||
|
open var itree: Any
|
||||||
|
open fun context(): TreeNodes
|
||||||
|
open fun copy(
|
||||||
|
dest: InspireTree,
|
||||||
|
hierarchy: Boolean? = definedExternally /* null */,
|
||||||
|
includeState: Boolean? = definedExternally /* null */
|
||||||
|
): TreeNode
|
||||||
|
|
||||||
|
open fun copyHierarchy(
|
||||||
|
excludeNode: Boolean? = definedExternally /* null */,
|
||||||
|
includeState: Boolean? = definedExternally /* null */
|
||||||
|
): TreeNode
|
||||||
|
|
||||||
|
open fun deselect(shallow: Boolean? = definedExternally /* null */): TreeNode
|
||||||
|
open fun editable(): Boolean
|
||||||
|
open fun editing(): Boolean
|
||||||
|
open fun expand(): Promise<TreeNode>
|
||||||
|
open fun expanded(): Boolean
|
||||||
|
open fun expandParents(): TreeNode
|
||||||
|
open fun focus(): TreeNode
|
||||||
|
open fun focused(): Boolean
|
||||||
|
open fun getChildren(): TreeNodes
|
||||||
|
open fun getParent(): TreeNode
|
||||||
|
open fun getParents(): TreeNodes
|
||||||
|
open fun getTextualHierarchy(): Array<String>
|
||||||
|
open fun hasAncestor(): Boolean
|
||||||
|
open fun hasChildren(): Boolean
|
||||||
|
open fun hasOrWillHaveChildren(): Boolean
|
||||||
|
open fun hasParent(): Boolean
|
||||||
|
open fun hasVisibleChildren(): Boolean
|
||||||
|
open fun hidden(): Boolean
|
||||||
|
open fun hide(): TreeNode
|
||||||
|
open fun indeterminate(): Boolean
|
||||||
|
open fun indexPath(): String
|
||||||
|
open fun isFirstRenderable(): Boolean
|
||||||
|
open fun isLastRenderable(): Boolean
|
||||||
|
open fun lastDeepestVisibleChild(): TreeNode
|
||||||
|
open fun loadChildren(): Promise<TreeNodes>
|
||||||
|
open fun loading(): Boolean
|
||||||
|
open fun markDirty(): TreeNode
|
||||||
|
open fun matched(): TreeNodes
|
||||||
|
open fun nextVisibleAncestralSiblingNode(): TreeNode
|
||||||
|
open fun nextVisibleChildNode(): TreeNode
|
||||||
|
open fun nextVisibleNode(): TreeNode
|
||||||
|
open fun nextVisibleSiblingNode(): TreeNode
|
||||||
|
open fun pagination(): Pagination
|
||||||
|
open fun previousVisibleNode(): TreeNode
|
||||||
|
open fun previousVisibleSiblingNode(): TreeNode
|
||||||
|
open fun recurseDown(iteratee: NodeIteratee): TreeNode
|
||||||
|
open fun recurseUp(iteratee: NodeIteratee): TreeNode
|
||||||
|
open fun refreshIndeterminateState(): TreeNode
|
||||||
|
open fun reload(): Promise<TreeNodes>
|
||||||
|
open fun remove(includeState: Boolean? = definedExternally /* null */): Any
|
||||||
|
open fun removed(): Boolean
|
||||||
|
open fun renderable(): Boolean
|
||||||
|
open fun rendered(): Boolean
|
||||||
|
open fun restore(): TreeNode
|
||||||
|
open fun select(shallow: Boolean? = definedExternally /* null */): TreeNode
|
||||||
|
open fun selectable(): Boolean
|
||||||
|
open fun selected(): Boolean
|
||||||
|
open fun set(key: Number, `val`: Any): TreeNode
|
||||||
|
open fun set(key: String, `val`: Any): TreeNode
|
||||||
|
open fun show(): TreeNode
|
||||||
|
open fun softRemove(): TreeNode
|
||||||
|
open fun state(key: Any?, `val`: Boolean? = definedExternally /* null */): dynamic /* Boolean | Any? */
|
||||||
|
open fun state(key: String, `val`: Boolean? = definedExternally /* null */): dynamic /* Boolean | Any? */
|
||||||
|
open fun states(keys: Array<String>, `val`: Boolean): Boolean
|
||||||
|
open fun toggleCheck(): TreeNode
|
||||||
|
open fun toggleCollapse(): TreeNode
|
||||||
|
open fun toggleEditing(): TreeNode
|
||||||
|
open fun toggleSelect(): TreeNode
|
||||||
|
open fun toObject(
|
||||||
|
excludeChildren: Boolean? = definedExternally /* null */,
|
||||||
|
includeState: Boolean? = definedExternally /* null */
|
||||||
|
): Any
|
||||||
|
|
||||||
|
override fun toString(): String
|
||||||
|
open fun tree(): InspireTree
|
||||||
|
open fun uncheck(shallow: Boolean? = definedExternally /* null */): TreeNode
|
||||||
|
open fun visible(): Boolean
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
@file:Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE")
|
||||||
|
|
||||||
|
package hep.dataforge.vis.spatial.tree
|
||||||
|
|
||||||
|
import hep.dataforge.meta.string
|
||||||
|
import hep.dataforge.names.EmptyName
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
import hep.dataforge.vis.common.VisualGroup
|
||||||
|
import hep.dataforge.vis.common.VisualObject
|
||||||
|
import hep.dataforge.vis.common.getProperty
|
||||||
|
import hep.dataforge.vis.spatial.selected
|
||||||
|
import hep.dataforge.vis.spatial.visible
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
import kotlin.js.json
|
||||||
|
|
||||||
|
operator fun Name.plus(other: NameToken): Name = Name(tokens + other)
|
||||||
|
|
||||||
|
fun InspireTree.render(element: HTMLElement, block: DomConfig.() -> Unit = {}) {
|
||||||
|
val config = (json(
|
||||||
|
"target" to element
|
||||||
|
) as DomConfig).apply(block)
|
||||||
|
InspireTreeDOM(this, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
|
||||||
|
val config = (json(
|
||||||
|
"checkbox" to json(
|
||||||
|
"autoCheckChildren" to false
|
||||||
|
)
|
||||||
|
) as Config).apply(block)
|
||||||
|
return InspireTree(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun VisualGroup.toTree(onFocus: (VisualObject?, String?)->Unit = {obj,name->}): InspireTree {
|
||||||
|
|
||||||
|
val map = HashMap<String, VisualObject>()
|
||||||
|
|
||||||
|
fun generateNodeConfig(item: VisualObject, fullName: Name): NodeConfig {
|
||||||
|
val title = item.getProperty("title").string ?: fullName.last()?.toString() ?: "root"
|
||||||
|
val text = "$title[${item::class.toString().replace("class ","")}]"
|
||||||
|
return json(
|
||||||
|
"children" to if ((item as? VisualGroup)?.children?.isEmpty() != false) {
|
||||||
|
emptyArray<NodeConfig>()
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
},
|
||||||
|
"text" to text,
|
||||||
|
"id" to fullName.toString(),
|
||||||
|
"itree" to json(
|
||||||
|
"state" to json(
|
||||||
|
"checked" to (item.visible ?: true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) as NodeConfig
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TreeNode.fillChildren(group: VisualGroup, groupName: Name) {
|
||||||
|
group.children.forEach { (token, obj) ->
|
||||||
|
val name = groupName + token
|
||||||
|
val nodeConfig = generateNodeConfig(obj, name)
|
||||||
|
val childNode = addChild(nodeConfig)
|
||||||
|
map[childNode.id] = obj
|
||||||
|
if (obj is VisualGroup) {
|
||||||
|
childNode.fillChildren(obj, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val inspireTree = createInspireTree{
|
||||||
|
|
||||||
|
}
|
||||||
|
val nodeConfig = generateNodeConfig(this, EmptyName)
|
||||||
|
val rootNode = inspireTree.addNode(nodeConfig)
|
||||||
|
map[rootNode.id] = this
|
||||||
|
rootNode.fillChildren(this, EmptyName)
|
||||||
|
|
||||||
|
inspireTree.on("node.selected") { node: TreeNode, isLoadEvent: Boolean ->
|
||||||
|
if (!isLoadEvent) {
|
||||||
|
map[node.id]?.selected = node.selected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inspireTree.on("node.deselect") { node: TreeNode ->
|
||||||
|
map[node.id]?.selected = node.selected()
|
||||||
|
}
|
||||||
|
|
||||||
|
inspireTree.on("node.checked") { node: TreeNode, isLoadEvent: Boolean ->
|
||||||
|
if (!isLoadEvent) {
|
||||||
|
map[node.id]?.visible = node.checked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inspireTree.on("node.unchecked") { node: TreeNode ->
|
||||||
|
if(!node.indeterminate()){
|
||||||
|
map[node.id]?.visible = node.checked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inspireTree.on("node.focused") { node: TreeNode, isLoadEvent: Boolean ->
|
||||||
|
if (!isLoadEvent) {
|
||||||
|
onFocus(map[node.id],node.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inspireTree.collapseDeep()
|
||||||
|
|
||||||
|
return inspireTree
|
||||||
|
}
|
@ -60,7 +60,9 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
|||||||
gridRoot.append {
|
gridRoot.append {
|
||||||
span("border") {
|
span("border") {
|
||||||
div("col-6") {
|
div("col-6") {
|
||||||
output.attach(div { id = "output-$name" }) { 500 }
|
div { id = "output-$name" }.also{
|
||||||
|
output.attach(it)
|
||||||
|
}
|
||||||
hr()
|
hr()
|
||||||
h2 { +(meta["title"].string ?: name.toString()) }
|
h2 { +(meta["title"].string ?: name.toString()) }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user