MMApp fully on react (with crutches)
This commit is contained in:
parent
e6879fee15
commit
ea73650b50
@ -40,10 +40,6 @@ kotlin {
|
|||||||
api(npm("inline-style-prefixer"))
|
api(npm("inline-style-prefixer"))
|
||||||
|
|
||||||
api(npm("source-map-resolve","0.6.0"))
|
api(npm("source-map-resolve","0.6.0"))
|
||||||
api(npm("bootstrap","4.4.1"))
|
|
||||||
api(npm("popper.js","1.14.7"))
|
|
||||||
api(npm("jquery","3.5.0"))
|
|
||||||
//api(npm("jsoneditor", "8.6.1"))
|
|
||||||
api(npm("file-saver","2.0.2"))
|
api(npm("file-saver","2.0.2"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.isEmpty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return nearest selectable parent [Name]
|
||||||
|
*/
|
||||||
|
tailrec fun Name.selectable(): Name? = when {
|
||||||
|
isEmpty() -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
last()?.body?.startsWith("@") != true -> {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
cutLast().selectable()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package hep.dataforge.js
|
||||||
|
|
||||||
|
import kotlinx.html.*
|
||||||
|
import kotlinx.html.js.div
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.*
|
||||||
|
|
||||||
|
inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
|
||||||
|
div("card w-100") {
|
||||||
|
div("card-body") {
|
||||||
|
h3(classes = "card-title") { +title }
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun RBuilder.card(title: String, crossinline block: RBuilder.() -> Unit) {
|
||||||
|
div("card w-100") {
|
||||||
|
div("card-body") {
|
||||||
|
h3(classes = "card-title") { +title }
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun TagConsumer<HTMLElement>.accordion(id: String, elements: List<Pair<String, DIV.() -> Unit>>) {
|
||||||
|
div("container-fluid") {
|
||||||
|
div("accordion") {
|
||||||
|
this.id = id
|
||||||
|
elements.forEachIndexed { index, (title, builder) ->
|
||||||
|
val headerID = "${id}-${index}-heading"
|
||||||
|
val collapseID = "${id}-${index}-collapse"
|
||||||
|
div("card") {
|
||||||
|
div("card-header") {
|
||||||
|
this.id = headerID
|
||||||
|
h5("mb-0") {
|
||||||
|
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
||||||
|
attributes["data-toggle"] = "collapse"
|
||||||
|
attributes["data-target"] = "#$collapseID"
|
||||||
|
attributes["aria-expanded"] = "false"
|
||||||
|
attributes["aria-controls"] = collapseID
|
||||||
|
+title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("collapse") {
|
||||||
|
this.id = collapseID
|
||||||
|
attributes["aria-labelledby"] = headerID
|
||||||
|
attributes["data-parent"] = "#$id"
|
||||||
|
div("card-body", block = builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typealias AccordionBuilder = MutableList<Pair<String, DIV.() -> Unit>>
|
||||||
|
|
||||||
|
fun AccordionBuilder.entry(title: String, builder: DIV.() -> Unit) {
|
||||||
|
add(title to builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TagConsumer<HTMLElement>.accordion(id: String, builder: AccordionBuilder.() -> Unit) {
|
||||||
|
val list = ArrayList<Pair<String, DIV.() -> Unit>>().apply(builder)
|
||||||
|
accordion(id, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.accordion(id: String, elements: List<Pair<String, RDOMBuilder<DIV>.() -> Unit>>) {
|
||||||
|
div("container-fluid") {
|
||||||
|
div("accordion") {
|
||||||
|
attrs {
|
||||||
|
this.id = id
|
||||||
|
}
|
||||||
|
elements.forEachIndexed { index, (title, builder) ->
|
||||||
|
val headerID = "${id}-${index}-heading"
|
||||||
|
val collapseID = "${id}-${index}-collapse"
|
||||||
|
div("card") {
|
||||||
|
div("card-header") {
|
||||||
|
attrs {
|
||||||
|
this.id = headerID
|
||||||
|
}
|
||||||
|
h5("mb-0") {
|
||||||
|
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
||||||
|
attrs {
|
||||||
|
attributes["data-toggle"] = "collapse"
|
||||||
|
attributes["data-target"] = "#$collapseID"
|
||||||
|
attributes["aria-expanded"] = "false"
|
||||||
|
attributes["aria-controls"] = collapseID
|
||||||
|
}
|
||||||
|
+title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("collapse") {
|
||||||
|
attrs {
|
||||||
|
this.id = collapseID
|
||||||
|
attributes["aria-labelledby"] = headerID
|
||||||
|
attributes["data-parent"] = "#$id"
|
||||||
|
}
|
||||||
|
div("card-body", block = builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias RAccordionBuilder = MutableList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>
|
||||||
|
|
||||||
|
fun RAccordionBuilder.entry(title: String, builder: RDOMBuilder<DIV>.() -> Unit) {
|
||||||
|
add(title to builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.accordion(id: String, builder: RAccordionBuilder.() -> Unit) {
|
||||||
|
val list = ArrayList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>().apply(builder)
|
||||||
|
accordion(id, list)
|
||||||
|
}
|
@ -15,3 +15,4 @@ fun <T> RComponent<*, *>.initState(init: () -> T): ReadWriteProperty<RComponent<
|
|||||||
pair.second(value)
|
pair.second(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +34,10 @@ class MetaViewerComponent : RComponent<MetaViewerProps, TreeState>() {
|
|||||||
override fun RBuilder.render() {
|
override fun RBuilder.render() {
|
||||||
div("d-inline-block text-truncate") {
|
div("d-inline-block text-truncate") {
|
||||||
if (props.meta.items.isNotEmpty()) {
|
if (props.meta.items.isNotEmpty()) {
|
||||||
span("objTree-caret") {
|
span("tree-caret") {
|
||||||
attrs {
|
attrs {
|
||||||
if (state.expanded) {
|
if (state.expanded) {
|
||||||
classes += "objTree-caret-down"
|
classes += "tree-caret-down"
|
||||||
}
|
}
|
||||||
onClickFunction = onClick
|
onClickFunction = onClick
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package hep.dataforge.vis.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
|
import hep.dataforge.js.card
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
|
import hep.dataforge.names.startsWith
|
||||||
import hep.dataforge.vis.VisualGroup
|
import hep.dataforge.vis.VisualGroup
|
||||||
import hep.dataforge.vis.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.isEmpty
|
import hep.dataforge.vis.isEmpty
|
||||||
@ -14,6 +16,7 @@ import react.dom.*
|
|||||||
|
|
||||||
interface ObjectTreeProps : RProps {
|
interface ObjectTreeProps : RProps {
|
||||||
var name: Name
|
var name: Name
|
||||||
|
var selected: Name?
|
||||||
var obj: VisualObject
|
var obj: VisualObject
|
||||||
var clickCallback: (Name) -> Unit
|
var clickCallback: (Name) -> Unit
|
||||||
}
|
}
|
||||||
@ -22,25 +25,39 @@ interface TreeState : RState {
|
|||||||
var expanded: Boolean
|
var expanded: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
class ObjectTree : RComponent<ObjectTreeProps, TreeState>() {
|
||||||
|
|
||||||
override fun TreeState.init() {
|
override fun TreeState.init(props: ObjectTreeProps) {
|
||||||
expanded = false
|
expanded = props.selected?.startsWith(props.name) ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val onClick: (Event) -> Unit = {
|
private val onClick: (Event) -> Unit = {
|
||||||
setState {
|
setState {
|
||||||
expanded = !expanded
|
expanded = !expanded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun RBuilder.treeLabel(text: String) {
|
||||||
|
a("#", classes = "tree-label") {
|
||||||
|
+text
|
||||||
|
attrs {
|
||||||
|
if (props.name == props.selected) {
|
||||||
|
classes += "tree-label-selected"
|
||||||
|
}
|
||||||
|
onClickFunction = { props.clickCallback(props.name) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun RBuilder.render() {
|
override fun RBuilder.render() {
|
||||||
val token = props.name.last()?.toString() ?: "World"
|
val token = props.name.last()?.toString() ?: "World"
|
||||||
val obj = props.obj
|
val obj = props.obj
|
||||||
|
|
||||||
//display as node if any child is visible
|
//display as node if any child is visible
|
||||||
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
if (obj is VisualGroup) {
|
||||||
div("d-inline-block text-truncate") {
|
div("d-inline-block text-truncate") {
|
||||||
|
if (obj.children.any { !it.key.body.startsWith("@") }) {
|
||||||
span("tree-caret") {
|
span("tree-caret") {
|
||||||
attrs {
|
attrs {
|
||||||
if (state.expanded) {
|
if (state.expanded) {
|
||||||
@ -49,12 +66,8 @@ class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
|||||||
onClickFunction = onClick
|
onClickFunction = onClick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a("#",classes = "tree-label") {
|
|
||||||
+token
|
|
||||||
attrs {
|
|
||||||
onClickFunction = { props.clickCallback(props.name) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
treeLabel(token)
|
||||||
}
|
}
|
||||||
if (state.expanded) {
|
if (state.expanded) {
|
||||||
ul("tree") {
|
ul("tree") {
|
||||||
@ -63,10 +76,11 @@ class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
|||||||
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
||||||
.forEach { (childToken, child) ->
|
.forEach { (childToken, child) ->
|
||||||
li("tree-item") {
|
li("tree-item") {
|
||||||
child(ObjectTreeComponent::class) {
|
child(ObjectTree::class) {
|
||||||
attrs {
|
attrs {
|
||||||
name = props.name + childToken
|
name = props.name + childToken
|
||||||
this.obj = child
|
this.obj = child
|
||||||
|
this.selected = props.selected
|
||||||
clickCallback = props.clickCallback
|
clickCallback = props.clickCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,35 +91,40 @@ class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
|||||||
} else {
|
} else {
|
||||||
div("d-inline-block text-truncate") {
|
div("d-inline-block text-truncate") {
|
||||||
span("tree-leaf") {}
|
span("tree-leaf") {}
|
||||||
a("#",classes = "tree-label") {
|
treeLabel(token)
|
||||||
+token
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.renderObjectTree(
|
||||||
|
visualObject: VisualObject,
|
||||||
|
clickCallback: (Name) -> Unit = {}
|
||||||
|
) = render(this){
|
||||||
|
card("Object tree") {
|
||||||
|
child(ObjectTree::class) {
|
||||||
attrs {
|
attrs {
|
||||||
onClickFunction = { props.clickCallback(props.name) }
|
this.name = Name.EMPTY
|
||||||
}
|
this.obj = visualObject
|
||||||
}
|
this.selected = null
|
||||||
|
this.clickCallback = clickCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RBuilder.objectTree(
|
fun RBuilder.objectTree(
|
||||||
obj: VisualObject,
|
visualObject: VisualObject,
|
||||||
|
selected: Name? = null,
|
||||||
clickCallback: (Name) -> Unit = {}
|
clickCallback: (Name) -> Unit = {}
|
||||||
) = card("Object tree") {
|
){
|
||||||
child(ObjectTreeComponent::class) {
|
child(ObjectTree::class) {
|
||||||
attrs {
|
attrs {
|
||||||
name = Name.EMPTY
|
this.name = Name.EMPTY
|
||||||
this.obj = obj
|
this.obj = visualObject
|
||||||
|
this.selected = selected
|
||||||
this.clickCallback = clickCallback
|
this.clickCallback = clickCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Element.objectTree(
|
|
||||||
obj: VisualObject,
|
|
||||||
clickCallback: (Name) -> Unit = {}
|
|
||||||
) {
|
|
||||||
render(this) {
|
|
||||||
objectTree(obj, clickCallback)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
package hep.dataforge.vis.editor
|
|
||||||
|
|
||||||
import kotlinx.html.*
|
|
||||||
import kotlinx.html.js.div
|
|
||||||
import org.w3c.dom.HTMLElement
|
|
||||||
import react.RBuilder
|
|
||||||
import react.ReactElement
|
|
||||||
import react.dom.div
|
|
||||||
import react.dom.h3
|
|
||||||
|
|
||||||
inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
|
|
||||||
div("card w-100") {
|
|
||||||
div("card-body") {
|
|
||||||
h3(classes = "card-title") { +title }
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun RBuilder.card(title: String, crossinline block: RBuilder.() -> Unit): ReactElement = div("card w-100") {
|
|
||||||
div("card-body") {
|
|
||||||
h3(classes = "card-title") { +title }
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun TagConsumer<HTMLElement>.accordion(id: String, elements: Map<String, DIV.() -> Unit>) {
|
|
||||||
div("container-fluid") {
|
|
||||||
div("accordion") {
|
|
||||||
this.id = id
|
|
||||||
elements.entries.forEachIndexed { index, (title, builder) ->
|
|
||||||
val headerID = "${id}-${index}-heading"
|
|
||||||
val collapseID = "${id}-${index}-collapse"
|
|
||||||
div("card") {
|
|
||||||
div("card-header") {
|
|
||||||
this.id = headerID
|
|
||||||
h5("mb-0") {
|
|
||||||
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
|
||||||
attributes["data-toggle"] = "collapse"
|
|
||||||
attributes["data-target"] = "#$collapseID"
|
|
||||||
attributes["aria-expanded"] = "false"
|
|
||||||
attributes["aria-controls"] = collapseID
|
|
||||||
+title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div("collapse") {
|
|
||||||
this.id = collapseID
|
|
||||||
attributes["aria-labelledby"] = headerID
|
|
||||||
attributes["data-parent"] = "#$id"
|
|
||||||
div("card-body", block = builder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AccordionBuilder {
|
|
||||||
private val map = HashMap<String, DIV.() -> Unit>()
|
|
||||||
fun entry(title: String, block: DIV.() -> Unit) {
|
|
||||||
map[title] = block
|
|
||||||
}
|
|
||||||
|
|
||||||
fun build(consumer: TagConsumer<HTMLElement>, id: String) {
|
|
||||||
consumer.accordion(id, map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun TagConsumer<HTMLElement>.accordion(id: String, block: AccordionBuilder.() -> Unit) {
|
|
||||||
AccordionBuilder().apply(block).build(this, id)
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
package hep.dataforge.vis.editor
|
|
||||||
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import hep.dataforge.names.plus
|
|
||||||
import hep.dataforge.vis.VisualGroup
|
|
||||||
import hep.dataforge.vis.VisualObject
|
|
||||||
import hep.dataforge.vis.isEmpty
|
|
||||||
import kotlinx.html.TagConsumer
|
|
||||||
import kotlinx.html.dom.append
|
|
||||||
import kotlinx.html.js.*
|
|
||||||
import org.w3c.dom.Element
|
|
||||||
import org.w3c.dom.HTMLElement
|
|
||||||
import org.w3c.dom.HTMLSpanElement
|
|
||||||
import kotlin.dom.clear
|
|
||||||
|
|
||||||
//fun Element.displayObjectTree(
|
|
||||||
// obj: VisualObject,
|
|
||||||
// clickCallback: (Name) -> Unit = {}
|
|
||||||
//) {
|
|
||||||
// clear()
|
|
||||||
// append {
|
|
||||||
// card("Object tree") {
|
|
||||||
// subTree(Name.EMPTY, obj, clickCallback)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
private fun TagConsumer<HTMLElement>.subTree(
|
|
||||||
name: Name,
|
|
||||||
obj: VisualObject,
|
|
||||||
clickCallback: (Name) -> Unit
|
|
||||||
) {
|
|
||||||
val token = name.last()?.toString()?:"World"
|
|
||||||
|
|
||||||
//display as node if any child is visible
|
|
||||||
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
|
||||||
lateinit var toggle: HTMLSpanElement
|
|
||||||
div("d-inline-block text-truncate") {
|
|
||||||
toggle = span("objTree-caret")
|
|
||||||
label("objTree-label") {
|
|
||||||
+token
|
|
||||||
onClickFunction = { clickCallback(name) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val subtree = ul("objTree-subtree")
|
|
||||||
toggle.onclick = {
|
|
||||||
toggle.classList.toggle("objTree-caret-down")
|
|
||||||
subtree.apply {
|
|
||||||
//If expanded, add children dynamically
|
|
||||||
if (toggle.classList.contains("objTree-caret-down")) {
|
|
||||||
obj.children.entries
|
|
||||||
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
|
||||||
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
|
||||||
.forEach { (childToken, child) ->
|
|
||||||
append {
|
|
||||||
li().apply {
|
|
||||||
subTree(name + childToken, child, clickCallback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if not, clear them to conserve memory on very long lists
|
|
||||||
this.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
div("d-inline-block text-truncate") {
|
|
||||||
span("objTree-leaf")
|
|
||||||
label("objTree-label") {
|
|
||||||
+token
|
|
||||||
onClickFunction = { clickCallback(name) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
|||||||
@file:Suppress(
|
|
||||||
"INTERFACE_WITH_SUPERCLASS",
|
|
||||||
"OVERRIDING_FINAL_MEMBER",
|
|
||||||
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
|
||||||
"CONFLICTING_OVERLOADS",
|
|
||||||
"EXTERNAL_DELEGATION"
|
|
||||||
)
|
|
||||||
|
|
||||||
package hep.dataforge.vis.editor
|
|
||||||
|
|
||||||
import org.w3c.dom.HTMLElement
|
|
||||||
|
|
||||||
external interface Node {
|
|
||||||
var field: String
|
|
||||||
var value: String? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var path: dynamic
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface NodeName {
|
|
||||||
var path: Array<String>
|
|
||||||
var type: dynamic /* 'object' | 'array' */
|
|
||||||
var size: Number
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface ValidationError {
|
|
||||||
var path: dynamic
|
|
||||||
var message: String
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface Template {
|
|
||||||
var text: String
|
|
||||||
var title: String
|
|
||||||
var className: String? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var field: String
|
|
||||||
var value: Any
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface `T$6` {
|
|
||||||
var startFrom: Number
|
|
||||||
var options: Array<String>
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface AutoCompleteOptions {
|
|
||||||
var confirmKeys: Array<Number>? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var caseSensitive: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
// var getOptions: AutoCompleteOptionsGetter? get() = definedExternally; set(value) = definedExternally
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface SelectionPosition {
|
|
||||||
var row: Number
|
|
||||||
var column: Number
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface SerializableNode {
|
|
||||||
var value: Any
|
|
||||||
var path: dynamic
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface Color {
|
|
||||||
var rgba: Array<Number>
|
|
||||||
var hsla: Array<Number>
|
|
||||||
var rgbString: String
|
|
||||||
var rgbaString: String
|
|
||||||
var hslString: String
|
|
||||||
var hslaString: String
|
|
||||||
var hex: String
|
|
||||||
}
|
|
||||||
|
|
||||||
//external interface `T$0` {
|
|
||||||
// var field: Boolean
|
|
||||||
// var value: Boolean
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//external interface `T$1` {
|
|
||||||
// @nativeGetter
|
|
||||||
// operator fun get(key: String): String?
|
|
||||||
//
|
|
||||||
// @nativeSetter
|
|
||||||
// operator fun set(key: String, value: String)
|
|
||||||
//}
|
|
||||||
|
|
||||||
//external interface Languages {
|
|
||||||
// @nativeGetter
|
|
||||||
// operator fun get(lang: String): `T$1`?
|
|
||||||
//
|
|
||||||
// @nativeSetter
|
|
||||||
// operator fun set(lang: String, value: `T$1`)
|
|
||||||
//}
|
|
||||||
|
|
||||||
external interface JSONEditorOptions {
|
|
||||||
// var ace: AceAjax.Ace? get() = definedExternally; set(value) = definedExternally
|
|
||||||
// var ajv: Ajv? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onChange: (() -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onChangeJSON: ((json: Any) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onChangeText: ((jsonString: String) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onEditable: ((node: Node) -> dynamic)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onError: ((error: Error) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onModeChange: ((newMode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */, oldMode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onNodeName: ((nodeName: NodeName) -> String?)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onValidate: ((json: Any) -> dynamic)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var escapeUnicode: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var sortObjectKeys: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var history: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var mode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */
|
|
||||||
var modes: Array<dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */>? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var name: String? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var schema: Any? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var schemaRefs: Any? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var search: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var indentation: Number? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var theme: String? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var templates: Array<Template>? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var autocomplete: AutoCompleteOptions? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var mainMenuBar: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var navigationBar: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var statusBar: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onTextSelectionChange: ((start: SelectionPosition, end: SelectionPosition, text: String) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onSelectionChange: ((start: SerializableNode, end: SerializableNode) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onEvent: ((node: Node, event: String) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var colorPicker: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onColorPicker: ((parent: HTMLElement, color: String, onChange: (color: Color) -> Unit) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var timestampTag: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var language: String? get() = definedExternally; set(value) = definedExternally
|
|
||||||
//var languages: Languages? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var modalAnchor: HTMLElement? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var enableSort: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var enableTransform: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var maxVisibleChilds: Number? get() = definedExternally; set(value) = definedExternally
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface JsonPath {
|
|
||||||
var path: dynamic
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface EditorSelection {
|
|
||||||
var start: SerializableNode
|
|
||||||
var end: SerializableNode
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface TextSelection {
|
|
||||||
var start: SelectionPosition
|
|
||||||
var end: SelectionPosition
|
|
||||||
var text: String
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsModule("jsoneditor")
|
|
||||||
@JsNonModule
|
|
||||||
external open class JSONEditor(
|
|
||||||
container: HTMLElement,
|
|
||||||
options: JSONEditorOptions? = definedExternally /* null */,
|
|
||||||
json: dynamic = definedExternally /* null */
|
|
||||||
) {
|
|
||||||
open fun collapseAll()
|
|
||||||
open fun destroy()
|
|
||||||
open fun expandAll()
|
|
||||||
open fun focus()
|
|
||||||
open fun get(): Any
|
|
||||||
open fun getMode(): dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */
|
|
||||||
open fun getName(): String?
|
|
||||||
open fun getNodesByRange(start: JsonPath, end: JsonPath): Array<SerializableNode>
|
|
||||||
open fun getSelection(): EditorSelection
|
|
||||||
open fun getText(): String
|
|
||||||
open fun getTextSelection(): TextSelection
|
|
||||||
open fun refresh()
|
|
||||||
open fun set(json: Any)
|
|
||||||
open fun setMode(mode: String /* 'tree' */)
|
|
||||||
open fun setMode(mode: String /* 'view' */)
|
|
||||||
open fun setMode(mode: String /* 'form' */)
|
|
||||||
open fun setMode(mode: String /* 'code' */)
|
|
||||||
open fun setMode(mode: String /* 'text' */)
|
|
||||||
open fun setName(name: String? = definedExternally /* null */)
|
|
||||||
open fun setSchema(schema: Any?, schemaRefs: Any? = definedExternally /* null */)
|
|
||||||
open fun setSelection(start: JsonPath, end: JsonPath)
|
|
||||||
open fun setText(jsonString: String)
|
|
||||||
open fun setTextSelection(start: SelectionPosition, end: SelectionPosition)
|
|
||||||
open fun update(json: Any)
|
|
||||||
open fun updateText(jsonString: String)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
var VALID_OPTIONS: Array<String>
|
|
||||||
// var ace: AceAjax.Ace
|
|
||||||
// var Ajv: Ajv
|
|
||||||
var VanillaPicker: Any
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
package hep.dataforge.vis.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
|
import hep.dataforge.js.card
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.MetaBuilder
|
import hep.dataforge.meta.MetaBuilder
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
@ -8,77 +9,20 @@ import hep.dataforge.names.isEmpty
|
|||||||
import hep.dataforge.vis.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import react.RBuilder
|
import react.RBuilder
|
||||||
import react.ReactElement
|
|
||||||
import react.dom.li
|
import react.dom.li
|
||||||
import react.dom.nav
|
import react.dom.nav
|
||||||
import react.dom.ol
|
import react.dom.ol
|
||||||
import react.dom.render
|
import react.dom.render
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
////FIXME something rotten in JS-Meta converter
|
|
||||||
//fun Meta.toDynamic() = JSON.parse<dynamic>(toJson().toString())
|
|
||||||
//
|
|
||||||
////TODO add node descriptor instead of configuring property selector
|
|
||||||
//fun Element.displayPropertyEditor(
|
|
||||||
// name: Name,
|
|
||||||
// item: VisualObject,
|
|
||||||
// propertySelector: (VisualObject) -> Meta = { it.config }
|
|
||||||
//) {
|
|
||||||
// clear()
|
|
||||||
//
|
|
||||||
// append {
|
|
||||||
// card("Properties") {
|
|
||||||
// if (!name.isEmpty()) {
|
|
||||||
// nav {
|
|
||||||
// attributes["aria-label"] = "breadcrumb"
|
|
||||||
// ol("breadcrumb") {
|
|
||||||
// name.tokens.forEach { token ->
|
|
||||||
// li("breadcrumb-item") {
|
|
||||||
// +token.toString()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// val dMeta: dynamic = propertySelector(item).toDynamic()
|
|
||||||
// val options: JSONEditorOptions = jsObject {
|
|
||||||
// mode = "form"
|
|
||||||
// onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
|
|
||||||
// }
|
|
||||||
// JSONEditor(div(), options, dMeta)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val styles = item.styles
|
|
||||||
// if (styles.isNotEmpty()) {
|
|
||||||
// card("Styles") {
|
|
||||||
// item.styles.forEach { style ->
|
|
||||||
// val styleMeta = item.findStyle(style)
|
|
||||||
// h4("container") { +style }
|
|
||||||
// if (styleMeta != null) {
|
|
||||||
// div("container").apply {
|
|
||||||
// val options: JSONEditorOptions = jsObject {
|
|
||||||
// mode = "view"
|
|
||||||
// }
|
|
||||||
// JSONEditor(
|
|
||||||
// this,
|
|
||||||
// options,
|
|
||||||
// styleMeta.toDynamic()
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
fun RBuilder.visualPropertyEditor(
|
fun RBuilder.visualPropertyEditor(
|
||||||
path: Name,
|
path: Name,
|
||||||
item: VisualObject,
|
item: VisualObject,
|
||||||
descriptor: NodeDescriptor? = item.descriptor,
|
descriptor: NodeDescriptor? = item.descriptor,
|
||||||
title: String = "Properties",
|
title: String = "Properties",
|
||||||
default: MetaBuilder.() -> Unit = {}
|
default: MetaBuilder.() -> Unit = {}
|
||||||
): ReactElement = card(title) {
|
) {
|
||||||
|
card(title) {
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
nav {
|
nav {
|
||||||
attrs {
|
attrs {
|
||||||
@ -95,6 +39,7 @@ fun RBuilder.visualPropertyEditor(
|
|||||||
}
|
}
|
||||||
configEditor(item, descriptor, Meta(default))
|
configEditor(item, descriptor, Meta(default))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Element.visualPropertyEditor(
|
fun Element.visualPropertyEditor(
|
||||||
path: Name,
|
path: Name,
|
||||||
|
@ -38,3 +38,7 @@ ul, .tree {
|
|||||||
.tree-label-inactive {
|
.tree-label-inactive {
|
||||||
color: gray;
|
color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tree-label-selected{
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
7
dataforge-vis-common/src/jsMain/resources/js/bootstrap.bundle.min.js
vendored
Normal file
7
dataforge-vis-common/src/jsMain/resources/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
dataforge-vis-common/src/jsMain/resources/js/jquery-3.4.1.min.js
vendored
Normal file
2
dataforge-vis-common/src/jsMain/resources/js/jquery-3.4.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -7,6 +7,10 @@ plugins {
|
|||||||
serialization()
|
serialization()
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
|
js {
|
||||||
|
useCommonJs()
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -14,6 +14,7 @@ import hep.dataforge.vis.spatial.specifications.Camera
|
|||||||
import hep.dataforge.vis.spatial.specifications.Canvas
|
import hep.dataforge.vis.spatial.specifications.Canvas
|
||||||
import hep.dataforge.vis.spatial.specifications.Controls
|
import hep.dataforge.vis.spatial.specifications.Controls
|
||||||
import hep.dataforge.vis.spatial.three.ThreeMaterials.HIGHLIGHT_MATERIAL
|
import hep.dataforge.vis.spatial.three.ThreeMaterials.HIGHLIGHT_MATERIAL
|
||||||
|
import hep.dataforge.vis.spatial.three.ThreeMaterials.SELECTED_MATERIAL
|
||||||
import info.laht.threekt.WebGLRenderer
|
import info.laht.threekt.WebGLRenderer
|
||||||
import info.laht.threekt.cameras.PerspectiveCamera
|
import info.laht.threekt.cameras.PerspectiveCamera
|
||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
@ -23,6 +24,7 @@ import info.laht.threekt.external.controls.OrbitControls
|
|||||||
import info.laht.threekt.external.controls.TrackballControls
|
import info.laht.threekt.external.controls.TrackballControls
|
||||||
import info.laht.threekt.geometries.EdgesGeometry
|
import info.laht.threekt.geometries.EdgesGeometry
|
||||||
import info.laht.threekt.helpers.AxesHelper
|
import info.laht.threekt.helpers.AxesHelper
|
||||||
|
import info.laht.threekt.materials.LineBasicMaterial
|
||||||
import info.laht.threekt.math.Vector2
|
import info.laht.threekt.math.Vector2
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
@ -51,7 +53,7 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
|||||||
private val raycaster = Raycaster()
|
private val raycaster = Raycaster()
|
||||||
private val mousePosition: Vector2 = Vector2()
|
private val mousePosition: Vector2 = Vector2()
|
||||||
|
|
||||||
var clickListener: ((Name) -> Unit)? = null
|
var onClick: ((Name?) -> Unit)? = null
|
||||||
|
|
||||||
val axes = AxesHelper(canvas.axes.size.toInt()).apply {
|
val axes = AxesHelper(canvas.axes.size.toInt()).apply {
|
||||||
visible = canvas.axes.visible
|
visible = canvas.axes.visible
|
||||||
@ -63,6 +65,8 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
|||||||
|
|
||||||
val camera = buildCamera(canvas.camera)
|
val camera = buildCamera(canvas.camera)
|
||||||
|
|
||||||
|
private var picked: Object3D? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
element.clear()
|
element.clear()
|
||||||
|
|
||||||
@ -75,29 +79,26 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
|||||||
}
|
}
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
element.addEventListener("mousedown", { event ->
|
element.addEventListener("mousedown", {
|
||||||
val mesh = pick()
|
val picked = pick()
|
||||||
if (mesh != null) {
|
onClick?.invoke(picked?.fullName())
|
||||||
val name = mesh.fullName()
|
|
||||||
clickListener?.invoke(name)
|
|
||||||
}
|
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
camera.aspect = 1.0
|
camera.aspect = 1.0
|
||||||
|
|
||||||
val renderer = WebGLRenderer { antialias = true }.apply {
|
val renderer = WebGLRenderer { antialias = true }.apply {
|
||||||
setClearColor(Colors.skyblue, 1)
|
setClearColor(Colors.skyblue, 1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addControls(renderer.domElement, canvas.controls)
|
addControls(renderer.domElement, canvas.controls)
|
||||||
|
|
||||||
fun animate() {
|
fun animate() {
|
||||||
val mesh = pick()
|
val picked = pick()
|
||||||
|
|
||||||
if (mesh != null && highlighted != mesh) {
|
if (picked != null && this.picked != picked) {
|
||||||
highlighted?.toggleHighlight(false)
|
this.picked?.toggleHighlight(false,HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||||
mesh.toggleHighlight(true)
|
picked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||||
|
this.picked = picked
|
||||||
}
|
}
|
||||||
|
|
||||||
window.requestAnimationFrame {
|
window.requestAnimationFrame {
|
||||||
@ -118,18 +119,6 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
|||||||
animate()
|
animate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pick(): Mesh? {
|
|
||||||
// update the picking ray with the camera and mouse position
|
|
||||||
raycaster.setFromCamera(mousePosition, camera)
|
|
||||||
|
|
||||||
// calculate objects intersecting the picking ray
|
|
||||||
return root?.let { root ->
|
|
||||||
val intersects = raycaster.intersectObject(root, true)
|
|
||||||
val intersect = intersects.firstOrNull()
|
|
||||||
intersect?.`object` as? Mesh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve full name of the object relative to the global root
|
* Resolve full name of the object relative to the global root
|
||||||
*/
|
*/
|
||||||
@ -142,6 +131,25 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Object3D.isStatic(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Object3D?.upTrace(): Object3D? = if (this?.name?.startsWith("@") == true) parent else this
|
||||||
|
|
||||||
|
private fun pick(): Object3D? {
|
||||||
|
// update the picking ray with the camera and mouse position
|
||||||
|
raycaster.setFromCamera(mousePosition, camera)
|
||||||
|
|
||||||
|
// calculate objects intersecting the picking ray
|
||||||
|
return root?.let { root ->
|
||||||
|
val intersects = raycaster.intersectObject(root, true)
|
||||||
|
val obj = intersects.map { it.`object` }.firstOrNull { !it.isStatic() }
|
||||||
|
obj.upTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun buildCamera(spec: Camera) = PerspectiveCamera(
|
private fun buildCamera(spec: Camera) = PerspectiveCamera(
|
||||||
spec.fov,
|
spec.fov,
|
||||||
1.0,
|
1.0,
|
||||||
@ -173,42 +181,61 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
|||||||
root = object3D
|
root = object3D
|
||||||
}
|
}
|
||||||
|
|
||||||
private var highlighted: Mesh? = null
|
private var highlighted: Object3D? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle highlight for the given [Mesh] object
|
* Toggle highlight for the given [Mesh] object
|
||||||
*/
|
*/
|
||||||
private fun Mesh.toggleHighlight(highlight: Boolean) {
|
private fun Object3D.toggleHighlight(
|
||||||
|
highlight: Boolean,
|
||||||
|
edgesName: String,
|
||||||
|
material: LineBasicMaterial = SELECTED_MATERIAL
|
||||||
|
) {
|
||||||
|
if (userData[DO_NOT_HIGHLIGHT_TAG] == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this is Mesh) {
|
||||||
if (highlight) {
|
if (highlight) {
|
||||||
val edges = LineSegments(
|
val edges = LineSegments(
|
||||||
EdgesGeometry(geometry as BufferGeometry),
|
EdgesGeometry(geometry as BufferGeometry),
|
||||||
HIGHLIGHT_MATERIAL
|
material
|
||||||
).apply {
|
).apply {
|
||||||
name = "@highlight"
|
name = edgesName
|
||||||
}
|
}
|
||||||
add(edges)
|
add(edges)
|
||||||
highlighted = this
|
|
||||||
} else {
|
} else {
|
||||||
val highlightEdges = children.find { it.name == "@highlight" }
|
val highlightEdges = children.find { it.name == edgesName }
|
||||||
highlightEdges?.let { remove(it) }
|
highlightEdges?.let { remove(it) }
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
children.filter { it.name != edgesName }.forEach {
|
||||||
|
it.toggleHighlight(highlight, edgesName, material)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle highlight for element with given name
|
* Toggle highlight for element with given name
|
||||||
*/
|
*/
|
||||||
fun highlight(name: Name?) {
|
fun select(name: Name?) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
highlighted?.toggleHighlight(false)
|
highlighted?.toggleHighlight(false, SELECT_NAME, SELECTED_MATERIAL)
|
||||||
highlighted = null
|
highlighted = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val mesh = root?.findChild(name) as? Mesh
|
val obj = root?.findChild(name)
|
||||||
if (mesh != null && highlighted != mesh) {
|
if (obj != null && highlighted != obj) {
|
||||||
highlighted?.toggleHighlight(false)
|
highlighted?.toggleHighlight(false, SELECT_NAME, SELECTED_MATERIAL)
|
||||||
mesh.toggleHighlight(true)
|
obj.toggleHighlight(true, SELECT_NAME, SELECTED_MATERIAL)
|
||||||
|
highlighted = obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DO_NOT_HIGHLIGHT_TAG = "doNotHighlight"
|
||||||
|
private const val HIGHLIGHT_NAME = "@highlight"
|
||||||
|
private const val SELECT_NAME = "@select"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ThreePlugin.output(element: HTMLElement, spec: Canvas = Canvas.empty()): ThreeCanvas =
|
fun ThreePlugin.output(element: HTMLElement, spec: Canvas = Canvas.empty()): ThreeCanvas =
|
||||||
@ -216,4 +243,3 @@ fun ThreePlugin.output(element: HTMLElement, spec: Canvas = Canvas.empty()): Thr
|
|||||||
|
|
||||||
fun ThreePlugin.render(element: HTMLElement, obj: VisualObject3D, spec: Canvas = Canvas.empty()): Unit =
|
fun ThreePlugin.render(element: HTMLElement, obj: VisualObject3D, spec: Canvas = Canvas.empty()): Unit =
|
||||||
output(element, spec).render(obj)
|
output(element, spec).render(obj)
|
||||||
|
|
||||||
|
@ -1,55 +1,73 @@
|
|||||||
package hep.dataforge.vis.spatial.three
|
package hep.dataforge.vis.spatial.three
|
||||||
|
|
||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import hep.dataforge.vis.spatial.specifications.Canvas
|
import hep.dataforge.vis.spatial.specifications.Canvas
|
||||||
import kotlinx.html.id
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
import react.RBuilder
|
import react.RBuilder
|
||||||
import react.RComponent
|
import react.RComponent
|
||||||
import react.RProps
|
import react.RProps
|
||||||
import react.RState
|
import react.RState
|
||||||
import react.dom.div
|
import react.dom.div
|
||||||
import kotlin.browser.document
|
import react.dom.findDOMNode
|
||||||
import kotlin.dom.clear
|
import kotlin.dom.clear
|
||||||
|
|
||||||
interface ThreeCanvasProps : RProps {
|
interface ThreeCanvasProps : RProps {
|
||||||
|
var context: Context
|
||||||
var obj: VisualObject3D
|
var obj: VisualObject3D
|
||||||
var canvasId: String
|
var options: Canvas?
|
||||||
var options: Canvas
|
var selected: Name?
|
||||||
|
var clickCallback: (Name?) -> Unit
|
||||||
|
var canvasCallback: ((ThreeCanvas?) -> Unit)?
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThreeCanvasComponent : RComponent<ThreeCanvasProps, RState>() {
|
interface ThreeCanvasState : RState {
|
||||||
|
var element: Element?
|
||||||
|
// var canvas: ThreeCanvas?
|
||||||
|
}
|
||||||
|
|
||||||
private val three: ThreePlugin = Global.plugins.fetch(ThreePlugin)
|
class ThreeCanvasComponent : RComponent<ThreeCanvasProps, ThreeCanvasState>() {
|
||||||
|
|
||||||
|
var canvas: ThreeCanvas? = null
|
||||||
|
|
||||||
override fun componentDidMount() {
|
override fun componentDidMount() {
|
||||||
val element = document.getElementById(props.canvasId) as? HTMLElement
|
val element = state.element as? HTMLElement ?: error("Canvas element not found")
|
||||||
?: error("Element with id 'canvas' not found on page")
|
val three: ThreePlugin = props.context.plugins.load(ThreePlugin)
|
||||||
val output = three.output(element, props.options)
|
canvas = three.output(element, props.options ?: Canvas.empty())
|
||||||
output.render(props.obj)
|
props.canvasCallback?.invoke(canvas)
|
||||||
|
canvas?.render(props.obj)
|
||||||
|
canvas?.onClick = props.clickCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun componentWillUnmount() {
|
override fun componentWillUnmount() {
|
||||||
val element = document.getElementById(props.canvasId) as? HTMLElement
|
state.element?.clear()
|
||||||
?: error("Element with id 'canvas' not found on page")
|
props.canvasCallback?.invoke(null)
|
||||||
element.clear()
|
}
|
||||||
|
|
||||||
|
override fun componentDidUpdate(prevProps: ThreeCanvasProps, prevState: ThreeCanvasState, snapshot: Any) {
|
||||||
|
if (prevProps.obj != props.obj) {
|
||||||
|
componentDidMount()
|
||||||
|
}
|
||||||
|
if (prevProps.selected != props.selected) {
|
||||||
|
canvas?.select(props.selected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun RBuilder.render() {
|
override fun RBuilder.render() {
|
||||||
div {
|
div {
|
||||||
attrs {
|
ref {
|
||||||
id = props.canvasId
|
state.element = findDOMNode(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RBuilder.threeCanvas(object3D: VisualObject3D, id: String = "threeCanvas", options: Canvas.() -> Unit = {}) {
|
fun RBuilder.threeCanvas(object3D: VisualObject3D, options: Canvas.() -> Unit = {}) {
|
||||||
child(ThreeCanvasComponent::class) {
|
child(ThreeCanvasComponent::class) {
|
||||||
attrs {
|
attrs {
|
||||||
this.obj = object3D
|
this.obj = object3D
|
||||||
this.canvasId = id
|
|
||||||
this.options = Canvas.invoke(options)
|
this.options = Canvas.invoke(options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package hep.dataforge.vis.spatial.three
|
|||||||
|
|
||||||
import hep.dataforge.vis.spatial.Label3D
|
import hep.dataforge.vis.spatial.Label3D
|
||||||
import hep.dataforge.vis.spatial.color
|
import hep.dataforge.vis.spatial.color
|
||||||
|
import hep.dataforge.vis.spatial.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
|
||||||
import info.laht.threekt.DoubleSide
|
import info.laht.threekt.DoubleSide
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.geometries.PlaneBufferGeometry
|
import info.laht.threekt.geometries.PlaneBufferGeometry
|
||||||
@ -51,6 +52,7 @@ object ThreeCanvasLabelFactory: ThreeFactory<Label3D> {
|
|||||||
|
|
||||||
mesh.updatePosition(obj)
|
mesh.updatePosition(obj)
|
||||||
|
|
||||||
|
mesh.userData[DO_NOT_HIGHLIGHT_TAG] = true
|
||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,11 +22,17 @@ object ThreeMaterials {
|
|||||||
color.set(DEFAULT_LINE_COLOR)
|
color.set(DEFAULT_LINE_COLOR)
|
||||||
}
|
}
|
||||||
|
|
||||||
val HIGHLIGHT_MATERIAL = LineBasicMaterial().apply {
|
val SELECTED_MATERIAL = LineBasicMaterial().apply {
|
||||||
color.set(Colors.ivory)
|
color.set(Colors.ivory)
|
||||||
linewidth = 8.0
|
linewidth = 8.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val HIGHLIGHT_MATERIAL = LineBasicMaterial().apply {
|
||||||
|
color.set(Colors.blue)
|
||||||
|
linewidth = 8.0
|
||||||
|
}
|
||||||
|
|
||||||
fun getLineMaterial(meta: Meta?): LineBasicMaterial {
|
fun getLineMaterial(meta: Meta?): LineBasicMaterial {
|
||||||
if (meta == null) return DEFAULT_LINE
|
if (meta == null) return DEFAULT_LINE
|
||||||
return LineBasicMaterial().apply {
|
return LineBasicMaterial().apply {
|
||||||
|
@ -1,19 +1,25 @@
|
|||||||
package hep.dataforge.vis.spatial.three
|
package hep.dataforge.vis.spatial.three
|
||||||
|
|
||||||
|
import hep.dataforge.js.accordion
|
||||||
|
import hep.dataforge.js.entry
|
||||||
import hep.dataforge.js.requireJS
|
import hep.dataforge.js.requireJS
|
||||||
import hep.dataforge.vis.editor.accordion
|
|
||||||
import hep.dataforge.vis.spatial.Visual3D
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.*
|
||||||
import kotlinx.html.TagConsumer
|
|
||||||
import kotlinx.html.button
|
|
||||||
import kotlinx.html.dom.append
|
import kotlinx.html.dom.append
|
||||||
import kotlinx.html.js.*
|
import kotlinx.html.js.onChangeFunction
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import org.w3c.files.Blob
|
import org.w3c.files.Blob
|
||||||
import org.w3c.files.BlobPropertyBag
|
import org.w3c.files.BlobPropertyBag
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.button
|
||||||
|
import react.dom.div
|
||||||
|
import react.dom.input
|
||||||
|
import react.dom.label
|
||||||
import kotlin.dom.clear
|
import kotlin.dom.clear
|
||||||
|
|
||||||
private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
|
private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
|
||||||
@ -25,6 +31,70 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
|
|||||||
fileSaver.saveAs(blob, fileName)
|
fileSaver.saveAs(blob, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun RBuilder.canvasControls(canvas: ThreeCanvas) = accordion("controls") {
|
||||||
|
entry("Settings") {
|
||||||
|
div("row") {
|
||||||
|
div("col-2") {
|
||||||
|
label("checkbox-inline") {
|
||||||
|
input(type = InputType.checkBox){
|
||||||
|
attrs {
|
||||||
|
defaultChecked = canvas.axes.visible
|
||||||
|
onChangeFunction = {
|
||||||
|
canvas.axes.visible = (it.target as HTMLInputElement).checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+"Axes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("col-1") {
|
||||||
|
button {
|
||||||
|
+"Export"
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
val json = (canvas.content as? VisualGroup3D)?.let { group ->
|
||||||
|
Visual3D.json.stringify(
|
||||||
|
VisualGroup3D.serializer(),
|
||||||
|
group
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (json != null) {
|
||||||
|
saveData(it, "object.json", "text/json") {
|
||||||
|
json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry("Layers") {
|
||||||
|
div("row") {
|
||||||
|
(0..11).forEach { layer ->
|
||||||
|
div("col-1") {
|
||||||
|
label { +layer.toString() }
|
||||||
|
input(type = InputType.checkBox){
|
||||||
|
attrs {
|
||||||
|
if (layer == 0) {
|
||||||
|
defaultChecked = true
|
||||||
|
}
|
||||||
|
onChangeFunction = {
|
||||||
|
if ((it.target as HTMLInputElement).checked) {
|
||||||
|
canvas.camera.layers.enable(layer)
|
||||||
|
} else {
|
||||||
|
canvas.camera.layers.disable(layer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
||||||
clear()
|
clear()
|
||||||
append {
|
append {
|
||||||
@ -33,7 +103,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
div("row") {
|
div("row") {
|
||||||
div("col-2") {
|
div("col-2") {
|
||||||
label("checkbox-inline") {
|
label("checkbox-inline") {
|
||||||
input(type = InputType.checkBox).apply {
|
input(type = InputType.checkBox) {
|
||||||
checked = canvas.axes.visible
|
checked = canvas.axes.visible
|
||||||
onChangeFunction = {
|
onChangeFunction = {
|
||||||
canvas.axes.visible = checked
|
canvas.axes.visible = checked
|
||||||
@ -67,7 +137,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
(0..11).forEach { layer ->
|
(0..11).forEach { layer ->
|
||||||
div("col-1") {
|
div("col-1") {
|
||||||
label { +layer.toString() }
|
label { +layer.toString() }
|
||||||
input(type = InputType.checkBox).apply {
|
input(type = InputType.checkBox) {
|
||||||
if (layer == 0) {
|
if (layer == 0) {
|
||||||
checked = true
|
checked = true
|
||||||
}
|
}
|
||||||
@ -84,61 +154,6 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* card("Settings") {
|
|
||||||
div("row") {
|
|
||||||
div("col-2") {
|
|
||||||
label("checkbox-inline") {
|
|
||||||
input(type = InputType.checkBox).apply {
|
|
||||||
checked = canvas.axes.visible
|
|
||||||
onChangeFunction = {
|
|
||||||
canvas.axes.visible = checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+"Axes"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div("col-1") {
|
|
||||||
button {
|
|
||||||
+"Export"
|
|
||||||
onClickFunction = {
|
|
||||||
val json = (canvas.content as? VisualGroup3D)?.let { group ->
|
|
||||||
Visual3D.json.stringify(
|
|
||||||
VisualGroup3D.serializer(),
|
|
||||||
group
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (json != null) {
|
|
||||||
saveData(it, "object.json", "text/json"){
|
|
||||||
json
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
card("Layers") {
|
|
||||||
div("row") {
|
|
||||||
(0..11).forEach { layer ->
|
|
||||||
div("col-1") {
|
|
||||||
label { +layer.toString() }
|
|
||||||
input(type = InputType.checkBox).apply {
|
|
||||||
if (layer == 0) {
|
|
||||||
checked = true
|
|
||||||
}
|
|
||||||
onChangeFunction = {
|
|
||||||
if (checked) {
|
|
||||||
canvas.camera.layers.enable(layer)
|
|
||||||
} else {
|
|
||||||
canvas.camera.layers.disable(layer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -153,7 +153,7 @@ open external class Object3D {
|
|||||||
* An object that can be used to store custom data about the Object3D.
|
* An object that can be used to store custom data about the Object3D.
|
||||||
* It should not hold references to functions as these will not be cloned.
|
* It should not hold references to functions as these will not be cloned.
|
||||||
*/
|
*/
|
||||||
var userData: Map<String, Any>
|
var userData: dynamic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional callback that is executed immediately before the Object3D is rendered.
|
* An optional callback that is executed immediately before the Object3D is rendered.
|
||||||
|
@ -7,14 +7,11 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.isEmpty
|
import hep.dataforge.names.isEmpty
|
||||||
import hep.dataforge.vis.VisualGroup
|
import hep.dataforge.vis.VisualGroup
|
||||||
import hep.dataforge.vis.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.editor.objectTree
|
import hep.dataforge.vis.editor.renderObjectTree
|
||||||
import hep.dataforge.vis.editor.visualPropertyEditor
|
import hep.dataforge.vis.editor.visualPropertyEditor
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY
|
|
||||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
|
||||||
import hep.dataforge.vis.spatial.gdml.GDMLTransformer
|
import hep.dataforge.vis.spatial.gdml.GDMLTransformer
|
||||||
import hep.dataforge.vis.spatial.gdml.LUnit
|
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||||
@ -160,37 +157,15 @@ private class GDMLDemoApp : Application {
|
|||||||
visual is VisualGroup -> visual[name] ?: return
|
visual is VisualGroup -> visual[name] ?: return
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
|
canvas.select(name)
|
||||||
editorElement.visualPropertyEditor(name, child) {
|
editorElement.visualPropertyEditor(name, child)
|
||||||
VISIBLE_KEY put true
|
|
||||||
if (child is VisualObject3D) {
|
|
||||||
MATERIAL_COLOR_KEY put "#ffffff"
|
|
||||||
MATERIAL_OPACITY_KEY put 1.0
|
|
||||||
MATERIAL_WIREFRAME_KEY put false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// editorElement.displayPropertyEditor(name, child) { item ->
|
|
||||||
// //val descriptorMeta = Material3D.descriptor
|
|
||||||
//
|
|
||||||
// val properties = item.allProperties()
|
|
||||||
// val bottom = Meta {
|
|
||||||
// VISIBLE_KEY put (item.visible ?: true)
|
|
||||||
// if (item is VisualObject3D) {
|
|
||||||
// MATERIAL_COLOR_KEY put "#ffffff"
|
|
||||||
// MATERIAL_OPACITY_KEY put 1.0
|
|
||||||
// MATERIAL_WIREFRAME_KEY put false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// properties.withBottom(bottom)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// canvas.clickListener = ::selectElement
|
// canvas.clickListener = ::selectElement
|
||||||
|
|
||||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||||
treeElement.objectTree(visual) { treeName ->
|
treeElement.renderObjectTree(visual) { treeName ->
|
||||||
selectElement(treeName)
|
selectElement(treeName)
|
||||||
canvas.highlight(treeName)
|
|
||||||
}
|
}
|
||||||
canvas.render(visual)
|
canvas.render(visual)
|
||||||
message(null)
|
message(null)
|
||||||
|
@ -72,3 +72,12 @@ application {
|
|||||||
//configure<JavaFXOptions> {
|
//configure<JavaFXOptions> {
|
||||||
// modules("javafx.controls")
|
// modules("javafx.controls")
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
val common = project(":dataforge-vis-common")
|
||||||
|
|
||||||
|
val copyJsResourcesFromCommon by tasks.creating(Copy::class){
|
||||||
|
from(common.buildDir.resolve("processedResources\\js\\main\\"))
|
||||||
|
into(buildDir.resolve("processedResources\\js\\main\\"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.getByPath("jsProcessResources").dependsOn(copyJsResourcesFromCommon)
|
@ -8,7 +8,7 @@ import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE
|
|||||||
/**
|
/**
|
||||||
* A single pixel
|
* A single pixel
|
||||||
*/
|
*/
|
||||||
open class SC1(
|
class SC1(
|
||||||
val name: String,
|
val name: String,
|
||||||
val center: Point3D,
|
val center: Point3D,
|
||||||
val xSize: Double = PIXEL_XY_SIZE, val ySize: Double = PIXEL_XY_SIZE, val zSize: Double = PIXEL_Z_SIZE
|
val xSize: Double = PIXEL_XY_SIZE, val ySize: Double = PIXEL_XY_SIZE, val zSize: Double = PIXEL_Z_SIZE
|
||||||
|
@ -0,0 +1,138 @@
|
|||||||
|
package ru.mipt.npm.muon.monitor
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.js.card
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.isEmpty
|
||||||
|
import hep.dataforge.vis.editor.objectTree
|
||||||
|
import hep.dataforge.vis.editor.visualPropertyEditor
|
||||||
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
|
import hep.dataforge.vis.spatial.specifications.Camera
|
||||||
|
import hep.dataforge.vis.spatial.specifications.Canvas
|
||||||
|
import hep.dataforge.vis.spatial.three.ThreeCanvas
|
||||||
|
import hep.dataforge.vis.spatial.three.ThreeCanvasComponent
|
||||||
|
import hep.dataforge.vis.spatial.three.canvasControls
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.features.json.JsonFeature
|
||||||
|
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import react.*
|
||||||
|
import react.dom.button
|
||||||
|
import react.dom.div
|
||||||
|
import kotlin.math.PI
|
||||||
|
|
||||||
|
interface MMAppProps : RProps {
|
||||||
|
var model: Model
|
||||||
|
var context: Context
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MMAppState : RState {
|
||||||
|
var model: Model
|
||||||
|
var selected: Name?
|
||||||
|
var canvas: ThreeCanvas?
|
||||||
|
}
|
||||||
|
|
||||||
|
class MMAppComponent : RComponent<MMAppProps, MMAppState>() {
|
||||||
|
|
||||||
|
private val model = Model()
|
||||||
|
|
||||||
|
private val connection = HttpClient {
|
||||||
|
install(JsonFeature) {
|
||||||
|
serializer = KotlinxSerializer(Json(context = Visual3D.serialModule))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun MMAppState.init(props: MMAppProps) {
|
||||||
|
this.model = props.model
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onSelect: (Name?) -> Unit = {
|
||||||
|
setState {
|
||||||
|
selected = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val canvasConfig = Canvas {
|
||||||
|
camera = Camera {
|
||||||
|
distance = 2100.0
|
||||||
|
latitude = PI / 6
|
||||||
|
azimuth = PI + PI / 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun RBuilder.render() {
|
||||||
|
val visual = model.root
|
||||||
|
val selected = state.selected
|
||||||
|
|
||||||
|
div("row") {
|
||||||
|
div("col-lg-3") {
|
||||||
|
//tree
|
||||||
|
card("Object tree") {
|
||||||
|
objectTree(visual, selected, onSelect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("col-lg-6") {
|
||||||
|
//canvas
|
||||||
|
child(ThreeCanvasComponent::class) {
|
||||||
|
attrs {
|
||||||
|
this.context = props.context
|
||||||
|
this.obj = visual
|
||||||
|
this.options = canvasConfig
|
||||||
|
this.selected = selected
|
||||||
|
this.clickCallback = onSelect
|
||||||
|
this.canvasCallback = {
|
||||||
|
setState{
|
||||||
|
canvas = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("col-lg-3") {
|
||||||
|
div("row") {
|
||||||
|
//settings
|
||||||
|
state.canvas?.let { canvasControls(it) }
|
||||||
|
card("Events") {
|
||||||
|
button {
|
||||||
|
+"Next"
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
GlobalScope.launch {
|
||||||
|
val event = connection.get<Event>("http://localhost:8080/event")
|
||||||
|
model.displayEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
+"Clear"
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
model.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("row") {
|
||||||
|
//properties
|
||||||
|
if (selected != null) {
|
||||||
|
val selectedObject = when {
|
||||||
|
selected.isEmpty() -> visual
|
||||||
|
else -> visual[selected]
|
||||||
|
}
|
||||||
|
if (selectedObject != null) {
|
||||||
|
//TODO replace by explicit breadcrumbs with callback
|
||||||
|
visualPropertyEditor(selected, selectedObject, descriptor = VisualObject3D.descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,31 +3,13 @@ package ru.mipt.npm.muon.monitor
|
|||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.js.Application
|
import hep.dataforge.js.Application
|
||||||
import hep.dataforge.js.startApplication
|
import hep.dataforge.js.startApplication
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import hep.dataforge.names.isEmpty
|
|
||||||
import hep.dataforge.vis.VisualGroup
|
|
||||||
import hep.dataforge.vis.VisualObject
|
|
||||||
import hep.dataforge.vis.editor.card
|
|
||||||
import hep.dataforge.vis.editor.objectTree
|
|
||||||
import hep.dataforge.vis.editor.visualPropertyEditor
|
|
||||||
import hep.dataforge.vis.spatial.Visual3D
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
|
||||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
|
||||||
import hep.dataforge.vis.spatial.three.displayCanvasControls
|
|
||||||
import hep.dataforge.vis.spatial.three.output
|
|
||||||
import info.laht.threekt.math.Vector3
|
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.features.json.JsonFeature
|
import io.ktor.client.features.json.JsonFeature
|
||||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||||
import io.ktor.client.request.get
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.html.js.button
|
|
||||||
import kotlinx.html.js.onClickFunction
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.w3c.dom.HTMLElement
|
import react.dom.render
|
||||||
import kotlin.browser.document
|
import kotlin.browser.document
|
||||||
import kotlin.dom.clear
|
|
||||||
|
|
||||||
private class MMDemoApp : Application {
|
private class MMDemoApp : Application {
|
||||||
|
|
||||||
@ -42,64 +24,80 @@ private class MMDemoApp : Application {
|
|||||||
override fun start(state: Map<String, Any>) {
|
override fun start(state: Map<String, Any>) {
|
||||||
|
|
||||||
val context = Global.context("demo") {}
|
val context = Global.context("demo") {}
|
||||||
val three = context.plugins.load(ThreePlugin)
|
// val three = context.plugins.load(ThreePlugin)
|
||||||
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
|
||||||
|
|
||||||
val canvasElement = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
|
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
|
||||||
val settingsElement = document.getElementById("settings")
|
|
||||||
?: error("Element with id 'settings' not found on page")
|
|
||||||
val treeElement = document.getElementById("tree") ?: error("Element with id 'tree' not found on page")
|
|
||||||
val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
|
|
||||||
|
|
||||||
canvasElement.clear()
|
render(element) {
|
||||||
val visual: VisualObject3D = model.root
|
child(MMAppComponent::class) {
|
||||||
|
attrs {
|
||||||
//output.camera.layers.enable(1)
|
this.model = model
|
||||||
val canvas = three.output(canvasElement as HTMLElement)
|
this.context = context
|
||||||
|
|
||||||
canvas.camera.layers.set(0)
|
|
||||||
canvas.camera.position.z = -2000.0
|
|
||||||
canvas.camera.position.y = 500.0
|
|
||||||
canvas.camera.lookAt(Vector3(0, 0, 0))
|
|
||||||
settingsElement.displayCanvasControls(canvas) {
|
|
||||||
card("Events") {
|
|
||||||
button {
|
|
||||||
+"Next"
|
|
||||||
onClickFunction = {
|
|
||||||
GlobalScope.launch {
|
|
||||||
val event = connection.get<Event>("http://localhost:8080/event")
|
|
||||||
model.displayEvent(event)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button {
|
// //val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||||
+"Clear"
|
//
|
||||||
onClickFunction = {
|
// val canvasElement = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
|
||||||
model.reset()
|
// val settingsElement = document.getElementById("settings")
|
||||||
}
|
// ?: error("Element with id 'settings' not found on page")
|
||||||
}
|
// val treeElement = document.getElementById("tree") ?: error("Element with id 'tree' not found on page")
|
||||||
}
|
// val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
|
||||||
}
|
//
|
||||||
|
// canvasElement.clear()
|
||||||
|
// val visual = model.root
|
||||||
fun selectElement(name: Name) {
|
//
|
||||||
val child: VisualObject = when {
|
// //output.camera.layers.enable(1)
|
||||||
name.isEmpty() -> visual
|
// val canvas = three.output(canvasElement as HTMLElement)
|
||||||
visual is VisualGroup -> visual[name] ?: return
|
//
|
||||||
else -> return
|
// canvas.camera.layers.set(0)
|
||||||
}
|
// canvas.camera.position.z = -2000.0
|
||||||
editorElement.visualPropertyEditor(name, child, descriptor = VisualObject3D.descriptor)
|
// canvas.camera.position.y = 500.0
|
||||||
|
// canvas.camera.lookAt(Vector3(0, 0, 0))
|
||||||
}
|
//
|
||||||
|
// settingsElement.displayCanvasControls(canvas) {
|
||||||
// canvas.clickListener = ::selectElement
|
// card("Events") {
|
||||||
|
// button {
|
||||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
// +"Next"
|
||||||
treeElement.objectTree(visual) { name ->
|
// onClickFunction = {
|
||||||
selectElement(name)
|
// GlobalScope.launch {
|
||||||
canvas.highlight(name)
|
// val event = connection.get<Event>("http://localhost:8080/event")
|
||||||
}
|
// model.displayEvent(event)
|
||||||
canvas.render(visual)
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// button {
|
||||||
|
// +"Clear"
|
||||||
|
// onClickFunction = {
|
||||||
|
// model.reset()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var objectTreeContainer: ObjectTreeContainer? = null
|
||||||
|
//
|
||||||
|
// fun selectElement(name: Name?) {
|
||||||
|
// if (name != null) {
|
||||||
|
// canvas.select(name)
|
||||||
|
// val child: VisualObject = when {
|
||||||
|
// name.isEmpty() -> visual
|
||||||
|
// visual is VisualGroup -> visual[name] ?: return
|
||||||
|
// else -> return
|
||||||
|
// }
|
||||||
|
// editorElement.visualPropertyEditor(name, child, descriptor = VisualObject3D.descriptor)
|
||||||
|
// objectTreeContainer?.select(name)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// val selectElementFunction: (Name?) -> Unit = { name ->
|
||||||
|
// selectElement(name?.selectable())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// canvas.onClick = selectElementFunction
|
||||||
|
//
|
||||||
|
// objectTreeContainer = treeElement.renderObjectTree(visual, selectElementFunction)
|
||||||
|
// canvas.render(visual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,40 +0,0 @@
|
|||||||
/* Remove default bullets */
|
|
||||||
ul, .tree {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style the caret/arrow */
|
|
||||||
.tree-caret {
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none; /* Prevent text selection */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the caret/arrow with a unicode, and style it */
|
|
||||||
.tree-caret::before {
|
|
||||||
content: "\25B6";
|
|
||||||
color: black;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-leaf{
|
|
||||||
user-select: none;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-leaf::before {
|
|
||||||
content: "\25C6";
|
|
||||||
color: black;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
|
|
||||||
.tree-caret-down::before {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-label-inactive {
|
|
||||||
color: gray;
|
|
||||||
}
|
|
@ -1,748 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="240"
|
|
||||||
height="144"
|
|
||||||
id="svg4136"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.91 r13725"
|
|
||||||
sodipodi:docname="jsoneditor-icons.svg">
|
|
||||||
<title
|
|
||||||
id="title6512">JSON Editor Icons</title>
|
|
||||||
<metadata
|
|
||||||
id="metadata4148">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title>JSON Editor Icons</dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<defs
|
|
||||||
id="defs4146" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ff63ff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1920"
|
|
||||||
inkscape:window-height="1026"
|
|
||||||
id="namedview4144"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="4"
|
|
||||||
inkscape:cx="13.229181"
|
|
||||||
inkscape:cy="119.82429"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg4136"
|
|
||||||
showguides="false"
|
|
||||||
borderlayer="false"
|
|
||||||
inkscape:showpageshadow="true"
|
|
||||||
showborder="true">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid4640"
|
|
||||||
empspacing="24" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
|
|
||||||
id="svg_1"
|
|
||||||
height="16"
|
|
||||||
width="16"
|
|
||||||
y="4"
|
|
||||||
x="4" />
|
|
||||||
<rect
|
|
||||||
id="svg_1-7"
|
|
||||||
height="16"
|
|
||||||
width="16"
|
|
||||||
y="3.999995"
|
|
||||||
x="28.000006"
|
|
||||||
style="fill:#ec3f29;fill-opacity:0.94117647;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
|
|
||||||
x="52.000004"
|
|
||||||
y="3.999995"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
id="rect4165" />
|
|
||||||
<rect
|
|
||||||
id="rect4175"
|
|
||||||
height="16"
|
|
||||||
width="16"
|
|
||||||
y="3.9999852"
|
|
||||||
x="172.00002"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4175-3"
|
|
||||||
height="16"
|
|
||||||
width="16"
|
|
||||||
y="3.999995"
|
|
||||||
x="196"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
|
|
||||||
<g
|
|
||||||
id="g4299"
|
|
||||||
style="stroke:none">
|
|
||||||
<rect
|
|
||||||
x="7.0000048"
|
|
||||||
y="10.999998"
|
|
||||||
width="9.9999924"
|
|
||||||
height="1.9999986"
|
|
||||||
id="svg_1-1"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
x="11.000005"
|
|
||||||
y="7.0000114"
|
|
||||||
width="1.9999955"
|
|
||||||
height="9.9999838"
|
|
||||||
id="svg_1-1-1"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g4299-3"
|
|
||||||
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,12.000001)"
|
|
||||||
style="stroke:none">
|
|
||||||
<rect
|
|
||||||
x="7.0000048"
|
|
||||||
y="10.999998"
|
|
||||||
width="9.9999924"
|
|
||||||
height="1.9999986"
|
|
||||||
id="svg_1-1-0"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
x="11.000005"
|
|
||||||
y="7.0000114"
|
|
||||||
width="1.9999955"
|
|
||||||
height="9.9999838"
|
|
||||||
id="svg_1-1-1-9"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0" />
|
|
||||||
</g>
|
|
||||||
<rect
|
|
||||||
id="svg_1-7-5"
|
|
||||||
height="6.9999905"
|
|
||||||
width="6.9999909"
|
|
||||||
y="7.0000048"
|
|
||||||
x="55.000004"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
x="58"
|
|
||||||
y="10.00001"
|
|
||||||
width="6.9999909"
|
|
||||||
height="6.9999905"
|
|
||||||
id="rect4354" />
|
|
||||||
<rect
|
|
||||||
id="svg_1-7-5-7"
|
|
||||||
height="6.9999905"
|
|
||||||
width="6.9999909"
|
|
||||||
y="10.000005"
|
|
||||||
x="58.000004"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#3c80df;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647" />
|
|
||||||
<g
|
|
||||||
id="g4378">
|
|
||||||
<rect
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
|
||||||
x="198"
|
|
||||||
y="10.999999"
|
|
||||||
width="7.9999909"
|
|
||||||
height="1.9999965"
|
|
||||||
id="svg_1-7-5-3" />
|
|
||||||
<rect
|
|
||||||
id="rect4374"
|
|
||||||
height="1.9999946"
|
|
||||||
width="11.999995"
|
|
||||||
y="7.0000005"
|
|
||||||
x="198"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4376"
|
|
||||||
height="1.9999995"
|
|
||||||
width="3.9999928"
|
|
||||||
y="14.999996"
|
|
||||||
x="198"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(1,0,0,-1,-23.999995,23.999995)"
|
|
||||||
id="g4383">
|
|
||||||
<rect
|
|
||||||
id="rect4385"
|
|
||||||
height="1.9999965"
|
|
||||||
width="7.9999909"
|
|
||||||
y="10.999999"
|
|
||||||
x="198"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
|
||||||
x="198"
|
|
||||||
y="7.0000005"
|
|
||||||
width="11.999995"
|
|
||||||
height="1.9999946"
|
|
||||||
id="rect4387" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
|
||||||
x="198"
|
|
||||||
y="14.999996"
|
|
||||||
width="3.9999928"
|
|
||||||
height="1.9999995"
|
|
||||||
id="rect4389" />
|
|
||||||
</g>
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none"
|
|
||||||
id="rect3754-4"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
x="76"
|
|
||||||
y="3.9999199" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 85.10447,6.0157384 -0.0156,1.4063 c 3.02669,-0.2402 0.33008,3.6507996 2.48438,4.5780996 -2.18694,1.0938 0.49191,4.9069 -2.45313,4.5781 l -0.0156,1.4219 c 5.70828,0.559 1.03264,-5.1005 4.70313,-5.2656 l 0,-1.4063 c -3.61303,-0.027 1.11893,-5.7069996 -4.70313,-5.3124996 z"
|
|
||||||
id="path4351"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 82.78125,5.9984384 0.0156,1.4063 c -3.02668,-0.2402 -0.33007,3.6506996 -2.48437,4.5780996 2.18694,1.0938 -0.49192,4.9069 2.45312,4.5781 l 0.0156,1.4219 c -5.70827,0.559 -1.03263,-5.1004 -4.70312,-5.2656 l 0,-1.4063 c 3.61303,-0.027 -1.11894,-5.7070996 4.70312,-5.3124996 z"
|
|
||||||
id="path4351-9"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none"
|
|
||||||
id="rect3754-25"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
x="100"
|
|
||||||
y="3.9999199" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
|
||||||
d="m 103.719,5.6719384 0,12.7187996 3.03125,0 0,-1.5313 -1.34375,0 0,-9.6249996 1.375,0 0,-1.5625 z"
|
|
||||||
id="path2987"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
|
||||||
d="m 112.2185,5.6721984 0,12.7187996 -3.03125,0 0,-1.5313 1.34375,0 0,-9.6249996 -1.375,0 0,-1.5625 z"
|
|
||||||
id="path2987-1"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none"
|
|
||||||
id="rect3754-73"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
x="124"
|
|
||||||
y="3.9999199" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
|
||||||
d="m 126.2824,17.602938 1.78957,0 1.14143,-2.8641 5.65364,0 1.14856,2.8641 1.76565,0 -4.78687,-11.1610996 -1.91903,0 z"
|
|
||||||
id="path3780"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none"
|
|
||||||
d="m 129.72704,13.478838 4.60852,0.01 -2.30426,-5.5497996 z"
|
|
||||||
id="path3782"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none"
|
|
||||||
id="rect3754-35"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
x="148"
|
|
||||||
y="3.9999199" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
|
||||||
d="m 156.47655,5.8917384 0,2.1797 0.46093,2.3983996 1.82813,0 0.39844,-2.3983996 0,-2.1797 z"
|
|
||||||
id="path5008-2"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
|
||||||
d="m 152.51561,5.8906384 0,2.1797 0.46094,2.3983996 1.82812,0 0.39844,-2.3983996 0,-2.1797 z"
|
|
||||||
id="path5008-2-8"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<rect
|
|
||||||
id="svg_1-7-2"
|
|
||||||
height="1.9999961"
|
|
||||||
width="11.999996"
|
|
||||||
y="64"
|
|
||||||
x="54"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="svg_1-7-2-2"
|
|
||||||
height="2.9999905"
|
|
||||||
width="2.9999907"
|
|
||||||
y="52"
|
|
||||||
x="80.000008"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
|
||||||
x="85.000008"
|
|
||||||
y="52"
|
|
||||||
width="2.9999907"
|
|
||||||
height="2.9999905"
|
|
||||||
id="rect4561" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
|
||||||
x="80.000008"
|
|
||||||
y="58"
|
|
||||||
width="2.9999907"
|
|
||||||
height="2.9999905"
|
|
||||||
id="rect4563" />
|
|
||||||
<rect
|
|
||||||
id="rect4565"
|
|
||||||
height="2.9999905"
|
|
||||||
width="2.9999907"
|
|
||||||
y="58"
|
|
||||||
x="85.000008"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4567"
|
|
||||||
height="2.9999905"
|
|
||||||
width="2.9999907"
|
|
||||||
y="64"
|
|
||||||
x="80.000008"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
|
||||||
x="85.000008"
|
|
||||||
y="64"
|
|
||||||
width="2.9999907"
|
|
||||||
height="2.9999905"
|
|
||||||
id="rect4569" />
|
|
||||||
<circle
|
|
||||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="path4571"
|
|
||||||
cx="110.06081"
|
|
||||||
cy="57.939209"
|
|
||||||
r="4.7438836" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
|
||||||
x="116.64566"
|
|
||||||
y="-31.79752"
|
|
||||||
width="4.229713"
|
|
||||||
height="6.4053884"
|
|
||||||
id="rect4563-2"
|
|
||||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
|
|
||||||
<path
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 125,56 138.77027,56.095 132,64 Z"
|
|
||||||
id="path4613"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccc" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4615"
|
|
||||||
d="M 149,64 162.77027,63.905 156,56 Z"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
|
||||||
x="54"
|
|
||||||
y="53"
|
|
||||||
width="11.999996"
|
|
||||||
height="1.9999961"
|
|
||||||
id="rect4638" />
|
|
||||||
<rect
|
|
||||||
id="svg_1-7-2-24"
|
|
||||||
height="1.9999957"
|
|
||||||
width="12.99999"
|
|
||||||
y="-56"
|
|
||||||
x="53"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
|
||||||
transform="matrix(0,1,-1,0,0,0)" />
|
|
||||||
<rect
|
|
||||||
transform="matrix(0,1,-1,0,0,0)"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
|
||||||
x="53"
|
|
||||||
y="-66"
|
|
||||||
width="12.99999"
|
|
||||||
height="1.9999957"
|
|
||||||
id="rect4657" />
|
|
||||||
<rect
|
|
||||||
id="rect4659"
|
|
||||||
height="0.99999291"
|
|
||||||
width="11.999999"
|
|
||||||
y="57"
|
|
||||||
x="54"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
|
||||||
x="54"
|
|
||||||
y="88.000122"
|
|
||||||
width="11.999996"
|
|
||||||
height="1.9999961"
|
|
||||||
id="rect4661" />
|
|
||||||
<rect
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
|
||||||
x="80.000008"
|
|
||||||
y="76.000122"
|
|
||||||
width="2.9999907"
|
|
||||||
height="2.9999905"
|
|
||||||
id="rect4663" />
|
|
||||||
<rect
|
|
||||||
id="rect4665"
|
|
||||||
height="2.9999905"
|
|
||||||
width="2.9999907"
|
|
||||||
y="76.000122"
|
|
||||||
x="85.000008"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
|
||||||
<rect
|
|
||||||
id="rect4667"
|
|
||||||
height="2.9999905"
|
|
||||||
width="2.9999907"
|
|
||||||
y="82.000122"
|
|
||||||
x="80.000008"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
|
||||||
<rect
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
|
||||||
x="85.000008"
|
|
||||||
y="82.000122"
|
|
||||||
width="2.9999907"
|
|
||||||
height="2.9999905"
|
|
||||||
id="rect4669" />
|
|
||||||
<rect
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
|
||||||
x="80.000008"
|
|
||||||
y="88.000122"
|
|
||||||
width="2.9999907"
|
|
||||||
height="2.9999905"
|
|
||||||
id="rect4671" />
|
|
||||||
<rect
|
|
||||||
id="rect4673"
|
|
||||||
height="2.9999905"
|
|
||||||
width="2.9999907"
|
|
||||||
y="88.000122"
|
|
||||||
x="85.000008"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
|
||||||
<circle
|
|
||||||
r="4.7438836"
|
|
||||||
cy="81.939331"
|
|
||||||
cx="110.06081"
|
|
||||||
id="circle4675"
|
|
||||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
|
||||||
<rect
|
|
||||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
|
|
||||||
id="rect4677"
|
|
||||||
height="6.4053884"
|
|
||||||
width="4.229713"
|
|
||||||
y="-14.826816"
|
|
||||||
x="133.6163"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-opacity:1" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4679"
|
|
||||||
d="m 125,80.000005 13.77027,0.09499 L 132,87.999992 Z"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
|
||||||
<path
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 149,88.0002 162.77027,87.9052 156,80.0002 Z"
|
|
||||||
id="path4681"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccc" />
|
|
||||||
<rect
|
|
||||||
id="rect4683"
|
|
||||||
height="1.9999961"
|
|
||||||
width="11.999996"
|
|
||||||
y="77.000122"
|
|
||||||
x="54"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
|
||||||
<rect
|
|
||||||
transform="matrix(0,1,-1,0,0,0)"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
|
||||||
x="77.000122"
|
|
||||||
y="-56"
|
|
||||||
width="12.99999"
|
|
||||||
height="1.9999957"
|
|
||||||
id="rect4685" />
|
|
||||||
<rect
|
|
||||||
id="rect4687"
|
|
||||||
height="1.9999957"
|
|
||||||
width="12.99999"
|
|
||||||
y="-66"
|
|
||||||
x="77.000122"
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
|
||||||
transform="matrix(0,1,-1,0,0,0)" />
|
|
||||||
<rect
|
|
||||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
|
||||||
x="54"
|
|
||||||
y="81.000122"
|
|
||||||
width="11.999999"
|
|
||||||
height="0.99999291"
|
|
||||||
id="rect4689" />
|
|
||||||
<rect
|
|
||||||
id="rect4761-1"
|
|
||||||
height="1.9999945"
|
|
||||||
width="15.99999"
|
|
||||||
y="101"
|
|
||||||
x="76.000008"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4761-0"
|
|
||||||
height="1.9999945"
|
|
||||||
width="15.99999"
|
|
||||||
y="105"
|
|
||||||
x="76.000008"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4761-7"
|
|
||||||
height="1.9999945"
|
|
||||||
width="9"
|
|
||||||
y="109"
|
|
||||||
x="76.000008"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4761-1-1"
|
|
||||||
height="1.9999945"
|
|
||||||
width="12"
|
|
||||||
y="125"
|
|
||||||
x="76.000008"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4761-1-1-4"
|
|
||||||
height="1.9999945"
|
|
||||||
width="10"
|
|
||||||
y="137"
|
|
||||||
x="76.000008"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4761-1-1-4-4"
|
|
||||||
height="1.9999945"
|
|
||||||
width="10"
|
|
||||||
y="129"
|
|
||||||
x="82"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:none;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
id="rect4761-1-1-4-4-3"
|
|
||||||
height="1.9999945"
|
|
||||||
width="9"
|
|
||||||
y="133"
|
|
||||||
x="82"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:none;stroke-width:0" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 36.398438,100.0254 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,100.5991 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1452 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533865,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550756,0 6.710442,-2.4113 7.650391,-5.9414 0.939949,-3.5301 -0.618463,-7.2736 -3.710938,-9.0703 -1.159678,-0.6738 -2.431087,-1.0231 -3.701171,-1.0625 z"
|
|
||||||
id="path4138" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 59.722656,99.9629 c -1.270084,0.039 -2.541493,0.3887 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5402 -3.710937,9.0703 0.939949,3.5301 4.09768,5.9414 7.648437,5.9414 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4056 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
|
|
||||||
id="path4138-1" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.96599996;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 10.5,100 0,2 -2.4999996,0 L 12,107 l 4,-5 -2.5,0 0,-2 -3,0 z"
|
|
||||||
id="path3055-0-77" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.96599996;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 4.9850574,108.015 14.0298856,-0.03"
|
|
||||||
id="path5244-5-0-5"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.96599996;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 4.9849874,132.015 14.0298866,-0.03"
|
|
||||||
id="path5244-5-0-5-8"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 36.398438,123.9629 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,124.5366 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1453 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533864,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550757,0 6.710442,-2.4093 7.650391,-5.9394 0.939949,-3.5301 -0.618463,-7.2756 -3.710938,-9.0723 -1.159678,-0.6737 -2.431087,-1.0231 -3.701171,-1.0625 z"
|
|
||||||
id="path4138-12" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 59.722656,123.9629 c -1.270084,0.039 -2.541493,0.3888 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5422 -3.710937,9.0723 0.939949,3.5301 4.09768,5.9394 7.648437,5.9394 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4055 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
|
|
||||||
id="path4138-1-3" />
|
|
||||||
<path
|
|
||||||
id="path6191"
|
|
||||||
d="m 10.5,116 0,-2 -2.4999996,0 L 12,109 l 4,5 -2.5,0 0,2 -3,0 z"
|
|
||||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.96599996;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.96599996;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 10.5,129 0,-2 -2.4999996,0 L 12,122 l 4,5 -2.5,0 0,2 -3,0 z"
|
|
||||||
id="path6193" />
|
|
||||||
<path
|
|
||||||
id="path6195"
|
|
||||||
d="m 10.5,135 0,2 -2.4999996,0 L 12,142 l 4,-5 -2.5,0 0,-2 -3,0 z"
|
|
||||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.96599996;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="star"
|
|
||||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="path4500"
|
|
||||||
sodipodi:sides="3"
|
|
||||||
sodipodi:cx="11.55581"
|
|
||||||
sodipodi:cy="60.073242"
|
|
||||||
sodipodi:r1="5.1116104"
|
|
||||||
sodipodi:r2="2.5558052"
|
|
||||||
sodipodi:arg1="0"
|
|
||||||
sodipodi:arg2="1.0471976"
|
|
||||||
inkscape:flatsided="false"
|
|
||||||
inkscape:rounded="0"
|
|
||||||
inkscape:randomized="0"
|
|
||||||
d="m 16.66742,60.073242 -3.833708,2.213392 -3.8337072,2.213393 0,-4.426785 0,-4.426784 3.8337082,2.213392 z"
|
|
||||||
inkscape:transform-center-x="-1.2779026" />
|
|
||||||
<path
|
|
||||||
inkscape:transform-center-x="1.277902"
|
|
||||||
d="m -31.500004,60.073242 -3.833708,2.213392 -3.833707,2.213393 0,-4.426785 0,-4.426784 3.833707,2.213392 z"
|
|
||||||
inkscape:randomized="0"
|
|
||||||
inkscape:rounded="0"
|
|
||||||
inkscape:flatsided="false"
|
|
||||||
sodipodi:arg2="1.0471976"
|
|
||||||
sodipodi:arg1="0"
|
|
||||||
sodipodi:r2="2.5558052"
|
|
||||||
sodipodi:r1="5.1116104"
|
|
||||||
sodipodi:cy="60.073242"
|
|
||||||
sodipodi:cx="-36.611614"
|
|
||||||
sodipodi:sides="3"
|
|
||||||
id="path4502"
|
|
||||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
sodipodi:type="star"
|
|
||||||
transform="scale(-1,1)" />
|
|
||||||
<path
|
|
||||||
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z"
|
|
||||||
inkscape:randomized="0"
|
|
||||||
inkscape:rounded="0"
|
|
||||||
inkscape:flatsided="false"
|
|
||||||
sodipodi:arg2="1.0471976"
|
|
||||||
sodipodi:arg1="0"
|
|
||||||
sodipodi:r2="2.5558052"
|
|
||||||
sodipodi:r1="5.1116104"
|
|
||||||
sodipodi:cy="60.073212"
|
|
||||||
sodipodi:cx="11.55581"
|
|
||||||
sodipodi:sides="3"
|
|
||||||
id="path4504"
|
|
||||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
sodipodi:type="star"
|
|
||||||
transform="matrix(0,1,-1,0,72.0074,71.7877)"
|
|
||||||
inkscape:transform-center-y="1.2779029" />
|
|
||||||
<path
|
|
||||||
inkscape:transform-center-y="-1.2779026"
|
|
||||||
transform="matrix(0,-1,-1,0,96,96)"
|
|
||||||
sodipodi:type="star"
|
|
||||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="path4506"
|
|
||||||
sodipodi:sides="3"
|
|
||||||
sodipodi:cx="11.55581"
|
|
||||||
sodipodi:cy="60.073212"
|
|
||||||
sodipodi:r1="5.1116104"
|
|
||||||
sodipodi:r2="2.5558052"
|
|
||||||
sodipodi:arg1="0"
|
|
||||||
sodipodi:arg2="1.0471976"
|
|
||||||
inkscape:flatsided="false"
|
|
||||||
inkscape:rounded="0"
|
|
||||||
inkscape:randomized="0"
|
|
||||||
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4615-5"
|
|
||||||
d="m 171.82574,65.174193 16.34854,0 -8.17427,-13.348454 z"
|
|
||||||
style="fill:#fbb917;fill-opacity:1;fill-rule:evenodd;stroke:#fbb917;stroke-width:1.65161395;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
|
||||||
<path
|
|
||||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="m 179,55 0,6 2,0 0,-6"
|
|
||||||
id="path4300"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="m 179,62 0,2 2,0 0,-2"
|
|
||||||
id="path4300-6"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:0.8"
|
|
||||||
d="M 99.994369,113.0221 102,114.98353 l 7,-6.9558 3,0.97227 2,-1 1,-2 0,-3 -3,3 -3,-3 3,-3 -3,0 -2,1 -1,2 0.99437,3.0221 z"
|
|
||||||
id="path4268"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccc" />
|
|
||||||
<rect
|
|
||||||
id="rect4175-3-5"
|
|
||||||
height="16"
|
|
||||||
width="16"
|
|
||||||
y="4"
|
|
||||||
x="220"
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="m 234,6 0,2 -5,5 0,5 -2,0 0,-5 -5,-5 0,-2"
|
|
||||||
id="path3546"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<g
|
|
||||||
transform="matrix(1.3333328,0,0,-1.5999992,-139.9999,127.19999)"
|
|
||||||
id="g4383-6">
|
|
||||||
<rect
|
|
||||||
id="rect4385-2"
|
|
||||||
height="1.2499905"
|
|
||||||
width="5.9999924"
|
|
||||||
y="12.625005"
|
|
||||||
x="198.00002"
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:#000000;stroke-width:0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:#000000;stroke-width:0"
|
|
||||||
x="198.00002"
|
|
||||||
y="15.125007"
|
|
||||||
width="7.4999928"
|
|
||||||
height="1.2499949"
|
|
||||||
id="rect4387-9" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:#000000;stroke-width:0"
|
|
||||||
x="198.00002"
|
|
||||||
y="7.6250024"
|
|
||||||
width="2.9999909"
|
|
||||||
height="1.2499905"
|
|
||||||
id="rect4389-1-0" />
|
|
||||||
<rect
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;stroke:#000000;stroke-width:0"
|
|
||||||
x="198.00002"
|
|
||||||
y="10.125004"
|
|
||||||
width="4.4999919"
|
|
||||||
height="1.2499905"
|
|
||||||
id="rect4389-1-9" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;fill-rule:evenodd;stroke:none;stroke-width:0.68465352px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="m 207.00001,16.375004 0,-5.625005 -2.25,0 3,-3.1250014 3,3.1250014 -2.25,0 0,5.625005 -1.5,0"
|
|
||||||
id="path4402"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff;fill-opacity:0.8;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="m 164,100 0,3 -6,6 0,7 -4,0 0,-7 -6,-6 0,-3"
|
|
||||||
id="path3546-2-2"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<rect
|
|
||||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
|
|
||||||
id="svg_1-3"
|
|
||||||
height="16"
|
|
||||||
width="16"
|
|
||||||
y="28"
|
|
||||||
x="4" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="ccccccccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4402-5-7"
|
|
||||||
d="m 15,41 0,-7 -4,0 0,3 -5,-4 5,-4 0,3 6,0 0,9"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.68465352px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 31 KiB |
@ -7,6 +7,8 @@
|
|||||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="css/main.css">
|
<link rel="stylesheet" href="css/main.css">
|
||||||
<script type="text/javascript" src="main.bundle.js"></script>
|
<script type="text/javascript" src="main.bundle.js"></script>
|
||||||
|
<script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script>
|
||||||
|
<script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="testApp">
|
<body class="testApp">
|
||||||
|
|
||||||
@ -15,7 +17,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div id="app"></div>
|
||||||
|
<!-- <div class="row">
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-3">
|
||||||
<div class="row" id="tree"></div>
|
<div class="row" id="tree"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -26,7 +29,7 @@
|
|||||||
<div class="row" id="settings"></div>
|
<div class="row" id="settings"></div>
|
||||||
<div class="row" id="editor"></div>
|
<div class="row" id="editor"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>-->
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user