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("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"))
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,10 +34,10 @@ class MetaViewerComponent : RComponent<MetaViewerProps, TreeState>() {
|
||||
override fun RBuilder.render() {
|
||||
div("d-inline-block text-truncate") {
|
||||
if (props.meta.items.isNotEmpty()) {
|
||||
span("objTree-caret") {
|
||||
span("tree-caret") {
|
||||
attrs {
|
||||
if (state.expanded) {
|
||||
classes += "objTree-caret-down"
|
||||
classes += "tree-caret-down"
|
||||
}
|
||||
onClickFunction = onClick
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package hep.dataforge.vis.editor
|
||||
|
||||
import hep.dataforge.js.card
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.vis.VisualGroup
|
||||
import hep.dataforge.vis.VisualObject
|
||||
import hep.dataforge.vis.isEmpty
|
||||
@ -14,6 +16,7 @@ import react.dom.*
|
||||
|
||||
interface ObjectTreeProps : RProps {
|
||||
var name: Name
|
||||
var selected: Name?
|
||||
var obj: VisualObject
|
||||
var clickCallback: (Name) -> Unit
|
||||
}
|
||||
@ -22,25 +25,39 @@ interface TreeState : RState {
|
||||
var expanded: Boolean
|
||||
}
|
||||
|
||||
class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
||||
class ObjectTree : RComponent<ObjectTreeProps, TreeState>() {
|
||||
|
||||
override fun TreeState.init() {
|
||||
expanded = false
|
||||
override fun TreeState.init(props: ObjectTreeProps) {
|
||||
expanded = props.selected?.startsWith(props.name) ?: false
|
||||
}
|
||||
|
||||
|
||||
private val onClick: (Event) -> Unit = {
|
||||
setState {
|
||||
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() {
|
||||
val token = props.name.last()?.toString() ?: "World"
|
||||
val obj = props.obj
|
||||
|
||||
//display as node if any child is visible
|
||||
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
||||
if (obj is VisualGroup) {
|
||||
div("d-inline-block text-truncate") {
|
||||
if (obj.children.any { !it.key.body.startsWith("@") }) {
|
||||
span("tree-caret") {
|
||||
attrs {
|
||||
if (state.expanded) {
|
||||
@ -49,12 +66,8 @@ class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
||||
onClickFunction = onClick
|
||||
}
|
||||
}
|
||||
a("#",classes = "tree-label") {
|
||||
+token
|
||||
attrs {
|
||||
onClickFunction = { props.clickCallback(props.name) }
|
||||
}
|
||||
}
|
||||
treeLabel(token)
|
||||
}
|
||||
if (state.expanded) {
|
||||
ul("tree") {
|
||||
@ -63,10 +76,11 @@ class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
||||
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
||||
.forEach { (childToken, child) ->
|
||||
li("tree-item") {
|
||||
child(ObjectTreeComponent::class) {
|
||||
child(ObjectTree::class) {
|
||||
attrs {
|
||||
name = props.name + childToken
|
||||
this.obj = child
|
||||
this.selected = props.selected
|
||||
clickCallback = props.clickCallback
|
||||
}
|
||||
}
|
||||
@ -77,35 +91,40 @@ class ObjectTreeComponent : RComponent<ObjectTreeProps, TreeState>() {
|
||||
} else {
|
||||
div("d-inline-block text-truncate") {
|
||||
span("tree-leaf") {}
|
||||
a("#",classes = "tree-label") {
|
||||
+token
|
||||
treeLabel(token)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Element.renderObjectTree(
|
||||
visualObject: VisualObject,
|
||||
clickCallback: (Name) -> Unit = {}
|
||||
) = render(this){
|
||||
card("Object tree") {
|
||||
child(ObjectTree::class) {
|
||||
attrs {
|
||||
onClickFunction = { props.clickCallback(props.name) }
|
||||
}
|
||||
}
|
||||
this.name = Name.EMPTY
|
||||
this.obj = visualObject
|
||||
this.selected = null
|
||||
this.clickCallback = clickCallback
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun RBuilder.objectTree(
|
||||
obj: VisualObject,
|
||||
visualObject: VisualObject,
|
||||
selected: Name? = null,
|
||||
clickCallback: (Name) -> Unit = {}
|
||||
) = card("Object tree") {
|
||||
child(ObjectTreeComponent::class) {
|
||||
){
|
||||
child(ObjectTree::class) {
|
||||
attrs {
|
||||
name = Name.EMPTY
|
||||
this.obj = obj
|
||||
this.name = Name.EMPTY
|
||||
this.obj = visualObject
|
||||
this.selected = selected
|
||||
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
|
||||
|
||||
import hep.dataforge.js.card
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
@ -8,77 +9,20 @@ import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.vis.VisualObject
|
||||
import org.w3c.dom.Element
|
||||
import react.RBuilder
|
||||
import react.ReactElement
|
||||
import react.dom.li
|
||||
import react.dom.nav
|
||||
import react.dom.ol
|
||||
import react.dom.render
|
||||
import kotlin.collections.set
|
||||
|
||||
////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(
|
||||
path: Name,
|
||||
item: VisualObject,
|
||||
descriptor: NodeDescriptor? = item.descriptor,
|
||||
title: String = "Properties",
|
||||
default: MetaBuilder.() -> Unit = {}
|
||||
): ReactElement = card(title) {
|
||||
) {
|
||||
card(title) {
|
||||
if (!path.isEmpty()) {
|
||||
nav {
|
||||
attrs {
|
||||
@ -94,6 +38,7 @@ fun RBuilder.visualPropertyEditor(
|
||||
}
|
||||
}
|
||||
configEditor(item, descriptor, Meta(default))
|
||||
}
|
||||
}
|
||||
|
||||
fun Element.visualPropertyEditor(
|
||||
|
@ -38,3 +38,7 @@ ul, .tree {
|
||||
.tree-label-inactive {
|
||||
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()
|
||||
|
||||
kotlin {
|
||||
js {
|
||||
useCommonJs()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
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.Controls
|
||||
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.cameras.PerspectiveCamera
|
||||
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.geometries.EdgesGeometry
|
||||
import info.laht.threekt.helpers.AxesHelper
|
||||
import info.laht.threekt.materials.LineBasicMaterial
|
||||
import info.laht.threekt.math.Vector2
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
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 mousePosition: Vector2 = Vector2()
|
||||
|
||||
var clickListener: ((Name) -> Unit)? = null
|
||||
var onClick: ((Name?) -> Unit)? = null
|
||||
|
||||
val axes = AxesHelper(canvas.axes.size.toInt()).apply {
|
||||
visible = canvas.axes.visible
|
||||
@ -63,6 +65,8 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
||||
|
||||
val camera = buildCamera(canvas.camera)
|
||||
|
||||
private var picked: Object3D? = null
|
||||
|
||||
init {
|
||||
element.clear()
|
||||
|
||||
@ -75,29 +79,26 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
||||
}
|
||||
}, false)
|
||||
|
||||
element.addEventListener("mousedown", { event ->
|
||||
val mesh = pick()
|
||||
if (mesh != null) {
|
||||
val name = mesh.fullName()
|
||||
clickListener?.invoke(name)
|
||||
}
|
||||
element.addEventListener("mousedown", {
|
||||
val picked = pick()
|
||||
onClick?.invoke(picked?.fullName())
|
||||
}, false)
|
||||
|
||||
camera.aspect = 1.0
|
||||
|
||||
val renderer = WebGLRenderer { antialias = true }.apply {
|
||||
setClearColor(Colors.skyblue, 1)
|
||||
|
||||
}
|
||||
|
||||
addControls(renderer.domElement, canvas.controls)
|
||||
|
||||
fun animate() {
|
||||
val mesh = pick()
|
||||
val picked = pick()
|
||||
|
||||
if (mesh != null && highlighted != mesh) {
|
||||
highlighted?.toggleHighlight(false)
|
||||
mesh.toggleHighlight(true)
|
||||
if (picked != null && this.picked != picked) {
|
||||
this.picked?.toggleHighlight(false,HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||
picked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||
this.picked = picked
|
||||
}
|
||||
|
||||
window.requestAnimationFrame {
|
||||
@ -118,18 +119,6 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
||||
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
|
||||
*/
|
||||
@ -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(
|
||||
spec.fov,
|
||||
1.0,
|
||||
@ -173,42 +181,61 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canv
|
||||
root = object3D
|
||||
}
|
||||
|
||||
private var highlighted: Mesh? = null
|
||||
private var highlighted: Object3D? = null
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
val edges = LineSegments(
|
||||
EdgesGeometry(geometry as BufferGeometry),
|
||||
HIGHLIGHT_MATERIAL
|
||||
material
|
||||
).apply {
|
||||
name = "@highlight"
|
||||
name = edgesName
|
||||
}
|
||||
add(edges)
|
||||
highlighted = this
|
||||
} else {
|
||||
val highlightEdges = children.find { it.name == "@highlight" }
|
||||
val highlightEdges = children.find { it.name == edgesName }
|
||||
highlightEdges?.let { remove(it) }
|
||||
}
|
||||
} else {
|
||||
children.filter { it.name != edgesName }.forEach {
|
||||
it.toggleHighlight(highlight, edgesName, material)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle highlight for element with given name
|
||||
*/
|
||||
fun highlight(name: Name?) {
|
||||
fun select(name: Name?) {
|
||||
if (name == null) {
|
||||
highlighted?.toggleHighlight(false)
|
||||
highlighted?.toggleHighlight(false, SELECT_NAME, SELECTED_MATERIAL)
|
||||
highlighted = null
|
||||
return
|
||||
}
|
||||
val mesh = root?.findChild(name) as? Mesh
|
||||
if (mesh != null && highlighted != mesh) {
|
||||
highlighted?.toggleHighlight(false)
|
||||
mesh.toggleHighlight(true)
|
||||
val obj = root?.findChild(name)
|
||||
if (obj != null && highlighted != obj) {
|
||||
highlighted?.toggleHighlight(false, SELECT_NAME, SELECTED_MATERIAL)
|
||||
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 =
|
||||
@ -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 =
|
||||
output(element, spec).render(obj)
|
||||
|
||||
|
@ -1,55 +1,73 @@
|
||||
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.specifications.Canvas
|
||||
import kotlinx.html.id
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.HTMLElement
|
||||
import react.RBuilder
|
||||
import react.RComponent
|
||||
import react.RProps
|
||||
import react.RState
|
||||
import react.dom.div
|
||||
import kotlin.browser.document
|
||||
import react.dom.findDOMNode
|
||||
import kotlin.dom.clear
|
||||
|
||||
interface ThreeCanvasProps : RProps {
|
||||
var context: Context
|
||||
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() {
|
||||
val element = document.getElementById(props.canvasId) as? HTMLElement
|
||||
?: error("Element with id 'canvas' not found on page")
|
||||
val output = three.output(element, props.options)
|
||||
output.render(props.obj)
|
||||
val element = state.element as? HTMLElement ?: error("Canvas element not found")
|
||||
val three: ThreePlugin = props.context.plugins.load(ThreePlugin)
|
||||
canvas = three.output(element, props.options ?: Canvas.empty())
|
||||
props.canvasCallback?.invoke(canvas)
|
||||
canvas?.render(props.obj)
|
||||
canvas?.onClick = props.clickCallback
|
||||
}
|
||||
|
||||
override fun componentWillUnmount() {
|
||||
val element = document.getElementById(props.canvasId) as? HTMLElement
|
||||
?: error("Element with id 'canvas' not found on page")
|
||||
element.clear()
|
||||
state.element?.clear()
|
||||
props.canvasCallback?.invoke(null)
|
||||
}
|
||||
|
||||
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() {
|
||||
div {
|
||||
attrs {
|
||||
id = props.canvasId
|
||||
ref {
|
||||
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) {
|
||||
attrs {
|
||||
this.obj = object3D
|
||||
this.canvasId = id
|
||||
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.color
|
||||
import hep.dataforge.vis.spatial.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
|
||||
import info.laht.threekt.DoubleSide
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.PlaneBufferGeometry
|
||||
@ -18,7 +19,7 @@ import kotlin.reflect.KClass
|
||||
/**
|
||||
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
||||
*/
|
||||
object ThreeCanvasLabelFactory: ThreeFactory<Label3D> {
|
||||
object ThreeCanvasLabelFactory : ThreeFactory<Label3D> {
|
||||
override val type: KClass<in Label3D> get() = Label3D::class
|
||||
|
||||
override fun invoke(obj: Label3D): Object3D {
|
||||
@ -31,7 +32,7 @@ object ThreeCanvasLabelFactory: ThreeFactory<Label3D> {
|
||||
//canvas.width = metrics.width.toInt()
|
||||
|
||||
|
||||
context.fillText(obj.text, (canvas.width - metrics.width)/2, 0.5*canvas.height)
|
||||
context.fillText(obj.text, (canvas.width - metrics.width) / 2, 0.5 * canvas.height)
|
||||
|
||||
|
||||
// canvas contents will be used for a texture
|
||||
@ -51,6 +52,7 @@ object ThreeCanvasLabelFactory: ThreeFactory<Label3D> {
|
||||
|
||||
mesh.updatePosition(obj)
|
||||
|
||||
mesh.userData[DO_NOT_HIGHLIGHT_TAG] = true
|
||||
return mesh
|
||||
}
|
||||
}
|
@ -22,11 +22,17 @@ object ThreeMaterials {
|
||||
color.set(DEFAULT_LINE_COLOR)
|
||||
}
|
||||
|
||||
val HIGHLIGHT_MATERIAL = LineBasicMaterial().apply {
|
||||
val SELECTED_MATERIAL = LineBasicMaterial().apply {
|
||||
color.set(Colors.ivory)
|
||||
linewidth = 8.0
|
||||
}
|
||||
|
||||
|
||||
val HIGHLIGHT_MATERIAL = LineBasicMaterial().apply {
|
||||
color.set(Colors.blue)
|
||||
linewidth = 8.0
|
||||
}
|
||||
|
||||
fun getLineMaterial(meta: Meta?): LineBasicMaterial {
|
||||
if (meta == null) return DEFAULT_LINE
|
||||
return LineBasicMaterial().apply {
|
||||
|
@ -1,19 +1,25 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.js.accordion
|
||||
import hep.dataforge.js.entry
|
||||
import hep.dataforge.js.requireJS
|
||||
import hep.dataforge.vis.editor.accordion
|
||||
import hep.dataforge.vis.spatial.Visual3D
|
||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.TagConsumer
|
||||
import kotlinx.html.button
|
||||
import kotlinx.html.*
|
||||
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.HTMLElement
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.events.Event
|
||||
import org.w3c.files.Blob
|
||||
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
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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 = {}) {
|
||||
clear()
|
||||
append {
|
||||
@ -33,7 +103,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
||||
div("row") {
|
||||
div("col-2") {
|
||||
label("checkbox-inline") {
|
||||
input(type = InputType.checkBox).apply {
|
||||
input(type = InputType.checkBox) {
|
||||
checked = canvas.axes.visible
|
||||
onChangeFunction = {
|
||||
canvas.axes.visible = checked
|
||||
@ -67,7 +137,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
||||
(0..11).forEach { layer ->
|
||||
div("col-1") {
|
||||
label { +layer.toString() }
|
||||
input(type = InputType.checkBox).apply {
|
||||
input(type = InputType.checkBox) {
|
||||
if (layer == 0) {
|
||||
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()
|
||||
}
|
||||
}
|
@ -153,7 +153,7 @@ open external class 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.
|
||||
*/
|
||||
var userData: Map<String, Any>
|
||||
var userData: dynamic
|
||||
|
||||
/**
|
||||
* 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.vis.VisualGroup
|
||||
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.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY
|
||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||
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.LUnit
|
||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||
@ -160,37 +157,15 @@ private class GDMLDemoApp : Application {
|
||||
visual is VisualGroup -> visual[name] ?: return
|
||||
else -> return
|
||||
}
|
||||
|
||||
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.select(name)
|
||||
editorElement.visualPropertyEditor(name, child)
|
||||
}
|
||||
|
||||
// canvas.clickListener = ::selectElement
|
||||
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(visual) { treeName ->
|
||||
treeElement.renderObjectTree(visual) { treeName ->
|
||||
selectElement(treeName)
|
||||
canvas.highlight(treeName)
|
||||
}
|
||||
canvas.render(visual)
|
||||
message(null)
|
||||
|
@ -72,3 +72,12 @@ application {
|
||||
//configure<JavaFXOptions> {
|
||||
// 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
|
||||
*/
|
||||
open class SC1(
|
||||
class SC1(
|
||||
val name: String,
|
||||
val center: Point3D,
|
||||
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.js.Application
|
||||
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.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.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.button
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.w3c.dom.HTMLElement
|
||||
import react.dom.render
|
||||
import kotlin.browser.document
|
||||
import kotlin.dom.clear
|
||||
|
||||
private class MMDemoApp : Application {
|
||||
|
||||
@ -42,64 +24,80 @@ private class MMDemoApp : Application {
|
||||
override fun start(state: Map<String, Any>) {
|
||||
|
||||
val context = Global.context("demo") {}
|
||||
val three = context.plugins.load(ThreePlugin)
|
||||
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||
// val three = context.plugins.load(ThreePlugin)
|
||||
|
||||
val canvasElement = document.getElementById("canvas") ?: error("Element with id 'canvas' 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")
|
||||
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
|
||||
|
||||
canvasElement.clear()
|
||||
val visual: VisualObject3D = model.root
|
||||
|
||||
//output.camera.layers.enable(1)
|
||||
val canvas = three.output(canvasElement as HTMLElement)
|
||||
|
||||
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)
|
||||
render(element) {
|
||||
child(MMAppComponent::class) {
|
||||
attrs {
|
||||
this.model = model
|
||||
this.context = context
|
||||
}
|
||||
}
|
||||
}
|
||||
button {
|
||||
+"Clear"
|
||||
onClickFunction = {
|
||||
model.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun selectElement(name: Name) {
|
||||
val child: VisualObject = when {
|
||||
name.isEmpty() -> visual
|
||||
visual is VisualGroup -> visual[name] ?: return
|
||||
else -> return
|
||||
}
|
||||
editorElement.visualPropertyEditor(name, child, descriptor = VisualObject3D.descriptor)
|
||||
|
||||
}
|
||||
|
||||
// canvas.clickListener = ::selectElement
|
||||
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(visual) { name ->
|
||||
selectElement(name)
|
||||
canvas.highlight(name)
|
||||
}
|
||||
canvas.render(visual)
|
||||
// //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 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
|
||||
//
|
||||
// //output.camera.layers.enable(1)
|
||||
// val canvas = three.output(canvasElement as HTMLElement)
|
||||
//
|
||||
// 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 {
|
||||
// +"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/main.css">
|
||||
<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>
|
||||
<body class="testApp">
|
||||
|
||||
@ -15,7 +17,8 @@
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div id="app"></div>
|
||||
<!-- <div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="row" id="tree"></div>
|
||||
</div>
|
||||
@ -26,7 +29,7 @@
|
||||
<div class="row" id="settings"></div>
|
||||
<div class="row" id="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user