import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.css.* import react.RProps import react.child import react.functionalComponent import space.kscience.dataforge.context.Context import space.kscience.plotly.models.Trace import space.kscience.visionforge.markup.VisionOfMarkup import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.solid import space.kscience.visionforge.solid.* import styled.css import styled.styledDiv import kotlin.math.sqrt external interface DemoProps : RProps { var context: Context } val GravityDemo = functionalComponent<DemoProps> { props -> val velocityTrace = Trace{ name = "velocity" } val energyTrace = Trace{ name = "energy" } val markup = VisionOfMarkup() styledDiv { css { height = 100.vh - 50.pt } styledDiv { css { height = 50.vh } child(ThreeCanvasWithControls) { attrs { context = props.context solid { sphere(5.0, "ball") { detail = 16 color("red") val h = 100.0 y = h context.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 val energy = g * y.toDouble() + velocity * velocity / 2 y = y.toDouble() + velocity * dt velocityTrace.appendXYLatest(time, y) energyTrace.appendXYLatest(time, energy) if (y.toDouble() <= 2.5) { //conservation of energy velocity = sqrt(2 * g * h) } markup.content = """ ## Bouncing sphere parameters **velocity** = $velocity **energy** = $energy """.trimIndent() } } } box(200, 5, 200, name = "floor") { y = -2.5 } } } } } flexRow { css { alignContent = Align.stretch alignItems = Align.stretch height = 50.vh - 50.pt } plotly { traces(velocityTrace) } Markup { attrs { this.markup = markup } } } } }