Fix canvas update
This commit is contained in:
parent
fb3ff4d6fc
commit
359eb05f83
@ -20,7 +20,6 @@ kotlin {
|
|||||||
useCommonJs()
|
useCommonJs()
|
||||||
browser {
|
browser {
|
||||||
commonWebpackConfig {
|
commonWebpackConfig {
|
||||||
sourceMaps = false
|
|
||||||
cssSupport.enabled = false
|
cssSupport.enabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import space.kscience.visionforge.html.HtmlVisionFragment
|
|||||||
import space.kscience.visionforge.html.Page
|
import space.kscience.visionforge.html.Page
|
||||||
import space.kscience.visionforge.html.embedVisionFragment
|
import space.kscience.visionforge.html.embedVisionFragment
|
||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
import space.kscience.visionforge.plotly.toVision
|
import space.kscience.visionforge.plotly.asVision
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
import space.kscience.visionforge.visionManager
|
import space.kscience.visionforge.visionManager
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ internal class VisionForgePlayGroundForJupyter : JupyterIntegration() {
|
|||||||
|
|
||||||
render<Plot> { plot ->
|
render<Plot> { plot ->
|
||||||
val fragment = HtmlVisionFragment {
|
val fragment = HtmlVisionFragment {
|
||||||
vision(plot.toVision())
|
vision(plot.asVision())
|
||||||
}
|
}
|
||||||
|
|
||||||
HTML(produceHtmlVisionString(fragment))
|
HTML(produceHtmlVisionString(fragment))
|
||||||
|
@ -3,11 +3,13 @@ package ru.mipt.npm.muon.monitor
|
|||||||
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
|
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
|
||||||
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
|
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
|
||||||
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
|
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
|
||||||
|
import space.kscience.visionforge.VisionManager
|
||||||
import space.kscience.visionforge.removeAll
|
import space.kscience.visionforge.removeAll
|
||||||
|
import space.kscience.visionforge.root
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
class Model {
|
class Model(val manager: VisionManager) {
|
||||||
private val map = HashMap<String, SolidGroup>()
|
private val map = HashMap<String, SolidGroup>()
|
||||||
private val events = HashSet<Event>()
|
private val events = HashSet<Event>()
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ class Model {
|
|||||||
var tracks: SolidGroup
|
var tracks: SolidGroup
|
||||||
|
|
||||||
val root: SolidGroup = SolidGroup().apply {
|
val root: SolidGroup = SolidGroup().apply {
|
||||||
|
root(this@Model.manager)
|
||||||
rotationX = PI / 2
|
rotationX = PI / 2
|
||||||
group("bottom") {
|
group("bottom") {
|
||||||
Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach {
|
Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach {
|
||||||
@ -78,7 +81,5 @@ class Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
fun encodeToString(): String = manager.encodeToString(this.root)
|
||||||
fun buildGeometry() = Model().root
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,13 +7,16 @@ import kotlinx.browser.document
|
|||||||
import react.child
|
import react.child
|
||||||
import react.dom.render
|
import react.dom.render
|
||||||
import space.kscience.dataforge.context.Global
|
import space.kscience.dataforge.context.Global
|
||||||
|
import space.kscience.dataforge.context.fetch
|
||||||
import space.kscience.visionforge.Application
|
import space.kscience.visionforge.Application
|
||||||
|
import space.kscience.visionforge.VisionManager
|
||||||
import space.kscience.visionforge.bootstrap.useBootstrap
|
import space.kscience.visionforge.bootstrap.useBootstrap
|
||||||
import space.kscience.visionforge.startApplication
|
import space.kscience.visionforge.startApplication
|
||||||
|
|
||||||
private class MMDemoApp : Application {
|
private class MMDemoApp : Application {
|
||||||
|
|
||||||
private val model = Model()
|
private val visionManager = Global.fetch(VisionManager)
|
||||||
|
private val model = Model(visionManager)
|
||||||
|
|
||||||
private val connection = HttpClient {
|
private val connection = HttpClient {
|
||||||
install(JsonFeature) {
|
install(JsonFeature) {
|
||||||
|
@ -52,7 +52,7 @@ fun Application.module(context: Context = Global) {
|
|||||||
}
|
}
|
||||||
get("/geometry") {
|
get("/geometry") {
|
||||||
call.respondText(
|
call.respondText(
|
||||||
solidManager.visionManager.encodeToString(Model.buildGeometry()),
|
Model(solidManager.visionManager).encodeToString(),
|
||||||
contentType = ContentType.Application.Json,
|
contentType = ContentType.Application.Json,
|
||||||
status = HttpStatusCode.OK
|
status = HttpStatusCode.OK
|
||||||
)
|
)
|
||||||
|
@ -15,8 +15,9 @@ group = "ru.mipt.npm"
|
|||||||
|
|
||||||
dependencies{
|
dependencies{
|
||||||
implementation(project(":visionforge-threejs:visionforge-threejs-server"))
|
implementation(project(":visionforge-threejs:visionforge-threejs-server"))
|
||||||
|
implementation("ch.qos.logback:logback-classic:1.2.3")
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("ru.mipt.npm.gradle.sat.SatServerKt")
|
mainClass.set("ru.mipt.npm.sat.SatServerKt")
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package space.kscience.visionforge.solid.demo
|
package space.kscience.visionforge.solid.demo
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.invoke
|
import space.kscience.dataforge.meta.invoke
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.toName
|
||||||
@ -73,7 +76,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
//override color for this cube
|
//override color for this cube
|
||||||
color(1530)
|
color(1530)
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
launch(Dispatchers.Main) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(500)
|
delay(500)
|
||||||
visible = !(visible ?: false)
|
visible = !(visible ?: false)
|
||||||
@ -82,7 +85,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
launch(Dispatchers.Main) {
|
||||||
val random = Random(111)
|
val random = Random(111)
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
|
@ -19,6 +19,7 @@ import space.kscience.visionforge.VisionLayout
|
|||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.three.ThreeCanvas
|
import space.kscience.visionforge.solid.three.ThreeCanvas
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
|
import space.kscience.visionforge.solid.three.configure
|
||||||
|
|
||||||
class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
|
class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
|
||||||
private lateinit var navigationElement: HTMLElement
|
private lateinit var navigationElement: HTMLElement
|
||||||
@ -70,7 +71,7 @@ class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val element = document.getElementById("output-$name") ?: error("Element not found")
|
val element = document.getElementById("output-$name") ?: error("Element not found")
|
||||||
three.createCanvas(element, canvasOptions)
|
three.getOrCreateCanvas(element).also { it.configure(canvasOptions) }
|
||||||
}.render(vision)
|
}.render(vision)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("ru.mipt.npm.gradle.js")
|
|
||||||
}
|
|
||||||
|
|
||||||
val dataforgeVersion: String by rootProject.extra
|
|
||||||
|
|
||||||
dependencies{
|
|
||||||
api(project(":ui:react"))
|
|
||||||
|
|
||||||
api("subroh0508.net.kotlinmaterialui:core:0.4.5")
|
|
||||||
api("subroh0508.net.kotlinmaterialui:lab:0.4.5")
|
|
||||||
api(npm("@material-ui/core","4.9.14"))
|
|
||||||
api(npm("@material-ui/lab","4.0.0-alpha.51"))
|
|
||||||
//api(npm("@material-ui/icons","4.9.1"))
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package space.kscience.visionforge.material
|
|
||||||
|
|
||||||
//@JsModule("@material-ui/icons/ExpandMore")
|
|
||||||
//external class ExpandMoreIcon : Component<RProps, RState>{
|
|
||||||
// override fun render(): dynamic
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//@JsModule("@material-ui/icons/ChevronRight")
|
|
||||||
//external class ChevronRightIcon : Component<RProps, RState>{
|
|
||||||
// override fun render(): dynamic
|
|
||||||
//}
|
|
@ -1,97 +0,0 @@
|
|||||||
package space.kscience.visionforge.material
|
|
||||||
|
|
||||||
import space.kscience.visionforge.react.component
|
|
||||||
import space.kscience.visionforge.react.state
|
|
||||||
import kotlinx.html.DIV
|
|
||||||
import materialui.components.card.card
|
|
||||||
import materialui.components.cardcontent.cardContent
|
|
||||||
import materialui.components.cardheader.cardHeader
|
|
||||||
import materialui.components.container.container
|
|
||||||
import materialui.components.container.enums.ContainerMaxWidth
|
|
||||||
import materialui.components.expansionpanel.expansionPanel
|
|
||||||
import materialui.components.expansionpaneldetails.expansionPanelDetails
|
|
||||||
import materialui.components.expansionpanelsummary.expansionPanelSummary
|
|
||||||
import materialui.components.grid.GridElementBuilder
|
|
||||||
import materialui.components.grid.enums.GridDirection
|
|
||||||
import materialui.components.grid.enums.GridStyle
|
|
||||||
import materialui.components.grid.grid
|
|
||||||
import materialui.components.paper.paper
|
|
||||||
import materialui.components.typography.typographyH5
|
|
||||||
import react.RBuilder
|
|
||||||
import react.RProps
|
|
||||||
import react.child
|
|
||||||
import react.dom.RDOMBuilder
|
|
||||||
|
|
||||||
|
|
||||||
fun accordionComponent(elements: List<Pair<String, RDOMBuilder<DIV>.() -> Unit>>) =
|
|
||||||
component<RProps> {
|
|
||||||
val expandedIndex: Int? by state { null }
|
|
||||||
|
|
||||||
container {
|
|
||||||
attrs {
|
|
||||||
maxWidth = ContainerMaxWidth.`false`
|
|
||||||
}
|
|
||||||
elements.forEachIndexed { index, (header, body) ->
|
|
||||||
expansionPanel {
|
|
||||||
attrs {
|
|
||||||
expanded = index == expandedIndex
|
|
||||||
}
|
|
||||||
expansionPanelSummary {
|
|
||||||
typographyH5 {
|
|
||||||
+header
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expansionPanelDetails {
|
|
||||||
this.body()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typealias RAccordionBuilder = MutableList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>
|
|
||||||
|
|
||||||
fun RAccordionBuilder.entry(title: String, builder: RDOMBuilder<DIV>.() -> Unit) {
|
|
||||||
add(title to builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RBuilder.accordion(builder: RAccordionBuilder.() -> Unit) {
|
|
||||||
val list: List<Pair<String, RDOMBuilder<DIV>.() -> Unit>> =
|
|
||||||
ArrayList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>().apply(builder)
|
|
||||||
child(accordionComponent(list))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RBuilder.materialCard(title: String, block: RBuilder.() -> Unit) {
|
|
||||||
card {
|
|
||||||
cardHeader {
|
|
||||||
attrs {
|
|
||||||
this.title = typographyH5 {
|
|
||||||
+title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cardContent {
|
|
||||||
paper {
|
|
||||||
this.block()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RBuilder.column(vararg classMap: Pair<GridStyle, String>, block: GridElementBuilder<DIV>.() -> Unit) =
|
|
||||||
grid(*classMap) {
|
|
||||||
attrs {
|
|
||||||
container = true
|
|
||||||
direction = GridDirection.column
|
|
||||||
}
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RBuilder.row(vararg classMap: Pair<GridStyle, String>, block: GridElementBuilder<DIV>.() -> Unit) =
|
|
||||||
grid(*classMap) {
|
|
||||||
attrs {
|
|
||||||
container = true
|
|
||||||
direction = GridDirection.row
|
|
||||||
}
|
|
||||||
block()
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
package space.kscience.visionforge.material
|
|
||||||
|
|
||||||
import space.kscience.dataforge.names.Name
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
import space.kscience.dataforge.names.toName
|
|
||||||
import space.kscience.visionforge.Vision
|
|
||||||
import space.kscience.visionforge.VisionGroup
|
|
||||||
import space.kscience.visionforge.isEmpty
|
|
||||||
import space.kscience.visionforge.react.component
|
|
||||||
import space.kscience.visionforge.react.state
|
|
||||||
import kotlinx.html.UL
|
|
||||||
import materialui.lab.components.treeItem.treeItem
|
|
||||||
import materialui.lab.components.treeView.SingleSelectTreeViewElementBuilder
|
|
||||||
import materialui.lab.components.treeView.treeView
|
|
||||||
import react.FunctionalComponent
|
|
||||||
import react.RBuilder
|
|
||||||
import react.RProps
|
|
||||||
import react.child
|
|
||||||
import react.dom.span
|
|
||||||
|
|
||||||
interface ObjectTreeProps : RProps {
|
|
||||||
var name: Name
|
|
||||||
var selected: Name?
|
|
||||||
var obj: Vision
|
|
||||||
var clickCallback: (Name?) -> Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun RBuilder.treeBranch(name: Name, obj: Vision): Unit {
|
|
||||||
treeItem {
|
|
||||||
val token = name.last()?.toString() ?: "World"
|
|
||||||
attrs {
|
|
||||||
nodeId = name.toString()
|
|
||||||
label {
|
|
||||||
span {
|
|
||||||
+token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj is VisionGroup) {
|
|
||||||
obj.children.entries
|
|
||||||
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
|
||||||
.sortedBy { (it.value as? VisionGroup)?.isEmpty ?: true }
|
|
||||||
.forEach { (childToken, child) ->
|
|
||||||
treeBranch(name + childToken, child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val ObjectTree: FunctionalComponent<ObjectTreeProps> = component { props ->
|
|
||||||
var selected: String? by state { props.selected.toString() }
|
|
||||||
treeView {
|
|
||||||
this as SingleSelectTreeViewElementBuilder<UL>
|
|
||||||
attrs {
|
|
||||||
this.selected = selected
|
|
||||||
this.onNodeSelect{ _, selectedItem ->
|
|
||||||
selected = selectedItem
|
|
||||||
val itemName = selected?.toName()
|
|
||||||
props.clickCallback(itemName)
|
|
||||||
Unit
|
|
||||||
}
|
|
||||||
defaultCollapseIcon {
|
|
||||||
span{
|
|
||||||
+"-"
|
|
||||||
}
|
|
||||||
//child(ExpandMoreIcon::class) {}
|
|
||||||
}//{<ExpandMoreIcon />}
|
|
||||||
defaultExpandIcon {
|
|
||||||
span{
|
|
||||||
+"+"
|
|
||||||
}
|
|
||||||
//child(ChevronRightIcon::class) {}
|
|
||||||
}//{<ChevronRightIcon />}
|
|
||||||
}
|
|
||||||
treeBranch(props.name, props.obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RBuilder.objectTree(
|
|
||||||
vision: Vision,
|
|
||||||
selected: Name? = null,
|
|
||||||
clickCallback: (Name?) -> Unit = {}
|
|
||||||
) {
|
|
||||||
child(ObjectTree) {
|
|
||||||
attrs {
|
|
||||||
this.name = Name.EMPTY
|
|
||||||
this.obj = vision
|
|
||||||
this.selected = selected
|
|
||||||
this.clickCallback = clickCallback
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
|||||||
package materialui.components.slider
|
|
||||||
|
|
||||||
import kotlinx.html.DIV
|
|
||||||
import kotlinx.html.Tag
|
|
||||||
import materialui.components.MaterialElementBuilder
|
|
||||||
import materialui.components.getValue
|
|
||||||
import materialui.components.inputbase.enums.InputBaseStyle
|
|
||||||
import materialui.components.setValue
|
|
||||||
import react.RClass
|
|
||||||
import react.ReactElement
|
|
||||||
|
|
||||||
class SliderElementBuilder<Props: SliderProps> internal constructor(
|
|
||||||
type: RClass<Props>,
|
|
||||||
classMap: List<Pair<Enum<*>, String>>
|
|
||||||
) : MaterialElementBuilder<DIV, Props>(type, classMap, { DIV(mapOf(), it) }) {
|
|
||||||
fun Tag.classes(vararg classMap: Pair<InputBaseStyle, String>) {
|
|
||||||
classes(classMap.toList())
|
|
||||||
}
|
|
||||||
var Tag.defaultValue: Number? by materialProps
|
|
||||||
var Tag.disabled: Boolean? by materialProps// = false
|
|
||||||
var Tag.getAriaLabel: String? by materialProps
|
|
||||||
var Tag.getAriaValueText: String? by materialProps
|
|
||||||
var Tag.marks: Array<String>? by materialProps
|
|
||||||
var Tag.max: Number? by materialProps// = 100
|
|
||||||
var Tag.min: Number? by materialProps// = 0,
|
|
||||||
var Tag.name: String? by materialProps
|
|
||||||
var Tag.onChange: ((dynamic, Number) -> Unit)? by materialProps
|
|
||||||
var Tag.onChangeCommitted: ((dynamic, Number) -> Unit)? by materialProps
|
|
||||||
var Tag.orientation: SliderOrientation? by materialProps
|
|
||||||
var Tag.scale: ((Number) -> Number)? by materialProps// {it}
|
|
||||||
var Tag.step: Number? by materialProps// = 1,
|
|
||||||
//ThumbComponent = 'span',
|
|
||||||
var Tag.track: SliderTrack by materialProps
|
|
||||||
var Tag.value: Number? by materialProps
|
|
||||||
var Tag.ValueLabelComponent: ReactElement? by materialProps
|
|
||||||
var Tag.valueLabelDisplay: SliderValueLabelDisplay by materialProps
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package materialui.components.slider
|
|
||||||
|
|
||||||
enum class SliderOrientation {
|
|
||||||
horizontal,
|
|
||||||
vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class SliderTrack{
|
|
||||||
normal,
|
|
||||||
`false`,
|
|
||||||
inverted,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class SliderValueLabelDisplay{
|
|
||||||
on,
|
|
||||||
auto,
|
|
||||||
off
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package materialui.components.slider
|
|
||||||
|
|
||||||
import materialui.components.StandardProps
|
|
||||||
import materialui.components.input.enums.InputStyle
|
|
||||||
import react.RBuilder
|
|
||||||
import react.RClass
|
|
||||||
import react.ReactElement
|
|
||||||
|
|
||||||
@JsModule("@material-ui/core/Slider")
|
|
||||||
private external val sliderModule: dynamic
|
|
||||||
|
|
||||||
external interface SliderProps : StandardProps {
|
|
||||||
var defaultValue: Number?
|
|
||||||
var disabled: Boolean?// = false
|
|
||||||
var getAriaLabel: String?
|
|
||||||
var getAriaValueText: String?
|
|
||||||
var marks: Array<String>?
|
|
||||||
var max: Number?// = 100
|
|
||||||
var min: Number?// = 0,
|
|
||||||
var name: String?
|
|
||||||
var onChange: ((dynamic, Number) -> Unit)?
|
|
||||||
var onChangeCommitted: ((dynamic, Number) -> Unit)?
|
|
||||||
var orientation: SliderOrientation?
|
|
||||||
var scale: ((Number) -> Number)?// {it}
|
|
||||||
var step: Number? // = 1,
|
|
||||||
//ThumbComponent = 'span',
|
|
||||||
var track: SliderTrack
|
|
||||||
var value: Number?
|
|
||||||
var ValueLabelComponent: ReactElement?
|
|
||||||
var valueLabelDisplay: SliderValueLabelDisplay
|
|
||||||
//valueLabelFormat = Identity,
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UnsafeCastFromDynamic")
|
|
||||||
private val sliderComponent: RClass<SliderProps> = sliderModule.default
|
|
||||||
|
|
||||||
fun RBuilder.slider(vararg classMap: Pair<InputStyle, String>, block: SliderElementBuilder<SliderProps>.() -> Unit) =
|
|
||||||
child(SliderElementBuilder(sliderComponent, classMap.toList()).apply(block).create())
|
|
@ -14,6 +14,7 @@ import space.kscience.visionforge.solid.Solid
|
|||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
import space.kscience.visionforge.solid.three.ThreeCanvas
|
import space.kscience.visionforge.solid.three.ThreeCanvas
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
|
import space.kscience.visionforge.solid.three.configure
|
||||||
import styled.css
|
import styled.css
|
||||||
import styled.styledDiv
|
import styled.styledDiv
|
||||||
|
|
||||||
@ -41,7 +42,10 @@ public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functio
|
|||||||
useEffect(listOf(props.obj, props.options, elementRef)) {
|
useEffect(listOf(props.obj, props.options, elementRef)) {
|
||||||
if (canvas == null) {
|
if (canvas == null) {
|
||||||
val element = elementRef.current as? HTMLElement ?: error("Canvas element not found")
|
val element = elementRef.current as? HTMLElement ?: error("Canvas element not found")
|
||||||
val newCanvas: ThreeCanvas = three.createCanvas(element, props.options ?: Canvas3DOptions.empty())
|
val newCanvas: ThreeCanvas = three.getOrCreateCanvas(element)
|
||||||
|
props.options?.let {
|
||||||
|
newCanvas.configure(it)
|
||||||
|
}
|
||||||
props.canvasCallback?.invoke(newCanvas)
|
props.canvasCallback?.invoke(newCanvas)
|
||||||
canvas = newCanvas
|
canvas = newCanvas
|
||||||
}
|
}
|
||||||
|
@ -13,18 +13,25 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.toName
|
||||||
import space.kscience.visionforge.Vision.Companion.TYPE
|
import space.kscience.visionforge.Vision.Companion.TYPE
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A root type for display hierarchy
|
* A root type for display hierarchy
|
||||||
*/
|
*/
|
||||||
@Type(TYPE)
|
@Type(TYPE)
|
||||||
public interface Vision : Described {
|
public interface Vision : Described, CoroutineScope {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parent object of this one. If null, this one is a root.
|
* The parent object of this one. If null, this one is a root.
|
||||||
*/
|
*/
|
||||||
public var parent: VisionGroup?
|
public var parent: VisionGroup?
|
||||||
|
|
||||||
|
public val manager: VisionManager? get() = parent?.manager
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = manager?.context?.coroutineContext ?: EmptyCoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get property.
|
* Get property.
|
||||||
* @param inherit toggles parent node property lookup. Null means inference from descriptor. Default is false.
|
* @param inherit toggles parent node property lookup. Null means inference from descriptor. Default is false.
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -30,14 +28,14 @@ internal data class PropertyListener(
|
|||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("vision")
|
@SerialName("vision")
|
||||||
public open class VisionBase(
|
public open class VisionBase : Vision {
|
||||||
internal var properties: Config? = null,
|
protected var properties: Config? = null
|
||||||
@Transient override var parent: VisionGroup? = null,
|
|
||||||
@Transient public val coroutineScope: CoroutineScope = GlobalScope,
|
@Transient
|
||||||
) : Vision {
|
override var parent: VisionGroup? = null
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
protected fun getOrCreateConfig(): Config {
|
protected fun getOrCreateProperties(): Config {
|
||||||
if (properties == null) {
|
if (properties == null) {
|
||||||
val newProperties = Config()
|
val newProperties = Config()
|
||||||
properties = newProperties
|
properties = newProperties
|
||||||
@ -77,7 +75,7 @@ public open class VisionBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
|
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
|
||||||
getOrCreateConfig().setItem(name, item)
|
getOrCreateProperties().setItem(name, item)
|
||||||
if (notify) {
|
if (notify) {
|
||||||
invalidateProperty(name)
|
invalidateProperty(name)
|
||||||
}
|
}
|
||||||
@ -104,7 +102,7 @@ public open class VisionBase(
|
|||||||
get() = propertyInvalidationFlow
|
get() = propertyInvalidationFlow
|
||||||
|
|
||||||
override fun invalidateProperty(propertyName: Name) {
|
override fun invalidateProperty(propertyName: Name) {
|
||||||
coroutineScope.launch {
|
launch {
|
||||||
if (propertyName == STYLE_KEY) {
|
if (propertyName == STYLE_KEY) {
|
||||||
updateStyles(styles)
|
updateStyles(styles)
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,7 @@ public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(s
|
|||||||
public operator fun <V : Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit =
|
public operator fun <V : Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit =
|
||||||
set(token.asName(), child)
|
set(token.asName(), child)
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainerBuilder<V>.set(key: String?, child: V?): Unit = set(key?.toName(), child)
|
public operator fun <V : Vision> VisionContainerBuilder<V>.set(key: String?, child: V?): Unit =
|
||||||
|
set(key?.toName(), child)
|
||||||
|
|
||||||
public fun MutableVisionGroup.removeAll(): Unit = children.keys.map { it.asName() }.forEach { this[it] = null }
|
public fun MutableVisionGroup.removeAll(): Unit = children.keys.map { it.asName() }.forEach { this[it] = null }
|
@ -48,7 +48,7 @@ public open class VisionGroupBase(
|
|||||||
* Propagate children change event upwards
|
* Propagate children change event upwards
|
||||||
*/
|
*/
|
||||||
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
|
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
|
||||||
coroutineScope.launch {
|
launch {
|
||||||
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
|
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,3 +142,15 @@ public open class VisionGroupBase(
|
|||||||
super.update(change)
|
super.update(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-serializable root group used to propagate manager to its children
|
||||||
|
*/
|
||||||
|
internal class RootVisionGroup(override val manager: VisionManager) : VisionGroupBase()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Designate this [VisionGroup] as a root group and assign a [VisionManager] as its parent
|
||||||
|
*/
|
||||||
|
public fun Vision.root(manager: VisionManager){
|
||||||
|
parent = RootVisionGroup(manager)
|
||||||
|
}
|
@ -14,7 +14,7 @@ public fun TagConsumer<*>.embedVisionFragment(
|
|||||||
fragment: HtmlVisionFragment,
|
fragment: HtmlVisionFragment,
|
||||||
): Map<Name, Vision> {
|
): Map<Name, Vision> {
|
||||||
val visionMap = HashMap<Name, Vision>()
|
val visionMap = HashMap<Name, Vision>()
|
||||||
val consumer = object : VisionTagConsumer<Any?>(this@embedVisionFragment, idPrefix) {
|
val consumer = object : VisionTagConsumer<Any?>(this@embedVisionFragment, manager, idPrefix) {
|
||||||
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
||||||
visionMap[name] = vision
|
visionMap[name] = vision
|
||||||
script {
|
script {
|
||||||
|
@ -17,7 +17,7 @@ import kotlin.collections.set
|
|||||||
* A placeholder object to attach inline vision builders.
|
* A placeholder object to attach inline vision builders.
|
||||||
*/
|
*/
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
public class VisionOutput @PublishedApi internal constructor() {
|
public class VisionOutput @PublishedApi internal constructor(public val manager: VisionManager) {
|
||||||
public var meta: Meta = Meta.EMPTY
|
public var meta: Meta = Meta.EMPTY
|
||||||
|
|
||||||
//TODO expose a way to define required plugins.
|
//TODO expose a way to define required plugins.
|
||||||
@ -32,6 +32,7 @@ public class VisionOutput @PublishedApi internal constructor() {
|
|||||||
*/
|
*/
|
||||||
public abstract class VisionTagConsumer<R>(
|
public abstract class VisionTagConsumer<R>(
|
||||||
private val root: TagConsumer<R>,
|
private val root: TagConsumer<R>,
|
||||||
|
public val manager:VisionManager,
|
||||||
private val idPrefix: String? = null,
|
private val idPrefix: String? = null,
|
||||||
) : TagConsumer<R> by root {
|
) : TagConsumer<R> by root {
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ public abstract class VisionTagConsumer<R>(
|
|||||||
script {
|
script {
|
||||||
attributes["class"] = OUTPUT_META_CLASS
|
attributes["class"] = OUTPUT_META_CLASS
|
||||||
unsafe {
|
unsafe {
|
||||||
+VisionManager.defaultJson.encodeToString(MetaSerializer, outputMeta)
|
+manager.jsonFormat.encodeToString(MetaSerializer, outputMeta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,7 +77,7 @@ public abstract class VisionTagConsumer<R>(
|
|||||||
name: Name,
|
name: Name,
|
||||||
visionProvider: VisionOutput.() -> Vision,
|
visionProvider: VisionOutput.() -> Vision,
|
||||||
): T {
|
): T {
|
||||||
val output = VisionOutput()
|
val output = VisionOutput(manager)
|
||||||
val vision = output.visionProvider()
|
val vision = output.visionProvider()
|
||||||
return vision(name, vision, output.meta)
|
return vision(name, vision, output.meta)
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,13 @@ package space.kscience.visionforge.html
|
|||||||
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.html.stream.createHTML
|
import kotlinx.html.stream.createHTML
|
||||||
|
import space.kscience.dataforge.context.Global
|
||||||
|
import space.kscience.dataforge.context.fetch
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.set
|
import space.kscience.dataforge.meta.set
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.VisionBase
|
|
||||||
import space.kscience.visionforge.configure
|
|
||||||
import space.kscience.visionforge.meta
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
|
typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
|
||||||
@ -20,7 +19,7 @@ fun FlowContent.renderVisionFragment(
|
|||||||
fragment: HtmlVisionFragment,
|
fragment: HtmlVisionFragment,
|
||||||
): Map<Name, Vision> {
|
): Map<Name, Vision> {
|
||||||
val visionMap = HashMap<Name, Vision>()
|
val visionMap = HashMap<Name, Vision>()
|
||||||
val consumer = object : VisionTagConsumer<Any?>(consumer, idPrefix) {
|
val consumer = object : VisionTagConsumer<Any?>(consumer, Global.fetch(VisionManager), idPrefix) {
|
||||||
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
||||||
visionMap[name] = vision
|
visionMap[name] = vision
|
||||||
renderer(name, vision, outputMeta)
|
renderer(name, vision, outputMeta)
|
||||||
|
@ -128,7 +128,7 @@ public class VisionClient : AbstractPlugin() {
|
|||||||
|
|
||||||
logger.info { "Updating vision data from $wsUrl" }
|
logger.info { "Updating vision data from $wsUrl" }
|
||||||
|
|
||||||
val ws = WebSocket(wsUrl.toString()).apply {
|
WebSocket(wsUrl.toString()).apply {
|
||||||
onmessage = { messageEvent ->
|
onmessage = { messageEvent ->
|
||||||
val stringData: String? = messageEvent.data as? String
|
val stringData: String? = messageEvent.data as? String
|
||||||
if (stringData != null) {
|
if (stringData != null) {
|
||||||
|
@ -17,7 +17,7 @@ public interface ElementVisionRenderer {
|
|||||||
/**
|
/**
|
||||||
* Display the [vision] inside a given [element] replacing its current content
|
* Display the [vision] inside a given [element] replacing its current content
|
||||||
*/
|
*/
|
||||||
public fun render(element: Element, vision: Vision, meta: Meta = Meta.EMPTY): Unit
|
public fun render(element: Element, vision: Vision, meta: Meta = Meta.EMPTY)
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public const val TYPE: String = "elementVisionRenderer"
|
public const val TYPE: String = "elementVisionRenderer"
|
||||||
|
@ -2,7 +2,7 @@ plugins {
|
|||||||
id("ru.mipt.npm.gradle.mpp")
|
id("ru.mipt.npm.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
val plotlyVersion = "0.4.2"
|
val plotlyVersion = "0.4.3"
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
useSerialization()
|
useSerialization()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.visionforge.plotly
|
package space.kscience.visionforge.plotly
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.Config
|
import space.kscience.dataforge.meta.Config
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
@ -7,13 +8,23 @@ import space.kscience.plotly.Plot
|
|||||||
import space.kscience.plotly.Plotly
|
import space.kscience.plotly.Plotly
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.visionforge.VisionBase
|
||||||
import space.kscience.visionforge.html.VisionOutput
|
import space.kscience.visionforge.html.VisionOutput
|
||||||
|
import space.kscience.visionforge.root
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
public class VisionOfPlotly(private val plotConfig: Config) : VisionBase(plotConfig){
|
@SerialName("vision.plotly")
|
||||||
public val plot: Plot get() = Plot(plotConfig)
|
public class VisionOfPlotly private constructor() : VisionBase() {
|
||||||
|
public constructor(plot: Plot) : this() {
|
||||||
|
properties = plot.config
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Plot.toVision(): VisionOfPlotly = VisionOfPlotly(config)
|
public val plot: Plot get() = Plot(properties ?: Config())
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Plot.asVision(): VisionOfPlotly = VisionOfPlotly(this)
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
public inline fun VisionOutput.plotly(block: Plot.() -> Unit): VisionOfPlotly = VisionOfPlotly(Plotly.plot(block).config)
|
public inline fun VisionOutput.plotly(
|
||||||
|
block: Plot.() -> Unit,
|
||||||
|
): VisionOfPlotly = VisionOfPlotly(Plotly.plot(block)).apply {
|
||||||
|
root(this@plotly.manager)
|
||||||
|
}
|
@ -31,6 +31,8 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
|||||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||||
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
||||||
val config = PlotlyConfig.read(meta)
|
val config = PlotlyConfig.read(meta)
|
||||||
|
println(plot.config)
|
||||||
|
println(plot.data[0].toMeta())
|
||||||
element.plot(plot, config)
|
element.plot(plot, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,12 +43,6 @@ import java.net.URI
|
|||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
|
||||||
public enum class VisionServerDataMode {
|
|
||||||
EMBED,
|
|
||||||
FETCH,
|
|
||||||
CONNECT
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ktor plugin container with given [routing]
|
* A ktor plugin container with given [routing]
|
||||||
@ -61,7 +55,9 @@ public class VisionServer internal constructor(
|
|||||||
override val config: Config = Config()
|
override val config: Config = Config()
|
||||||
public var updateInterval: Long by config.long(300, key = UPDATE_INTERVAL_KEY)
|
public var updateInterval: Long by config.long(300, key = UPDATE_INTERVAL_KEY)
|
||||||
public var cacheFragments: Boolean by config.boolean(true)
|
public var cacheFragments: Boolean by config.boolean(true)
|
||||||
public var dataMode: VisionServerDataMode = VisionServerDataMode.CONNECT
|
public var dataEmbed: Boolean by config.boolean(true, "data.embed".toName())
|
||||||
|
public var dataFetch: Boolean by config.boolean(false, "data.fetch".toName())
|
||||||
|
public var dataConnect: Boolean by config.boolean(true, "data.connect".toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a list of headers that should be applied to all pages
|
* a list of headers that should be applied to all pages
|
||||||
@ -79,26 +75,27 @@ public class VisionServer internal constructor(
|
|||||||
): Map<Name, Vision> {
|
): Map<Name, Vision> {
|
||||||
val visionMap = HashMap<Name, Vision>()
|
val visionMap = HashMap<Name, Vision>()
|
||||||
|
|
||||||
val consumer = object : VisionTagConsumer<Any?>(consumer) {
|
val consumer = object : VisionTagConsumer<Any?>(consumer, visionManager) {
|
||||||
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
||||||
visionMap[name] = vision
|
visionMap[name] = vision
|
||||||
// Toggle update mode
|
// Toggle update mode
|
||||||
when (dataMode) {
|
if (dataConnect) {
|
||||||
VisionServerDataMode.EMBED -> {
|
attributes[OUTPUT_CONNECT_ATTRIBUTE] = "auto"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataFetch) {
|
||||||
|
attributes[OUTPUT_FETCH_ATTRIBUTE] = "auto"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataEmbed) {
|
||||||
script {
|
script {
|
||||||
|
type = "text/json"
|
||||||
attributes["class"] = OUTPUT_DATA_CLASS
|
attributes["class"] = OUTPUT_DATA_CLASS
|
||||||
unsafe {
|
unsafe {
|
||||||
+"\n${visionManager.encodeToString(vision)}\n"
|
+"\n${visionManager.encodeToString(vision)}\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VisionServerDataMode.FETCH -> {
|
|
||||||
attributes[OUTPUT_FETCH_ATTRIBUTE] = "auto"
|
|
||||||
}
|
|
||||||
VisionServerDataMode.CONNECT -> {
|
|
||||||
attributes[OUTPUT_CONNECT_ATTRIBUTE] = "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,4 +68,5 @@ public class Solids(meta: Meta) : VisionPlugin(meta) {
|
|||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
public inline fun VisionOutput.solid(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)
|
public inline fun VisionOutput.solid(block: SolidGroup.() -> Unit): SolidGroup =
|
||||||
|
SolidGroup().apply(block).apply { root(this@solid.manager) }
|
||||||
|
@ -24,9 +24,7 @@ import org.w3c.dom.Node
|
|||||||
import org.w3c.dom.events.MouseEvent
|
import org.w3c.dom.events.MouseEvent
|
||||||
import space.kscience.dataforge.context.info
|
import space.kscience.dataforge.context.info
|
||||||
import space.kscience.dataforge.context.logger
|
import space.kscience.dataforge.context.logger
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.string
|
|
||||||
import space.kscience.dataforge.meta.useProperty
|
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
@ -41,8 +39,8 @@ import kotlin.math.sin
|
|||||||
*/
|
*/
|
||||||
public class ThreeCanvas(
|
public class ThreeCanvas(
|
||||||
public val three: ThreePlugin,
|
public val three: ThreePlugin,
|
||||||
public val options: Canvas3DOptions,
|
|
||||||
) {
|
) {
|
||||||
|
public val options = Canvas3DOptions()
|
||||||
|
|
||||||
private var boundingBox: Box3? = null
|
private var boundingBox: Box3? = null
|
||||||
private var root: Object3D? = null
|
private var root: Object3D? = null
|
||||||
@ -316,3 +314,10 @@ public class ThreeCanvas(
|
|||||||
private const val CLIP_HELPER_NAME = "@clipping"
|
private const val CLIP_HELPER_NAME = "@clipping"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun ThreeCanvas.configure(options: Canvas3DOptions) {
|
||||||
|
this.options.update(options.toMeta())
|
||||||
|
options.onChange(this) { name, _, newItem ->
|
||||||
|
options[name] = newItem
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ import org.w3c.dom.Element
|
|||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
import space.kscience.dataforge.context.*
|
import space.kscience.dataforge.context.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.update
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.visionforge.ElementVisionRenderer
|
import space.kscience.visionforge.ElementVisionRenderer
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
@ -111,12 +112,13 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun createCanvas(
|
private val canvasCache = HashMap<Element, ThreeCanvas>()
|
||||||
|
|
||||||
|
public fun getOrCreateCanvas(
|
||||||
element: Element,
|
element: Element,
|
||||||
options: Canvas3DOptions = Canvas3DOptions.empty(),
|
): ThreeCanvas = canvasCache.getOrPut(element){ThreeCanvas(this).apply {
|
||||||
): ThreeCanvas = ThreeCanvas(this, options).apply {
|
|
||||||
attach(element)
|
attach(element)
|
||||||
}
|
}}
|
||||||
|
|
||||||
override fun content(target: String): Map<Name, Any> {
|
override fun content(target: String): Map<Name, Any> {
|
||||||
return when (target) {
|
return when (target) {
|
||||||
@ -128,11 +130,10 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
override fun rateVision(vision: Vision): Int =
|
override fun rateVision(vision: Vision): Int =
|
||||||
if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING else ElementVisionRenderer.ZERO_RATING
|
if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING else ElementVisionRenderer.ZERO_RATING
|
||||||
|
|
||||||
public fun renderSolid(
|
fun renderSolid(
|
||||||
element: Element,
|
element: Element,
|
||||||
vision: Solid,
|
vision: Solid,
|
||||||
options: Canvas3DOptions,
|
): ThreeCanvas = getOrCreateCanvas(element).apply {
|
||||||
): ThreeCanvas = createCanvas(element, options).apply {
|
|
||||||
render(vision)
|
render(vision)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,8 +141,9 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
renderSolid(
|
renderSolid(
|
||||||
element,
|
element,
|
||||||
vision as? Solid ?: error("Solid expected but ${vision::class} found"),
|
vision as? Solid ?: error("Solid expected but ${vision::class} found"),
|
||||||
Canvas3DOptions.read(meta)
|
).apply {
|
||||||
)
|
options.update(meta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object : PluginFactory<ThreePlugin> {
|
public companion object : PluginFactory<ThreePlugin> {
|
||||||
@ -154,8 +156,10 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
public fun ThreePlugin.render(
|
public fun ThreePlugin.render(
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
obj: Solid,
|
obj: Solid,
|
||||||
options: Canvas3DOptions.() -> Unit = {},
|
optionsBuilder: Canvas3DOptions.() -> Unit = {},
|
||||||
): ThreeCanvas = renderSolid(element, obj, Canvas3DOptions(options))
|
): ThreeCanvas = renderSolid(element, obj).apply {
|
||||||
|
options.apply(optionsBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
internal operator fun Object3D.set(token: NameToken, object3D: Object3D) {
|
internal operator fun Object3D.set(token: NameToken, object3D: Object3D) {
|
||||||
object3D.name = token.toString()
|
object3D.name = token.toString()
|
||||||
|
Loading…
Reference in New Issue
Block a user