Generalize three with controls

This commit is contained in:
Alexander Nozik 2021-05-10 22:07:16 +03:00
parent 5afa9117c4
commit 1f8700efde
22 changed files with 231 additions and 130 deletions

View File

@ -22,7 +22,7 @@ allprojects {
}
group = "space.kscience"
version = "0.2.0-dev-16"
version = "0.2.0-dev-17"
}
subprojects {

View File

@ -14,10 +14,15 @@ repositories{
kotlin {
js(IR) {
useCommonJs()
browser {
webpackTask {
this.outputFileName = "js/visionforge-playground.js"
}
commonWebpackConfig {
sourceMaps = false
cssSupport.enabled = false
}
}
binaries.executable()
}
@ -54,7 +59,7 @@ kotlin {
val jsMain by getting{
dependencies {
api(project(":ui:bootstrap"))
implementation(project(":ui:ring"))
api(project(":visionforge-threejs"))
}
}

View File

@ -1,10 +1,10 @@
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.ring.ThreeWithControls
import space.kscience.visionforge.runVisionClient
import space.kscience.visionforge.solid.three.ThreePlugin
@DFExperimental
fun main() = runVisionClient {
plugin(PlotlyPlugin)
plugin(ThreePlugin)
plugin(ThreeWithControls)
}

View File

@ -3,14 +3,17 @@ package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context
import space.kscience.gdml.*
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.visible
import java.nio.file.Path
fun main() {
val context = Context {
plugin(Solids)
}
context.makeVisionFile {
context.makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceLocation.EMBED) {
vision("canvas") {
Gdml {
// geometry variables
@ -39,7 +42,7 @@ fun main() {
structure {
val worldMaterial = materials.composite("G4_AIR")
val worldBox = solids.box(worldSize, worldSize, worldSize)
val worldBox = solids.box(worldSize, worldSize, worldSize, name = "world")
val shieldingMaterial = materials.composite("G4_Pb")
val scintillatorMaterial = materials.composite("BC408")
@ -221,7 +224,14 @@ fun main() {
}
}
}.toVision {
this.solidAction
configure { parent, solid, material ->
//disable visibility for the world box
if(solid.name == "world"){
visible = false
}
//make all solids semi-transparent
transparent()
}
}
}
}

View File

@ -0,0 +1,3 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -8,10 +8,15 @@ description = "Jupyter api artifact for GDML rendering"
kotlin{
explicitApi = null
js{
useCommonJs()
browser {
webpackTask {
this.outputFileName = "js/gdml-jupyter.js"
}
commonWebpackConfig {
sourceMaps = false
cssSupport.enabled = false
}
}
binaries.executable()
}
@ -42,7 +47,7 @@ kotlin{
jsMain {
dependencies {
api(project(":visionforge-threejs"))
implementation(project(":ui:bootstrap"))
implementation(project(":ui:ring"))
}
}

View File

@ -1,27 +1,12 @@
package space.kscience.visionforge.gdml.jupyter
import kotlinx.css.ListStyleType
import kotlinx.css.listStyleType
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.bootstrap.useBootstrap
import space.kscience.visionforge.ring.ThreeWithControls
import space.kscience.visionforge.runVisionClient
import styled.injectGlobal
@DFExperimental
@JsExport
fun main(): Unit = runVisionClient {
useBootstrap()
injectGlobal {
rule("ul.nav") {
listStyleType = ListStyleType.none
}
rule(".treeStyles-tree") {
listStyleType = ListStyleType.none
}
rule("ol.breadcrumb") {
listStyleType = ListStyleType.none
}
}
plugin(ThreeWithControls)
}

View File

@ -1,83 +0,0 @@
package space.kscience.visionforge.gdml.jupyter
import kotlinx.css.*
import react.RProps
import react.child
import react.dom.h1
import react.functionalComponent
import react.useState
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision
import space.kscience.visionforge.bootstrap.gridRow
import space.kscience.visionforge.bootstrap.nameCrumbs
import space.kscience.visionforge.bootstrap.threeControls
import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css
import styled.styledDiv
external interface GdmlViewProps : RProps {
var context: Context
var rootVision: Vision?
var selected: Name?
}
@JsExport
val GdmlView = functionalComponent<GdmlViewProps>("GdmlView") { props ->
var selected by useState { props.selected }
var canvas: ThreeCanvas? by useState { null }
var vision: Vision? by useState { props.rootVision }
val onSelect: (Name?) -> Unit = {
selected = it
}
gridRow {
flexColumn {
css {
+"col-lg-9"
height = 100.vh
}
styledDiv {
css {
+"mx-auto"
+"page-header"
}
h1 { +"GDML/JSON loader demo" }
}
nameCrumbs(selected, "World", onSelect)
//canvas
child(ThreeCanvasComponent) {
attrs {
this.context = props.context
this.obj = vision as? Solid
this.selected = selected
this.options = Canvas3DOptions.invoke {
this.onSelect = onSelect
}
this.canvasCallback = {
canvas = it
}
}
}
}
flexColumn {
css {
+"col-lg-3"
padding(top = 4.px)
//border(1.px, BorderStyle.solid, Color.lightGray)
height = 100.vh
overflowY = Overflow.auto
}
canvas?.let {
threeControls(it, selected, onSelect)
}
}
}
}

View File

@ -36,9 +36,6 @@ internal class GdmlForJupyter : JupyterIntegration() {
js("three") {
classPath("js/gdml-jupyter.js")
}
// css("override") {
// classPath("css/jupyter-override.css")
// }
}
import(

View File

@ -0,0 +1,3 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -2,6 +2,8 @@ package space.kscience.visionforge.react
import kotlinx.css.Display
import kotlinx.css.display
import kotlinx.css.height
import kotlinx.css.pct
import org.w3c.dom.Element
import org.w3c.dom.HTMLElement
import react.*
@ -60,6 +62,7 @@ public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functio
styledDiv {
css {
display = Display.contents
height = 100.pct
}
ref = elementRef
}

View File

@ -21,6 +21,7 @@ dependencies{
implementation(npm("@jetbrains/icons", "3.14.1"))
implementation(npm("@jetbrains/ring-ui", "4.0.7"))
implementation(npm("core-js","3.12.1"))
implementation(npm("file-saver", "2.0.2"))
compileOnly(npm("url-loader","4.1.1"))
compileOnly(npm("postcss-loader","5.2.0"))
compileOnly(npm("source-map-loader","2.0.1"))

View File

@ -0,0 +1,23 @@
package ringui.grid
import react.RBuilder
import react.RHandler
import react.dom.WithClassName
public external interface ColProps : WithClassName {
public var xs: dynamic // number or boolean
public var sm: dynamic // number or boolean
public var md: dynamic // number or boolean
public var lg: dynamic // number or boolean
public var xsOffset: Number
public var smOffset: Number
public var mdOffset: Number
public var lgOffset: Number
public var reverse: Boolean
}
public fun RBuilder.ringCol(handler: RHandler<ColProps>){
GridModule.Col {
handler()
}
}

View File

@ -0,0 +1,20 @@
package ringui.grid
import react.RBuilder
import react.RClass
import react.RHandler
import react.RProps
@JsModule("@jetbrains/ring-ui/components/grid/grid")
internal external object GridModule {
val Grid: RClass<RProps>
val Row: RClass<RowProps>
val Col: RClass<dynamic>
}
public fun RBuilder.ringGrid(handler: RHandler<RProps>) {
GridModule.Grid {
handler()
}
}

View File

@ -0,0 +1,33 @@
package ringui.grid
import react.RBuilder
import react.RHandler
import react.dom.WithClassName
public enum class RowPosition {
xs,
sm,
md,
lg
}
public external interface RowProps : WithClassName {
public var reverse: Boolean
public var start: RowPosition
public var center: RowPosition
public var end: RowPosition
public var top: RowPosition
public var middle: RowPosition
public var baseline: RowPosition
public var bottom: RowPosition
public var around: RowPosition
public var between: RowPosition
public var first: RowPosition
public var last: RowPosition
}
public fun RBuilder.ringRow(handler: RHandler<RowProps>){
GridModule.Row {
handler()
}
}

View File

@ -0,0 +1,87 @@
package space.kscience.visionforge.ring
import kotlinx.css.*
import react.RProps
import react.child
import react.functionalComponent
import react.useState
import ringui.grid.ringCol
import ringui.grid.ringGrid
import ringui.grid.ringRow
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision
import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css
import styled.styledDiv
public external interface GdmlViewProps : RProps {
public var context: Context
public var rootVision: Vision?
public var selected: Name?
}
@JsExport
public val ThreeViewWithControls: (props: GdmlViewProps) -> dynamic =
functionalComponent<GdmlViewProps>("ThreeViewWithControls") { props ->
var selected by useState { props.selected }
var canvas: ThreeCanvas? by useState { null }
val onSelect: (Name?) -> Unit = {
selected = it
}
styledDiv {
css {
height = 100.pct
}
ringGrid {
ringRow {
ringCol {
attrs {
xs = 12
sm = 12
md = 8
lg = 9
}
child(ThreeCanvasComponent) {
attrs {
this.context = props.context
this.obj = props.rootVision as? Solid
this.selected = selected
this.options = Canvas3DOptions.invoke {
this.onSelect = onSelect
}
this.canvasCallback = {
canvas = it
}
}
}
}
ringCol {
attrs {
xs = 12
sm = 12
md = 4
lg = 3
}
styledDiv {
css {
padding(top = 4.px)
//border(1.px, BorderStyle.solid, Color.lightGray)
height = 100.pct
overflowY = Overflow.auto
}
canvas?.let {
ringThreeControls(it, selected, onSelect)
}
}
}
}
}
}
}

View File

@ -1,4 +1,4 @@
package space.kscience.visionforge.gdml.jupyter
package space.kscience.visionforge.ring
import org.w3c.dom.Element
import react.child
@ -15,8 +15,8 @@ import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.three.ThreePlugin
import kotlin.reflect.KClass
class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer {
val three by require(ThreePlugin)
public class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer {
public val three by require(ThreePlugin)
override val tag: PluginTag get() = Companion.tag
@ -25,7 +25,7 @@ class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer {
override fun render(element: Element, vision: Vision, meta: Meta) {
react.dom.render(element) {
child(GdmlView) {
child(ThreeViewWithControls) {
attrs {
this.context = this@ThreeWithControls.context
this.rootVision = vision
@ -41,7 +41,7 @@ class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer {
}
}
companion object : PluginFactory<ThreeWithControls> {
public companion object : PluginFactory<ThreeWithControls> {
override val tag: PluginTag = PluginTag("vision.threejs.withControls", PluginTag.DATAFORGE_GROUP)
override val type: KClass<ThreeWithControls> = ThreeWithControls::class
override fun invoke(meta: Meta, context: Context): ThreeWithControls = ThreeWithControls()

View File

@ -217,10 +217,7 @@ public fun VisionClient.renderAllVisions(): Unit = whenDocumentLoaded {
*/
public fun runVisionClient(contextBuilder: ContextBuilder.() -> Unit) {
console.info("Starting VisionForge context")
val context = Context("VisionForge"){
contextBuilder()
//plugin(VisionClient)
}
val context = Context("VisionForge", contextBuilder)
val visionClient = context.fetch(VisionClient)
window.asDynamic()[RENDER_FUNCTION_NAME] = visionClient::renderAllVisionsById

View File

@ -3,6 +3,7 @@ package space.kscience.visionforge.html
import kotlinx.html.link
import kotlinx.html.script
import kotlinx.html.unsafe
import org.slf4j.LoggerFactory
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.VisionManager
import java.nio.file.Files
@ -49,18 +50,22 @@ private fun ByteArray.toHexString() = asUByteArray().joinToString("") { it.toStr
*/
@OptIn(ExperimentalPathApi::class)
internal fun checkOrStoreFile(htmlPath: Path, filePath: Path, resource: String): Path {
//TODO add logging
val fullPath = htmlPath.resolveSibling(filePath).toAbsolutePath().resolve(resource)
val logger = LoggerFactory.getLogger("")
val bytes = VisionManager::class.java.getResourceAsStream("/$resource").readAllBytes()
logger.info("Resolving or storing resource file $resource")
val fullPath = htmlPath.resolveSibling(filePath).toAbsolutePath().resolve(resource)
logger.debug("Full path to resource file $resource: $fullPath")
val bytes = VisionManager.Companion::class.java.getResourceAsStream("/$resource")?.readAllBytes()
?: error("Resource $resource not found on classpath")
val md = MessageDigest.getInstance("MD5")
val checksum = md.digest(bytes).toHexString()
val md5File = fullPath.resolveSibling(fullPath.fileName.toString() + ".md5")
val skip: Boolean = Files.exists(fullPath) && Files.exists(md5File) && md5File.readText() == checksum
if (!skip) {
logger.debug("File $fullPath does not exist or wrong checksum. Writing file")
Files.createDirectories(fullPath.parent)
Files.write(fullPath, bytes, StandardOpenOption.CREATE, StandardOpenOption.WRITE)
Files.write(md5File, checksum.encodeToByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE)

View File

@ -48,8 +48,8 @@ public class GdmlTransformer {
useStyle(name)
}
public fun Solid.opaque() {
useStyle("opaque") {
public fun Solid.transparent() {
useStyle("transparent") {
SolidMaterial.MATERIAL_OPACITY_KEY put 0.3
"edges.enabled" put true
}
@ -73,7 +73,7 @@ public class GdmlTransformer {
{ parent, solid, material ->
val styleName = "materials.${material.name}"
if (parent.physVolumes.isNotEmpty()) opaque()
if (parent.physVolumes.isNotEmpty()) transparent()
useStyle(styleName) {
val vfMaterial = SolidMaterial().apply {
@ -85,6 +85,13 @@ public class GdmlTransformer {
}
private set
public fun configure(block: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit) {
val oldConfigure = configureSolid
configureSolid = { parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial ->
oldConfigure(parent, solid, material)
block(parent, solid, material)
}
}
public companion object {

View File

@ -3,6 +3,7 @@ plugins {
}
kotlin{
explicitApi = null
js{
binaries.library()
}

View File

@ -110,7 +110,6 @@ public class ThreeCanvas(
width = "100%"
height = "100%"
display = "block"
zIndex = "1000"
}
}