Compare commits
3 Commits
dev
...
refactor/c
| Author | SHA1 | Date | |
|---|---|---|---|
| 16bfb5b005 | |||
| 56061d1da0 | |||
| 99862f52b8 |
@@ -5,6 +5,7 @@
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
- Replaced `VisionTagConsumer` with a proper `VisionHtmlContext` as a context parameter.
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import space.kscience.gradle.useApache2Licence
|
||||
import space.kscience.gradle.useSPCTeam
|
||||
|
||||
@@ -17,17 +17,19 @@ allprojects {
|
||||
subprojects {
|
||||
if (name.startsWith("visionforge")) apply<MavenPublishPlugin>()
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
maven("https://maven.jzy3d.org/releases")
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
}
|
||||
// repositories {
|
||||
// mavenLocal()
|
||||
// maven("https://repo.kotlin.link")
|
||||
// mavenCentral()
|
||||
// maven("https://maven.jzy3d.org/releases")
|
||||
// maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
// }
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll("-Xcontext-parameters")
|
||||
plugins.withId("org.jetbrains.kotlin.multiplatform") {
|
||||
extensions.configure<KotlinMultiplatformExtension>{
|
||||
compilerOptions{
|
||||
freeCompilerArgs.addAll("-Xcontext-parameters")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import space.kscience.dataforge.meta.*
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.meta
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.*
|
||||
import java.util.zip.ZipInputStream
|
||||
import kotlin.io.path.Path
|
||||
|
||||
@@ -10,6 +10,7 @@ import space.kscience.plotly.models.scatter
|
||||
import space.kscience.plotly.plotly
|
||||
import space.kscience.tables.ColumnHeader
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.markup.markdown
|
||||
import space.kscience.visionforge.solid.axes
|
||||
import space.kscience.visionforge.solid.box
|
||||
|
||||
@@ -14,6 +14,7 @@ import space.kscience.kmath.geometry.euclidean3d.RotationOrder
|
||||
import space.kscience.kmath.geometry.euclidean3d.fromEuler
|
||||
import space.kscience.kmath.geometry.euclidean3d.fromRotation
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.*
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
|
||||
@@ -3,6 +3,7 @@ package space.kscience.visionforge.examples
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
|
||||
import space.kscience.kmath.geometry.radians
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.*
|
||||
import kotlin.math.PI
|
||||
|
||||
|
||||
@@ -15,8 +15,10 @@ import space.kscience.plotly.PlotlyPlugin
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.plotly.models.invoke
|
||||
import space.kscience.plotly.plot
|
||||
import space.kscience.plotly.plotly
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.server.openInBrowser
|
||||
import space.kscience.visionforge.server.visionPage
|
||||
import kotlin.math.PI
|
||||
@@ -51,15 +53,14 @@ suspend fun main() {
|
||||
|
||||
h1 { +"This is the plot page" }
|
||||
a("/other") { +"The other page" }
|
||||
vision {
|
||||
plotly {
|
||||
traces(sinTrace, cosTrace)
|
||||
layout {
|
||||
title = "Other dynamic plot"
|
||||
xaxis.title = "x axis name"
|
||||
yaxis.title = "y axis name"
|
||||
}
|
||||
plot {
|
||||
traces(sinTrace, cosTrace)
|
||||
layout {
|
||||
title = "Other dynamic plot"
|
||||
xaxis.title = "x axis name"
|
||||
yaxis.title = "y axis name"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.extruded
|
||||
import space.kscience.visionforge.solid.polygon
|
||||
|
||||
@@ -10,6 +10,7 @@ import space.kscience.dataforge.context.request
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.VisionOfHtmlForm
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.html.visionOfForm
|
||||
import space.kscience.visionforge.onPropertyChange
|
||||
import space.kscience.visionforge.server.close
|
||||
|
||||
@@ -3,6 +3,7 @@ package space.kscience.visionforge.examples
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
|
||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
|
||||
@@ -5,6 +5,7 @@ package space.kscience.visionforge.examples
|
||||
import space.kscience.gdml.*
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.color
|
||||
import space.kscience.visionforge.solid.invoke
|
||||
@@ -12,229 +13,230 @@ import space.kscience.visionforge.visible
|
||||
import java.nio.file.Path
|
||||
|
||||
fun main() = makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceLocation.EMBED) {
|
||||
vision("canvas") {
|
||||
requirePlugin(Solids)
|
||||
Gdml {
|
||||
// geometry variables
|
||||
val worldSize = 500
|
||||
vision("canvas") {
|
||||
requirePlugin(Solids)
|
||||
Gdml {
|
||||
// geometry variables
|
||||
val worldSize = 500
|
||||
// chamber
|
||||
val chamberHeight = 30 // length of the chamber
|
||||
val chamberDiameter = 102 // inner diameter of the copper chamber
|
||||
val chamberOuterSquareSide = 134 // chamber has a square footprint
|
||||
val chamberBackplateThickness = 15 // thickness of the backplate of the chamber
|
||||
// teflon disk
|
||||
val cathodeTeflonDiskHoleRadius = 15
|
||||
val cathodeTeflonDiskThickness = 5
|
||||
val cathodeCopperSupportOuterRadius = 45
|
||||
val cathodeCopperSupportInnerRadius = 8.5
|
||||
val cathodeCopperSupportThickness = 1.0
|
||||
// mylar cathode
|
||||
val mylarCathodeThickness = 0.004
|
||||
// patern
|
||||
val cathodePatternLineWidth = 0.3
|
||||
val cathodePatternDiskRadius = 4.25
|
||||
// readout
|
||||
val chamberTeflonWallThickness = 1
|
||||
val readoutKaptonThickness = 0.5
|
||||
val readoutCopperThickness = 0.2
|
||||
val readoutPlaneSide = 60
|
||||
|
||||
structure {
|
||||
val worldMaterial = materials.composite("G4_AIR")
|
||||
val worldBox = solids.box(worldSize, worldSize, worldSize, name = "world")
|
||||
|
||||
val shieldingMaterial = materials.composite("G4_Pb")
|
||||
val scintillatorMaterial = materials.composite("BC408")
|
||||
val captureMaterial = materials.composite("G4_Cd")
|
||||
|
||||
// chamber
|
||||
val chamberHeight = 30 // length of the chamber
|
||||
val chamberDiameter = 102 // inner diameter of the copper chamber
|
||||
val chamberOuterSquareSide = 134 // chamber has a square footprint
|
||||
val chamberBackplateThickness = 15 // thickness of the backplate of the chamber
|
||||
// teflon disk
|
||||
val cathodeTeflonDiskHoleRadius = 15
|
||||
val cathodeTeflonDiskThickness = 5
|
||||
val cathodeCopperSupportOuterRadius = 45
|
||||
val cathodeCopperSupportInnerRadius = 8.5
|
||||
val cathodeCopperSupportThickness = 1.0
|
||||
// mylar cathode
|
||||
val mylarCathodeThickness = 0.004
|
||||
// patern
|
||||
val cathodePatternLineWidth = 0.3
|
||||
val cathodePatternDiskRadius = 4.25
|
||||
// readout
|
||||
val chamberTeflonWallThickness = 1
|
||||
val readoutKaptonThickness = 0.5
|
||||
val readoutCopperThickness = 0.2
|
||||
val readoutPlaneSide = 60
|
||||
|
||||
structure {
|
||||
val worldMaterial = materials.composite("G4_AIR")
|
||||
val worldBox = solids.box(worldSize, worldSize, worldSize, name = "world")
|
||||
|
||||
val shieldingMaterial = materials.composite("G4_Pb")
|
||||
val scintillatorMaterial = materials.composite("BC408")
|
||||
val captureMaterial = materials.composite("G4_Cd")
|
||||
|
||||
// chamber
|
||||
val copperMaterial = materials.composite("G4_Cu")
|
||||
val chamberSolidBase = solids.box(chamberOuterSquareSide, chamberOuterSquareSide, chamberHeight)
|
||||
val chamberSolidHole = solids.tube(chamberDiameter / 2, chamberHeight)
|
||||
val chamberSolid = solids.subtraction(chamberSolidBase, chamberSolidHole)
|
||||
val chamberBodyVolume = volume(copperMaterial, chamberSolid)
|
||||
val chamberBackplateSolid =
|
||||
solids.box(chamberOuterSquareSide, chamberOuterSquareSide, chamberBackplateThickness)
|
||||
val chamberBackplateVolume = volume(copperMaterial, chamberBackplateSolid)
|
||||
// chamber teflon walls
|
||||
val teflonMaterial = materials.composite("G4_TEFLON")
|
||||
val chamberTeflonWallSolid = solids.tube(chamberDiameter / 2, chamberHeight) {
|
||||
rmin = chamberDiameter / 2.0 - chamberTeflonWallThickness
|
||||
}
|
||||
val chamberTeflonWallVolume = volume(teflonMaterial, chamberTeflonWallSolid)
|
||||
// cathode
|
||||
val cathodeCopperDiskMaterial = materials.composite("G4_Cu")
|
||||
val cathodeWindowMaterial = materials.composite("G4_MYLAR")
|
||||
|
||||
val cathodeTeflonDiskSolidBase =
|
||||
solids.tube(chamberOuterSquareSide / 2, cathodeTeflonDiskThickness) {
|
||||
rmin = cathodeTeflonDiskHoleRadius
|
||||
}
|
||||
val cathodeCopperDiskSolid =
|
||||
solids.tube(cathodeCopperSupportOuterRadius, cathodeCopperSupportThickness) {
|
||||
rmin = cathodeCopperSupportInnerRadius
|
||||
}
|
||||
|
||||
val cathodeTeflonDiskSolid = solids.subtraction(cathodeTeflonDiskSolidBase, cathodeCopperDiskSolid)
|
||||
val cathodeTeflonDiskVolume = volume(teflonMaterial, cathodeTeflonDiskSolid)
|
||||
|
||||
val cathodeWindowSolid = solids.tube(cathodeTeflonDiskHoleRadius, mylarCathodeThickness)
|
||||
val cathodeWindowVolume = volume(cathodeWindowMaterial, cathodeWindowSolid)
|
||||
|
||||
val cathodeFillingMaterial = materials.composite("G4_Galactic")
|
||||
val cathodeFillingSolidBase = solids.tube(cathodeTeflonDiskHoleRadius, cathodeTeflonDiskThickness)
|
||||
|
||||
val cathodeFillingSolid = solids.subtraction(cathodeFillingSolidBase, cathodeCopperDiskSolid) {
|
||||
position(z = chamberHeight / 2 - mylarCathodeThickness / 2)
|
||||
}
|
||||
val cathodeFillingVolume = volume(cathodeFillingMaterial, cathodeFillingSolid)
|
||||
|
||||
// pattern
|
||||
val cathodePatternLineAux = solids.box(
|
||||
cathodePatternLineWidth,
|
||||
cathodeCopperSupportInnerRadius * 2,
|
||||
cathodeCopperSupportThickness
|
||||
)
|
||||
val cathodePatternCentralHole = solids.tube(
|
||||
cathodePatternDiskRadius - 0 * cathodePatternLineWidth,
|
||||
cathodeCopperSupportThickness * 1.1
|
||||
)
|
||||
val cathodePatternLine = solids.subtraction(cathodePatternLineAux, cathodePatternCentralHole)
|
||||
|
||||
val cathodePatternDisk = solids.tube(
|
||||
cathodePatternDiskRadius,
|
||||
cathodeCopperSupportThickness
|
||||
) { rmin = cathodePatternDiskRadius - cathodePatternLineWidth }
|
||||
|
||||
|
||||
val cathodeCopperDiskSolidAux0 =
|
||||
solids.union(cathodeCopperDiskSolid, cathodePatternLine) {
|
||||
rotation(x = 0, y = 0, z = 0)
|
||||
}
|
||||
val cathodeCopperDiskSolidAux1 =
|
||||
solids.union(cathodeCopperDiskSolidAux0, cathodePatternLine) {
|
||||
rotation = GdmlRotation(
|
||||
"cathodePatternRotation1", x = 0, y = 0, z = 45
|
||||
)
|
||||
}
|
||||
val cathodeCopperDiskSolidAux2 =
|
||||
solids.union(cathodeCopperDiskSolidAux1, cathodePatternLine) {
|
||||
rotation = GdmlRotation(
|
||||
"cathodePatternRotation2", x = 0, y = 0, z = 90
|
||||
)
|
||||
}
|
||||
val cathodeCopperDiskSolidAux3 =
|
||||
solids.union(cathodeCopperDiskSolidAux2, cathodePatternLine) {
|
||||
rotation = GdmlRotation(
|
||||
"cathodePatternRotation3", x = 0, y = 0, z = 135
|
||||
)
|
||||
}
|
||||
|
||||
val cathodeCopperDiskFinal =
|
||||
solids.union(cathodeCopperDiskSolidAux3, cathodePatternDisk)
|
||||
|
||||
|
||||
val cathodeCopperDiskVolume =
|
||||
volume(cathodeCopperDiskMaterial, cathodeCopperDiskFinal)
|
||||
|
||||
val gasSolidOriginal = solids.tube(
|
||||
chamberDiameter / 2 - chamberTeflonWallThickness,
|
||||
chamberHeight
|
||||
)
|
||||
|
||||
val kaptonReadoutMaterial = materials.composite("G4_KAPTON")
|
||||
val kaptonReadoutSolid = solids.box(
|
||||
chamberOuterSquareSide,
|
||||
chamberOuterSquareSide,
|
||||
readoutKaptonThickness)
|
||||
val kaptonReadoutVolume = volume( kaptonReadoutMaterial, kaptonReadoutSolid)
|
||||
|
||||
val copperReadoutSolid =
|
||||
solids.box(readoutPlaneSide, readoutPlaneSide, readoutCopperThickness)
|
||||
val copperReadoutVolume = volume(copperMaterial, copperReadoutSolid)
|
||||
|
||||
val gasSolidAux =
|
||||
solids.subtraction(gasSolidOriginal, copperReadoutSolid) {
|
||||
position(z = -chamberHeight / 2 + readoutCopperThickness / 2)
|
||||
}
|
||||
|
||||
val gasMaterial = materials.composite("G4_Ar")
|
||||
val gasSolid =
|
||||
solids.subtraction( gasSolidAux, cathodeWindowSolid) {
|
||||
position(z = chamberHeight / 2 - mylarCathodeThickness / 2)
|
||||
rotation(z = 45)
|
||||
}
|
||||
val gasVolume = volume(gasMaterial, gasSolid)
|
||||
|
||||
// world setup
|
||||
world = volume(worldMaterial, worldBox) {
|
||||
physVolume(gasVolume) {
|
||||
name = "gas"
|
||||
}
|
||||
physVolume(kaptonReadoutVolume) {
|
||||
name = "kaptonReadout"
|
||||
position {
|
||||
z = -chamberHeight / 2 - readoutKaptonThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(copperReadoutVolume) {
|
||||
name = "copperReadout"
|
||||
position {
|
||||
z = -chamberHeight / 2 + readoutCopperThickness / 2
|
||||
}
|
||||
rotation { z = 45 }
|
||||
}
|
||||
physVolume(chamberBodyVolume) {
|
||||
name = "chamberBody"
|
||||
}
|
||||
physVolume(chamberBackplateVolume) {
|
||||
name = "chamberBackplate"
|
||||
position {
|
||||
z = -chamberHeight / 2 - readoutKaptonThickness - chamberBackplateThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(chamberTeflonWallVolume) {
|
||||
name = "chamberTeflonWall"
|
||||
}
|
||||
physVolume(cathodeTeflonDiskVolume) {
|
||||
name = "cathodeTeflonDisk"
|
||||
position {
|
||||
z = chamberHeight / 2 + cathodeTeflonDiskThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(cathodeCopperDiskVolume) {
|
||||
name = "cathodeCopperDisk"
|
||||
position {
|
||||
z = chamberHeight / 2 + cathodeCopperSupportThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(cathodeWindowVolume) {
|
||||
name = "cathodeWindow"
|
||||
position {
|
||||
z = chamberHeight / 2 - mylarCathodeThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(cathodeFillingVolume) {
|
||||
name = "cathodeFilling"
|
||||
position {
|
||||
z = chamberHeight / 2 + cathodeTeflonDiskThickness / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
val copperMaterial = materials.composite("G4_Cu")
|
||||
val chamberSolidBase = solids.box(chamberOuterSquareSide, chamberOuterSquareSide, chamberHeight)
|
||||
val chamberSolidHole = solids.tube(chamberDiameter / 2, chamberHeight)
|
||||
val chamberSolid = solids.subtraction(chamberSolidBase, chamberSolidHole)
|
||||
val chamberBodyVolume = volume(copperMaterial, chamberSolid)
|
||||
val chamberBackplateSolid =
|
||||
solids.box(chamberOuterSquareSide, chamberOuterSquareSide, chamberBackplateThickness)
|
||||
val chamberBackplateVolume = volume(copperMaterial, chamberBackplateSolid)
|
||||
// chamber teflon walls
|
||||
val teflonMaterial = materials.composite("G4_TEFLON")
|
||||
val chamberTeflonWallSolid = solids.tube(chamberDiameter / 2, chamberHeight) {
|
||||
rmin = chamberDiameter / 2.0 - chamberTeflonWallThickness
|
||||
}
|
||||
}.toVision {
|
||||
solids { _, solid, _ ->
|
||||
//disable visibility for the world box
|
||||
if(solid.name == "world"){
|
||||
visible = false
|
||||
val chamberTeflonWallVolume = volume(teflonMaterial, chamberTeflonWallSolid)
|
||||
// cathode
|
||||
val cathodeCopperDiskMaterial = materials.composite("G4_Cu")
|
||||
val cathodeWindowMaterial = materials.composite("G4_MYLAR")
|
||||
|
||||
val cathodeTeflonDiskSolidBase =
|
||||
solids.tube(chamberOuterSquareSide / 2, cathodeTeflonDiskThickness) {
|
||||
rmin = cathodeTeflonDiskHoleRadius
|
||||
}
|
||||
if(solid.name.startsWith("gas")){
|
||||
color("green")
|
||||
} else {
|
||||
//make all solids semi-transparent
|
||||
transparent()
|
||||
val cathodeCopperDiskSolid =
|
||||
solids.tube(cathodeCopperSupportOuterRadius, cathodeCopperSupportThickness) {
|
||||
rmin = cathodeCopperSupportInnerRadius
|
||||
}
|
||||
|
||||
val cathodeTeflonDiskSolid = solids.subtraction(cathodeTeflonDiskSolidBase, cathodeCopperDiskSolid)
|
||||
val cathodeTeflonDiskVolume = volume(teflonMaterial, cathodeTeflonDiskSolid)
|
||||
|
||||
val cathodeWindowSolid = solids.tube(cathodeTeflonDiskHoleRadius, mylarCathodeThickness)
|
||||
val cathodeWindowVolume = volume(cathodeWindowMaterial, cathodeWindowSolid)
|
||||
|
||||
val cathodeFillingMaterial = materials.composite("G4_Galactic")
|
||||
val cathodeFillingSolidBase = solids.tube(cathodeTeflonDiskHoleRadius, cathodeTeflonDiskThickness)
|
||||
|
||||
val cathodeFillingSolid = solids.subtraction(cathodeFillingSolidBase, cathodeCopperDiskSolid) {
|
||||
position(z = chamberHeight / 2 - mylarCathodeThickness / 2)
|
||||
}
|
||||
val cathodeFillingVolume = volume(cathodeFillingMaterial, cathodeFillingSolid)
|
||||
|
||||
// pattern
|
||||
val cathodePatternLineAux = solids.box(
|
||||
cathodePatternLineWidth,
|
||||
cathodeCopperSupportInnerRadius * 2,
|
||||
cathodeCopperSupportThickness
|
||||
)
|
||||
val cathodePatternCentralHole = solids.tube(
|
||||
cathodePatternDiskRadius - 0 * cathodePatternLineWidth,
|
||||
cathodeCopperSupportThickness * 1.1
|
||||
)
|
||||
val cathodePatternLine = solids.subtraction(cathodePatternLineAux, cathodePatternCentralHole)
|
||||
|
||||
val cathodePatternDisk = solids.tube(
|
||||
cathodePatternDiskRadius,
|
||||
cathodeCopperSupportThickness
|
||||
) { rmin = cathodePatternDiskRadius - cathodePatternLineWidth }
|
||||
|
||||
|
||||
val cathodeCopperDiskSolidAux0 =
|
||||
solids.union(cathodeCopperDiskSolid, cathodePatternLine) {
|
||||
rotation(x = 0, y = 0, z = 0)
|
||||
}
|
||||
val cathodeCopperDiskSolidAux1 =
|
||||
solids.union(cathodeCopperDiskSolidAux0, cathodePatternLine) {
|
||||
rotation = GdmlRotation(
|
||||
"cathodePatternRotation1", x = 0, y = 0, z = 45
|
||||
)
|
||||
}
|
||||
val cathodeCopperDiskSolidAux2 =
|
||||
solids.union(cathodeCopperDiskSolidAux1, cathodePatternLine) {
|
||||
rotation = GdmlRotation(
|
||||
"cathodePatternRotation2", x = 0, y = 0, z = 90
|
||||
)
|
||||
}
|
||||
val cathodeCopperDiskSolidAux3 =
|
||||
solids.union(cathodeCopperDiskSolidAux2, cathodePatternLine) {
|
||||
rotation = GdmlRotation(
|
||||
"cathodePatternRotation3", x = 0, y = 0, z = 135
|
||||
)
|
||||
}
|
||||
|
||||
val cathodeCopperDiskFinal =
|
||||
solids.union(cathodeCopperDiskSolidAux3, cathodePatternDisk)
|
||||
|
||||
|
||||
val cathodeCopperDiskVolume =
|
||||
volume(cathodeCopperDiskMaterial, cathodeCopperDiskFinal)
|
||||
|
||||
val gasSolidOriginal = solids.tube(
|
||||
chamberDiameter / 2 - chamberTeflonWallThickness,
|
||||
chamberHeight
|
||||
)
|
||||
|
||||
val kaptonReadoutMaterial = materials.composite("G4_KAPTON")
|
||||
val kaptonReadoutSolid = solids.box(
|
||||
chamberOuterSquareSide,
|
||||
chamberOuterSquareSide,
|
||||
readoutKaptonThickness
|
||||
)
|
||||
val kaptonReadoutVolume = volume(kaptonReadoutMaterial, kaptonReadoutSolid)
|
||||
|
||||
val copperReadoutSolid =
|
||||
solids.box(readoutPlaneSide, readoutPlaneSide, readoutCopperThickness)
|
||||
val copperReadoutVolume = volume(copperMaterial, copperReadoutSolid)
|
||||
|
||||
val gasSolidAux =
|
||||
solids.subtraction(gasSolidOriginal, copperReadoutSolid) {
|
||||
position(z = -chamberHeight / 2 + readoutCopperThickness / 2)
|
||||
}
|
||||
|
||||
val gasMaterial = materials.composite("G4_Ar")
|
||||
val gasSolid =
|
||||
solids.subtraction(gasSolidAux, cathodeWindowSolid) {
|
||||
position(z = chamberHeight / 2 - mylarCathodeThickness / 2)
|
||||
rotation(z = 45)
|
||||
}
|
||||
val gasVolume = volume(gasMaterial, gasSolid)
|
||||
|
||||
// world setup
|
||||
world = volume(worldMaterial, worldBox) {
|
||||
physVolume(gasVolume) {
|
||||
name = "gas"
|
||||
}
|
||||
physVolume(kaptonReadoutVolume) {
|
||||
name = "kaptonReadout"
|
||||
position {
|
||||
z = -chamberHeight / 2 - readoutKaptonThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(copperReadoutVolume) {
|
||||
name = "copperReadout"
|
||||
position {
|
||||
z = -chamberHeight / 2 + readoutCopperThickness / 2
|
||||
}
|
||||
rotation { z = 45 }
|
||||
}
|
||||
physVolume(chamberBodyVolume) {
|
||||
name = "chamberBody"
|
||||
}
|
||||
physVolume(chamberBackplateVolume) {
|
||||
name = "chamberBackplate"
|
||||
position {
|
||||
z = -chamberHeight / 2 - readoutKaptonThickness - chamberBackplateThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(chamberTeflonWallVolume) {
|
||||
name = "chamberTeflonWall"
|
||||
}
|
||||
physVolume(cathodeTeflonDiskVolume) {
|
||||
name = "cathodeTeflonDisk"
|
||||
position {
|
||||
z = chamberHeight / 2 + cathodeTeflonDiskThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(cathodeCopperDiskVolume) {
|
||||
name = "cathodeCopperDisk"
|
||||
position {
|
||||
z = chamberHeight / 2 + cathodeCopperSupportThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(cathodeWindowVolume) {
|
||||
name = "cathodeWindow"
|
||||
position {
|
||||
z = chamberHeight / 2 - mylarCathodeThickness / 2
|
||||
}
|
||||
}
|
||||
physVolume(cathodeFillingVolume) {
|
||||
name = "cathodeFilling"
|
||||
position {
|
||||
z = chamberHeight / 2 + cathodeTeflonDiskThickness / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.toVision {
|
||||
solids { _, solid, _ ->
|
||||
//disable visibility for the world box
|
||||
if (solid.name == "world") {
|
||||
visible = false
|
||||
}
|
||||
if (solid.name.startsWith("gas")) {
|
||||
color("green")
|
||||
} else {
|
||||
//make all solids semi-transparent
|
||||
transparent()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.gdml.gdml
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.solid
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.markup.markdown
|
||||
|
||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import space.kscience.plotly.Plotly
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.models.*
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
|
||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
vision {
|
||||
|
||||
@@ -4,6 +4,7 @@ import kotlinx.html.div
|
||||
import kotlinx.html.h1
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.*
|
||||
import java.nio.file.Paths
|
||||
import kotlin.random.Random
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.*
|
||||
import kotlin.math.PI
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.box
|
||||
import space.kscience.visionforge.solid.invoke
|
||||
import space.kscience.visionforge.solid.material
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.polygon
|
||||
import space.kscience.visionforge.solid.solid
|
||||
|
||||
@@ -4,6 +4,7 @@ import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.tables.ColumnHeader
|
||||
import space.kscience.tables.valueRow
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.tables.table
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.meta
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.server.close
|
||||
import space.kscience.visionforge.server.openInBrowser
|
||||
import space.kscience.visionforge.server.visionPage
|
||||
|
||||
@@ -4,6 +4,7 @@ import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.*
|
||||
import space.kscience.visionforge.three.makeThreeJsFile
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@ dependencies {
|
||||
}
|
||||
|
||||
kotlin{
|
||||
jvmToolchain(17)
|
||||
jvmToolchain(21)
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-Xcontext-parameters")
|
||||
}
|
||||
}
|
||||
|
||||
// A workaround for https://youtrack.jetbrains.com/issue/KT-44101
|
||||
|
||||
@@ -13,16 +13,17 @@ import space.kscience.plotly.models.geo.json.GeoJsonFeatureCollection
|
||||
import space.kscience.plotly.models.geo.json.combine
|
||||
import space.kscience.plotly.models.geo.openStreetMap
|
||||
import space.kscience.plotly.plot
|
||||
import space.kscience.visionforge.html.HtmlVisionContext
|
||||
import space.kscience.visionforge.plotly.serveSinglePage
|
||||
import space.kscience.visionforge.server.openInBrowser
|
||||
import java.net.URL
|
||||
import java.net.URI
|
||||
import kotlin.random.Random
|
||||
|
||||
suspend fun main() {
|
||||
|
||||
//downloading GeoJson
|
||||
val geoJsonString =
|
||||
URL("https://raw.githubusercontent.com/isellsoap/deutschlandGeoJSON/main/4_kreise/4_niedrig.geo.json").readText()
|
||||
URI("https://raw.githubusercontent.com/isellsoap/deutschlandGeoJSON/main/4_kreise/4_niedrig.geo.json").toURL().readText()
|
||||
|
||||
|
||||
// Filtering GeoJson features and creating new feature set
|
||||
@@ -50,7 +51,7 @@ suspend fun main() {
|
||||
locations.numbers = features.map { it.id!!.int }
|
||||
// Set random values to locations
|
||||
z.numbers = features.map { Random.nextDouble(1.0, 10.0) }
|
||||
context.launch {
|
||||
contextOf<HtmlVisionContext>().context.launch {
|
||||
while (isActive) {
|
||||
delay(300)
|
||||
z.numbers = features.map { Random.nextDouble(1.0, 10.0) }
|
||||
|
||||
@@ -10,7 +10,7 @@ import space.kscience.plotly.models.geo.json.GeoJsonFeatureCollection
|
||||
import space.kscience.plotly.models.geo.json.combine
|
||||
import space.kscience.plotly.models.geo.openStreetMap
|
||||
import space.kscience.plotly.openInBrowser
|
||||
import java.net.URL
|
||||
import java.net.URI
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ fun main() {
|
||||
|
||||
//downloading GeoJson
|
||||
val geoJsonString =
|
||||
URL("https://raw.githubusercontent.com/isellsoap/deutschlandGeoJSON/main/4_kreise/4_niedrig.geo.json").readText()
|
||||
URI("https://raw.githubusercontent.com/isellsoap/deutschlandGeoJSON/main/4_kreise/4_niedrig.geo.json")
|
||||
.toURL()
|
||||
.readText()
|
||||
|
||||
|
||||
// Filtering GeoJson features and creating new feature set
|
||||
|
||||
@@ -11,8 +11,9 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.html.HtmlVisionContext
|
||||
import space.kscience.visionforge.html.VisionOutput
|
||||
import space.kscience.visionforge.html.VisionTagConsumer
|
||||
import space.kscience.visionforge.html.vision
|
||||
import kotlin.js.JsName
|
||||
|
||||
/**
|
||||
@@ -77,7 +78,10 @@ public class PlotlyConfig : Scheme() {
|
||||
* By default, this property is initialized as an empty list and can be updated to include
|
||||
* necessary class names as strings.
|
||||
*/
|
||||
public var classes: List<String> by stringList(default = emptyArray(), key = VisionTagConsumer.OUTPUT_DIV_CLASSES_KEY.asName())
|
||||
public var classes: List<String> by stringList(
|
||||
default = emptyArray(),
|
||||
key = HtmlVisionContext.OUTPUT_DIV_CLASSES_KEY.asName()
|
||||
)
|
||||
|
||||
public fun withEditorButton() {
|
||||
showEditInChartStudio = true
|
||||
@@ -106,14 +110,10 @@ public inline fun VisionOutput.plotly(
|
||||
return Plotly.plot(block)
|
||||
}
|
||||
|
||||
|
||||
//FIXME rework VisionTagConsumer toa a context
|
||||
context(rootConsumer: VisionTagConsumer<*>)
|
||||
public fun TagConsumer<*>.plot(
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
public fun <T> TagConsumer<T>.plot(
|
||||
config: PlotlyConfig = PlotlyConfig(),
|
||||
block: Plot.() -> Unit,
|
||||
): Unit = with(rootConsumer) {
|
||||
this@plot.vision {
|
||||
plotly(config, block)
|
||||
}
|
||||
}
|
||||
): T = vision {
|
||||
plotly(config, block)
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ pluginManagement {
|
||||
val toolsVersion: String by extra
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
plugins {
|
||||
@@ -26,9 +26,10 @@ dependencyResolutionManagement {
|
||||
val toolsVersion: String by extra
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://maven.jzy3d.org/releases")
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
versionCatalogs {
|
||||
|
||||
@@ -16,8 +16,8 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.html.HtmlVisionContext
|
||||
import space.kscience.visionforge.html.VisionOutput
|
||||
import space.kscience.visionforge.html.VisionTagConsumer
|
||||
|
||||
/**
|
||||
* A Kotlin-browser plugin that renders visions based on provided renderers and governs communication with the server.
|
||||
@@ -116,7 +116,7 @@ public fun Vision(
|
||||
name: Name? = null,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
) {
|
||||
val actualName = name ?: NameToken(VisionTagConsumer.DEFAULT_VISION_NAME, vision.hashCode().toUInt().toString()).asName()
|
||||
val actualName = name ?: NameToken(HtmlVisionContext.DEFAULT_VISION_NAME, vision.hashCode().toUInt().toString()).asName()
|
||||
context.request(ComposeVisionClient).renderVision(actualName, vision, meta)
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ public fun Vision(
|
||||
meta: Meta = Meta.EMPTY,
|
||||
buildOutput: VisionOutput.() -> Vision,
|
||||
) {
|
||||
val actualName = name ?: NameToken(VisionTagConsumer.DEFAULT_VISION_NAME, buildOutput.hashCode().toUInt().toString()).asName()
|
||||
val actualName = name ?: NameToken(HtmlVisionContext.DEFAULT_VISION_NAME, buildOutput.hashCode().toUInt().toString()).asName()
|
||||
val output = VisionOutput(context, actualName)
|
||||
val vision = output.buildOutput()
|
||||
context.request(ComposeVisionClient).renderVision(actualName, vision, meta)
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.html.*
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.ContextAware
|
||||
import space.kscience.dataforge.context.PluginFactory
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.DEFAULT_VISION_NAME
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_CLASS
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_DIV_CLASSES_KEY
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_META_CLASS
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_NAME_ATTRIBUTE
|
||||
|
||||
/**
|
||||
* A placeholder object to attach inline vision builders.
|
||||
*/
|
||||
@VisionBuilder
|
||||
public class VisionOutput(override val context: Context, public val name: Name) : ContextAware {
|
||||
public var meta: Meta = Meta.EMPTY
|
||||
|
||||
private val requirements: MutableSet<PluginFactory<*>> = HashSet()
|
||||
|
||||
public fun requirePlugin(factory: PluginFactory<*>) {
|
||||
requirements.add(factory)
|
||||
}
|
||||
|
||||
public val visionManager: VisionManager
|
||||
get() = if (requirements.all { req -> context.plugins.find(true) { it.tag == req.tag } != null }) {
|
||||
context.visionManager
|
||||
} else {
|
||||
val newContext = context.buildContext(NameToken(DEFAULT_VISION_NAME, name.toString()).asName()) {
|
||||
plugin(VisionManager)
|
||||
requirements.forEach { plugin(it) }
|
||||
}
|
||||
newContext.visionManager
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public inline fun VisionOutput.meta(block: MutableMeta.() -> Unit) {
|
||||
this.meta = Meta(block)
|
||||
}
|
||||
|
||||
public fun VisionOutput.meta(metaRepr: MetaRepr) {
|
||||
this.meta = metaRepr.toMeta()
|
||||
}
|
||||
|
||||
/**
|
||||
* Modified scope that allows rendering output fragments and visions in them
|
||||
*/
|
||||
@VisionBuilder
|
||||
public abstract class HtmlVisionContext(
|
||||
override val context: Context,
|
||||
private val idPrefix: String? = null,
|
||||
) : ContextAware {
|
||||
|
||||
public open fun resolveId(name: Name): String = (idPrefix ?: "output") + "[$name]"
|
||||
|
||||
/**
|
||||
* Render a vision inside the output fragment
|
||||
* @param manager a [VisionManager] to be used in renderer
|
||||
* @param name name of the output container
|
||||
* @param vision an object to be rendered
|
||||
* @param outputMeta optional configuration for the output container
|
||||
*/
|
||||
public abstract fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta)
|
||||
|
||||
|
||||
public companion object {
|
||||
public const val OUTPUT_CLASS: String = "visionforge-output"
|
||||
public const val OUTPUT_META_CLASS: String = "visionforge-output-meta"
|
||||
public const val OUTPUT_DATA_CLASS: String = "visionforge-output-data"
|
||||
|
||||
public const val OUTPUT_DIV_CLASSES_KEY: String = "classes"
|
||||
|
||||
public const val OUTPUT_FETCH_ATTRIBUTE: String = "data-output-fetch"
|
||||
public const val OUTPUT_CONNECT_ATTRIBUTE: String = "data-output-connect"
|
||||
|
||||
public const val OUTPUT_RENDERED: String = "data-output-rendered"
|
||||
|
||||
public const val OUTPUT_NAME_ATTRIBUTE: String = "data-output-name"
|
||||
public const val OUTPUT_ENDPOINT_ATTRIBUTE: String = "data-output-endpoint"
|
||||
public const val DEFAULT_ENDPOINT: String = "."
|
||||
|
||||
public const val AUTO_DATA_ATTRIBUTE: String = "@auto"
|
||||
|
||||
public const val DEFAULT_VISION_NAME: String = "vision"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a placeholder for a vision output with optional [Vision] in it
|
||||
*/
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
public fun <T> TagConsumer<T>.addVision(
|
||||
name: Name,
|
||||
manager: VisionManager,
|
||||
vision: Vision?,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
): T = if (vision == null) div {
|
||||
+"Empty Vision output"
|
||||
} else div {
|
||||
id = htmlContext.resolveId(name)
|
||||
|
||||
classes = setOf(OUTPUT_CLASS, *(outputMeta[OUTPUT_DIV_CLASSES_KEY].stringList?.toTypedArray() ?: emptyArray()))
|
||||
if (vision.parent == null) {
|
||||
vision.setAsRoot(manager)
|
||||
}
|
||||
attributes[OUTPUT_NAME_ATTRIBUTE] = name.toString()
|
||||
with(htmlContext) {
|
||||
renderVision(manager, name, vision, outputMeta)
|
||||
}
|
||||
if (!outputMeta.isEmpty()) {
|
||||
//Hard-code output configuration
|
||||
script {
|
||||
type = "text/json"
|
||||
attributes["class"] = OUTPUT_META_CLASS
|
||||
unsafe {
|
||||
+("\n" + manager.jsonFormat.encodeToString(MetaSerializer, outputMeta) + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@VisionBuilder
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
public fun <T> TagConsumer<T>.vision(
|
||||
vision: Vision,
|
||||
name: Name? = null,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
) {
|
||||
val actualName = name ?: NameToken(DEFAULT_VISION_NAME, vision.hashCode().toUInt().toString()).asName()
|
||||
addVision(actualName, htmlContext.context.visionManager, vision, outputMeta)
|
||||
}
|
||||
|
||||
|
||||
@VisionBuilder
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
private fun <T> TagConsumer<T>.vision(
|
||||
visionManager: VisionManager,
|
||||
name: Name,
|
||||
vision: Vision,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
): T = div {
|
||||
id = htmlContext.resolveId(name)
|
||||
classes = setOf(OUTPUT_CLASS)
|
||||
vision.setAsRoot(visionManager)
|
||||
attributes[OUTPUT_NAME_ATTRIBUTE] = name.toString()
|
||||
with(htmlContext) {
|
||||
renderVision(visionManager, name, vision, outputMeta)
|
||||
}
|
||||
|
||||
if (!outputMeta.isEmpty()) {
|
||||
//Hard-code output configuration
|
||||
script {
|
||||
attributes["class"] = OUTPUT_META_CLASS
|
||||
unsafe {
|
||||
+visionManager.jsonFormat.encodeToString(MetaSerializer, outputMeta)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
private fun <T> TagConsumer<T>.vision(
|
||||
name: Name,
|
||||
vision: Vision,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
): T = vision(htmlContext.context.visionManager, name, vision, outputMeta)
|
||||
|
||||
/**
|
||||
* Insert a vision in this HTML.
|
||||
*/
|
||||
@VisionBuilder
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
public fun <T> TagConsumer<T>.vision(
|
||||
name: Name? = null,
|
||||
visionProvider: VisionOutput.() -> Vision,
|
||||
): T {
|
||||
val actualName = name ?: NameToken(DEFAULT_VISION_NAME, visionProvider.hashCode().toUInt().toString()).asName()
|
||||
val output = VisionOutput(htmlContext.context, actualName)
|
||||
val vision = output.visionProvider()
|
||||
return vision(output.visionManager, actualName, vision, output.meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a vision in this HTML.
|
||||
*/
|
||||
@VisionBuilder
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
public fun <T> TagConsumer<T>.vision(
|
||||
name: String?,
|
||||
visionProvider: VisionOutput.() -> Vision,
|
||||
): T = vision(name?.parseAsName(), visionProvider)
|
||||
@@ -3,16 +3,15 @@ package space.kscience.visionforge.html
|
||||
import kotlinx.html.*
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionManager
|
||||
|
||||
public fun interface HtmlVisionFragment {
|
||||
public fun VisionTagConsumer<*>.append()
|
||||
context(htmlContext: HtmlVisionContext) public fun TagConsumer<*>.append()
|
||||
}
|
||||
|
||||
public fun HtmlVisionFragment.appendTo(consumer: VisionTagConsumer<*>): Unit = consumer.append()
|
||||
context(scope: HtmlVisionContext)
|
||||
public fun HtmlVisionFragment.appendTo(consumer: TagConsumer<*>): Unit = consumer.append()
|
||||
|
||||
public data class VisionDisplay(val visionManager: VisionManager, val vision: Vision, val meta: Meta)
|
||||
|
||||
@@ -36,23 +35,7 @@ public fun TagConsumer<*>.visionFragment(
|
||||
fragment: HtmlVisionFragment,
|
||||
) {
|
||||
|
||||
val consumer = object : VisionTagConsumer<Any?>(this@visionFragment, visionManager, idPrefix) {
|
||||
|
||||
override fun <T> TagConsumer<T>.vision(name: Name?, buildOutput: VisionOutput.() -> Vision): T {
|
||||
//Avoid re-creating cached visions
|
||||
val actualName = name ?: NameToken(
|
||||
DEFAULT_VISION_NAME,
|
||||
buildOutput.hashCode().toString(16)
|
||||
).asName()
|
||||
|
||||
val display = displayCache.getOrPut(actualName) {
|
||||
val output = VisionOutput(context, actualName)
|
||||
val vision = output.buildOutput()
|
||||
VisionDisplay(output.visionManager, vision, output.meta)
|
||||
}
|
||||
|
||||
return addVision(actualName, display.visionManager, display.vision, display.meta)
|
||||
}
|
||||
val consumer = object : HtmlVisionContext(visionManager.context, idPrefix) {
|
||||
|
||||
override fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta) {
|
||||
|
||||
@@ -79,7 +62,9 @@ public fun TagConsumer<*>.visionFragment(
|
||||
}
|
||||
}
|
||||
|
||||
fragment.appendTo(consumer)
|
||||
with(consumer) {
|
||||
fragment.appendTo(this@visionFragment)
|
||||
}
|
||||
}
|
||||
|
||||
public fun FlowContent.visionFragment(
|
||||
@@ -1,173 +0,0 @@
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.html.*
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.ContextAware
|
||||
import space.kscience.dataforge.context.PluginFactory
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.DEFAULT_VISION_NAME
|
||||
import space.kscience.visionforge.setAsRoot
|
||||
import space.kscience.visionforge.visionManager
|
||||
|
||||
@DslMarker
|
||||
public annotation class VisionDSL
|
||||
|
||||
/**
|
||||
* A placeholder object to attach inline vision builders.
|
||||
*/
|
||||
@VisionDSL
|
||||
public class VisionOutput(override val context: Context, public val name: Name) : ContextAware {
|
||||
public var meta: Meta = Meta.EMPTY
|
||||
|
||||
private val requirements: MutableSet<PluginFactory<*>> = HashSet()
|
||||
|
||||
public fun requirePlugin(factory: PluginFactory<*>) {
|
||||
requirements.add(factory)
|
||||
}
|
||||
|
||||
public val visionManager: VisionManager
|
||||
get() = if (requirements.all { req -> context.plugins.find(true) { it.tag == req.tag } != null }) {
|
||||
context.visionManager
|
||||
} else {
|
||||
val newContext = context.buildContext(NameToken(DEFAULT_VISION_NAME, name.toString()).asName()) {
|
||||
plugin(VisionManager)
|
||||
requirements.forEach { plugin(it) }
|
||||
}
|
||||
newContext.visionManager
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public inline fun VisionOutput.meta(block: MutableMeta.() -> Unit) {
|
||||
this.meta = Meta(block)
|
||||
}
|
||||
|
||||
public fun VisionOutput.meta(metaRepr: MetaRepr) {
|
||||
this.meta = metaRepr.toMeta()
|
||||
}
|
||||
|
||||
/**
|
||||
* Modified [TagConsumer] that allows rendering output fragments and visions in them
|
||||
*/
|
||||
@VisionDSL
|
||||
public abstract class VisionTagConsumer<R>(
|
||||
private val root: TagConsumer<R>,
|
||||
public val visionManager: VisionManager,
|
||||
private val idPrefix: String? = null,
|
||||
) : TagConsumer<R> by root, ContextAware {
|
||||
|
||||
override val context: Context get() = visionManager.context
|
||||
|
||||
public open fun resolveId(name: Name): String = (idPrefix ?: "output") + "[$name]"
|
||||
|
||||
/**
|
||||
* Render a vision inside the output fragment
|
||||
* @param manager a [VisionManager] to be used in renderer
|
||||
* @param name name of the output container
|
||||
* @param vision an object to be rendered
|
||||
* @param outputMeta optional configuration for the output container
|
||||
*/
|
||||
protected abstract fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta)
|
||||
|
||||
/**
|
||||
* Create a placeholder for a vision output with optional [Vision] in it
|
||||
* TODO with multi-receivers could be replaced by [VisionTagConsumer, TagConsumer] extension
|
||||
*/
|
||||
protected fun <T> TagConsumer<T>.addVision(
|
||||
name: Name,
|
||||
manager: VisionManager,
|
||||
vision: Vision?,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
): T = if (vision == null) div {
|
||||
+"Empty Vision output"
|
||||
} else div {
|
||||
id = resolveId(name)
|
||||
|
||||
classes = setOf(OUTPUT_CLASS, *(outputMeta[OUTPUT_DIV_CLASSES_KEY].stringList?.toTypedArray() ?: emptyArray()))
|
||||
if (vision.parent == null) {
|
||||
vision.setAsRoot(manager)
|
||||
}
|
||||
attributes[OUTPUT_NAME_ATTRIBUTE] = name.toString()
|
||||
renderVision(manager, name, vision, outputMeta)
|
||||
if (!outputMeta.isEmpty()) {
|
||||
//Hard-code output configuration
|
||||
script {
|
||||
type = "text/json"
|
||||
attributes["class"] = OUTPUT_META_CLASS
|
||||
unsafe {
|
||||
+("\n" + manager.jsonFormat.encodeToString(MetaSerializer, outputMeta) + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a vision in this HTML.
|
||||
* TODO replace by multi-receiver
|
||||
*/
|
||||
@VisionDSL
|
||||
public open fun <T> TagConsumer<T>.vision(
|
||||
name: Name? = null,
|
||||
buildOutput: VisionOutput.() -> Vision,
|
||||
): T {
|
||||
val actualName = name ?: NameToken(DEFAULT_VISION_NAME, buildOutput.hashCode().toUInt().toString()).asName()
|
||||
val output = VisionOutput(context, actualName)
|
||||
val vision = output.buildOutput()
|
||||
return addVision(actualName, output.visionManager, vision, output.meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO to be replaced by multi-receiver
|
||||
*/
|
||||
@VisionDSL
|
||||
public fun <T> TagConsumer<T>.vision(
|
||||
name: String?,
|
||||
buildOutput: VisionOutput.() -> Vision,
|
||||
): T = vision(name?.parseAsName(), buildOutput)
|
||||
|
||||
@VisionDSL
|
||||
public open fun <T> TagConsumer<T>.vision(
|
||||
vision: Vision,
|
||||
name: Name? = null,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
) {
|
||||
val actualName = name ?: NameToken(DEFAULT_VISION_NAME, vision.hashCode().toUInt().toString()).asName()
|
||||
addVision(actualName, context.visionManager, vision, outputMeta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the resulting object produced by [TagConsumer]
|
||||
*/
|
||||
protected open fun processResult(result: R) {
|
||||
//do nothing by default
|
||||
}
|
||||
|
||||
override fun finalize(): R = root.finalize().also { processResult(it) }
|
||||
|
||||
public companion object {
|
||||
public const val OUTPUT_CLASS: String = "visionforge-output"
|
||||
public const val OUTPUT_META_CLASS: String = "visionforge-output-meta"
|
||||
public const val OUTPUT_DATA_CLASS: String = "visionforge-output-data"
|
||||
|
||||
public const val OUTPUT_DIV_CLASSES_KEY: String = "classes"
|
||||
|
||||
public const val OUTPUT_FETCH_ATTRIBUTE: String = "data-output-fetch"
|
||||
public const val OUTPUT_CONNECT_ATTRIBUTE: String = "data-output-connect"
|
||||
|
||||
public const val OUTPUT_RENDERED: String = "data-output-rendered"
|
||||
|
||||
public const val OUTPUT_NAME_ATTRIBUTE: String = "data-output-name"
|
||||
public const val OUTPUT_ENDPOINT_ATTRIBUTE: String = "data-output-endpoint"
|
||||
public const val DEFAULT_ENDPOINT: String = "."
|
||||
|
||||
public const val AUTO_DATA_ATTRIBUTE: String = "@auto"
|
||||
|
||||
public const val DEFAULT_VISION_NAME: String = "vision"
|
||||
}
|
||||
}
|
||||
@@ -9,25 +9,25 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionGroup
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.visionManager
|
||||
import kotlin.collections.set
|
||||
import kotlin.test.Test
|
||||
|
||||
typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
|
||||
|
||||
fun FlowContent.renderVisionFragment(
|
||||
renderer: DIV.(name: Name, vision: Vision, meta: Meta) -> Unit,
|
||||
internal fun FlowContent.renderVisionFragment(
|
||||
renderer: FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit,
|
||||
idPrefix: String? = null,
|
||||
fragment: HtmlVisionFragment,
|
||||
): Map<Name, Vision> {
|
||||
val visionMap = HashMap<Name, Vision>()
|
||||
val consumer = object : VisionTagConsumer<Any?>(consumer, Global.visionManager, idPrefix) {
|
||||
val visionContext = object : HtmlVisionContext(Global, idPrefix) {
|
||||
override fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta) {
|
||||
visionMap[name] = vision
|
||||
renderer(name, vision, outputMeta)
|
||||
}
|
||||
}
|
||||
fragment.appendTo(consumer)
|
||||
context(visionContext) {
|
||||
fragment.appendTo(consumer)
|
||||
}
|
||||
return visionMap
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.serialization.encodeToString
|
||||
import org.w3c.dom.*
|
||||
import org.w3c.dom.url.URL
|
||||
import space.kscience.dataforge.context.*
|
||||
@@ -24,11 +23,11 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_ENDPOINT_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_FETCH_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_NAME_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_RENDERED
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_ENDPOINT_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_FETCH_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_NAME_ATTRIBUTE
|
||||
import space.kscience.visionforge.html.HtmlVisionContext.Companion.OUTPUT_RENDERED
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
/**
|
||||
@@ -94,7 +93,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
|
||||
private fun startVisionUpdate(element: Element, visionName: Name, vision: Vision, outputMeta: Meta) {
|
||||
element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr ->
|
||||
val wsUrl = if (attr.value.isBlank() || attr.value == VisionTagConsumer.AUTO_DATA_ATTRIBUTE) {
|
||||
val wsUrl = if (attr.value.isBlank() || attr.value == HtmlVisionContext.AUTO_DATA_ATTRIBUTE) {
|
||||
val endpoint = resolveEndpoint(element)
|
||||
logger.info { "Vision server is resolved to $endpoint" }
|
||||
URL(endpoint).apply {
|
||||
@@ -194,10 +193,10 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch from server and render a vision, described in a given with [VisionTagConsumer.OUTPUT_CLASS] class.
|
||||
* Fetch from server and render a vision, described in a given with [HtmlVisionContext.OUTPUT_CLASS] class.
|
||||
*/
|
||||
public fun renderVisionIn(element: Element) {
|
||||
if (!element.classList.contains(VisionTagConsumer.OUTPUT_CLASS)) error("The element $element is not an output element")
|
||||
if (!element.classList.contains(HtmlVisionContext.OUTPUT_CLASS)) error("The element $element is not an output element")
|
||||
val name = resolveName(element)?.parseAsName() ?: error("The element is not a vision output")
|
||||
|
||||
if (element.attributes[OUTPUT_RENDERED]?.value == "true") {
|
||||
@@ -207,7 +206,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
logger.info { "Rendering VF output with name $name" }
|
||||
}
|
||||
|
||||
val outputMeta = element.getEmbeddedData(VisionTagConsumer.OUTPUT_META_CLASS)?.let {
|
||||
val outputMeta = element.getEmbeddedData(HtmlVisionContext.OUTPUT_META_CLASS)?.let {
|
||||
VisionManager.defaultJson.decodeFromString(MetaSerializer, it).also {
|
||||
logger.info { "Output meta for $name: $it" }
|
||||
}
|
||||
@@ -218,7 +217,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
element.attributes[OUTPUT_FETCH_ATTRIBUTE] != null -> {
|
||||
val attr = element.attributes[OUTPUT_FETCH_ATTRIBUTE]!!
|
||||
|
||||
val fetchUrl = if (attr.value.isBlank() || attr.value == VisionTagConsumer.AUTO_DATA_ATTRIBUTE) {
|
||||
val fetchUrl = if (attr.value.isBlank() || attr.value == HtmlVisionContext.AUTO_DATA_ATTRIBUTE) {
|
||||
val endpoint = resolveEndpoint(element)
|
||||
logger.info { "Vision server is resolved to $endpoint" }
|
||||
URL(endpoint).apply {
|
||||
@@ -244,9 +243,9 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
}
|
||||
|
||||
// use embedded data if it is available
|
||||
element.getElementsByClassName(VisionTagConsumer.OUTPUT_DATA_CLASS).length > 0 -> {
|
||||
element.getElementsByClassName(HtmlVisionContext.OUTPUT_DATA_CLASS).length > 0 -> {
|
||||
//Getting embedded vision data
|
||||
val embeddedVision = element.getEmbeddedData(VisionTagConsumer.OUTPUT_DATA_CLASS)!!.let {
|
||||
val embeddedVision = element.getEmbeddedData(HtmlVisionContext.OUTPUT_DATA_CLASS)!!.let {
|
||||
visionManager.decodeFromString(it)
|
||||
}
|
||||
logger.info { "Found embedded vision data with name $name" }
|
||||
@@ -292,10 +291,10 @@ 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 [HtmlVisionContext.OUTPUT_CLASS] class inside given [element].
|
||||
*/
|
||||
public fun JsVisionClient.renderAllVisionsIn(element: Element) {
|
||||
val elements = element.getElementsByClassName(VisionTagConsumer.OUTPUT_CLASS)
|
||||
val elements = element.getElementsByClassName(HtmlVisionContext.OUTPUT_CLASS)
|
||||
logger.info { "Finished search for outputs. Found ${elements.length} items" }
|
||||
elements.asList().forEach { child ->
|
||||
renderVisionIn(child)
|
||||
@@ -316,7 +315,7 @@ public fun JsVisionClient.renderAllVisionsById(document: Document, id: String):
|
||||
|
||||
|
||||
/**
|
||||
* 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 [HtmlVisionContext.OUTPUT_CLASS] class in the document body
|
||||
*/
|
||||
public fun JsVisionClient.renderAllVisions(): Unit = whenDocumentLoaded {
|
||||
val element = body ?: error("Document does not have a body")
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.html.*
|
||||
import space.kscience.dataforge.context.ContextAware
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaSerializer
|
||||
import space.kscience.dataforge.meta.isEmpty
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.DEFAULT_VISION_NAME
|
||||
import space.kscience.visionforge.setAsRoot
|
||||
import space.kscience.visionforge.visionManager
|
||||
|
||||
/**
|
||||
* Rendering context for visions in HTML
|
||||
*/
|
||||
public interface HtmlVisionContext : ContextAware {
|
||||
|
||||
/**
|
||||
* Generate div id for vision div tag
|
||||
*/
|
||||
public fun generateId(name: Name): String = "vision[$name]"
|
||||
|
||||
/**
|
||||
* Render vision at given [DIV]
|
||||
*/
|
||||
public fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta)
|
||||
}
|
||||
|
||||
|
||||
//public typealias HtmlVisionContextFragment = context(htmlContext: HtmlVisionContext) TagConsumer<*>.() -> Unit
|
||||
|
||||
//context(HtmlVisionContext)
|
||||
//public fun HtmlVisionFragment(
|
||||
// content: TagConsumer<*>.() -> Unit,
|
||||
//): HtmlVisionFragment = HtmlVisionFragment { }
|
||||
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
private fun <T> TagConsumer<T>.vision(
|
||||
visionManager: VisionManager,
|
||||
name: Name,
|
||||
vision: Vision,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
): T = div {
|
||||
id = htmlContext.generateId(name)
|
||||
classes = setOf(VisionTagConsumer.OUTPUT_CLASS)
|
||||
vision.setAsRoot(visionManager)
|
||||
attributes[VisionTagConsumer.OUTPUT_NAME_ATTRIBUTE] = name.toString()
|
||||
if (!outputMeta.isEmpty()) {
|
||||
//Hard-code output configuration
|
||||
script {
|
||||
attributes["class"] = VisionTagConsumer.OUTPUT_META_CLASS
|
||||
unsafe {
|
||||
+visionManager.jsonFormat.encodeToString(MetaSerializer, outputMeta)
|
||||
}
|
||||
}
|
||||
}
|
||||
with(htmlContext) {
|
||||
renderVision(name, vision, outputMeta)
|
||||
}
|
||||
}
|
||||
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
private fun <T> TagConsumer<T>.vision(
|
||||
name: Name,
|
||||
vision: Vision,
|
||||
outputMeta: Meta = Meta.EMPTY,
|
||||
): T = vision(htmlContext.context.visionManager, name, vision, outputMeta)
|
||||
|
||||
/**
|
||||
* Insert a vision in this HTML.
|
||||
*/
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
@VisionDSL
|
||||
public fun <T> TagConsumer<T>.vision(
|
||||
name: Name? = null,
|
||||
visionProvider: VisionOutput.() -> Vision,
|
||||
): T {
|
||||
val actualName = name ?: NameToken(DEFAULT_VISION_NAME, visionProvider.hashCode().toUInt().toString()).asName()
|
||||
val output = VisionOutput(htmlContext.context, actualName)
|
||||
val vision = output.visionProvider()
|
||||
return vision(output.visionManager, actualName, vision, output.meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a vision in this HTML.
|
||||
*/
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
@VisionDSL
|
||||
public fun <T> TagConsumer<T>.vision(
|
||||
name: String?,
|
||||
visionProvider: VisionOutput.() -> Vision,
|
||||
): T = vision(name?.parseAsName(), visionProvider)
|
||||
@@ -118,7 +118,7 @@ public fun VisionForge.html(body: TagConsumer<*>.() -> Unit): MimeTypedResult =
|
||||
/**
|
||||
* Create a fragment without a head to be embedded in the page
|
||||
*/
|
||||
public fun VisionForge.fragment(body: VisionTagConsumer<*>.() -> Unit): MimeTypedResult = produceHtml(false, body)
|
||||
public fun VisionForge.fragment(body: HtmlVisionFragment): MimeTypedResult = produceHtml(false, body)
|
||||
|
||||
|
||||
/**
|
||||
@@ -126,6 +126,6 @@ public fun VisionForge.fragment(body: VisionTagConsumer<*>.() -> Unit): MimeType
|
||||
*/
|
||||
public fun VisionForge.page(
|
||||
pageHeaders: Map<String, HtmlFragment> = emptyMap(),
|
||||
body: VisionTagConsumer<*>.() -> Unit,
|
||||
body: HtmlVisionFragment,
|
||||
): VisionPage = VisionPage(visionManager, pageHeaders, body)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import space.kscience.plotly.Plot
|
||||
import space.kscience.plotly.PlotlyPlugin
|
||||
import space.kscience.tables.Table
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.markup.MarkupPlugin
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.tables.TableVisionPlugin
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.html.TagConsumer
|
||||
import kotlinx.serialization.PolymorphicSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.modules.PolymorphicModuleBuilder
|
||||
@@ -13,7 +14,9 @@ import space.kscience.dataforge.context.PluginTag
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.html.HtmlVisionContext
|
||||
import space.kscience.visionforge.html.VisionOutput
|
||||
import space.kscience.visionforge.html.vision
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
|
||||
|
||||
@@ -100,3 +103,15 @@ public inline fun VisionOutput.solid(options: Canvas3DOptions? = null, block: So
|
||||
@VisionBuilder
|
||||
public inline fun VisionOutput.solid(options: Canvas3DOptions.() -> Unit, block: SolidGroup.() -> Unit): SolidGroup =
|
||||
solid(Canvas3DOptions(options), block)
|
||||
|
||||
|
||||
@VisionBuilder
|
||||
context(htmlContext: HtmlVisionContext)
|
||||
public fun <T> TagConsumer<T>.solid(
|
||||
name: String? = null,
|
||||
options: Canvas3DOptions? = null,
|
||||
block: SolidGroup.() -> Unit
|
||||
): T = vision(name) {
|
||||
requirePlugin(Solids)
|
||||
solid(options = options, block = block)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user