Fix after dev merge.

This commit is contained in:
Alexander Nozik 2021-01-12 12:52:22 +03:00
parent 33146fef1b
commit 0c1d6139ae
45 changed files with 511 additions and 304 deletions

View File

@ -1,9 +1,9 @@
package hep.dataforge.vision.gdml.demo
import hep.dataforge.Application
import hep.dataforge.context.Global
import hep.dataforge.startApplication
import hep.dataforge.vision.Application
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.startApplication
import kotlinx.browser.document
import react.child
import react.dom.render

View File

@ -1,8 +1,8 @@
package ru.mipt.npm.muon.monitor
import hep.dataforge.Application
import hep.dataforge.context.Global
import hep.dataforge.startApplication
import hep.dataforge.vision.Application
import hep.dataforge.vision.startApplication
import io.ktor.client.HttpClient
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.KotlinxSerializer

View File

@ -4,7 +4,7 @@ import hep.dataforge.meta.Meta
import hep.dataforge.meta.invoke
import hep.dataforge.names.toName
import hep.dataforge.vision.Colors
import hep.dataforge.vision.layout.Page
import hep.dataforge.vision.VisionLayout
import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.visible
@ -15,12 +15,12 @@ import kotlin.math.sin
import kotlin.random.Random
fun Page<Solid>.demo(name: String, title: String = name, block: SolidGroup.() -> Unit) {
fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGroup.() -> Unit) {
val meta = Meta {
"title" put title
}
val output = output(name.toName(), meta)?: error("Output with name $name not found")
output.solidGroup (builder = block)
val vision = SolidGroup(block)
render(name.toName(), vision)
}
val canvasOptions = Canvas3DOptions {
@ -35,7 +35,7 @@ val canvasOptions = Canvas3DOptions {
}
}
fun Page<Solid>.showcase() {
fun VisionLayout<Solid>.showcase() {
demo("shapes", "Basic shapes") {
box(100.0, 100.0, 100.0) {
z = -110.0
@ -136,14 +136,14 @@ fun Page<Solid>.showcase() {
}
}
fun Page<Solid>.showcaseCSG() {
fun VisionLayout<Solid>.showcaseCSG() {
demo("CSG.simple", "CSG operations") {
composite(CompositeType.INTERSECT) {
y = 300
box(100, 100, 100) {
z = 50
}
sphere(50){
sphere(50) {
detail = 32
}
material {
@ -154,7 +154,7 @@ fun Page<Solid>.showcaseCSG() {
box(100, 100, 100) {
z = 50
}
sphere(50){
sphere(50) {
detail = 32
}
color("lightgreen")
@ -165,7 +165,7 @@ fun Page<Solid>.showcaseCSG() {
box(100, 100, 100) {
z = 50
}
sphere(50){
sphere(50) {
detail = 32
}
color("teal")

View File

@ -1,9 +1,9 @@
package hep.dataforge.vision.solid.demo
import hep.dataforge.Application
import hep.dataforge.startApplication
import hep.dataforge.vision.Application
import hep.dataforge.vision.solid.x
import hep.dataforge.vision.solid.y
import hep.dataforge.vision.startApplication
import kotlinx.browser.document
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay

View File

@ -5,8 +5,7 @@ import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.string
import hep.dataforge.names.Name
import hep.dataforge.vision.layout.Output
import hep.dataforge.vision.layout.Page
import hep.dataforge.vision.VisionLayout
import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.three.ThreeCanvas
import hep.dataforge.vision.solid.three.ThreePlugin
@ -20,7 +19,7 @@ import org.w3c.dom.Element
import org.w3c.dom.HTMLDivElement
import org.w3c.dom.HTMLElement
class ThreeDemoGrid(element: Element) : Page<Solid> {
class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
private lateinit var navigationElement: HTMLElement
private lateinit var contentElement: HTMLDivElement
@ -47,31 +46,31 @@ class ThreeDemoGrid(element: Element) : Page<Solid> {
}
}
@Suppress("UNCHECKED_CAST")
override fun output(name: Name, meta: Meta): Output<Solid> = outputs.getOrPut(name) {
navigationElement.append {
li("nav-item") {
a(classes = "nav-link") {
href = "#$name"
+name.toString()
override fun render(name: Name, vision: Solid, meta: Meta) {
outputs.getOrPut(name) {
navigationElement.append {
li("nav-item") {
a(classes = "nav-link") {
href = "#$name"
+name.toString()
}
}
}
}
contentElement.append {
div("container") {
id = name.toString()
hr()
h2 { +(meta["title"].string ?: name.toString()) }
hr()
div {
style = "height: 600px;"
id = "output-$name"
contentElement.append {
div("container") {
id = name.toString()
hr()
h2 { +(meta["title"].string ?: name.toString()) }
hr()
div {
style = "height: 600px;"
id = "output-$name"
}
}
}
}
val element = document.getElementById("output-$name") ?: error("Element not found")
three.createCanvas(element, canvasOptions)
val element = document.getElementById("output-$name") ?: error("Element not found")
three.createCanvas(element, canvasOptions)
}.render(vision)
}
}

View File

@ -3,8 +3,7 @@ package hep.dataforge.vision.solid.demo
import hep.dataforge.context.Global
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.vision.layout.Output
import hep.dataforge.vision.layout.Page
import hep.dataforge.vision.VisionLayout
import hep.dataforge.vision.solid.FX3DPlugin
import hep.dataforge.vision.solid.FXCanvas3D
import hep.dataforge.vision.solid.Solid
@ -13,7 +12,7 @@ import javafx.scene.Parent
import javafx.scene.control.Tab
import tornadofx.*
class FXDemoGrid : View(title = "DataForge-vis FX demo"), Page<Solid> {
class FXDemoGrid : View(title = "DataForge-vis FX demo"), VisionLayout<Solid> {
private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>()
override val root: Parent = borderpane {
@ -26,8 +25,8 @@ class FXDemoGrid : View(title = "DataForge-vis FX demo"), Page<Solid> {
private val fx3d = Global.plugins.fetch(FX3DPlugin)
override fun output(name: Name, meta: Meta): Output<Solid> = outputs.getOrPut(name) {
FXCanvas3D(fx3d, canvasOptions)
override fun render(name: Name, vision: Solid, meta: Meta) {
outputs.getOrPut(name) { FXCanvas3D(fx3d, canvasOptions) }.render(vision)
}
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1,27 +1,9 @@
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.client.VisionClient
import hep.dataforge.vision.client.renderAllVisions
import hep.dataforge.vision.plotly.PlotlyPlugin
import hep.dataforge.vision.solid.three.ThreePlugin
import kotlinx.browser.window
import hep.dataforge.vision.plotly.withPlotly
import hep.dataforge.vision.renderVisionsInWindow
import hep.dataforge.vision.solid.three.loadThreeJs
@DFExperimental
fun main() {
val visionContext: Context = Global.context("VISION") {
plugin(ThreePlugin)
plugin(PlotlyPlugin)
plugin(VisionClient)
}
//Loading three-js renderer
val clientManager = visionContext.plugins.fetch(VisionClient)
//Fetch from server and render visions for all outputs
window.onload = {
clientManager.renderAllVisions()
}
//startApplication(::PlayGroundApp)
withPlotly()
loadThreeJs()
renderVisionsInWindow()
}

View File

@ -1,6 +1,8 @@
package hep.dataforge.vision.solid
package hep.dataforge.vision.examples
import com.github.ricky12awesome.jss.encodeToSchema
import hep.dataforge.vision.solid.SolidGroup
import hep.dataforge.vision.solid.SolidManager
import kotlinx.serialization.json.Json
fun main() {

View File

@ -1,38 +0,0 @@
package hep.dataforge.vision.solid
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.makeVisionFile
import hep.dataforge.vision.scriptHeader
import hep.dataforge.vision.three.server.VisionServer
import hep.dataforge.vision.three.server.useScript
import java.nio.file.Path
/**
* A global vision context used to resolve different vision renderers
*/
@DFExperimental
public val VisionForge: Context = Global.context("VISION") {
plugin(VisionManager)
plugin(SolidManager)
}
public fun VisionServer.usePlayground(): Unit {
useScript("js/visionforge-playground.js")
}
@DFExperimental
public fun Context.makeVisionFile(
fragment: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge page",
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true,
): Unit = makeVisionFile(fragment, path = path, title = title, show = show) { actualPath ->
scriptHeader("js/visionforge-playground.js", actualPath, resourceLocation)
}

View File

@ -1,19 +0,0 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.fragment
@OptIn(DFExperimental::class)
fun main() {
val fragment = VisionManager.fragment {
vision("canvas") {
solid {
box(100, 100, 100)
}
}
}
VisionForge.makeVisionFile(fragment = fragment, resourceLocation = ResourceLocation.SYSTEM)
}

View File

@ -0,0 +1,25 @@
package hep.dataforge.vision.examples
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.VisionForge
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.fragment
import hep.dataforge.vision.plotly.plotly
import hep.dataforge.vision.plotly.withPlotly
import kscience.plotly.scatter
@DFExperimental
fun main() {
val fragment = VisionManager.fragment {
vision {
plotly {
scatter {
x(1,2,3)
y(5,8,7)
}
}
}
}
VisionForge.withPlotly().makeVisionFile(fragment)
}

View File

@ -1,9 +1,11 @@
package hep.dataforge.vision.solid
package hep.dataforge.vision.examples
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.VisionForge
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.ResourceLocation
import hep.dataforge.vision.html.fragment
import hep.dataforge.vision.solid.*
import kotlinx.html.h1
import java.nio.file.Paths
import kotlin.random.Random

View File

@ -0,0 +1,35 @@
package hep.dataforge.vision.examples
import hep.dataforge.context.Context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.html.ResourceLocation
import hep.dataforge.vision.html.scriptHeader
import hep.dataforge.vision.makeFile
import hep.dataforge.vision.page
import hep.dataforge.vision.three.server.VisionServer
import hep.dataforge.vision.three.server.useScript
import java.awt.Desktop
import java.nio.file.Path
public fun VisionServer.usePlayground(): Unit {
useScript("js/visionforge-playground.js")
}
@DFExperimental
public fun Context.makeVisionFile(
content: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge page",
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true,
): Unit {
val actualPath = page(title, content).makeFile(path) { actualPath ->
mapOf("threeJs" to scriptHeader("js/visionforge-playground.js", actualPath, resourceLocation))
}
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
}
// makeVisionFile(fragment, path = path, title = title, show = show) { actualPath ->
// scriptHeader("js/visionforge-playground.js", actualPath, resourceLocation)
//}

View File

@ -0,0 +1,22 @@
package hep.dataforge.vision.examples
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.VisionForge
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.ResourceLocation
import hep.dataforge.vision.html.fragment
import hep.dataforge.vision.solid.box
import hep.dataforge.vision.solid.solid
@OptIn(DFExperimental::class)
fun main() {
val content = VisionManager.fragment {
vision("canvas") {
solid {
box(100, 100, 100)
}
}
}
VisionForge.makeVisionFile(content, resourceLocation = ResourceLocation.SYSTEM)
}

View File

@ -0,0 +1,5 @@
package hep.dataforge.vision
import hep.dataforge.context.Context
public expect val VisionForge: Context

View File

@ -0,0 +1,8 @@
package hep.dataforge.vision
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
public interface VisionLayout<in V: Vision> {
public fun render(name: Name, vision: V, meta: Meta = Meta.EMPTY)
}

View File

@ -3,6 +3,8 @@ package hep.dataforge.vision
import hep.dataforge.context.*
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
@ -75,6 +77,18 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
}
}
public abstract class VisionPlugin(meta: Meta = Meta.EMPTY) : AbstractPlugin(meta) {
public val visionManager: VisionManager by require(VisionManager)
protected abstract val visionSerializersModule: SerializersModule
override fun content(target: String): Map<Name, Any> = when (target) {
VisionManager.VISION_SERIALIZER_MODULE_TARGET -> mapOf(tag.toString().toName() to visionSerializersModule)
else -> super.content(target)
}
}
/**
* Fetch a [VisionManager] from this plugin
*/

View File

@ -0,0 +1,26 @@
package hep.dataforge.vision.html
import hep.dataforge.context.Context
import kotlinx.html.*
public data class Page(
public val context: Context,
public val title: String,
public val headers: Map<String, HtmlFragment>,
public val content: HtmlVisionFragment
) {
public fun <R> render(root: TagConsumer<R>): R = root.apply {
head {
meta {
charset = "utf-8"
headers.values.forEach {
fragment(it)
}
}
title(title)
}
body {
embedVisionFragment(context.visionManager, fragment = content)
}
}.finalize()
}

View File

@ -4,19 +4,18 @@ import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionManager
import kotlinx.html.DIV
import kotlinx.html.FlowContent
import kotlinx.html.script
import kotlinx.html.unsafe
import kotlinx.html.*
public fun FlowContent.embedVisionFragment(
public fun TagConsumer<*>.embedVisionFragment(
manager: VisionManager,
idPrefix: String? = null,
fragment: HtmlVisionFragment,
) {
val consumer = object : VisionTagConsumer<Any?>(consumer, idPrefix) {
): Map<Name, Vision> {
val visionMap = HashMap<Name, Vision>()
val consumer = object : VisionTagConsumer<Any?>(this@embedVisionFragment, idPrefix) {
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
visionMap[name] = vision
script {
type = "text/json"
attributes["class"] = OUTPUT_DATA_CLASS
@ -27,17 +26,29 @@ public fun FlowContent.embedVisionFragment(
}
}
fragment(consumer)
return visionMap
}
public fun FlowContent.embedVisionFragment(
manager: VisionManager,
idPrefix: String? = null,
fragment: HtmlVisionFragment,
): Map<Name, Vision> = consumer.embedVisionFragment(manager, idPrefix, fragment)
public typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
public fun <R> FlowContent.renderVisionFragment(
public fun FlowContent.renderVisionFragment(
renderer: DIV.(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, idPrefix) {
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) = renderer(name, vision, outputMeta)
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
visionMap[name] = vision
renderer(name, vision, outputMeta)
}
}
fragment(consumer)
return visionMap
}

View File

@ -1,16 +0,0 @@
package hep.dataforge.vision.layout
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.vision.Vision
public fun interface Output<in V : Vision> {
public fun render(vision: V)
}
public interface Page<in V : Vision> {
public fun output(name: Name, meta: Meta = Meta.EMPTY): Output<V>?
}
public fun <V : Vision> Page<V>.render(name: Name, vision: V): Unit =
output(name)?.render(vision) ?: error("Could not resolve renderer for name $name")

View File

@ -3,7 +3,6 @@ package hep.dataforge.vision.html
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.set
import hep.dataforge.vision.VisionBase
import hep.dataforge.vision.configure
import kotlinx.html.*
import kotlinx.html.stream.createHTML
import kotlin.test.Test
@ -54,7 +53,7 @@ class HtmlTagTest {
fun testStringRender() {
println(
createHTML().div {
renderVisionFragment<String>(simpleVisionRenderer, fragment = fragment)
renderVisionFragment(simpleVisionRenderer, fragment = fragment)
}
)
}

View File

@ -1,4 +1,4 @@
package hep.dataforge
package hep.dataforge.vision
import kotlinx.browser.document
import kotlinx.dom.hasClass

View File

@ -0,0 +1,22 @@
package hep.dataforge.vision
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.vision.client.VisionClient
import hep.dataforge.vision.client.renderAllVisions
import kotlinx.browser.window
public actual val VisionForge: Context = Global.context("VisionForge").apply{
plugins.fetch(VisionManager)
plugins.fetch(VisionClient)
}
/**
* Render all visions in this [window] using current global state of [VisionForge]
*/
@JsExport
public fun renderVisionsInWindow(){
window.onload = {
VisionForge.plugins[VisionClient]?.renderAllVisions()
}
}

View File

@ -0,0 +1,8 @@
package hep.dataforge.vision
import hep.dataforge.context.Context
import hep.dataforge.context.Global
public actual val VisionForge: Context = Global.context("VisionForge").apply{
plugins.fetch(VisionManager)
}

View File

@ -1,8 +1,7 @@
package hep.dataforge.vision
package hep.dataforge.vision.html
import hep.dataforge.context.Context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.html.HtmlFragment
import hep.dataforge.vision.VisionManager
import kotlinx.html.link
import kotlinx.html.script
import kotlinx.html.unsafe
@ -100,14 +99,14 @@ internal fun fileCssHeader(
* Make a script header, automatically copying file to appropriate location
*/
@DFExperimental
public fun Context.scriptHeader(
public fun scriptHeader(
scriptResource: String,
htmlPath: Path,
htmlPath: Path?,
resourceLocation: ResourceLocation,
): HtmlFragment {
val targetPath = when (resourceLocation) {
ResourceLocation.LOCAL -> checkOrStoreFile(
htmlPath,
htmlPath ?: Path.of("."),
Path.of(VISIONFORGE_ASSETS_PATH),
scriptResource
)

View File

@ -0,0 +1,89 @@
package hep.dataforge.vision
import hep.dataforge.context.Context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.html.HtmlFragment
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.html.Page
import kotlinx.html.stream.createHTML
import java.awt.Desktop
import java.nio.file.Files
import java.nio.file.Path
//
///**
// * Create a full html string (including the head) for a given [HtmlVisionFragment]
// */
//@DFExperimental
//public fun Context.makeVisionString(
// fragment: HtmlVisionFragment,
// title: String = "VisionForge page",
// headerBuilder: () -> HtmlFragment,
//): String = createHTML().apply {
// head {
// meta {
// charset = "utf-8"
// fragment(headerBuilder())
// }
// title(title)
// }
// body {
// embedVisionFragment(visionManager, fragment = fragment)
// }
//}.finalize()
//
//
///**
// * Make a file with the embedded vision data
// */
//@DFExperimental
//public fun Context.makeVisionFile(
// fragment: HtmlVisionFragment,
// path: Path? = null,
// title: String = "VisionForge page",
// show: Boolean = true,
// headerBuilder: (Path) -> HtmlFragment,
//) {
// val actualFile = path?.let {
// Path.of(System.getProperty("user.home")).resolve(path)
// } ?: Files.createTempFile("tempPlot", ".html")
// //Files.createDirectories(actualFile.parent)
// val htmlString = makeVisionString(fragment, title) { headerBuilder(actualFile) }
//
// Files.writeString(actualFile, htmlString)
// if (show) {
// Desktop.getDesktop().browse(actualFile.toFile().toURI())
// }
//}
@DFExperimental
public fun Context.page(
title: String,
content: HtmlVisionFragment,
vararg headers: Pair<String, HtmlFragment>,
): Page = Page(this, title, mapOf(*headers), content)
@DFExperimental
public fun Page.makeFile(
path: Path?,
defaultHeaders: ((Path) -> Map<String,HtmlFragment>)? = null,
): Path {
val actualFile = path?.let {
Path.of(System.getProperty("user.home")).resolve(path)
} ?: Files.createTempFile("tempPlot", ".html")
val actualDefaultHeaders = defaultHeaders?.invoke(actualFile)
val actualPage = if(actualDefaultHeaders == null) this else copy(headers = actualDefaultHeaders + headers)
val htmlString = actualPage.render(createHTML())
Files.writeString(actualFile, htmlString)
return actualFile
}
@DFExperimental
public fun Page.show(path: Path? = null) {
val actualPath = makeFile(path)
Desktop.getDesktop().browse(actualPath.toFile().toURI())
}

View File

@ -1,51 +0,0 @@
package hep.dataforge.vision
import hep.dataforge.context.Context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.html.HtmlFragment
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.html.embedVisionFragment
import hep.dataforge.vision.html.fragment
import kotlinx.html.body
import kotlinx.html.head
import kotlinx.html.meta
import kotlinx.html.stream.createHTML
import kotlinx.html.title
import java.awt.Desktop
import java.nio.file.Files
import java.nio.file.Path
/**
* Make a file with the embedded vision data
*/
@DFExperimental
public fun Context.makeVisionFile(
fragment: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge page",
show: Boolean = true,
headerBuilder: (Path) -> HtmlFragment,
) {
val actualFile = path?.let {
Path.of(System.getProperty("user.home")).resolve(path)
} ?: Files.createTempFile("tempPlot", ".html")
//Files.createDirectories(actualFile.parent)
val htmlString = createHTML().apply {
head {
meta {
charset = "utf-8"
fragment(headerBuilder(actualFile))
}
title(title)
}
body {
embedVisionFragment(visionManager, fragment = fragment)
}
}.finalize()
Files.writeString(actualFile, htmlString)
if (show) {
Desktop.getDesktop().browse(actualFile.toFile().toURI())
}
}

View File

@ -2,7 +2,6 @@ package hep.dataforge.vision.solid
import hep.dataforge.context.Context
import hep.dataforge.context.ContextAware
import hep.dataforge.vision.layout.Output
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import javafx.application.Platform
import javafx.beans.property.ObjectProperty
@ -12,8 +11,10 @@ import javafx.scene.paint.Color
import org.fxyz3d.scene.Axes
import tornadofx.*
class FXCanvas3D(val plugin: FX3DPlugin, val spec: Canvas3DOptions = Canvas3DOptions.empty()) :
Fragment(), Output<Solid>, ContextAware {
class FXCanvas3D(
val plugin: FX3DPlugin,
val spec: Canvas3DOptions = Canvas3DOptions.empty(),
) : Fragment(), ContextAware {
override val context: Context get() = plugin.context
@ -78,7 +79,7 @@ class FXCanvas3D(val plugin: FX3DPlugin, val spec: Canvas3DOptions = Canvas3DOpt
}
}
override fun render(vision: Solid) {
fun render(vision: Solid) {
rootObject = vision
}
}

View File

@ -9,6 +9,27 @@ kscience {
val plotlyVersion = "0.3.1-dev"
kotlin {
js{
//binaries.library()
binaries.executable()
browser {
webpackTask {
this.outputFileName = "js/visionforge-three.js"
}
}
}
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
afterEvaluate {
from(jsBrowserDistribution)
}
}
}
sourceSets {
commonMain {
dependencies {

View File

@ -1,12 +1,16 @@
package hep.dataforge.vision.plotly
import hep.dataforge.meta.Config
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.VisionBase
import hep.dataforge.vision.html.VisionOutput
import kscience.plotly.Plot
import kscience.plotly.Plotly
public class VisionOfPlotly(public val plot: Plot): VisionBase(plot.config)
@Serializable
public class VisionOfPlotly(private val plotConfig: Config) : VisionBase(plotConfig){
public val plot: Plot get() = Plot(plotConfig)
}
@DFExperimental
public inline fun VisionOutput.plotly(block: Plot.() -> Unit): VisionOfPlotly = VisionOfPlotly(Plotly.plot(block))
public inline fun VisionOutput.plotly(block: Plot.() -> Unit): VisionOfPlotly = VisionOfPlotly(Plotly.plot(block).config)

View File

@ -0,0 +1,15 @@
package hep.dataforge.vision.plotly
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionPlugin
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
public expect class PlotlyPlugin : VisionPlugin
internal val plotlySerializersModule = SerializersModule {
polymorphic(Vision::class) {
subclass(VisionOfPlotly.serializer())
}
}

View File

@ -1,15 +0,0 @@
package hep.dataforge.vision.plotly
//public fun main() {
// val visionContext: Context = Global.context("vision-client")
//
// //Loading three-js renderer
// val threePlugin = visionContext.plugins.fetch(PlotlyPlugin)
//
// val clientManager = visionContext.plugins.fetch(VisionClient)
//
// //Fetch from server and render visions for all outputs
// window.onload = {
// clientManager.renderAllVisions()
// }
//}

View File

@ -1,23 +1,29 @@
package hep.dataforge.vision.plotly
import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.Context
import hep.dataforge.context.PluginFactory
import hep.dataforge.context.PluginTag
import hep.dataforge.context.*
import hep.dataforge.meta.Meta
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionForge
import hep.dataforge.vision.VisionPlugin
import hep.dataforge.vision.client.ElementVisionRenderer
import hep.dataforge.vision.client.VisionClient
import kotlinx.serialization.modules.SerializersModule
import kscience.plotly.PlotlyConfig
import kscience.plotly.plot
import org.w3c.dom.Element
import kotlin.reflect.KClass
public class PlotlyPlugin : AbstractPlugin(), ElementVisionRenderer {
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
public val visionClient: VisionClient by require(VisionClient)
override val tag: PluginTag get() = Companion.tag
override fun rateVision(vision: Vision): Int =
if (vision is VisionOfPlotly) ElementVisionRenderer.DEFAULT_RATING else ElementVisionRenderer.ZERO_RATING
override val visionSerializersModule: SerializersModule get() = plotlySerializersModule
override fun rateVision(vision: Vision): Int = when (vision) {
is VisionOfPlotly -> ElementVisionRenderer.DEFAULT_RATING
else -> ElementVisionRenderer.ZERO_RATING
}
override fun render(element: Element, vision: Vision, meta: Meta) {
val plot = (vision as? VisionOfPlotly)?.plot ?: error("Only VisionOfPlotly visions are supported")
@ -30,4 +36,12 @@ public class PlotlyPlugin : AbstractPlugin(), ElementVisionRenderer {
override val type: KClass<PlotlyPlugin> = PlotlyPlugin::class
override fun invoke(meta: Meta, context: Context): PlotlyPlugin = PlotlyPlugin()
}
}
/**
* Ensure that [PlotlyPlugin] is loaded in the global [VisionForge] context
*/
@JsExport
public fun withPlotly() {
VisionForge.plugins.fetch(PlotlyPlugin)
}

View File

@ -0,0 +1,30 @@
package hep.dataforge.vision.plotly
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.html.HtmlFragment
import hep.dataforge.vision.html.ResourceLocation
import hep.dataforge.vision.html.scriptHeader
import kotlinx.html.script
import kotlinx.html.unsafe
import java.nio.file.Path
internal val plotlyScriptLocation = "js/visionforge-three.js"
/**
* A header that stores/embeds plotly bundle and registers plotly renderer in the frontend
*/
@OptIn(DFExperimental::class)
public fun plotlyHeader(location: ResourceLocation, filePath: Path? = null): HtmlFragment = {
scriptHeader(
plotlyScriptLocation,
filePath,
resourceLocation = location
).invoke(this)
script {
type = "text/javascript"
unsafe {
//language=JavaScript
+"hep.dataforge.vision.plotly.loadPlotly()"
}
}
}

View File

@ -0,0 +1,27 @@
package hep.dataforge.vision.plotly
import hep.dataforge.context.Context
import hep.dataforge.context.Plugin
import hep.dataforge.context.PluginFactory
import hep.dataforge.context.PluginTag
import hep.dataforge.meta.Meta
import hep.dataforge.vision.VisionPlugin
import kotlinx.serialization.modules.SerializersModule
import kotlin.reflect.KClass
public actual class PlotlyPlugin : VisionPlugin(), Plugin {
override val tag: PluginTag get() = Companion.tag
override val visionSerializersModule: SerializersModule get() = plotlySerializersModule
public companion object : PluginFactory<PlotlyPlugin> {
override val tag: PluginTag = PluginTag("vision.plotly", PluginTag.DATAFORGE_GROUP)
override val type: KClass<PlotlyPlugin> = PlotlyPlugin::class
override fun invoke(meta: Meta, context: Context): PlotlyPlugin = PlotlyPlugin()
}
}
public fun Context.withPlotly(): Context = apply {
plugins.fetch(PlotlyPlugin)
}

View File

@ -11,7 +11,6 @@ import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue
import hep.dataforge.vision.*
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
import hep.dataforge.vision.layout.Output
import hep.dataforge.vision.solid.Solid.Companion.DETAIL_KEY
import hep.dataforge.vision.solid.Solid.Companion.IGNORE_KEY
import hep.dataforge.vision.solid.Solid.Companion.LAYER_KEY
@ -108,9 +107,6 @@ public var Solid.layer: Int
setProperty(LAYER_KEY, value)
}
@VisionBuilder
public fun Output<Solid>.solidGroup(builder: SolidGroup.() -> Unit): Unit = render(SolidGroup().apply(builder))
// Common properties
public enum class RotationOrder {

View File

@ -1,18 +1,11 @@
package hep.dataforge.vision.solid
import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.Context
import hep.dataforge.context.PluginFactory
import hep.dataforge.context.PluginTag
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionBase
import hep.dataforge.vision.VisionGroupBase
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.VisionManager.Companion.VISION_SERIALIZER_MODULE_TARGET
import hep.dataforge.vision.*
import hep.dataforge.vision.html.VisionOutput
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.json.Json
@ -23,16 +16,11 @@ import kotlinx.serialization.modules.subclass
import kotlin.reflect.KClass
public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
public val visionManager: VisionManager by require(VisionManager)
public class SolidManager(meta: Meta) : VisionPlugin(meta) {
override val tag: PluginTag get() = Companion.tag
override fun content(target: String): Map<Name, Any> = when (target) {
VISION_SERIALIZER_MODULE_TARGET -> mapOf(tag.name.toName() to serializersModuleForSolids)
else -> super.content(target)
}
override val visionSerializersModule: SerializersModule get() = serializersModuleForSolids
public companion object : PluginFactory<SolidManager> {
override val tag: PluginTag = PluginTag(name = "vision.solid", group = PluginTag.DATAFORGE_GROUP)
@ -66,15 +54,18 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
}
}
internal val jsonForSolids: Json = Json(VisionManager.defaultJson){
internal val jsonForSolids: Json = Json(VisionManager.defaultJson) {
serializersModule = serializersModuleForSolids
}
public fun encodeToString(solid: Solid): String = jsonForSolids.encodeToString(PolymorphicSerializer(Vision::class), solid)
public fun encodeToString(solid: Solid): String =
jsonForSolids.encodeToString(PolymorphicSerializer(Vision::class), solid)
public fun decodeFromString(str: String): Solid = jsonForSolids.decodeFromString(PolymorphicSerializer(Solid::class), str)
public fun decodeFromString(str: String): Solid =
jsonForSolids.decodeFromString(PolymorphicSerializer(Solid::class), str)
}
}
@VisionBuilder
@DFExperimental
public inline fun VisionOutput.solid(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)

View File

@ -4,16 +4,14 @@ import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.double
import hep.dataforge.meta.get
import kotlinx.serialization.Serializable
import kotlin.math.PI
public const val PI2: Float = 2 * PI.toFloat()
@Serializable
public data class Point2D(public var x: Double, public var y: Double){
public constructor(x: Number, y: Number) : this(x.toDouble(), y.toDouble())
}
public data class Point2D(public var x: Double, public var y: Double)
public fun Point2D(x: Number, y: Number): Point2D = Point2D(x.toDouble(), y.toDouble())
public fun Point2D.toMeta(): Meta = Meta {
Solid.X_KEY put x
@ -28,14 +26,14 @@ public data class Point3D(
public var y: Double,
public var z: Double,
) {
public constructor(x: Number, y: Number, z: Number) : this(x.toDouble(), y.toDouble(), z.toDouble())
public companion object{
public companion object {
public val ZERO: Point3D = Point3D(0.0, 0.0, 0.0)
public val ONE: Point3D = Point3D(1.0, 1.0, 1.0)
}
}
public fun Point3D(x: Number, y: Number, z: Number): Point3D = Point3D(x.toDouble(), y.toDouble(), z.toDouble())
public operator fun Point3D.plus(other: Point3D): Point3D = Point3D(
this.x + other.x,
this.y + other.y,

View File

@ -6,6 +6,12 @@ kscience {
useSerialization()
}
kotlin{
js{
binaries.library()
}
}
dependencies {
api(project(":visionforge-solid"))
implementation(npm("three", "0.122.0"))

View File

@ -1,12 +1,9 @@
package hep.dataforge.vision.solid.three
import hep.dataforge.meta.get
import hep.dataforge.meta.string
import hep.dataforge.names.Name
import hep.dataforge.names.plus
import hep.dataforge.names.toName
import hep.dataforge.vision.Colors
import hep.dataforge.vision.layout.Output
import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.specifications.*
import hep.dataforge.vision.solid.three.ThreeMaterials.HIGHLIGHT_MATERIAL
@ -39,7 +36,7 @@ import kotlin.math.sin
public class ThreeCanvas(
public val three: ThreePlugin,
public val options: Canvas3DOptions,
) : Output<Solid> {
) {
private var root: Object3D? = null
private val raycaster = Raycaster()
@ -195,7 +192,7 @@ public class ThreeCanvas(
}
}
public override fun render(vision: Solid) {
public fun render(vision: Solid) {
scene.children.find { it.name == "@root" }?.let {
//Throw error is something is already rendered here
error("Root object already is present in the canvas")

View File

@ -4,14 +4,13 @@ import hep.dataforge.context.*
import hep.dataforge.meta.Meta
import hep.dataforge.names.*
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionForge
import hep.dataforge.vision.client.ElementVisionRenderer
import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.visible
import info.laht.threekt.core.Object3D
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.w3c.dom.Element
import org.w3c.dom.HTMLElement
import kotlin.collections.set
@ -151,6 +150,14 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
}
}
/**
* Ensure that [ThreePlugin] is loaded in the global [VisionForge] context
*/
@JsExport
public fun loadThreeJs(){
VisionForge.plugins.fetch(ThreePlugin)
}
public fun ThreePlugin.render(
element: HTMLElement,
obj: Solid,

View File

@ -1,20 +1,9 @@
package hep.dataforge.vision.three.server
import hep.dataforge.context.Global
import hep.dataforge.vision.client.VisionClient
import hep.dataforge.vision.client.renderAllVisions
import hep.dataforge.vision.solid.three.ThreePlugin
import kotlinx.browser.window
import hep.dataforge.vision.renderVisionsInWindow
import hep.dataforge.vision.solid.three.loadThreeJs
public fun main() {
//Loading three-js renderer
val visionContext = Global.context("threejs") {
plugin(ThreePlugin)
}
val clientManager = visionContext.plugins.fetch(VisionClient)
//Fetch from server and render visions for all outputs
window.onload = {
clientManager.renderAllVisions()
}
loadThreeJs()
renderVisionsInWindow()
}

View File

@ -2,10 +2,12 @@ package hep.dataforge.vision.three.server
import hep.dataforge.context.Context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.makeVisionFile
import hep.dataforge.vision.scriptHeader
import hep.dataforge.vision.html.ResourceLocation
import hep.dataforge.vision.html.scriptHeader
import hep.dataforge.vision.makeFile
import hep.dataforge.vision.page
import java.awt.Desktop
import java.nio.file.Path
@ -14,12 +16,15 @@ public fun VisionServer.useThreeJs(): Unit {
}
@DFExperimental
public fun Context.makeVisionFile(
fragment: HtmlVisionFragment,
public fun Context.makeThreeJsFile(
content: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge page",
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true,
): Unit = makeVisionFile(fragment, path = path, title = title, show = show) { actualPath ->
scriptHeader("js/visionforge-three.js", actualPath, resourceLocation)
}
): Unit {
val actualPath = page(title, content).makeFile(path) { actualPath ->
mapOf("threeJs" to scriptHeader("js/visionforge-three.js", actualPath, resourceLocation))
}
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
}