Compare commits
17 Commits
1ebeefe01c
...
9c1246fb26
Author | SHA1 | Date | |
---|---|---|---|
9c1246fb26 | |||
cf6d73305b | |||
6144410d22 | |||
2578fd6f77 | |||
001efa711a | |||
8fac827acb | |||
bdc2885c0d | |||
d44f25ad4c | |||
35ec4bac0e | |||
ba70af3a24 | |||
20fc81305c | |||
086948492c | |||
25c3a19eed | |||
ea9d37b9a1 | |||
a695e5e7c9 | |||
140c59497e | |||
23cb8765b6 |
@ -1,5 +1,4 @@
|
|||||||
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
|
||||||
|
|
||||||
@ -8,7 +7,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.1")
|
val dataforgeVersion by extra("0.6.2")
|
||||||
val fxVersion by extra("11")
|
val fxVersion by extra("11")
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@ -45,14 +44,7 @@ ksciencePublish {
|
|||||||
useApache2Licence()
|
useApache2Licence()
|
||||||
useSPCTeam()
|
useSPCTeam()
|
||||||
}
|
}
|
||||||
github(githubProject = "visionforge", githubOrg = "SciProgCentre")
|
repository("spc","https://maven.sciprog.center/kscience")
|
||||||
space(
|
|
||||||
if (isInDevelopment) {
|
|
||||||
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
|
|
||||||
} else {
|
|
||||||
"https://maven.pkg.jetbrains.space/spc/p/sci/maven"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
sonatype()
|
sonatype()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ plugins {
|
|||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group = "demo"
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
js {
|
js {
|
||||||
|
@ -9,30 +9,38 @@ import react.Component
|
|||||||
import react.Props
|
import react.Props
|
||||||
import react.State
|
import react.State
|
||||||
|
|
||||||
external enum class DropEffects {
|
sealed external class DropEffects {
|
||||||
copy,
|
@JsName("copy")
|
||||||
move,
|
object Copy : DropEffects
|
||||||
link,
|
|
||||||
none
|
@JsName("move")
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ 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
|
||||||
@ -13,7 +12,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(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
|
border = Border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
|
||||||
flexGrow = 0.0
|
flexGrow = 0.0
|
||||||
alignContent = Align.center
|
alignContent = Align.center
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.js")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
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,11 +21,15 @@ 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)
|
||||||
implementation(projects.ui.ring)
|
}
|
||||||
|
jsMain {
|
||||||
|
implementation(projects.ui.ring)
|
||||||
|
}
|
||||||
}
|
}
|
@ -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.VisionClient
|
import space.kscience.visionforge.JsVisionClient
|
||||||
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(VisionClient)
|
plugin(JsVisionClient)
|
||||||
plugin(PlotlyPlugin)
|
plugin(PlotlyPlugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ private class JsPlaygroundApp : Application {
|
|||||||
createRoot(element).render {
|
createRoot(element).render {
|
||||||
styledDiv {
|
styledDiv {
|
||||||
css {
|
css {
|
||||||
padding(0.pt)
|
padding = Padding(0.pt)
|
||||||
margin(0.pt)
|
margin = Margin(0.pt)
|
||||||
height = 100.vh
|
height = 100.vh
|
||||||
width = 100.vw
|
width = 100.vw
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
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
|
||||||
@ -45,10 +44,10 @@ val Markup = fc<MarkupProps>("Markup") { props ->
|
|||||||
css {
|
css {
|
||||||
width = 100.pct
|
width = 100.pct
|
||||||
height = 100.pct
|
height = 100.pct
|
||||||
border(2.pt, BorderStyle.solid, Color.blue)
|
border= Border(2.pt, BorderStyle.solid, Color.blue)
|
||||||
padding(left = 8.pt)
|
padding = Padding(left = 8.pt)
|
||||||
backgroundColor = Color.white
|
backgroundColor = Color.white
|
||||||
flex(1.0)
|
flex = Flex(1.0)
|
||||||
zIndex = 10000
|
zIndex = 10000
|
||||||
}
|
}
|
||||||
ref = elementRef
|
ref = elementRef
|
@ -1,5 +1,4 @@
|
|||||||
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.*
|
||||||
@ -30,8 +29,8 @@ val Plotly = fc<PlotlyProps>("Plotly") { props ->
|
|||||||
css {
|
css {
|
||||||
width = 100.pct
|
width = 100.pct
|
||||||
height = 100.pct
|
height = 100.pct
|
||||||
border(2.pt, BorderStyle.solid, Color.blue)
|
border = Border(2.pt, BorderStyle.solid, Color.blue)
|
||||||
flex(1.0)
|
flex = Flex(1.0)
|
||||||
}
|
}
|
||||||
ref = elementRef
|
ref = elementRef
|
||||||
}
|
}
|
@ -13,6 +13,7 @@ kscience {
|
|||||||
useKtor()
|
useKtor()
|
||||||
fullStack(
|
fullStack(
|
||||||
"muon-monitor.js",
|
"muon-monitor.js",
|
||||||
|
development = true,
|
||||||
jvmConfig = { withJava() },
|
jvmConfig = { withJava() },
|
||||||
jsConfig = { useCommonJs() }
|
jsConfig = { useCommonJs() }
|
||||||
) {
|
) {
|
||||||
@ -34,8 +35,8 @@ kscience {
|
|||||||
implementation("ch.qos.logback:logback-classic:1.2.11")
|
implementation("ch.qos.logback:logback-classic:1.2.11")
|
||||||
}
|
}
|
||||||
jsMain {
|
jsMain {
|
||||||
implementation(project(":ui:ring"))
|
implementation(projects.ui.ring)
|
||||||
implementation(project(":visionforge-threejs"))
|
implementation(projects.visionforgeThreejs)
|
||||||
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ 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
|
||||||
@ -34,7 +35,7 @@ class Model(val manager: VisionManager) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tracks: SolidGroup
|
val tracks: SolidGroup = SolidGroup()
|
||||||
|
|
||||||
val root: SolidGroup = SolidGroup().apply {
|
val root: SolidGroup = SolidGroup().apply {
|
||||||
setAsRoot(this@Model.manager)
|
setAsRoot(this@Model.manager)
|
||||||
@ -59,7 +60,8 @@ 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) {
|
||||||
|
@ -17,7 +17,7 @@ kotlin {
|
|||||||
useCommonJs()
|
useCommonJs()
|
||||||
browser {
|
browser {
|
||||||
webpackTask {
|
webpackTask {
|
||||||
outputFileName = "js/visionforge-playground.js"
|
mainOutputFileName.set("js/visionforge-playground.js")
|
||||||
}
|
}
|
||||||
commonWebpackConfig {
|
commonWebpackConfig {
|
||||||
sourceMaps = true
|
sourceMaps = true
|
||||||
|
@ -14,6 +14,7 @@ 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
|
||||||
|
|
||||||
|
|
||||||
@ -25,6 +26,8 @@ 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()
|
||||||
|
@ -6,5 +6,8 @@ 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
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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.1.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("js")
|
id("space.kscience.gradle.mpp")
|
||||||
id("space.kscience.gradle.js")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion: String by rootProject.extra
|
val dataforgeVersion: String by rootProject.extra
|
||||||
|
|
||||||
dependencies {
|
kscience{
|
||||||
api(project(":visionforge-solid"))
|
js()
|
||||||
api(project(":ui:react"))
|
jsMain{
|
||||||
implementation(npm("file-saver", "2.0.2"))
|
dependencies {
|
||||||
implementation(npm("bootstrap","4.6.0"))
|
api(project(":visionforge-solid"))
|
||||||
implementation(npm("jquery","3.5.1"))
|
api(project(":ui:react"))
|
||||||
implementation(npm("popper.js","1.16.1"))
|
implementation(npm("file-saver", "2.0.2"))
|
||||||
|
implementation(npm("bootstrap","4.6.0"))
|
||||||
|
implementation(npm("jquery","3.5.1"))
|
||||||
|
implementation(npm("popper.js","1.16.1"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package space.kscience.visionforge.bootstrap
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
public fun useBootstrap(){
|
public fun useBootstrap(){
|
||||||
kotlinext.js.require("bootstrap/dist/css/bootstrap.min.css")
|
kotlinext.js.require<dynamic>("bootstrap/dist/css/bootstrap.min.css")
|
||||||
kotlinext.js.require("bootstrap")
|
kotlinext.js.require<dynamic>("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) {
|
@ -2,13 +2,9 @@ package space.kscience.visionforge.bootstrap
|
|||||||
|
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.css.BorderStyle
|
import kotlinx.css.*
|
||||||
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 kotlinx.html.org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import org.w3c.files.Blob
|
import org.w3c.files.Blob
|
||||||
import org.w3c.files.BlobPropertyBag
|
import org.w3c.files.BlobPropertyBag
|
||||||
import react.FC
|
import react.FC
|
||||||
@ -29,7 +25,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("file-saver")
|
val fileSaver = kotlinext.js.require<dynamic>("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)
|
||||||
}
|
}
|
||||||
@ -53,8 +49,8 @@ public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { prop
|
|||||||
flexColumn {
|
flexColumn {
|
||||||
flexRow {
|
flexRow {
|
||||||
css {
|
css {
|
||||||
border(1.px, BorderStyle.solid, Color.blue)
|
border = Border(1.px, BorderStyle.solid, Color.blue)
|
||||||
padding(4.px)
|
padding = Padding(4.px)
|
||||||
}
|
}
|
||||||
props.vision?.let { vision ->
|
props.vision?.let { vision ->
|
||||||
button {
|
button {
|
@ -1,7 +1,6 @@
|
|||||||
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
|
||||||
@ -33,13 +32,13 @@ public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
|
|||||||
}
|
}
|
||||||
tab("Tree") {
|
tab("Tree") {
|
||||||
css {
|
css {
|
||||||
border(1.px, BorderStyle.solid, Color.lightGray)
|
border = Border(1.px, BorderStyle.solid, Color.lightGray)
|
||||||
padding(10.px)
|
padding = Padding(10.px)
|
||||||
}
|
}
|
||||||
h2 { +"Object tree" }
|
h2 { +"Object tree" }
|
||||||
styledDiv {
|
styledDiv {
|
||||||
css {
|
css {
|
||||||
flex(1.0, 1.0, FlexBasis.inherit)
|
flex = 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)
|
@ -1,11 +1,16 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.js")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies{
|
kscience {
|
||||||
api(project(":visionforge-solid"))
|
js()
|
||||||
api("org.jetbrains.kotlin-wrappers:kotlin-styled")
|
jsMain {
|
||||||
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
|
dependencies {
|
||||||
|
api(projects.visionforgeSolid)
|
||||||
|
api("org.jetbrains.kotlin-wrappers:kotlin-styled")
|
||||||
|
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
|
||||||
// implementation(npm("react-select","4.3.0"))
|
// implementation(npm("react-select","4.3.0"))
|
||||||
implementation(project(":visionforge-threejs"))
|
api(projects.visionforgeThreejs)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -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 kotlinx.html.org.w3c.dom.events.Event
|
import 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
|
@ -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
|
@ -10,13 +10,16 @@ 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 kotlinx.html.org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import react.*
|
import react.*
|
||||||
import react.dom.attrs
|
import react.dom.attrs
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
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
|
||||||
@ -148,7 +151,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
|||||||
css {
|
css {
|
||||||
//+TreeStyles.resizeableInput
|
//+TreeStyles.resizeableInput
|
||||||
width = 160.px
|
width = 160.px
|
||||||
margin(1.px, 5.px)
|
margin = Margin(1.px, 5.px)
|
||||||
}
|
}
|
||||||
ValueChooser {
|
ValueChooser {
|
||||||
attrs {
|
attrs {
|
||||||
@ -167,7 +170,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
|||||||
css {
|
css {
|
||||||
width = 24.px
|
width = 24.px
|
||||||
alignSelf = Align.stretch
|
alignSelf = Align.stretch
|
||||||
margin(1.px, 5.px)
|
margin = Margin(1.px, 5.px)
|
||||||
backgroundColor = Color.white
|
backgroundColor = Color.white
|
||||||
borderStyle = BorderStyle.solid
|
borderStyle = BorderStyle.solid
|
||||||
borderRadius = 2.px
|
borderRadius = 2.px
|
@ -4,8 +4,9 @@ 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.org.w3c.dom.events.Event
|
import kotlinx.html.js.onInputFunction
|
||||||
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
|
||||||
@ -58,8 +59,8 @@ public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") {
|
|||||||
attrs {
|
attrs {
|
||||||
disabled = rangeDisabled
|
disabled = rangeDisabled
|
||||||
value = innerValue?.toString() ?: ""
|
value = innerValue?.toString() ?: ""
|
||||||
onChangeFunction = handleChange
|
// onChangeFunction = handleChange
|
||||||
consumer.onTagEvent(this, "input", handleChange)
|
onInputFunction = 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
|
@ -52,10 +52,10 @@ public object TreeStyles : StyleSheet("treeStyles", true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public val treeLabel:RuleSet by css {
|
public val treeLabel:RuleSet by css {
|
||||||
border = "none"
|
border = Border.none
|
||||||
padding(left = 4.pt, right = 4.pt, top = 0.pt, bottom = 0.pt)
|
padding = Padding(left = 4.pt, right = 4.pt, top = 0.pt, bottom = 0.pt)
|
||||||
textAlign = TextAlign.left
|
textAlign = TextAlign.left
|
||||||
flex(1.0)
|
flex = Flex(1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public val treeLabelInactive: RuleSet by css {
|
public val treeLabelInactive: RuleSet by css {
|
@ -1,13 +1,10 @@
|
|||||||
package space.kscience.visionforge.react
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
import kotlinx.css.Color
|
import kotlinx.css.*
|
||||||
import kotlinx.css.Cursor
|
import kotlinx.css.properties.TextDecoration
|
||||||
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 kotlinx.html.org.w3c.dom.events.Event
|
import 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
|
||||||
@ -37,7 +34,7 @@ private val TreeLabel = fc<ObjectTreeProps> { props ->
|
|||||||
color = Color("#069")
|
color = Color("#069")
|
||||||
cursor = Cursor.pointer
|
cursor = Cursor.pointer
|
||||||
hover {
|
hover {
|
||||||
textDecoration(TextDecorationLine.underline)
|
textDecoration = TextDecoration(setOf(TextDecorationLine.underline))
|
||||||
}
|
}
|
||||||
if (props.name == props.selected) {
|
if (props.name == props.selected) {
|
||||||
+TreeStyles.treeLabelSelected
|
+TreeStyles.treeLabelSelected
|
@ -1,15 +1,12 @@
|
|||||||
package space.kscience.visionforge.react
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
import kotlinx.css.margin
|
import kotlinx.css.*
|
||||||
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
|
||||||
@ -145,7 +142,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(0.px)
|
margin = Margin(0.px)
|
||||||
}
|
}
|
||||||
attrs {
|
attrs {
|
||||||
this.value = props.value?.let { value ->
|
this.value = props.value?.let { value ->
|
@ -1,11 +1,11 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.js")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion: String by rootProject.extra
|
val dataforgeVersion: String by rootProject.extra
|
||||||
|
|
||||||
kotlin{
|
kscience{
|
||||||
js(IR){
|
js{
|
||||||
useCommonJs()
|
useCommonJs()
|
||||||
browser {
|
browser {
|
||||||
commonWebpackConfig {
|
commonWebpackConfig {
|
||||||
@ -15,12 +15,11 @@ kotlin{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
jsMain{
|
||||||
|
api(projects.ui.react)
|
||||||
|
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
|
||||||
|
|
||||||
dependencies{
|
implementation(npm("core-js","3.12.1"))
|
||||||
api(project(":ui:react"))
|
implementation(npm("file-saver", "2.0.2"))
|
||||||
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
|
}
|
||||||
|
|
||||||
implementation(npm("core-js","3.12.1"))
|
|
||||||
implementation(npm("file-saver", "2.0.2"))
|
|
||||||
}
|
}
|
@ -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(10.0, 1.0, FlexBasis("600px"))
|
flex = 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(4.px)
|
padding = Padding(4.px)
|
||||||
minWidth = 400.px
|
minWidth = 400.px
|
||||||
height = 100.pct
|
height = 100.pct
|
||||||
overflowY = Overflow.auto
|
overflowY = Overflow.auto
|
||||||
flex(1.0, 10.0, FlexBasis("300px"))
|
flex = Flex(1.0, 10.0, FlexBasis("300px"))
|
||||||
}
|
}
|
||||||
ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs)
|
ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs)
|
||||||
}
|
}
|
@ -2,13 +2,9 @@ package space.kscience.visionforge.ring
|
|||||||
|
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.css.BorderStyle
|
import kotlinx.css.*
|
||||||
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 kotlinx.html.org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import org.w3c.files.Blob
|
import org.w3c.files.Blob
|
||||||
import org.w3c.files.BlobPropertyBag
|
import org.w3c.files.BlobPropertyBag
|
||||||
import react.FC
|
import react.FC
|
||||||
@ -34,7 +30,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("file-saver")
|
val fileSaver = kotlinext.js.require<dynamic>("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)
|
||||||
}
|
}
|
||||||
@ -58,8 +54,8 @@ internal val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { pr
|
|||||||
flexColumn {
|
flexColumn {
|
||||||
flexRow {
|
flexRow {
|
||||||
css {
|
css {
|
||||||
border(1.px, BorderStyle.solid, Color.blue)
|
border = Border(1.px, BorderStyle.solid, Color.blue)
|
||||||
padding(4.px)
|
padding = Padding(4.px)
|
||||||
}
|
}
|
||||||
props.vision?.let { vision ->
|
props.vision?.let { vision ->
|
||||||
button {
|
button {
|
@ -9,12 +9,34 @@ 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.
|
||||||
*/
|
*/
|
||||||
@ -28,6 +50,22 @@ 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]
|
||||||
*/
|
*/
|
@ -0,0 +1,42 @@
|
|||||||
|
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()))
|
||||||
|
}
|
||||||
|
}
|
@ -187,30 +187,10 @@ internal abstract class VisionChildrenImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
items?.forEach { set(it.key, null) }
|
items?.clear()
|
||||||
// if (!items.isNullOrEmpty()) {
|
updateJobs.values.forEach { it.cancel() }
|
||||||
// updateJobs.values.forEach {
|
updateJobs.clear()
|
||||||
// it.cancel()
|
onChange(Name.EMPTY)
|
||||||
// }
|
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
|
@ -3,50 +3,38 @@ 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.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
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(public val targetName: Name, public val meta: Meta) : VisionEvent
|
public class VisionMetaEvent(override val targetName: Name, public val meta: Meta) : VisionEvent
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
@Serializable
|
||||||
@SerialName("change")
|
@SerialName("change")
|
||||||
public data class VisionChange(
|
public class VisionChangeEvent(override val targetName: Name, public val change: VisionChange) : VisionEvent
|
||||||
public val vision: Vision? = null,
|
|
||||||
public val properties: Meta? = null,
|
public val Vision.Companion.CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
|
||||||
public val children: Map<Name, VisionChange>? = null,
|
|
||||||
) : VisionEvent
|
/**
|
||||||
|
* Set the payload to be sent to server on click
|
||||||
|
*/
|
||||||
|
public fun Vision.onClickPayload(payloadBuilder: MutableMeta.() -> Unit){
|
||||||
|
properties[VisionEvent.CLICK_EVENT_KEY] = Meta(payloadBuilder)
|
||||||
|
}
|
@ -5,6 +5,9 @@ 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
|
||||||
@ -12,7 +15,10 @@ 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.*
|
import space.kscience.dataforge.meta.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
|
||||||
@ -26,9 +32,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 VisionClient : AbstractPlugin() {
|
public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
private val visionManager: VisionManager by require(VisionManager)
|
override 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
|
||||||
@ -66,7 +72,7 @@ public class VisionClient : AbstractPlugin() {
|
|||||||
/**
|
/**
|
||||||
* Communicate vision property changed from rendering engine to model
|
* Communicate vision property changed from rendering engine to model
|
||||||
*/
|
*/
|
||||||
public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
|
override 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)
|
||||||
@ -82,7 +88,7 @@ public class VisionClient : AbstractPlugin() {
|
|||||||
/**
|
/**
|
||||||
* Send a custom feedback event
|
* Send a custom feedback event
|
||||||
*/
|
*/
|
||||||
public suspend fun sendEvent(event: VisionEvent) {
|
override suspend fun sendEvent(event: VisionEvent) {
|
||||||
eventCollector.emit(event)
|
eventCollector.emit(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,21 +147,19 @@ public class VisionClient : AbstractPlugin() {
|
|||||||
|
|
||||||
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 {
|
||||||
send(change.toJsonString(visionManager))
|
eventCollector.emit(VisionChangeEvent(name, change.deepCopy(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'" }
|
||||||
@ -251,37 +255,15 @@ public class VisionClient : AbstractPlugin() {
|
|||||||
textVisionRenderer(this),
|
textVisionRenderer(this),
|
||||||
formVisionRenderer(this)
|
formVisionRenderer(this)
|
||||||
).associateByName()
|
).associateByName()
|
||||||
} else super.content(target)
|
} else super<AbstractPlugin>.content(target)
|
||||||
|
|
||||||
public companion object : PluginFactory<VisionClient> {
|
public companion object : PluginFactory<JsVisionClient> {
|
||||||
override fun build(context: Context, meta: Meta): VisionClient = VisionClient()
|
override fun build(context: Context, meta: Meta): JsVisionClient = JsVisionClient()
|
||||||
|
|
||||||
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)
|
||||||
@ -293,7 +275,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 VisionClient.renderAllVisionsIn(element: Element) {
|
public fun JsVisionClient.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 ->
|
||||||
@ -304,7 +286,7 @@ public fun VisionClient.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 VisionClient.renderAllVisionsById(document: Document, id: String): Unit {
|
public fun JsVisionClient.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)
|
||||||
@ -317,13 +299,13 @@ public fun VisionClient.renderAllVisionsById(document: Document, id: String): Un
|
|||||||
/**
|
/**
|
||||||
* 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 VisionClient.renderAllVisions(): Unit = whenDocumentLoaded {
|
public fun JsVisionClient.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(VisionClient)
|
private val client = context.request(JsVisionClient)
|
||||||
|
|
||||||
override fun start(document: Document, state: Map<String, Any>) {
|
override fun start(document: Document, state: Map<String, Any>) {
|
||||||
context.logger.info {
|
context.logger.info {
|
||||||
@ -347,7 +329,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(VisionClient)
|
plugin(JsVisionClient)
|
||||||
contextBuilder()
|
contextBuilder()
|
||||||
}
|
}
|
||||||
|
|
@ -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: VisionClient,
|
client: JsVisionClient,
|
||||||
): 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: VisionClient,
|
client: JsVisionClient,
|
||||||
): 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: VisionClient,
|
client: JsVisionClient,
|
||||||
): 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
|
||||||
|
@ -9,7 +9,7 @@ kscience {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.visionforgeSolid)
|
api(projects.visionforgeSolid)
|
||||||
api("space.kscience:gdml:0.4.0")
|
api("space.kscience:gdml:0.5.0")
|
||||||
}
|
}
|
||||||
dependencies(jvmTest) {
|
dependencies(jvmTest) {
|
||||||
implementation(spclibs.logback.classic)
|
implementation(spclibs.logback.classic)
|
||||||
|
@ -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.VisionClient
|
import space.kscience.visionforge.JsVisionClient
|
||||||
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(VisionClient)
|
private val client by require(JsVisionClient)
|
||||||
|
|
||||||
public fun renderAllVisionsIn(element: Element) {
|
public fun renderAllVisionsIn(element: Element) {
|
||||||
client.renderAllVisionsIn(element)
|
client.renderAllVisionsIn(element)
|
||||||
|
@ -2,7 +2,7 @@ plugins {
|
|||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
val markdownVersion = "0.4.1"
|
val markdownVersion = "0.5.2"
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
|
@ -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: VisionClient by require(VisionClient)
|
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||||
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
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ plugins {
|
|||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
val plotlyVersion = "0.5.3"
|
val plotlyVersion = "0.6.0"
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
|
@ -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: VisionClient by require(VisionClient)
|
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||||
|
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
|
@ -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 VisionChange) {
|
if (event is VisionChangeEvent) {
|
||||||
update(event)
|
update(event.change)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resolveVision: (Name) -> Vision?,
|
resolveVision: (Name) -> Vision?,
|
||||||
|
@ -15,6 +15,9 @@ 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(
|
||||||
|
@ -5,6 +5,9 @@ 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>()
|
||||||
|
@ -12,7 +12,7 @@ import space.kscience.dataforge.names.asName
|
|||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
public abstract class LightSource : SolidBase<LightSource>() {
|
public abstract class LightSource : MiscSolid() {
|
||||||
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)
|
||||||
|
@ -6,13 +6,19 @@ 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 = "@xes"
|
public const val AXES_NAME: String = "@axes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ 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()) {
|
||||||
|
|
||||||
|
@ -152,7 +152,10 @@ 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
|
||||||
@ -163,7 +166,10 @@ internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@ -193,17 +199,17 @@ internal fun point(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var Solid.position: Float32Vector3D? by point(POSITION_KEY, 0f)
|
public var Solid.position: Float32Vector3D? by float32Vector(POSITION_KEY, 0f)
|
||||||
public var Solid.rotation: Float32Vector3D? by point(ROTATION_KEY, 0f)
|
public var Solid.rotation: Float32Vector3D? by float32Vector(ROTATION_KEY, 0f)
|
||||||
public var Solid.scale: Float32Vector3D? by point(SCALE_KEY, 1f)
|
public var Solid.scale: Float32Vector3D? by float32Vector(SCALE_KEY, 1f)
|
||||||
|
|
||||||
public var Solid.x: Number by float(X_POSITION_KEY, 0f)
|
public var Solid.x: Number by float32(X_POSITION_KEY, 0f)
|
||||||
public var Solid.y: Number by float(Y_POSITION_KEY, 0f)
|
public var Solid.y: Number by float32(Y_POSITION_KEY, 0f)
|
||||||
public var Solid.z: Number by float(Z_POSITION_KEY, 0f)
|
public var Solid.z: Number by float32(Z_POSITION_KEY, 0f)
|
||||||
|
|
||||||
public var Solid.rotationX: Number by float(X_ROTATION_KEY, 0f)
|
public var Solid.rotationX: Number by float32(X_ROTATION_KEY, 0f)
|
||||||
public var Solid.rotationY: Number by float(Y_ROTATION_KEY, 0f)
|
public var Solid.rotationY: Number by float32(Y_ROTATION_KEY, 0f)
|
||||||
public var Solid.rotationZ: Number by float(Z_ROTATION_KEY, 0f)
|
public var Solid.rotationZ: Number by float32(Z_ROTATION_KEY, 0f)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw quaternion value defined in properties
|
* Raw quaternion value defined in properties
|
||||||
@ -241,9 +247,9 @@ public var Solid.quaternion: Quaternion
|
|||||||
quaternionOrNull = value
|
quaternionOrNull = value
|
||||||
}
|
}
|
||||||
|
|
||||||
public var Solid.scaleX: Number by float(X_SCALE_KEY, 1f)
|
public var Solid.scaleX: Number by float32(X_SCALE_KEY, 1f)
|
||||||
public var Solid.scaleY: Number by float(Y_SCALE_KEY, 1f)
|
public var Solid.scaleY: Number by float32(Y_SCALE_KEY, 1f)
|
||||||
public var Solid.scaleZ: Number by float(Z_SCALE_KEY, 1f)
|
public var Solid.scaleZ: Number by float32(Z_SCALE_KEY, 1f)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add rotation with given [angle] relative to given [axis]
|
* Add rotation with given [angle] relative to given [axis]
|
||||||
|
@ -5,6 +5,9 @@ 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 {
|
||||||
|
@ -12,6 +12,9 @@ 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() {
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ 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
|
||||||
@ -240,94 +241,3 @@ 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"
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
@ -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: VisionClient by require(VisionClient)
|
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||||
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("tabulator-tables/dist/css/tabulator.min.css")
|
kotlinext.js.require<Any>("tabulator-tables/dist/css/tabulator.min.css")
|
||||||
kotlinext.js.require("tabulator-tables/src/js/modules/ResizeColumns/ResizeColumns.js")
|
kotlinext.js.require<Any>("tabulator-tables/src/js/modules/ResizeColumns/ResizeColumns.js")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun rateVision(vision: Vision): Int = when (vision) {
|
override fun rateVision(vision: Vision): Int = when (vision) {
|
||||||
|
@ -1,17 +1,23 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.js")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
api(projects.visionforgeSolid)
|
||||||
|
implementation(npm("three", "0.143.0"))
|
||||||
|
implementation(npm("three-csg-ts", "3.1.10"))
|
||||||
|
implementation(npm("three.meshline","1.4.0"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
|
||||||
api(projects.visionforgeSolid)
|
|
||||||
implementation(npm("three", "0.143.0"))
|
|
||||||
implementation(npm("three-csg-ts", "3.1.10"))
|
|
||||||
implementation(npm("three.meshline","1.4.0"))
|
|
||||||
}
|
|
||||||
|
@ -123,8 +123,8 @@ public class ThreeCanvas(
|
|||||||
element.appendChild(canvas)
|
element.appendChild(canvas)
|
||||||
updateSize()
|
updateSize()
|
||||||
canvas.addEventListener("pointerdown", {
|
canvas.addEventListener("pointerdown", {
|
||||||
val picked = pick()
|
val newPicked = pick()
|
||||||
options.onSelect?.invoke(picked?.fullName())
|
options.onSelect?.invoke(newPicked?.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 picked = pick()
|
val newPicked = pick()
|
||||||
|
|
||||||
if (picked != null && this.picked != picked) {
|
if (newPicked != null && picked !== newPicked) {
|
||||||
this.picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||||
picked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
newPicked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||||
this.picked = picked
|
picked = newPicked
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = 2f
|
thickness = 1f
|
||||||
cached = true
|
cached = true
|
||||||
}
|
}
|
||||||
//
|
//
|
@ -7,12 +7,10 @@ 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.ElementVisionRenderer
|
import space.kscience.visionforge.*
|
||||||
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.visible
|
import space.kscience.visionforge.solid.three.set
|
||||||
import three.core.Object3D
|
import three.core.Object3D
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -23,6 +21,8 @@ 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,6 +90,8 @@ 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
Loading…
Reference in New Issue
Block a user