Compare commits

..

No commits in common. "9c1246fb26d7fa052b95a05f8bfc81ec7a2e6d98" and "1ebeefe01c567be26df87405a19bc24060d8313f" have entirely different histories.

249 changed files with 370 additions and 354 deletions

View File

@ -1,4 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile
import space.kscience.gradle.isInDevelopment
import space.kscience.gradle.useApache2Licence import space.kscience.gradle.useApache2Licence
import space.kscience.gradle.useSPCTeam import space.kscience.gradle.useSPCTeam
@ -7,7 +8,7 @@ plugins {
// id("org.jetbrains.kotlinx.kover") version "0.5.0" // id("org.jetbrains.kotlinx.kover") version "0.5.0"
} }
val dataforgeVersion by extra("0.6.2") val dataforgeVersion by extra("0.6.1")
val fxVersion by extra("11") val fxVersion by extra("11")
allprojects { allprojects {
@ -44,7 +45,14 @@ ksciencePublish {
useApache2Licence() useApache2Licence()
useSPCTeam() useSPCTeam()
} }
repository("spc","https://maven.sciprog.center/kscience") github(githubProject = "visionforge", githubOrg = "SciProgCentre")
space(
if (isInDevelopment) {
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
} else {
"https://maven.pkg.jetbrains.space/spc/p/sci/maven"
}
)
sonatype() sonatype()
} }

View File

@ -2,8 +2,6 @@ plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.mpp")
} }
group = "demo"
kscience { kscience {
jvm() jvm()
js { js {

View File

@ -9,38 +9,30 @@ import react.Component
import react.Props import react.Props
import react.State import react.State
sealed external class DropEffects { external enum class DropEffects {
@JsName("copy") copy,
object Copy : DropEffects move,
link,
@JsName("move") none
object Move : DropEffects
@JsName("link")
object Link : DropEffects
@JsName("none")
object None : DropEffects
} }
external interface FileDropProps : Props { external interface FileDropProps: Props {
var className: String? var className: String?
var targetClassName: String? var targetClassName: String?
var draggingOverFrameClassName: String? var draggingOverFrameClassName: String?
var draggingOverTargetClassName: String? var draggingOverTargetClassName: String?
// var frame?: Exclude<HTMLElementTagNameMap[keyof HTMLElementTagNameMap], HTMLElement> | HTMLDocument; // var frame?: Exclude<HTMLElementTagNameMap[keyof HTMLElementTagNameMap], HTMLElement> | HTMLDocument;
var onFrameDragEnter: ((event: DragEvent) -> Unit)? var onFrameDragEnter: ((event: DragEvent) -> Unit)?
var onFrameDragLeave: ((event: DragEvent) -> Unit)? var onFrameDragLeave: ((event: DragEvent) -> Unit)?
var onFrameDrop: ((event: DragEvent) -> Unit)? var onFrameDrop: ((event: DragEvent) -> Unit)?
// var onDragOver: ReactDragEventHandler<HTMLDivElement>?
// var onDragOver: ReactDragEventHandler<HTMLDivElement>?
// var onDragLeave: ReactDragEventHandler<HTMLDivElement>? // var onDragLeave: ReactDragEventHandler<HTMLDivElement>?
var onDrop: ((files: FileList?, event: dynamic) -> Unit)?//event:DragEvent<HTMLDivElement>) var onDrop: ((files: FileList?, event: dynamic) -> Unit)?//event:DragEvent<HTMLDivElement>)
var dropEffect: DropEffects? var dropEffect: DropEffects?
} }
external interface FileDropState : State { external interface FileDropState: State {
var draggingOverFrame: Boolean var draggingOverFrame: Boolean
var draggingOverTarget: Boolean var draggingOverTarget: Boolean
} }

View File

@ -2,6 +2,7 @@ package space.kscience.visionforge.gdml.demo
import drop.FileDrop import drop.FileDrop
import kotlinx.css.* import kotlinx.css.*
import kotlinx.css.properties.border
import org.w3c.files.FileList import org.w3c.files.FileList
import react.RBuilder import react.RBuilder
import styled.css import styled.css
@ -12,7 +13,7 @@ import styled.styledDiv
fun RBuilder.fileDrop(title: String, action: (files: FileList?) -> Unit) { fun RBuilder.fileDrop(title: String, action: (files: FileList?) -> Unit) {
styledDiv { styledDiv {
css { css {
border = Border(style = BorderStyle.dashed, width = 1.px, color = Color.orange) border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
flexGrow = 0.0 flexGrow = 0.0
alignContent = Align.center alignContent = Align.center
} }

View File

@ -1,19 +1,19 @@
plugins { plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.js")
} }
kscience { kscience{
useCoroutines() useCoroutines()
} }
kotlin { kotlin{
explicitApi = null explicitApi = null
js { js{
useCommonJs() useCommonJs()
browser { browser {
binaries.executable() binaries.executable()
commonWebpackConfig { commonWebpackConfig {
cssSupport { cssSupport{
enabled.set(false) enabled.set(false)
} }
} }
@ -21,15 +21,11 @@ kotlin {
} }
} }
kscience {
dependencies { dependencies{
implementation(projects.visionforge.visionforgeGdml) implementation(projects.visionforge.visionforgeGdml)
implementation(projects.visionforge.visionforgePlotly) implementation(projects.visionforge.visionforgePlotly)
implementation(projects.visionforge.visionforgeMarkdown) implementation(projects.visionforge.visionforgeMarkdown)
implementation(projects.visionforge.visionforgeThreejs) implementation(projects.visionforge.visionforgeThreejs)
}
jsMain {
implementation(projects.ui.ring) implementation(projects.ui.ring)
}
} }

View File

@ -8,7 +8,7 @@ import space.kscience.plotly.models.Trace
import space.kscience.plotly.scatter import space.kscience.plotly.scatter
import space.kscience.visionforge.Application import space.kscience.visionforge.Application
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
import space.kscience.visionforge.JsVisionClient import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.react.createRoot import space.kscience.visionforge.react.createRoot
import space.kscience.visionforge.react.render import space.kscience.visionforge.react.render
@ -34,7 +34,7 @@ private class JsPlaygroundApp : Application {
val playgroundContext = Context { val playgroundContext = Context {
plugin(ThreeWithControlsPlugin) plugin(ThreeWithControlsPlugin)
plugin(JsVisionClient) plugin(VisionClient)
plugin(PlotlyPlugin) plugin(PlotlyPlugin)
} }
@ -43,8 +43,8 @@ private class JsPlaygroundApp : Application {
createRoot(element).render { createRoot(element).render {
styledDiv { styledDiv {
css { css {
padding = Padding(0.pt) padding(0.pt)
margin = Margin(0.pt) margin(0.pt)
height = 100.vh height = 100.vh
width = 100.vw width = 100.vw
} }

View File

@ -1,4 +1,5 @@
import kotlinx.css.* import kotlinx.css.*
import kotlinx.css.properties.border
import kotlinx.dom.clear import kotlinx.dom.clear
import kotlinx.html.dom.append import kotlinx.html.dom.append
import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
@ -44,10 +45,10 @@ val Markup = fc<MarkupProps>("Markup") { props ->
css { css {
width = 100.pct width = 100.pct
height = 100.pct height = 100.pct
border= Border(2.pt, BorderStyle.solid, Color.blue) border(2.pt, BorderStyle.solid, Color.blue)
padding = Padding(left = 8.pt) padding(left = 8.pt)
backgroundColor = Color.white backgroundColor = Color.white
flex = Flex(1.0) flex(1.0)
zIndex = 10000 zIndex = 10000
} }
ref = elementRef ref = elementRef

View File

@ -1,4 +1,5 @@
import kotlinx.css.* import kotlinx.css.*
import kotlinx.css.properties.border
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import react.* import react.*
@ -29,8 +30,8 @@ val Plotly = fc<PlotlyProps>("Plotly") { props ->
css { css {
width = 100.pct width = 100.pct
height = 100.pct height = 100.pct
border = Border(2.pt, BorderStyle.solid, Color.blue) border(2.pt, BorderStyle.solid, Color.blue)
flex = Flex(1.0) flex(1.0)
} }
ref = elementRef ref = elementRef
} }

View File

@ -13,7 +13,6 @@ kscience {
useKtor() useKtor()
fullStack( fullStack(
"muon-monitor.js", "muon-monitor.js",
development = true,
jvmConfig = { withJava() }, jvmConfig = { withJava() },
jsConfig = { useCommonJs() } jsConfig = { useCommonJs() }
) { ) {
@ -35,8 +34,8 @@ kscience {
implementation("ch.qos.logback:logback-classic:1.2.11") implementation("ch.qos.logback:logback-classic:1.2.11")
} }
jsMain { jsMain {
implementation(projects.ui.ring) implementation(project(":ui:ring"))
implementation(projects.visionforgeThreejs) implementation(project(":visionforge-threejs"))
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0")) //implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
} }
} }

View File

@ -3,7 +3,6 @@ package ru.mipt.npm.muon.monitor
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
import space.kscience.dataforge.names.asName
import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionManager import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.setAsRoot import space.kscience.visionforge.setAsRoot
@ -35,7 +34,7 @@ class Model(val manager: VisionManager) {
} }
} }
val tracks: SolidGroup = SolidGroup() var tracks: SolidGroup
val root: SolidGroup = SolidGroup().apply { val root: SolidGroup = SolidGroup().apply {
setAsRoot(this@Model.manager) setAsRoot(this@Model.manager)
@ -60,8 +59,7 @@ class Model(val manager: VisionManager) {
detector(it) detector(it)
} }
} }
tracks = solidGroup("tracks")
setChild("tracks".asName(), tracks)
} }
private fun highlight(pixel: String) { private fun highlight(pixel: String) {

View File

@ -17,7 +17,7 @@ kotlin {
useCommonJs() useCommonJs()
browser { browser {
webpackTask { webpackTask {
mainOutputFileName.set("js/visionforge-playground.js") outputFileName = "js/visionforge-playground.js"
} }
commonWebpackConfig { commonWebpackConfig {
sourceMaps = true sourceMaps = true

View File

@ -14,7 +14,6 @@ import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
import kotlin.io.path.Path import kotlin.io.path.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.writeText import kotlin.io.path.writeText
@ -26,8 +25,6 @@ private fun Meta.countTypes(): Sequence<String> = sequence {
} }
fun main() { fun main() {
Path("data").createDirectories()
val string = ZipInputStream(TGeoManager::class.java.getResourceAsStream("/root/geometry_run_7-2076.zip")!!).use { val string = ZipInputStream(TGeoManager::class.java.getResourceAsStream("/root/geometry_run_7-2076.zip")!!).use {
it.nextEntry it.nextEntry
it.readAllBytes().decodeToString() it.readAllBytes().decodeToString()

View File

@ -6,8 +6,5 @@ kotlin.js.compiler=ir
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4G org.gradle.jvmargs=-Xmx4G
toolsVersion=0.14.9-kotlin-1.8.20
org.jetbrains.compose.experimental.jscanvas.enabled=true org.jetbrains.compose.experimental.jscanvas.enabled=true
toolsVersion=0.15.0-kotlin-1.9.20-RC
#kotlin.experimental.tryK2=true
#kscience.wasm.disabled=true

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -1,19 +1,15 @@
plugins { plugins {
id("space.kscience.gradle.mpp") kotlin("js")
id("space.kscience.gradle.js")
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
kscience{ dependencies {
js()
jsMain{
dependencies {
api(project(":visionforge-solid")) api(project(":visionforge-solid"))
api(project(":ui:react")) api(project(":ui:react"))
implementation(npm("file-saver", "2.0.2")) implementation(npm("file-saver", "2.0.2"))
implementation(npm("bootstrap","4.6.0")) implementation(npm("bootstrap","4.6.0"))
implementation(npm("jquery","3.5.1")) implementation(npm("jquery","3.5.1"))
implementation(npm("popper.js","1.16.1")) implementation(npm("popper.js","1.16.1"))
}
}
} }

View File

@ -1,8 +1,8 @@
package space.kscience.visionforge.bootstrap package space.kscience.visionforge.bootstrap
public fun useBootstrap(){ public fun useBootstrap(){
kotlinext.js.require<dynamic>("bootstrap/dist/css/bootstrap.min.css") kotlinext.js.require("bootstrap/dist/css/bootstrap.min.css")
kotlinext.js.require<dynamic>("bootstrap") kotlinext.js.require("bootstrap")
} }
//public inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) { //public inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {

View File

@ -2,9 +2,13 @@ package space.kscience.visionforge.bootstrap
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.css.* import kotlinx.css.BorderStyle
import kotlinx.css.Color
import kotlinx.css.padding
import kotlinx.css.properties.border
import kotlinx.css.px
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.files.Blob import org.w3c.files.Blob
import org.w3c.files.BlobPropertyBag import org.w3c.files.BlobPropertyBag
import react.FC import react.FC
@ -25,7 +29,7 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
val fileSaver = kotlinext.js.require<dynamic>("file-saver") val fileSaver = kotlinext.js.require("file-saver")
val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8")) val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8"))
fileSaver.saveAs(blob, fileName) fileSaver.saveAs(blob, fileName)
} }
@ -49,8 +53,8 @@ public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { prop
flexColumn { flexColumn {
flexRow { flexRow {
css { css {
border = Border(1.px, BorderStyle.solid, Color.blue) border(1.px, BorderStyle.solid, Color.blue)
padding = Padding(4.px) padding(4.px)
} }
props.vision?.let { vision -> props.vision?.let { vision ->
button { button {

View File

@ -1,6 +1,7 @@
package space.kscience.visionforge.bootstrap package space.kscience.visionforge.bootstrap
import kotlinx.css.* import kotlinx.css.*
import kotlinx.css.properties.border
import react.FC import react.FC
import react.PropsWithChildren import react.PropsWithChildren
import react.RBuilder import react.RBuilder
@ -32,13 +33,13 @@ public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
} }
tab("Tree") { tab("Tree") {
css { css {
border = Border(1.px, BorderStyle.solid, Color.lightGray) border(1.px, BorderStyle.solid, Color.lightGray)
padding = Padding(10.px) padding(10.px)
} }
h2 { +"Object tree" } h2 { +"Object tree" }
styledDiv { styledDiv {
css { css {
flex = Flex(1.0, 1.0, FlexBasis.inherit) flex(1.0, 1.0, FlexBasis.inherit)
} }
props.vision?.let { props.vision?.let {
visionTree(it, props.selected, props.onSelect) visionTree(it, props.selected, props.onSelect)

View File

@ -1,16 +1,11 @@
plugins { plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.js")
} }
kscience { dependencies{
js() api(project(":visionforge-solid"))
jsMain {
dependencies {
api(projects.visionforgeSolid)
api("org.jetbrains.kotlin-wrappers:kotlin-styled") api("org.jetbrains.kotlin-wrappers:kotlin-styled")
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom") api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
// implementation(npm("react-select","4.3.0")) // implementation(npm("react-select","4.3.0"))
api(projects.visionforgeThreejs) implementation(project(":visionforge-threejs"))
}
}
} }

View File

@ -3,7 +3,7 @@ package space.kscience.visionforge.react
import kotlinx.css.Align import kotlinx.css.Align
import kotlinx.css.alignItems import kotlinx.css.alignItems
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event import kotlinx.html.org.w3c.dom.events.Event
import react.* import react.*
import react.dom.a import react.dom.a
import react.dom.attrs import react.dom.attrs

View File

@ -1,10 +1,10 @@
package space.kscience.visionforge.react package space.kscience.visionforge.react
import kotlinx.html.js.onChangeFunction import kotlinx.html.js.onChangeFunction
import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.dom.HTMLOptionElement import org.w3c.dom.HTMLOptionElement
import org.w3c.dom.HTMLSelectElement import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.asList import org.w3c.dom.asList
import org.w3c.dom.events.Event
import react.FC import react.FC
import react.dom.attrs import react.dom.attrs
import react.dom.option import react.dom.option

View File

@ -10,16 +10,13 @@ import kotlinx.coroutines.launch
import kotlinx.css.* import kotlinx.css.*
import kotlinx.css.properties.TextDecoration import kotlinx.css.properties.TextDecoration
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event import kotlinx.html.org.w3c.dom.events.Event
import react.* import react.*
import react.dom.attrs import react.dom.attrs
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.ValueRequirement import space.kscience.dataforge.meta.descriptors.ValueRequirement
import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.remove
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import space.kscience.visionforge.hidden import space.kscience.visionforge.hidden
import styled.css import styled.css
@ -151,7 +148,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
css { css {
//+TreeStyles.resizeableInput //+TreeStyles.resizeableInput
width = 160.px width = 160.px
margin = Margin(1.px, 5.px) margin(1.px, 5.px)
} }
ValueChooser { ValueChooser {
attrs { attrs {
@ -170,7 +167,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
css { css {
width = 24.px width = 24.px
alignSelf = Align.stretch alignSelf = Align.stretch
margin = Margin(1.px, 5.px) margin(1.px, 5.px)
backgroundColor = Color.white backgroundColor = Color.white
borderStyle = BorderStyle.solid borderStyle = BorderStyle.solid
borderRadius = 2.px borderRadius = 2.px

View File

@ -4,9 +4,8 @@ import kotlinx.css.pct
import kotlinx.css.width import kotlinx.css.width
import kotlinx.html.InputType import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onInputFunction import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLInputElement
import org.w3c.dom.events.Event
import react.FC import react.FC
import react.dom.attrs import react.dom.attrs
import react.fc import react.fc
@ -59,8 +58,8 @@ public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") {
attrs { attrs {
disabled = rangeDisabled disabled = rangeDisabled
value = innerValue?.toString() ?: "" value = innerValue?.toString() ?: ""
// onChangeFunction = handleChange onChangeFunction = handleChange
onInputFunction = handleChange consumer.onTagEvent(this, "input", handleChange)
val minValue = props.descriptor?.attributes?.get("min").string val minValue = props.descriptor?.attributes?.get("min").string
minValue?.let { minValue?.let {
min = it min = it

View File

@ -52,10 +52,10 @@ public object TreeStyles : StyleSheet("treeStyles", true) {
} }
public val treeLabel:RuleSet by css { public val treeLabel:RuleSet by css {
border = Border.none border = "none"
padding = Padding(left = 4.pt, right = 4.pt, top = 0.pt, bottom = 0.pt) padding(left = 4.pt, right = 4.pt, top = 0.pt, bottom = 0.pt)
textAlign = TextAlign.left textAlign = TextAlign.left
flex = Flex(1.0) flex(1.0)
} }
public val treeLabelInactive: RuleSet by css { public val treeLabelInactive: RuleSet by css {

View File

@ -1,10 +1,13 @@
package space.kscience.visionforge.react package space.kscience.visionforge.react
import kotlinx.css.* import kotlinx.css.Color
import kotlinx.css.properties.TextDecoration import kotlinx.css.Cursor
import kotlinx.css.color
import kotlinx.css.cursor
import kotlinx.css.properties.TextDecorationLine import kotlinx.css.properties.TextDecorationLine
import kotlinx.css.properties.textDecoration
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event import kotlinx.html.org.w3c.dom.events.Event
import react.* import react.*
import react.dom.attrs import react.dom.attrs
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
@ -34,7 +37,7 @@ private val TreeLabel = fc<ObjectTreeProps> { props ->
color = Color("#069") color = Color("#069")
cursor = Cursor.pointer cursor = Cursor.pointer
hover { hover {
textDecoration = TextDecoration(setOf(TextDecorationLine.underline)) textDecoration(TextDecorationLine.underline)
} }
if (props.name == props.selected) { if (props.name == props.selected) {
+TreeStyles.treeLabelSelected +TreeStyles.treeLabelSelected

View File

@ -1,12 +1,15 @@
package space.kscience.visionforge.react package space.kscience.visionforge.react
import kotlinx.css.* import kotlinx.css.margin
import kotlinx.css.pct
import kotlinx.css.px
import kotlinx.css.width
import kotlinx.html.InputType import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onKeyDownFunction import kotlinx.html.js.onKeyDownFunction
import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.events.Event
import react.FC import react.FC
import react.Props import react.Props
import react.dom.attrs import react.dom.attrs
@ -142,7 +145,7 @@ public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") {
styledInput(type = InputType.color) { styledInput(type = InputType.color) {
css { css {
width = 100.pct width = 100.pct
margin = Margin(0.px) margin(0.px)
} }
attrs { attrs {
this.value = props.value?.let { value -> this.value = props.value?.let { value ->

View File

@ -1,11 +1,11 @@
plugins { plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.js")
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
kscience{ kotlin{
js{ js(IR){
useCommonJs() useCommonJs()
browser { browser {
commonWebpackConfig { commonWebpackConfig {
@ -15,11 +15,12 @@ kscience{
} }
} }
} }
jsMain{ }
api(projects.ui.react)
dependencies{
api(project(":ui:react"))
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui") api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
implementation(npm("core-js","3.12.1")) implementation(npm("core-js","3.12.1"))
implementation(npm("file-saver", "2.0.2")) implementation(npm("file-saver", "2.0.2"))
}
} }

View File

@ -130,7 +130,7 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
css { css {
height = 100.pct height = 100.pct
minWidth = 600.px minWidth = 600.px
flex = Flex(10.0, 1.0, FlexBasis("600px")) flex(10.0, 1.0, FlexBasis("600px"))
position = Position.relative position = Position.relative
} }
@ -199,11 +199,11 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
} }
flexColumn { flexColumn {
css { css {
padding = Padding(4.px) padding(4.px)
minWidth = 400.px minWidth = 400.px
height = 100.pct height = 100.pct
overflowY = Overflow.auto overflowY = Overflow.auto
flex = Flex(1.0, 10.0, FlexBasis("300px")) flex(1.0, 10.0, FlexBasis("300px"))
} }
ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs) ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs)
} }

View File

@ -2,9 +2,13 @@ package space.kscience.visionforge.ring
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.css.* import kotlinx.css.BorderStyle
import kotlinx.css.Color
import kotlinx.css.padding
import kotlinx.css.properties.border
import kotlinx.css.px
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.files.Blob import org.w3c.files.Blob
import org.w3c.files.BlobPropertyBag import org.w3c.files.BlobPropertyBag
import react.FC import react.FC
@ -30,7 +34,7 @@ internal fun saveData(event: Event, fileName: String, mimeType: String = "text/p
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
val fileSaver = kotlinext.js.require<dynamic>("file-saver") val fileSaver = kotlinext.js.require("file-saver")
val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8")) val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8"))
fileSaver.saveAs(blob, fileName) fileSaver.saveAs(blob, fileName)
} }
@ -54,8 +58,8 @@ internal val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { pr
flexColumn { flexColumn {
flexRow { flexRow {
css { css {
border = Border(1.px, BorderStyle.solid, Color.blue) border(1.px, BorderStyle.solid, Color.blue)
padding = Padding(4.px) padding(4.px)
} }
props.vision?.let { vision -> props.vision?.let { vision ->
button { button {

View File

@ -9,34 +9,12 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import kotlin.time.Duration import kotlin.time.Duration
/**
* A vision used only in change propagation and showing that the target should be removed
*/
@Serializable
@SerialName("null")
public object NullVision : Vision {
override var parent: Vision?
get() = null
set(_) {
error("Can't set parent for null vision")
}
override val properties: MutableVisionProperties get() = error("Can't get properties of `NullVision`")
override val descriptor: MetaDescriptor? = null
}
/** /**
* Create a deep copy of given Vision without external connections. * Create a deep copy of given Vision without external connections.
*/ */
@ -50,22 +28,6 @@ private fun Vision.deepCopy(manager: VisionManager): Vision {
} }
/**
* An event that contains changes made to a vision.
*
* @param vision a new value for vision content. If the Vision is to be removed should be [NullVision]
* @param properties updated properties
* @param children a map of children changed in ths [VisionChange].
*/
@Serializable
@SerialName("change")
public data class VisionChange(
public val vision: Vision? = null,
public val properties: Meta? = null,
public val children: Map<Name, VisionChange>? = null,
)
/** /**
* An update for a [Vision] * An update for a [Vision]
*/ */

View File

@ -1,42 +0,0 @@
package space.kscience.visionforge
import kotlinx.coroutines.launch
import space.kscience.dataforge.context.Plugin
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName
/**
* A feedback client that communicates with a server and provides ability to propagate events and changes back to the model
*/
public interface VisionClient: Plugin {
public val visionManager: VisionManager
public suspend fun sendEvent(event: VisionEvent)
public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?)
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), item)
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit {
context.launch {
sendEvent(VisionMetaEvent(visionName, event.toMeta()))
}
}

View File

@ -187,10 +187,30 @@ internal abstract class VisionChildrenImpl(
} }
override fun clear() { override fun clear() {
items?.clear() items?.forEach { set(it.key, null) }
updateJobs.values.forEach { it.cancel() } // if (!items.isNullOrEmpty()) {
updateJobs.clear() // updateJobs.values.forEach {
onChange(Name.EMPTY) // it.cancel()
// }
// updateJobs.clear()
// items?.clear()
// }
} }
} }
//
//internal object VisionChildrenContainerSerializer : KSerializer<MutableVisionChildren> {
// private val mapSerializer = serializer<Map<NameToken, Vision>>()
//
// override val descriptor: SerialDescriptor = mapSerializer.descriptor
//
// override fun deserialize(decoder: Decoder): MutableVisionChildren {
// val map = decoder.decodeSerializableValue(mapSerializer)
// return VisionChildrenImpl(map)
// }
//
// override fun serialize(encoder: Encoder, value: MutableVisionChildren) {
// val map = value.keys.associateWith { value[it]!! }
// encoder.encodeSerializableValue(mapSerializer, map)
// }
//
//}

View File

@ -3,38 +3,50 @@ package space.kscience.visionforge
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
/** /**
* An event propagated from client to a server * An event propagated from client to a server
*/ */
@Serializable @Serializable
public sealed interface VisionEvent{ public sealed interface VisionEvent
public val targetName: Name
public companion object{
public val CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
}
}
/** /**
* An event that consists of custom meta * An event that consists of custom meta
*/ */
@Serializable @Serializable
@SerialName("meta") @SerialName("meta")
public class VisionMetaEvent(override val targetName: Name, public val meta: Meta) : VisionEvent public class VisionMetaEvent(public val targetName: Name, public val meta: Meta) : VisionEvent
@Serializable
@SerialName("change")
public class VisionChangeEvent(override val targetName: Name, public val change: VisionChange) : VisionEvent
public val Vision.Companion.CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
/** /**
* Set the payload to be sent to server on click * A vision used only in change propagation and showing that the target should be removed
*/ */
public fun Vision.onClickPayload(payloadBuilder: MutableMeta.() -> Unit){ @Serializable
properties[VisionEvent.CLICK_EVENT_KEY] = Meta(payloadBuilder) @SerialName("null")
public object NullVision : Vision {
override var parent: Vision?
get() = null
set(_) {
error("Can't set parent for null vision")
}
override val properties: MutableVisionProperties get() = error("Can't get properties of `NullVision`")
override val descriptor: MetaDescriptor? = null
} }
/**
* @param vision a new value for vision content. If the Vision is to be removed should be [NullVision]
* @param properties updated properties
* @param children a map of children changed in ths [VisionChange].
*/
@Serializable
@SerialName("change")
public data class VisionChange(
public val vision: Vision? = null,
public val properties: Meta? = null,
public val children: Map<Name, VisionChange>? = null,
) : VisionEvent

View File

@ -5,9 +5,6 @@ import kotlinx.browser.window
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -15,10 +12,7 @@ import kotlinx.coroutines.sync.withLock
import org.w3c.dom.* import org.w3c.dom.*
import org.w3c.dom.url.URL import org.w3c.dom.url.URL
import space.kscience.dataforge.context.* import space.kscience.dataforge.context.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.parseAsName
import space.kscience.visionforge.html.VisionTagConsumer import space.kscience.visionforge.html.VisionTagConsumer
@ -32,9 +26,9 @@ import kotlin.time.Duration.Companion.milliseconds
/** /**
* A Kotlin-browser plugin that renders visions based on provided renderers and governs communication with the server. * A Kotlin-browser plugin that renders visions based on provided renderers and governs communication with the server.
*/ */
public class JsVisionClient : AbstractPlugin(), VisionClient { public class VisionClient : AbstractPlugin() {
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
override val visionManager: VisionManager by require(VisionManager) private val visionManager: VisionManager by require(VisionManager)
/** /**
* Up-going tree traversal in search for endpoint attribute. If element is null, return window URL * Up-going tree traversal in search for endpoint attribute. If element is null, return window URL
@ -72,7 +66,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
/** /**
* Communicate vision property changed from rendering engine to model * Communicate vision property changed from rendering engine to model
*/ */
override fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) { public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
context.launch { context.launch {
mutex.withLock { mutex.withLock {
changeCollector.propertyChanged(visionName, propertyName, item) changeCollector.propertyChanged(visionName, propertyName, item)
@ -88,7 +82,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
/** /**
* Send a custom feedback event * Send a custom feedback event
*/ */
override suspend fun sendEvent(event: VisionEvent) { public suspend fun sendEvent(event: VisionEvent) {
eventCollector.emit(event) eventCollector.emit(event)
} }
@ -147,19 +141,21 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
onopen = { onopen = {
feedbackJob = visionManager.context.launch { feedbackJob = visionManager.context.launch {
eventCollector.filter { it.targetName == name }.onEach {
send(visionManager.jsonFormat.encodeToString(VisionEvent.serializer(), it))
}.launchIn(this)
while (isActive) { while (isActive) {
delay(feedbackAggregationTime.milliseconds) delay(feedbackAggregationTime.milliseconds)
val change = changeCollector[name] ?: continue val change = changeCollector[name] ?: continue
if (!change.isEmpty()) { if (!change.isEmpty()) {
mutex.withLock { mutex.withLock {
eventCollector.emit(VisionChangeEvent(name, change.deepCopy(visionManager))) send(change.toJsonString(visionManager))
change.reset() change.reset()
} }
} }
// // take channel for given vision name
// eventCollector[name]?.let { channel ->
// for (e in channel) {
// send(visionManager.jsonFormat.encodeToString(VisionEvent.serializer(), e))
// }
// }
} }
} }
logger.info { "WebSocket feedback channel established for output '$name'" } logger.info { "WebSocket feedback channel established for output '$name'" }
@ -255,15 +251,37 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
textVisionRenderer(this), textVisionRenderer(this),
formVisionRenderer(this) formVisionRenderer(this)
).associateByName() ).associateByName()
} else super<AbstractPlugin>.content(target) } else super.content(target)
public companion object : PluginFactory<JsVisionClient> { public companion object : PluginFactory<VisionClient> {
override fun build(context: Context, meta: Meta): JsVisionClient = JsVisionClient() override fun build(context: Context, meta: Meta): VisionClient = VisionClient()
override val tag: PluginTag = PluginTag(name = "vision.client.js", group = PluginTag.DATAFORGE_GROUP) override val tag: PluginTag = PluginTag(name = "vision.client.js", group = PluginTag.DATAFORGE_GROUP)
} }
} }
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), item)
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit {
context.launch {
sendEvent(VisionMetaEvent(visionName, event.toMeta()))
}
}
private fun whenDocumentLoaded(block: Document.() -> Unit): Unit { private fun whenDocumentLoaded(block: Document.() -> Unit): Unit {
if (document.body != null) { if (document.body != null) {
block(document) block(document)
@ -275,7 +293,7 @@ private fun whenDocumentLoaded(block: Document.() -> Unit): Unit {
/** /**
* Fetch and render visions for all elements with [VisionTagConsumer.OUTPUT_CLASS] class inside given [element]. * Fetch and render visions for all elements with [VisionTagConsumer.OUTPUT_CLASS] class inside given [element].
*/ */
public fun JsVisionClient.renderAllVisionsIn(element: Element) { public fun VisionClient.renderAllVisionsIn(element: Element) {
val elements = element.getElementsByClassName(VisionTagConsumer.OUTPUT_CLASS) val elements = element.getElementsByClassName(VisionTagConsumer.OUTPUT_CLASS)
logger.info { "Finished search for outputs. Found ${elements.length} items" } logger.info { "Finished search for outputs. Found ${elements.length} items" }
elements.asList().forEach { child -> elements.asList().forEach { child ->
@ -286,7 +304,7 @@ public fun JsVisionClient.renderAllVisionsIn(element: Element) {
/** /**
* Render all visions in an element with a given [id] * Render all visions in an element with a given [id]
*/ */
public fun JsVisionClient.renderAllVisionsById(document: Document, id: String): Unit { public fun VisionClient.renderAllVisionsById(document: Document, id: String): Unit {
val element = document.getElementById(id) val element = document.getElementById(id)
if (element != null) { if (element != null) {
renderAllVisionsIn(element) renderAllVisionsIn(element)
@ -299,13 +317,13 @@ public fun JsVisionClient.renderAllVisionsById(document: Document, id: String):
/** /**
* Fetch visions from the server for all elements with [VisionTagConsumer.OUTPUT_CLASS] class in the document body * Fetch visions from the server for all elements with [VisionTagConsumer.OUTPUT_CLASS] class in the document body
*/ */
public fun JsVisionClient.renderAllVisions(): Unit = whenDocumentLoaded { public fun VisionClient.renderAllVisions(): Unit = whenDocumentLoaded {
val element = body ?: error("Document does not have a body") val element = body ?: error("Document does not have a body")
renderAllVisionsIn(element) renderAllVisionsIn(element)
} }
public class VisionClientApplication(public val context: Context) : Application { public class VisionClientApplication(public val context: Context) : Application {
private val client = context.request(JsVisionClient) private val client = context.request(VisionClient)
override fun start(document: Document, state: Map<String, Any>) { override fun start(document: Document, state: Map<String, Any>) {
context.logger.info { context.logger.info {
@ -329,7 +347,7 @@ public fun runVisionClient(contextBuilder: ContextBuilder.() -> Unit) {
Global.logger.info { "Starting VisionForge context" } Global.logger.info { "Starting VisionForge context" }
val context = Context("VisionForge") { val context = Context("VisionForge") {
plugin(JsVisionClient) plugin(VisionClient)
contextBuilder() contextBuilder()
} }

View File

@ -20,7 +20,7 @@ import space.kscience.visionforge.html.VisionOfNumberField
import space.kscience.visionforge.html.VisionOfTextField import space.kscience.visionforge.html.VisionOfTextField
internal fun textVisionRenderer( internal fun textVisionRenderer(
client: JsVisionClient, client: VisionClient,
): ElementVisionRenderer = ElementVisionRenderer<VisionOfTextField> { name, vision, _ -> ): ElementVisionRenderer = ElementVisionRenderer<VisionOfTextField> { name, vision, _ ->
val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]" val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]"
vision.label?.let { vision.label?.let {
@ -42,7 +42,7 @@ internal fun textVisionRenderer(
} }
internal fun numberVisionRenderer( internal fun numberVisionRenderer(
client: JsVisionClient, client: VisionClient,
): ElementVisionRenderer = ElementVisionRenderer<VisionOfNumberField> { name, vision, _ -> ): ElementVisionRenderer = ElementVisionRenderer<VisionOfNumberField> { name, vision, _ ->
val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]" val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]"
vision.label?.let { vision.label?.let {
@ -87,7 +87,7 @@ internal fun FormData.toMeta(): Meta {
} }
internal fun formVisionRenderer( internal fun formVisionRenderer(
client: JsVisionClient, client: VisionClient,
): ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlForm> { name, vision, _ -> ): ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlForm> { name, vision, _ ->
val form = document.getElementById(vision.formId) as? HTMLFormElement val form = document.getElementById(vision.formId) as? HTMLFormElement

View File

@ -9,7 +9,7 @@ kscience {
} }
dependencies { dependencies {
api(projects.visionforgeSolid) api(projects.visionforgeSolid)
api("space.kscience:gdml:0.5.0") api("space.kscience:gdml:0.4.0")
} }
dependencies(jvmTest) { dependencies(jvmTest) {
implementation(spclibs.logback.classic) implementation(spclibs.logback.classic)

View File

@ -8,14 +8,14 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.visionforge.JsVisionClient import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.renderAllVisions import space.kscience.visionforge.renderAllVisions
import space.kscience.visionforge.renderAllVisionsById import space.kscience.visionforge.renderAllVisionsById
import space.kscience.visionforge.renderAllVisionsIn import space.kscience.visionforge.renderAllVisionsIn
@JsExport @JsExport
public class VFNotebookClient : AbstractPlugin() { public class VFNotebookClient : AbstractPlugin() {
private val client by require(JsVisionClient) private val client by require(VisionClient)
public fun renderAllVisionsIn(element: Element) { public fun renderAllVisionsIn(element: Element) {
client.renderAllVisionsIn(element) client.renderAllVisionsIn(element)

View File

@ -2,7 +2,7 @@ plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.mpp")
} }
val markdownVersion = "0.5.2" val markdownVersion = "0.4.1"
kscience { kscience {
jvm() jvm()

View File

@ -18,7 +18,7 @@ import space.kscience.visionforge.markup.VisionOfMarkup.Companion.COMMONMARK_FOR
import space.kscience.visionforge.markup.VisionOfMarkup.Companion.GFM_FORMAT import space.kscience.visionforge.markup.VisionOfMarkup.Companion.GFM_FORMAT
public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer { public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
public val visionClient: JsVisionClient by require(JsVisionClient) public val visionClient: VisionClient by require(VisionClient)
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
override val visionSerializersModule: SerializersModule get() = markupSerializersModule override val visionSerializersModule: SerializersModule get() = markupSerializersModule

View File

@ -2,7 +2,7 @@ plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.mpp")
} }
val plotlyVersion = "0.6.0" val plotlyVersion = "0.5.3"
kscience { kscience {
jvm() jvm()

View File

@ -11,12 +11,12 @@ import space.kscience.dataforge.names.asName
import space.kscience.plotly.PlotlyConfig import space.kscience.plotly.PlotlyConfig
import space.kscience.plotly.plot import space.kscience.plotly.plot
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.VisionPlugin import space.kscience.visionforge.VisionPlugin
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer { public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
public val visionClient: JsVisionClient by require(JsVisionClient) public val visionClient: VisionClient by require(VisionClient)
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag

View File

@ -75,8 +75,8 @@ public class VisionRoute(
public fun Application.serveVisionData( public fun Application.serveVisionData(
configuration: VisionRoute, configuration: VisionRoute,
onEvent: suspend Vision.(VisionEvent) -> Unit = { event -> onEvent: suspend Vision.(VisionEvent) -> Unit = { event ->
if (event is VisionChangeEvent) { if (event is VisionChange) {
update(event.change) update(event)
} }
}, },
resolveVision: (Name) -> Vision?, resolveVision: (Name) -> Vision?,

View File

@ -15,9 +15,6 @@ public enum class CompositeType {
SUBTRACT SUBTRACT
} }
/**
* A CSG-based composite solid
*/
@Serializable @Serializable
@SerialName("solid.composite") @SerialName("solid.composite")
public class Composite( public class Composite(

View File

@ -5,9 +5,6 @@ import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.setChild import space.kscience.visionforge.setChild
/**
* A convex hull shape
*/
@Serializable @Serializable
@SerialName("solid.convex") @SerialName("solid.convex")
public class Convex(public val points: List<Float32Vector3D>) : SolidBase<Convex>() public class Convex(public val points: List<Float32Vector3D>) : SolidBase<Convex>()

View File

@ -12,7 +12,7 @@ import space.kscience.dataforge.names.asName
import space.kscience.visionforge.* import space.kscience.visionforge.*
@Serializable @Serializable
public abstract class LightSource : MiscSolid() { public abstract class LightSource : SolidBase<LightSource>() {
override val descriptor: MetaDescriptor get() = LightSource.descriptor override val descriptor: MetaDescriptor get() = LightSource.descriptor
public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY) public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY)

View File

@ -6,19 +6,13 @@ import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.setChild import space.kscience.visionforge.setChild
/**
* Utility solids
*/
public abstract class MiscSolid: SolidBase<MiscSolid>() public abstract class MiscSolid: SolidBase<MiscSolid>()
/**
* X-Y-Z axes
*/
@Serializable @Serializable
@SerialName("solid.axes") @SerialName("solid.axes")
public class AxesSolid(public val size: Double): MiscSolid(){ public class AxesSolid(public val size: Double): MiscSolid(){
public companion object{ public companion object{
public const val AXES_NAME: String = "@axes" public const val AXES_NAME: String = "@xes"
} }
} }

View File

@ -7,9 +7,6 @@ import kotlin.math.sin
public typealias Shape2D = List<Float32Vector2D> public typealias Shape2D = List<Float32Vector2D>
/**
* A builder for 2D shapes
*/
@Serializable @Serializable
public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = ArrayList()) { public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = ArrayList()) {

View File

@ -152,10 +152,7 @@ public var Vision.ignore: Boolean?
// get() = getProperty(SELECTED_KEY).boolean // get() = getProperty(SELECTED_KEY).boolean
// set(value) = setProperty(SELECTED_KEY, value) // set(value) = setProperty(SELECTED_KEY, value)
/** internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
*A [Float] solid property delegate
*/
internal fun float32(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
object : ReadWriteProperty<Solid, Number> { object : ReadWriteProperty<Solid, Number> {
override fun getValue(thisRef: Solid, property: KProperty<*>): Number { override fun getValue(thisRef: Solid, property: KProperty<*>): Number {
return thisRef.properties.getValue(name)?.number ?: default return thisRef.properties.getValue(name)?.number ?: default
@ -166,10 +163,7 @@ internal fun float32(name: Name, default: Number): ReadWriteProperty<Solid, Numb
} }
} }
/** internal fun point(
* A [Float32Vector3D] solid property delegate
*/
internal fun float32Vector(
name: Name, name: Name,
defaultX: Float, defaultX: Float,
defaultY: Float = defaultX, defaultY: Float = defaultX,
@ -199,17 +193,17 @@ internal fun float32Vector(
} }
} }
public var Solid.position: Float32Vector3D? by float32Vector(POSITION_KEY, 0f) public var Solid.position: Float32Vector3D? by point(POSITION_KEY, 0f)
public var Solid.rotation: Float32Vector3D? by float32Vector(ROTATION_KEY, 0f) public var Solid.rotation: Float32Vector3D? by point(ROTATION_KEY, 0f)
public var Solid.scale: Float32Vector3D? by float32Vector(SCALE_KEY, 1f) public var Solid.scale: Float32Vector3D? by point(SCALE_KEY, 1f)
public var Solid.x: Number by float32(X_POSITION_KEY, 0f) public var Solid.x: Number by float(X_POSITION_KEY, 0f)
public var Solid.y: Number by float32(Y_POSITION_KEY, 0f) public var Solid.y: Number by float(Y_POSITION_KEY, 0f)
public var Solid.z: Number by float32(Z_POSITION_KEY, 0f) public var Solid.z: Number by float(Z_POSITION_KEY, 0f)
public var Solid.rotationX: Number by float32(X_ROTATION_KEY, 0f) public var Solid.rotationX: Number by float(X_ROTATION_KEY, 0f)
public var Solid.rotationY: Number by float32(Y_ROTATION_KEY, 0f) public var Solid.rotationY: Number by float(Y_ROTATION_KEY, 0f)
public var Solid.rotationZ: Number by float32(Z_ROTATION_KEY, 0f) public var Solid.rotationZ: Number by float(Z_ROTATION_KEY, 0f)
/** /**
* Raw quaternion value defined in properties * Raw quaternion value defined in properties
@ -247,9 +241,9 @@ public var Solid.quaternion: Quaternion
quaternionOrNull = value quaternionOrNull = value
} }
public var Solid.scaleX: Number by float32(X_SCALE_KEY, 1f) public var Solid.scaleX: Number by float(X_SCALE_KEY, 1f)
public var Solid.scaleY: Number by float32(Y_SCALE_KEY, 1f) public var Solid.scaleY: Number by float(Y_SCALE_KEY, 1f)
public var Solid.scaleZ: Number by float32(Z_SCALE_KEY, 1f) public var Solid.scaleZ: Number by float(Z_SCALE_KEY, 1f)
/** /**
* Add rotation with given [angle] relative to given [axis] * Add rotation with given [angle] relative to given [axis]

View File

@ -5,9 +5,6 @@ import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.visionforge.AbstractVision import space.kscience.visionforge.AbstractVision
/**
* An abstract solid that is both [Solid] and [AbstractVision]
*/
@Serializable @Serializable
@SerialName("solid") @SerialName("solid")
public open class SolidBase<T : Solid> : AbstractVision(), Solid { public open class SolidBase<T : Solid> : AbstractVision(), Solid {

View File

@ -12,9 +12,6 @@ import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_K
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY
/**
* A scheme for vision material
*/
@VisionBuilder @VisionBuilder
public class SolidMaterial : Scheme() { public class SolidMaterial : Scheme() {

View File

@ -21,7 +21,6 @@ import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD
* Get a vision prototype if it is a [SolidReference] or vision itself if it is not. * Get a vision prototype if it is a [SolidReference] or vision itself if it is not.
* Unref is recursive, so it always returns a non-reference. * Unref is recursive, so it always returns a non-reference.
*/ */
@Suppress("RecursivePropertyAccessor")
public val Vision.prototype: Solid public val Vision.prototype: Solid
get() = when (this) { get() = when (this) {
is SolidReference -> prototype.prototype is SolidReference -> prototype.prototype
@ -241,3 +240,94 @@ public fun SolidGroup.newRef(
} }
return children.ref(prototypeName, name?.parseAsName()) return children.ref(prototypeName, name?.parseAsName())
} }
//
//
///**
// * A reference [Solid] to reuse a template object
// */
//@Serializable
//@SerialName("solid.ref")
//public class SolidReferenceGroup(
// public val refName: Name,
//) : VisionGroup(), SolidReference, VisionGroup<Solid>, Solid {
//
// /**
// * Recursively search for defined template in the parent
// */
// override val prototype: Solid by lazy {
// if (parent == null) error("No parent is present for SolidReferenceGroup")
// if (parent !is PrototypeHolder) error("Parent does not hold prototypes")
// (parent as? PrototypeHolder)?.getPrototype(refName) ?: error("Prototype with name $refName not found")
// }
//
// override val items: Map<NameToken, VisionGroupItem<Solid>>
// get() = (prototype as? VisionGroup<*>)?.items
// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
// ?.mapValues {
// VisionGroupItem.Node(ReferenceChild(this, it.key.asName()))
// } ?: emptyMap()
//
// override val descriptor: MetaDescriptor get() = prototype.descriptor
//
//
// /**
// * A ProxyChild is created temporarily only to interact with properties, it does not store any values
// * (properties are stored in external cache) and created and destroyed on-demand).
// */
// private class ReferenceChild(
// val owner: SolidReferenceGroup,
// private val refName: Name,
// ) : SolidReference, VisionGroup<Solid>, Solid {
//
// override val prototype: Solid by lazy {
// if (refName.isEmpty()) {
// owner.prototype
// } else {
// val proto = (owner.prototype).children.get(refName)
// ?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}")
// proto as? Solid ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
//// proto.unref as? Solid
//// ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
// }
// }
//
// override val meta: ObservableMutableMeta by lazy {
// owner.meta.getOrCreate(childToken(refName).asName())
// }
//
// override val items: Map<NameToken, VisionGroupItem<Solid>>
// get() = (prototype as? VisionGroup<*>)?.items
// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
// ?.mapValues { (key, _) ->
// VisionGroupItem.Node(ReferenceChild(owner, refName + key.asName()))
// } ?: emptyMap()
//
// override var parent: VisionGroup<*>?
// get() {
// val parentName = refName.cutLast()
// return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName)
// }
// set(_) {
// error("Setting a parent for a reference child is not possible")
// }
//
// override fun invalidateProperty(propertyName: Name) {
// owner.invalidateProperty(childPropertyName(refName, propertyName))
// }
//
// override fun update(change: VisionChange) {
// change.properties?.let {
// updateProperties(it, Name.EMPTY)
// }
// }
//
// override val descriptor: MetaDescriptor get() = prototype.descriptor
//
// }
//
// public companion object {
// public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child"
// }
//}

View File

@ -12,21 +12,21 @@ import space.kscience.dataforge.meta.toDynamic
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import tabulator.Tabulator import tabulator.Tabulator
import tabulator.TabulatorFull import tabulator.TabulatorFull
public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer { public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer {
public val visionClient: JsVisionClient by require(JsVisionClient) public val visionClient: VisionClient by require(VisionClient)
public val tablesBase: TableVisionPlugin by require(TableVisionPlugin) public val tablesBase: TableVisionPlugin by require(TableVisionPlugin)
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
override fun attach(context: Context) { override fun attach(context: Context) {
super.attach(context) super.attach(context)
kotlinext.js.require<Any>("tabulator-tables/dist/css/tabulator.min.css") kotlinext.js.require("tabulator-tables/dist/css/tabulator.min.css")
kotlinext.js.require<Any>("tabulator-tables/src/js/modules/ResizeColumns/ResizeColumns.js") kotlinext.js.require("tabulator-tables/src/js/modules/ResizeColumns/ResizeColumns.js")
} }
override fun rateVision(vision: Vision): Int = when (vision) { override fun rateVision(vision: Vision): Int = when (vision) {

View File

@ -1,23 +1,17 @@
plugins { plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.js")
} }
kotlin{ kotlin{
explicitApi = org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode.Disabled explicitApi = org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode.Disabled
}
kscience{
js{ js{
binaries.library() binaries.library()
} }
jsMain{ }
dependencies {
dependencies {
api(projects.visionforgeSolid) api(projects.visionforgeSolid)
implementation(npm("three", "0.143.0")) implementation(npm("three", "0.143.0"))
implementation(npm("three-csg-ts", "3.1.10")) implementation(npm("three-csg-ts", "3.1.10"))
implementation(npm("three.meshline","1.4.0")) implementation(npm("three.meshline","1.4.0"))
}
}
} }

View File

@ -123,8 +123,8 @@ public class ThreeCanvas(
element.appendChild(canvas) element.appendChild(canvas)
updateSize() updateSize()
canvas.addEventListener("pointerdown", { canvas.addEventListener("pointerdown", {
val newPicked = pick() val picked = pick()
options.onSelect?.invoke(newPicked?.fullName()) options.onSelect?.invoke(picked?.fullName())
}, false) }, false)
//Attach listener to track mouse changes //Attach listener to track mouse changes
@ -143,12 +143,12 @@ public class ThreeCanvas(
addControls(canvas, options.controls) addControls(canvas, options.controls)
renderer.setAnimationLoop { renderer.setAnimationLoop {
val newPicked = pick() val picked = pick()
if (newPicked != null && picked !== newPicked) { if (picked != null && this.picked != picked) {
picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) this.picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
newPicked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) picked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
picked = newPicked this.picked = picked
} }
renderer.render(scene, camera) renderer.render(scene, camera)
@ -326,7 +326,7 @@ public class ThreeCanvas(
public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply { public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply {
color.set(Colors.blue) color.set(Colors.blue)
thickness = 1f thickness = 2f
cached = true cached = true
} }
// //

View File

@ -7,10 +7,12 @@ import org.w3c.dom.HTMLElement
import space.kscience.dataforge.context.* import space.kscience.dataforge.context.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import space.kscience.visionforge.* import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionChildren
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.set import space.kscience.visionforge.visible
import three.core.Object3D import three.core.Object3D
import kotlin.collections.set import kotlin.collections.set
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -21,8 +23,6 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
public val solids: Solids by require(Solids) public val solids: Solids by require(Solids)
public val client: VisionClient? get() = context.plugins.get<VisionClient>()
private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>() private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>()
private val compositeFactory = ThreeCompositeFactory(this) private val compositeFactory = ThreeCompositeFactory(this)
@ -90,8 +90,6 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
val child = vision.children.getChild(childName) val child = vision.children.getChild(childName)
logger.debug { "Changing vision $childName to $child" }
//removing old object //removing old object
findChild(childName)?.let { oldChild -> findChild(childName)?.let { oldChild ->
oldChild.parent?.remove(oldChild) oldChild.parent?.remove(oldChild)

Some files were not shown because too many files have changed in this diff Show More