Update examples

This commit is contained in:
Alexander Nozik 2021-08-15 20:04:21 +03:00
parent 95459422d6
commit 8a8bac48db
7 changed files with 169 additions and 93 deletions

View File

@ -1,6 +1,9 @@
package space.kscience.visionforge.gdml.demo package space.kscience.visionforge.gdml.demo
import kotlinx.browser.window import kotlinx.browser.window
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import org.w3c.files.File
import org.w3c.files.FileReader import org.w3c.files.FileReader
import org.w3c.files.get import org.w3c.files.get
import react.* import react.*
@ -27,32 +30,43 @@ external interface GDMLAppProps : RProps {
@JsExport @JsExport
val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props -> val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
val visionManager = useMemo(props.context) { props.context.fetch(Solids).visionManager } val visionManager = useMemo(props.context) { props.context.fetch(Solids).visionManager }
var vision: Solid? by useState { props.vision?.apply { root(visionManager) } } var deferredVision: Deferred<Solid?> by useState {
CompletableDeferred(props.vision)
}
fun loadData(name: String, data: String) { fun readFileAsync(file: File): Deferred<Solid?> {
val parsedVision = when { val deferred = CompletableDeferred<Solid?>()
name.endsWith(".gdml") || name.endsWith(".xml") -> { FileReader().apply {
val gdml = Gdml.decodeFromString(data) onload = {
gdml.toVision().apply { val data = result as String
root(visionManager) val name = file.name
console.info("Marking layers for file $name") val parsedVision = when {
markLayers() name.endsWith(".gdml") || name.endsWith(".xml") -> {
val gdml = Gdml.decodeFromString(data)
gdml.toVision().apply {
root(visionManager)
console.info("Marking layers for file $name")
markLayers()
}
}
name.endsWith(".json") -> visionManager.decodeFromString(data)
else -> {
window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name")
}
} }
deferred.complete(parsedVision as? Solid ?: error("Parsed vision is not a solid"))
} }
name.endsWith(".json") -> visionManager.decodeFromString(data) readAsText(file)
else -> {
window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name")
}
} }
vision = parsedVision as? Solid ?: error("Parsed vision is not a solid") return deferred
} }
child(ThreeCanvasWithControls) { child(ThreeCanvasWithControls) {
attrs { attrs {
this.context = props.context this.context = props.context
this.solid = vision this.builderOfSolid = deferredVision
this.selected = props.selected this.selected = props.selected
tab("Load") { tab("Load") {
h2 { h2 {
@ -61,13 +75,7 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
fileDrop("(drag file here)") { files -> fileDrop("(drag file here)") { files ->
val file = files?.get(0) val file = files?.get(0)
if (file != null) { if (file != null) {
FileReader().apply { deferredVision = readFileAsync(file)
onload = {
val string = result as String
loadData(file.name, string)
}
readAsText(file)
}
} }
} }
} }

View File

@ -1,5 +1,4 @@
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -17,6 +16,7 @@ import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.ThreeWithControlsPlugin import space.kscience.visionforge.ring.ThreeWithControlsPlugin
import space.kscience.visionforge.ring.solid
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import space.kscience.visionforge.startApplication import space.kscience.visionforge.startApplication
import styled.css import styled.css
@ -38,51 +38,6 @@ private class JsPlaygroundApp : Application {
val bouncingSphereTrace = Trace() val bouncingSphereTrace = Trace()
val bouncingSphere = SolidGroup {
sphere(5.0, "ball") {
detail = 16
color("red")
val h = 100.0
y = h
GlobalScope.launch {
val g = 10.0
val dt = 0.1
var time = 0.0
var velocity = 0.0
while (isActive) {
delay(20)
time += dt
velocity -= g * dt
y = y.toDouble() + velocity * dt
bouncingSphereTrace.appendXY(time, y)
if (y.toDouble() <= 2.5) {
//conservation of energy
velocity = sqrt(2 * g * h)
}
}
}
}
box(200, 5, 200, name = "floor") {
y = -2.5
}
}
val random = Random(112233)
val visionOfSpheres = SolidGroup {
repeat(100) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)
y = random.nextDouble(-300.0, 300.0)
z = random.nextDouble(-300.0, 300.0)
material {
color(random.nextInt())
}
detail = 16
}
}
}
render(element) { render(element) {
styledDiv { styledDiv {
css { css {
@ -94,18 +49,46 @@ private class JsPlaygroundApp : Application {
SmartTabs("gravity") { SmartTabs("gravity") {
Tab("gravity") { Tab("gravity") {
styledDiv { styledDiv {
css{ css {
height = 50.vh height = 50.vh
} }
child(ThreeCanvasWithControls) { child(ThreeCanvasWithControls) {
attrs { attrs {
context = playgroundContext context = playgroundContext
solid = bouncingSphere solid {
sphere(5.0, "ball") {
detail = 16
color("red")
val h = 100.0
y = h
launch {
val g = 10.0
val dt = 0.1
var time = 0.0
var velocity = 0.0
while (isActive) {
delay(20)
time += dt
velocity -= g * dt
y = y.toDouble() + velocity * dt
bouncingSphereTrace.appendXY(time, y)
if (y.toDouble() <= 2.5) {
//conservation of energy
velocity = sqrt(2 * g * h)
}
}
}
}
box(200, 5, 200, name = "floor") {
y = -2.5
}
}
} }
} }
} }
styledDiv { styledDiv {
css{ css {
height = 40.vh height = 40.vh
} }
@ -129,10 +112,28 @@ private class JsPlaygroundApp : Application {
// } // }
// } // }
Tab("spheres") { Tab("spheres") {
child(ThreeCanvasWithControls) { styledDiv {
attrs { css {
context = playgroundContext height = 90.vh
solid = visionOfSpheres }
child(ThreeCanvasWithControls) {
val random = Random(112233)
attrs {
context = playgroundContext
solid {
repeat(100) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)
y = random.nextDouble(-300.0, 300.0)
z = random.nextDouble(-300.0, 300.0)
material {
color(random.nextInt())
}
detail = 16
}
}
}
}
} }
} }
} }

View File

@ -0,0 +1,19 @@
@file:JsModule("@jetbrains/ring-ui/components/loader/loader")
@file:JsNonModule
package ringui
import react.ComponentClass
import react.dom.WithClassName
// https://github.com/JetBrains/ring-ui/blob/master/components/loader/loader.js
public external interface LoaderProps : WithClassName {
public var size: Number
public var colors: Array<String>
public var message: String
public var stop: Boolean
public var deterministic: Boolean
}
@JsName("default")
public external val Loader: ComponentClass<LoaderProps>

View File

@ -0,0 +1,16 @@
@file:JsModule("@jetbrains/ring-ui/components/loader-screen/loader-screen")
@file:JsNonModule
package ringui
import react.ComponentClass
import react.dom.WithClassName
// https://github.com/JetBrains/ring-ui/blob/master/components/loader-screen/loader-screen.js
public external interface LoaderScreenProps : WithClassName {
public var containerClassName: String
public var message: String
}
@JsName("default")
public external val LoaderScreen: ComponentClass<LoaderScreenProps>

View File

@ -1,18 +1,19 @@
package space.kscience.visionforge.ring package space.kscience.visionforge.ring
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.css.* import kotlinx.css.*
import react.* import react.*
import react.dom.div import react.dom.div
import react.dom.span import react.dom.span
import ringui.Island import ringui.*
import ringui.IslandContent
import ringui.IslandHeader
import ringui.Link
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.length import space.kscience.dataforge.names.length
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.computeProperties import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.react.ThreeCanvasComponent import space.kscience.visionforge.react.ThreeCanvasComponent
@ -20,17 +21,24 @@ import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.react.propertyEditor import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
public external interface ThreeCanvasWithControlsProps : RProps { public external interface ThreeCanvasWithControlsProps : RProps {
public var context: Context public var context: Context
public var solid: Solid? public var builderOfSolid: Deferred<Solid?>
public var selected: Name? public var selected: Name?
public var additionalTabs: Map<String, RBuilder.() -> Unit>? public var additionalTabs: Map<String, RBuilder.() -> Unit>?
} }
public fun ThreeCanvasWithControlsProps.solid(block: SolidGroup.() -> Unit) {
builderOfSolid = context.async {
SolidGroup(block)
}
}
public fun ThreeCanvasWithControlsProps.tab(title: String, block: RBuilder.() -> Unit) { public fun ThreeCanvasWithControlsProps.tab(title: String, block: RBuilder.() -> Unit) {
additionalTabs = (additionalTabs ?: emptyMap()) + (title to block) additionalTabs = (additionalTabs ?: emptyMap()) + (title to block)
} }
@ -72,6 +80,13 @@ public fun RBuilder.nameCrumbs(name: Name?, link: (Name) -> Unit): ReactElement
public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsProps> = public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsProps> =
functionalComponent("ThreeViewWithControls") { props -> functionalComponent("ThreeViewWithControls") { props ->
var selected by useState { props.selected } var selected by useState { props.selected }
var solid: Solid? by useState(null)
useEffect {
props.context.launch {
solid = props.builderOfSolid.await()
}
}
val onSelect: (Name?) -> Unit = { val onSelect: (Name?) -> Unit = {
selected = it selected = it
@ -83,15 +98,16 @@ public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsPro
} }
} }
val selectedVision = useMemo(selected) { val selectedVision: Vision? = useMemo(props.builderOfSolid, selected) {
selected?.let { selected?.let {
when { when {
it.isEmpty() -> props.solid it.isEmpty() -> solid
else -> (props.solid as? VisionGroup)?.get(it) else -> (solid as? VisionGroup)?.get(it)
} }
} }
} }
flexRow { flexRow {
css { css {
height = 100.pct height = 100.pct
@ -108,12 +124,20 @@ public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsPro
position = Position.relative position = Position.relative
} }
child(ThreeCanvasComponent) { if (solid == null) {
attrs { LoaderScreen {
this.context = props.context attrs {
this.solid = props.solid message = "Loading Three vision"
this.selected = selected }
this.options = options }
} else {
child(ThreeCanvasComponent) {
attrs {
this.context = props.context
this.solid = solid
this.selected = selected
this.options = options
}
} }
} }
@ -150,7 +174,8 @@ public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsPro
minWidth = 400.px minWidth = 400.px
flex(1.0, 10.0, FlexBasis("300px")) flex(1.0, 10.0, FlexBasis("300px"))
} }
ringThreeControls(options, props.solid, selected, onSelect, additionalTabs = props.additionalTabs) ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs)
} }
} }
} }

View File

@ -1,5 +1,6 @@
package space.kscience.visionforge.ring package space.kscience.visionforge.ring
import kotlinx.coroutines.async
import org.w3c.dom.Element import org.w3c.dom.Element
import react.child import react.child
import space.kscience.dataforge.context.AbstractPlugin import space.kscience.dataforge.context.AbstractPlugin
@ -28,7 +29,7 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
child(ThreeCanvasWithControls) { child(ThreeCanvasWithControls) {
attrs { attrs {
this.context = this@ThreeWithControlsPlugin.context this.context = this@ThreeWithControlsPlugin.context
this.solid = vision as? Solid this.builderOfSolid = context.async { vision as Solid}
} }
} }
} }

View File

@ -1,7 +1,10 @@
package space.kscience.visionforge package space.kscience.visionforge
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.coroutines.CoroutineScope
import kotlinx.dom.hasClass import kotlinx.dom.hasClass
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
public external val module: Module public external val module: Module
@ -25,7 +28,10 @@ public external interface Module {
* *
* Base interface for applications supporting Hot Module Replacement (HMR). * Base interface for applications supporting Hot Module Replacement (HMR).
*/ */
public interface Application { public interface Application: CoroutineScope {
override val coroutineContext: CoroutineContext get() = EmptyCoroutineContext
/** /**
* Starting point for an application. * Starting point for an application.
* @param state Initial state between Hot Module Replacement (HMR). * @param state Initial state between Hot Module Replacement (HMR).