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

View File

@ -1,5 +1,4 @@
import kotlinx.browser.document
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
@ -17,6 +16,7 @@ import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
import space.kscience.visionforge.ring.solid
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.startApplication
import styled.css
@ -38,51 +38,6 @@ private class JsPlaygroundApp : Application {
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) {
styledDiv {
css {
@ -94,18 +49,46 @@ private class JsPlaygroundApp : Application {
SmartTabs("gravity") {
Tab("gravity") {
styledDiv {
css{
css {
height = 50.vh
}
child(ThreeCanvasWithControls) {
attrs {
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 {
css{
css {
height = 40.vh
}
@ -129,10 +112,28 @@ private class JsPlaygroundApp : Application {
// }
// }
Tab("spheres") {
child(ThreeCanvasWithControls) {
attrs {
context = playgroundContext
solid = visionOfSpheres
styledDiv {
css {
height = 90.vh
}
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
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.css.*
import react.*
import react.dom.div
import react.dom.span
import ringui.Island
import ringui.IslandContent
import ringui.IslandHeader
import ringui.Link
import ringui.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.length
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.computeProperties
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.propertyEditor
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import styled.css
import styled.styledDiv
public external interface ThreeCanvasWithControlsProps : RProps {
public var context: Context
public var solid: Solid?
public var builderOfSolid: Deferred<Solid?>
public var selected: Name?
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) {
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> =
functionalComponent("ThreeViewWithControls") { props ->
var selected by useState { props.selected }
var solid: Solid? by useState(null)
useEffect {
props.context.launch {
solid = props.builderOfSolid.await()
}
}
val onSelect: (Name?) -> Unit = {
selected = it
@ -83,15 +98,16 @@ public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsPro
}
}
val selectedVision = useMemo(selected) {
val selectedVision: Vision? = useMemo(props.builderOfSolid, selected) {
selected?.let {
when {
it.isEmpty() -> props.solid
else -> (props.solid as? VisionGroup)?.get(it)
it.isEmpty() -> solid
else -> (solid as? VisionGroup)?.get(it)
}
}
}
flexRow {
css {
height = 100.pct
@ -108,12 +124,20 @@ public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsPro
position = Position.relative
}
child(ThreeCanvasComponent) {
attrs {
this.context = props.context
this.solid = props.solid
this.selected = selected
this.options = options
if (solid == null) {
LoaderScreen {
attrs {
message = "Loading Three vision"
}
}
} 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
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
import kotlinx.coroutines.async
import org.w3c.dom.Element
import react.child
import space.kscience.dataforge.context.AbstractPlugin
@ -28,7 +29,7 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
child(ThreeCanvasWithControls) {
attrs {
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
import kotlinx.browser.document
import kotlinx.coroutines.CoroutineScope
import kotlinx.dom.hasClass
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
public external val module: Module
@ -25,7 +28,10 @@ public external interface Module {
*
* 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.
* @param state Initial state between Hot Module Replacement (HMR).