forked from kscience/visionforge
Refactor server API
This commit is contained in:
parent
fd8f693151
commit
fef1df3ab4
@ -10,13 +10,14 @@ import space.kscience.visionforge.jupyter.VFIntegrationBase
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.plotly.asVision
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.visionManager
|
||||
|
||||
@DFExperimental
|
||||
internal class VisionForgePlayGroundForJupyter : VFIntegrationBase(
|
||||
Context("VisionForge") {
|
||||
plugin(Solids)
|
||||
plugin(PlotlyPlugin)
|
||||
}
|
||||
}.visionManager
|
||||
) {
|
||||
|
||||
override fun Builder.afterLoaded() {
|
||||
|
@ -8,8 +8,9 @@ import kotlinx.html.*
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.VisionOfHtmlForm
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.formFragment
|
||||
import space.kscience.visionforge.html.bindForm
|
||||
import space.kscience.visionforge.onPropertyChange
|
||||
import space.kscience.visionforge.server.EngineConnectorConfig
|
||||
import space.kscience.visionforge.server.close
|
||||
@ -28,8 +29,18 @@ fun main() {
|
||||
resources()
|
||||
}
|
||||
|
||||
visionPage(connector, visionManager, VisionPage.scriptHeader("js/visionforge-playground.js")) {
|
||||
val form = formFragment("form") {
|
||||
val form = VisionOfHtmlForm("form").apply {
|
||||
onPropertyChange(visionManager.context) {
|
||||
println(this)
|
||||
}
|
||||
}
|
||||
|
||||
visionPage(
|
||||
connector,
|
||||
visionManager,
|
||||
VisionPage.scriptHeader("js/visionforge-playground.js"),
|
||||
) {
|
||||
bindForm(form) {
|
||||
label {
|
||||
htmlFor = "fname"
|
||||
+"First name:"
|
||||
@ -61,10 +72,7 @@ fun main() {
|
||||
}
|
||||
}
|
||||
|
||||
vision("form") { form }
|
||||
form.onPropertyChange {
|
||||
println(this)
|
||||
}
|
||||
vision(form)
|
||||
}
|
||||
|
||||
}.start(false)
|
||||
|
@ -1,11 +1,7 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.visionforge.html.HtmlVisionFragment
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.importScriptHeader
|
||||
import space.kscience.visionforge.makeFile
|
||||
import space.kscience.visionforge.html.*
|
||||
import space.kscience.visionforge.visionManager
|
||||
import java.awt.Desktop
|
||||
import java.nio.file.Path
|
||||
|
@ -20,10 +20,10 @@ import space.kscience.dataforge.context.logger
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.HtmlFormFragment
|
||||
import space.kscience.visionforge.html.HtmlVisionFragment
|
||||
import space.kscience.visionforge.html.VisionCollector
|
||||
import space.kscience.visionforge.html.visionFragment
|
||||
import space.kscience.visionforge.server.EngineConnectorConfig
|
||||
import space.kscience.visionforge.server.VisionRoute
|
||||
@ -107,7 +107,7 @@ public class VFForNotebook(override val context: Context) : ContextAware, Corout
|
||||
//server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment)
|
||||
val cellRoute = "content-${counter++}"
|
||||
|
||||
val collector: VisionCollector = mutableMapOf()
|
||||
val collector: MutableMap<Name, Vision> = mutableMapOf()
|
||||
|
||||
val url = engine.environment.connectors.first().let {
|
||||
url {
|
||||
@ -121,15 +121,15 @@ public class VFForNotebook(override val context: Context) : ContextAware, Corout
|
||||
engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector)
|
||||
|
||||
visionFragment(
|
||||
context,
|
||||
visionManager,
|
||||
embedData = true,
|
||||
updatesUrl = url,
|
||||
collector = collector,
|
||||
onVisionRendered = { name, vision -> collector[name] = vision },
|
||||
fragment = fragment
|
||||
)
|
||||
} else {
|
||||
//if not, use static rendering
|
||||
visionFragment(context, fragment = fragment)
|
||||
visionFragment(visionManager, fragment = fragment)
|
||||
}
|
||||
}
|
||||
renderScriptForId(id)
|
||||
|
@ -9,6 +9,7 @@ import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.ContextAware
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.*
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextUInt
|
||||
@ -17,9 +18,12 @@ import kotlin.random.nextUInt
|
||||
* A base class for different Jupyter VF integrations
|
||||
*/
|
||||
@DFExperimental
|
||||
public abstract class VFIntegrationBase(final override val context: Context) : JupyterIntegration(), ContextAware {
|
||||
public abstract class VFIntegrationBase(
|
||||
public val visionManager: VisionManager,
|
||||
) : JupyterIntegration(), ContextAware {
|
||||
|
||||
protected val handler: VFForNotebook = VFForNotebook(context)
|
||||
override val context: Context get() = visionManager.context
|
||||
protected val handler: VFForNotebook = VFForNotebook(visionManager.context)
|
||||
|
||||
protected abstract fun Builder.afterLoaded()
|
||||
|
||||
@ -67,7 +71,7 @@ public abstract class VFIntegrationBase(final override val context: Context) : J
|
||||
val id = "fragment[${page.hashCode()}/${Random.nextUInt()}]"
|
||||
div {
|
||||
this.id = id
|
||||
visionFragment(context, fragment = page.content)
|
||||
visionFragment(visionManager, fragment = page.content)
|
||||
}
|
||||
renderScriptForId(id)
|
||||
}
|
||||
|
27
jupyter/src/jvmMain/kotlin/forms.kt
Normal file
27
jupyter/src/jvmMain/kotlin/forms.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package space.kscience.visionforge.jupyter
|
||||
|
||||
import kotlinx.html.FORM
|
||||
import kotlinx.html.form
|
||||
import kotlinx.html.id
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.visionforge.html.HtmlFragment
|
||||
import space.kscience.visionforge.html.VisionOfHtmlForm
|
||||
|
||||
public class HtmlFormFragment internal constructor(
|
||||
public val vision: VisionOfHtmlForm,
|
||||
public val formBody: HtmlFragment,
|
||||
){
|
||||
public val values: Meta? get() = vision.values
|
||||
public operator fun get(valueName: String): Meta? = values?.get(valueName)
|
||||
}
|
||||
|
||||
public fun HtmlFormFragment(id: String? = null, builder: FORM.() -> Unit): HtmlFormFragment {
|
||||
val realId = id ?: "form[${builder.hashCode().toUInt()}]"
|
||||
return HtmlFormFragment(VisionOfHtmlForm(realId)) {
|
||||
form {
|
||||
this.id = realId
|
||||
builder()
|
||||
}
|
||||
}
|
||||
}
|
@ -7,12 +7,13 @@ import space.kscience.gdml.Gdml
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.jupyter.VFIntegrationBase
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.visionManager
|
||||
|
||||
@DFExperimental
|
||||
internal class GdmlForJupyter : VFIntegrationBase(
|
||||
Context("GDML") {
|
||||
plugin(Solids)
|
||||
}
|
||||
}.visionManager
|
||||
) {
|
||||
|
||||
override fun Builder.afterLoaded() {
|
||||
|
@ -25,7 +25,7 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
override fun rateVision(vision: Vision): Int =
|
||||
if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING * 2 else ElementVisionRenderer.ZERO_RATING
|
||||
|
||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||
createRoot(element).render {
|
||||
child(ThreeCanvasWithControls) {
|
||||
attrs {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.html.*
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
@ -15,8 +14,6 @@ public typealias HtmlVisionFragment = VisionTagConsumer<*>.() -> Unit
|
||||
@DFExperimental
|
||||
public fun HtmlVisionFragment(content: VisionTagConsumer<*>.() -> Unit): HtmlVisionFragment = content
|
||||
|
||||
public typealias VisionCollector = MutableMap<Name, Pair<VisionOutput, Vision>>
|
||||
|
||||
|
||||
/**
|
||||
* Render a fragment in the given consumer and return a map of extracted visions
|
||||
@ -27,15 +24,18 @@ public typealias VisionCollector = MutableMap<Name, Pair<VisionOutput, Vision>>
|
||||
* @param idPrefix a prefix to be used before vision ids
|
||||
*/
|
||||
public fun TagConsumer<*>.visionFragment(
|
||||
context: Context,
|
||||
visionManager: VisionManager,
|
||||
embedData: Boolean = true,
|
||||
fetchDataUrl: String? = null,
|
||||
updatesUrl: String? = null,
|
||||
idPrefix: String? = null,
|
||||
collector: VisionCollector = mutableMapOf(),
|
||||
onVisionRendered: (Name, Vision) -> Unit = { _, _ -> },
|
||||
fragment: HtmlVisionFragment,
|
||||
) {
|
||||
val consumer = object : VisionTagConsumer<Any?>(this@visionFragment, context, idPrefix) {
|
||||
|
||||
val collector: MutableMap<Name, Pair<VisionOutput, Vision>> = mutableMapOf()
|
||||
|
||||
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
|
||||
@ -47,6 +47,7 @@ public fun TagConsumer<*>.visionFragment(
|
||||
val (output, vision) = collector.getOrPut(actualName) {
|
||||
val output = VisionOutput(context, actualName)
|
||||
val vision = output.buildOutput()
|
||||
onVisionRendered(actualName, vision)
|
||||
output to vision
|
||||
}
|
||||
|
||||
@ -54,8 +55,15 @@ public fun TagConsumer<*>.visionFragment(
|
||||
}
|
||||
|
||||
override fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta) {
|
||||
// Toggle update mode
|
||||
|
||||
val (_, actualVision) = collector.getOrPut(name) {
|
||||
val output = VisionOutput(context, name)
|
||||
onVisionRendered(name, vision)
|
||||
output to vision
|
||||
}
|
||||
|
||||
|
||||
// Toggle update mode
|
||||
updatesUrl?.let {
|
||||
attributes[OUTPUT_CONNECT_ATTRIBUTE] = it
|
||||
}
|
||||
@ -69,7 +77,7 @@ public fun TagConsumer<*>.visionFragment(
|
||||
type = "text/json"
|
||||
attributes["class"] = OUTPUT_DATA_CLASS
|
||||
unsafe {
|
||||
+"\n${manager.encodeToString(vision)}\n"
|
||||
+"\n${manager.encodeToString(actualVision)}\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -80,19 +88,20 @@ public fun TagConsumer<*>.visionFragment(
|
||||
}
|
||||
|
||||
public fun FlowContent.visionFragment(
|
||||
context: Context,
|
||||
visionManager: VisionManager,
|
||||
embedData: Boolean = true,
|
||||
fetchDataUrl: String? = null,
|
||||
updatesUrl: String? = null,
|
||||
onVisionRendered: (Name, Vision) -> Unit = { _, _ -> },
|
||||
idPrefix: String? = null,
|
||||
visionCache: VisionCollector = mutableMapOf(),
|
||||
|
||||
fragment: HtmlVisionFragment,
|
||||
): Unit = consumer.visionFragment(
|
||||
context,
|
||||
embedData,
|
||||
fetchDataUrl,
|
||||
updatesUrl,
|
||||
idPrefix,
|
||||
visionCache,
|
||||
visionManager = visionManager,
|
||||
embedData = embedData,
|
||||
fetchDataUrl = fetchDataUrl,
|
||||
updatesUrl = updatesUrl,
|
||||
idPrefix = idPrefix,
|
||||
onVisionRendered = onVisionRendered,
|
||||
fragment = fragment
|
||||
)
|
@ -7,7 +7,6 @@ import kotlinx.html.id
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.node
|
||||
|
||||
@Serializable
|
||||
@ -18,29 +17,10 @@ public class VisionOfHtmlForm(
|
||||
public var values: Meta? by mutableProperties.node()
|
||||
}
|
||||
|
||||
public class HtmlFormFragment internal constructor(
|
||||
public val vision: VisionOfHtmlForm,
|
||||
public val formBody: HtmlFragment,
|
||||
){
|
||||
public val values: Meta? get() = vision.values
|
||||
public operator fun get(valueName: String): Meta? = values?.get(valueName)
|
||||
}
|
||||
|
||||
public fun HtmlFormFragment(id: String? = null, builder: FORM.() -> Unit): HtmlFormFragment {
|
||||
val realId = id ?: "form[${builder.hashCode().toUInt()}]"
|
||||
return HtmlFormFragment(VisionOfHtmlForm(realId)) {
|
||||
form {
|
||||
this.id = realId
|
||||
builder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun <R> TagConsumer<R>.formFragment(
|
||||
id: String? = null,
|
||||
public fun <R> TagConsumer<R>.bindForm(
|
||||
visionOfForm: VisionOfHtmlForm,
|
||||
builder: FORM.() -> Unit,
|
||||
): VisionOfHtmlForm {
|
||||
val formFragment = HtmlFormFragment(id, builder)
|
||||
fragment(formFragment.formBody)
|
||||
return formFragment.vision
|
||||
): R = form {
|
||||
this.id = visionOfForm.formId
|
||||
builder()
|
||||
}
|
@ -2,6 +2,7 @@ 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.Meta
|
||||
import space.kscience.dataforge.meta.MetaSerializer
|
||||
@ -56,9 +57,11 @@ public class VisionOutput @PublishedApi internal constructor(public val context:
|
||||
@VisionDSL
|
||||
public abstract class VisionTagConsumer<R>(
|
||||
private val root: TagConsumer<R>,
|
||||
public val context: Context,
|
||||
public val visionManager: VisionManager,
|
||||
private val idPrefix: String? = null,
|
||||
) : TagConsumer<R> by root {
|
||||
) : TagConsumer<R> by root, ContextAware {
|
||||
|
||||
override val context: Context get() = visionManager.context
|
||||
|
||||
public open fun resolveId(name: Name): String = (idPrefix ?: "output") + "[$name]"
|
||||
|
||||
|
@ -18,7 +18,7 @@ fun FlowContent.renderVisionFragment(
|
||||
fragment: HtmlVisionFragment,
|
||||
): Map<Name, Vision> {
|
||||
val visionMap = HashMap<Name, Vision>()
|
||||
val consumer = object : VisionTagConsumer<Any?>(consumer, Global, idPrefix) {
|
||||
val consumer = object : VisionTagConsumer<Any?>(consumer, Global.visionManager, idPrefix) {
|
||||
override fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta) {
|
||||
visionMap[name] = vision
|
||||
renderer(name, vision, outputMeta)
|
||||
|
@ -4,6 +4,7 @@ import kotlinx.browser.document
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import org.w3c.dom.*
|
||||
import org.w3c.dom.url.URL
|
||||
@ -68,18 +69,6 @@ public class VisionClient : AbstractPlugin() {
|
||||
changeCollector.propertyChanged(visionName, propertyName, item)
|
||||
}
|
||||
|
||||
public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: Boolean) {
|
||||
visionPropertyChanged(visionName, propertyName, Meta(item))
|
||||
}
|
||||
|
||||
public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: String) {
|
||||
visionPropertyChanged(visionName, propertyName, Meta(item))
|
||||
}
|
||||
|
||||
public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: Number) {
|
||||
visionPropertyChanged(visionName, propertyName, Meta(item))
|
||||
}
|
||||
|
||||
public fun visionChanged(name: Name?, child: Vision?) {
|
||||
changeCollector.setChild(name, child)
|
||||
}
|
||||
@ -139,10 +128,12 @@ public class VisionClient : AbstractPlugin() {
|
||||
|
||||
onopen = {
|
||||
feedbackJob = visionManager.context.launch {
|
||||
delay(feedbackAggregationTime.milliseconds)
|
||||
if (!changeCollector.isEmpty()) {
|
||||
send(visionManager.encodeToString(changeCollector.deepCopy(visionManager)))
|
||||
changeCollector.reset()
|
||||
while (isActive) {
|
||||
delay(feedbackAggregationTime.milliseconds)
|
||||
if (!changeCollector.isEmpty()) {
|
||||
send(visionManager.encodeToString(changeCollector.deepCopy(visionManager)))
|
||||
changeCollector.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info { "WebSocket update channel established for output '$name'" }
|
||||
@ -247,6 +238,21 @@ public class VisionClient : AbstractPlugin() {
|
||||
}
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Meta?) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), item)
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Number) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: String) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Boolean) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
}
|
||||
|
||||
private fun whenDocumentLoaded(block: Document.() -> Unit): Unit {
|
||||
if (document.body != null) {
|
||||
|
@ -9,8 +9,11 @@ import org.w3c.dom.HTMLFormElement
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.get
|
||||
import org.w3c.xhr.FormData
|
||||
import space.kscience.dataforge.context.debug
|
||||
import space.kscience.dataforge.context.logger
|
||||
import space.kscience.dataforge.meta.DynamicMeta
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.toMap
|
||||
import space.kscience.dataforge.meta.valueSequence
|
||||
import space.kscience.visionforge.html.VisionOfHtmlForm
|
||||
import space.kscience.visionforge.html.VisionOfNumberField
|
||||
@ -33,7 +36,7 @@ internal fun textVisionRenderer(
|
||||
value = it ?: ""
|
||||
}
|
||||
onChangeFunction = {
|
||||
// client.visionPropertyChanged(name, VisionOfTextField::text.name.pa, value)
|
||||
client.visionPropertyChanged(name, VisionOfTextField::text.name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,7 +58,7 @@ internal fun numberVisionRenderer(
|
||||
value = it?.toDouble() ?: 0.0
|
||||
}
|
||||
onChangeFunction = {
|
||||
// vision.value = value.toDoubleOrNull()
|
||||
client.visionPropertyChanged(name, VisionOfNumberField::value.name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -90,9 +93,10 @@ internal fun formVisionRenderer(
|
||||
val form = document.getElementById(vision.formId) as? HTMLFormElement
|
||||
?: error("An element with id = '${vision.formId} is not a form")
|
||||
|
||||
console.info("Adding hooks to form '$form'")
|
||||
client.logger.debug{"Adding hooks to form with id = '$vision.formId'"}
|
||||
|
||||
vision.useProperty(VisionOfHtmlForm::values) { values ->
|
||||
client.logger.debug{"Updating form '${vision.formId}' with values $values"}
|
||||
val inputs = form.getElementsByTagName("input")
|
||||
values?.valueSequence()?.forEach { (token, value) ->
|
||||
(inputs[token.toString()] as? HTMLInputElement)?.value = value.toString()
|
||||
@ -102,8 +106,8 @@ internal fun formVisionRenderer(
|
||||
form.onsubmit = { event ->
|
||||
event.preventDefault()
|
||||
val formData = FormData(form).toMeta()
|
||||
//console.log(formData.toString())
|
||||
//vision.values = formData
|
||||
client.visionPropertyChanged(name, VisionOfHtmlForm::values.name, formData)
|
||||
console.info("Sent: ${formData.toMap()}")
|
||||
false
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.html.body
|
||||
import kotlinx.html.head
|
||||
@ -6,10 +6,7 @@ import kotlinx.html.meta
|
||||
import kotlinx.html.stream.createHTML
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.html.HtmlFragment
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.fragment
|
||||
import space.kscience.visionforge.html.visionFragment
|
||||
import space.kscience.visionforge.visionManager
|
||||
import java.awt.Desktop
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
@ -87,7 +84,7 @@ public fun VisionPage.makeFile(
|
||||
}
|
||||
}
|
||||
body {
|
||||
visionFragment(Global, fragment = content)
|
||||
visionFragment(Global.visionManager, fragment = content)
|
||||
}
|
||||
}.finalize()
|
||||
|
||||
|
@ -28,7 +28,7 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
else -> ElementVisionRenderer.ZERO_RATING
|
||||
}
|
||||
|
||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
||||
val config = PlotlyConfig.read(meta)
|
||||
element.plot(plot, config)
|
||||
|
@ -15,7 +15,6 @@ import io.ktor.server.util.*
|
||||
import io.ktor.server.websocket.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.ktor.websocket.*
|
||||
import kotlinx.coroutines.channels.consumeEach
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
@ -97,8 +96,8 @@ public fun Application.serveVisionData(
|
||||
val vision: Vision = resolveVision(Name.parse(name)) ?: error("Plot with id='$name' not registered")
|
||||
|
||||
launch {
|
||||
incoming.consumeEach {
|
||||
val data = it.data.decodeToString()
|
||||
for(frame in incoming) {
|
||||
val data = frame.data.decodeToString()
|
||||
application.log.debug("Received update: \n$data")
|
||||
val change = configuration.visionManager.jsonFormat.decodeFromString(
|
||||
VisionChange.serializer(), data
|
||||
@ -143,8 +142,8 @@ public fun Application.serveVisionData(
|
||||
|
||||
public fun Application.serveVisionData(
|
||||
configuration: VisionRoute,
|
||||
cache: VisionCollector,
|
||||
): Unit = serveVisionData(configuration) { cache[it]?.second }
|
||||
data: Map<Name, Vision>,
|
||||
): Unit = serveVisionData(configuration) { data[it] }
|
||||
|
||||
//
|
||||
///**
|
||||
@ -179,7 +178,7 @@ public fun Application.visionPage(
|
||||
) {
|
||||
require(WebSockets)
|
||||
|
||||
val collector: VisionCollector = mutableMapOf()
|
||||
val collector: MutableMap<Name, Vision> = mutableMapOf()
|
||||
|
||||
val html = createHTML().apply {
|
||||
head {
|
||||
@ -193,7 +192,7 @@ public fun Application.visionPage(
|
||||
body {
|
||||
//Load the fragment and remember all loaded visions
|
||||
visionFragment(
|
||||
context = configuration.context,
|
||||
visionManager = configuration.visionManager,
|
||||
embedData = configuration.dataMode == VisionRoute.Mode.EMBED,
|
||||
fetchDataUrl = if (configuration.dataMode != VisionRoute.Mode.EMBED) {
|
||||
url {
|
||||
@ -210,7 +209,7 @@ public fun Application.visionPage(
|
||||
path(route, "ws")
|
||||
}
|
||||
} else null,
|
||||
visionCache = collector,
|
||||
onVisionRendered = { name, vision -> collector[name] = vision },
|
||||
fragment = visionFragment
|
||||
)
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
else -> ElementVisionRenderer.ZERO_RATING
|
||||
}
|
||||
|
||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||
val table: VisionOfTable = (vision as? VisionOfTable)
|
||||
?: error("VisionOfTable expected but ${vision::class} found")
|
||||
|
||||
|
@ -86,7 +86,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
}.launchIn(context)
|
||||
|
||||
vision.children.changes.onEach { childName ->
|
||||
if(childName.isEmpty()) return@onEach
|
||||
if (childName.isEmpty()) return@onEach
|
||||
|
||||
val child = vision.children.getChild(childName)
|
||||
|
||||
@ -147,7 +147,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
render(vision)
|
||||
}
|
||||
|
||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||
renderSolid(
|
||||
element,
|
||||
vision as? Solid ?: error("Solid expected but ${vision::class} found"),
|
||||
|
@ -3,7 +3,6 @@ package space.kscience.visionforge.three
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.html.*
|
||||
import space.kscience.visionforge.makeFile
|
||||
import space.kscience.visionforge.visionManager
|
||||
import java.awt.Desktop
|
||||
import java.nio.file.Path
|
||||
|
Loading…
Reference in New Issue
Block a user