diff --git a/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt b/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt index 0bdee628..dd0d0b26 100644 --- a/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt +++ b/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt @@ -8,7 +8,7 @@ import space.kscience.plotly.models.Trace import space.kscience.plotly.scatter import space.kscience.visionforge.Application import space.kscience.visionforge.Colors -import space.kscience.visionforge.VisionClient +import space.kscience.visionforge.JsVisionClient import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.react.createRoot import space.kscience.visionforge.react.render @@ -34,7 +34,7 @@ private class JsPlaygroundApp : Application { val playgroundContext = Context { plugin(ThreeWithControlsPlugin) - plugin(VisionClient) + plugin(JsVisionClient) plugin(PlotlyPlugin) } diff --git a/demo/muon-monitor/build.gradle.kts b/demo/muon-monitor/build.gradle.kts index c8f26b2c..7023e1cc 100644 --- a/demo/muon-monitor/build.gradle.kts +++ b/demo/muon-monitor/build.gradle.kts @@ -13,6 +13,7 @@ kscience { useKtor() fullStack( "muon-monitor.js", + development = true, jvmConfig = { withJava() }, jsConfig = { useCommonJs() } ) { diff --git a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt index 2cc8e9a5..7f7958b9 100644 --- a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt +++ b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt @@ -3,6 +3,7 @@ package ru.mipt.npm.muon.monitor 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.UPPER_LAYER_Z +import space.kscience.dataforge.names.asName import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionManager import space.kscience.visionforge.setAsRoot @@ -34,7 +35,7 @@ class Model(val manager: VisionManager) { } } - var tracks: SolidGroup + val tracks: SolidGroup = SolidGroup() val root: SolidGroup = SolidGroup().apply { setAsRoot(this@Model.manager) @@ -59,7 +60,8 @@ class Model(val manager: VisionManager) { detector(it) } } - tracks = solidGroup("tracks") + + setChild("tracks".asName(), tracks) } private fun highlight(pixel: String) { diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionClient.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionClient.kt new file mode 100644 index 00000000..cc1c38b8 --- /dev/null +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionClient.kt @@ -0,0 +1,42 @@ +package space.kscience.visionforge + +import kotlinx.coroutines.launch +import space.kscience.dataforge.context.Plugin +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.MetaRepr +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.parseAsName + +/** + * A feedback client that communicates with a server and provides ability to propagate events and changes back to the model + */ +public interface VisionClient: Plugin { + public val visionManager: VisionManager + + public suspend fun sendEvent(event: VisionEvent) + + public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) +} + + +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), item) +} + +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +} + +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +} + +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +} + +public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit { + context.launch { + sendEvent(VisionMetaEvent(visionName, event.toMeta())) + } +} \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt index 77f989f4..c74f027d 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt @@ -187,30 +187,10 @@ internal abstract class VisionChildrenImpl( } override fun clear() { - items?.forEach { set(it.key, null) } -// if (!items.isNullOrEmpty()) { -// updateJobs.values.forEach { -// it.cancel() -// } -// updateJobs.clear() -// items?.clear() -// } + items?.clear() + updateJobs.values.forEach { it.cancel() } + updateJobs.clear() + onChange(Name.EMPTY) } } -// -//internal object VisionChildrenContainerSerializer : KSerializer { -// private val mapSerializer = serializer>() -// -// override val descriptor: SerialDescriptor = mapSerializer.descriptor -// -// override fun deserialize(decoder: Decoder): MutableVisionChildren { -// val map = decoder.decodeSerializableValue(mapSerializer) -// return VisionChildrenImpl(map) -// } -// -// override fun serialize(encoder: Encoder, value: MutableVisionChildren) { -// val map = value.keys.associateWith { value[it]!! } -// encoder.encodeSerializableValue(mapSerializer, map) -// } -// -//} + diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionEvent.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionEvent.kt index 6b85156a..f123cf46 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionEvent.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionEvent.kt @@ -3,6 +3,8 @@ package space.kscience.visionforge import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.MutableMeta +import space.kscience.dataforge.meta.set import space.kscience.dataforge.names.Name /** @@ -11,6 +13,10 @@ import space.kscience.dataforge.names.Name @Serializable public sealed interface VisionEvent{ public val targetName: Name + + public companion object{ + public val CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload") + } } /** @@ -22,4 +28,13 @@ public class VisionMetaEvent(override val targetName: Name, public val meta: Met @Serializable @SerialName("change") -public class VisionChangeEvent(override val targetName: Name, public val change: VisionChange) : VisionEvent \ No newline at end of file +public class VisionChangeEvent(override val targetName: Name, public val change: VisionChange) : VisionEvent + +public val Vision.Companion.CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload") + +/** + * Set the payload to be sent to server on click + */ +public fun Vision.onClickPayload(payloadBuilder: MutableMeta.() -> Unit){ + properties[VisionEvent.CLICK_EVENT_KEY] = Meta(payloadBuilder) +} \ No newline at end of file diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/JsVisionClient.kt similarity index 88% rename from visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt rename to visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/JsVisionClient.kt index 81493a6e..44d07309 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/JsVisionClient.kt @@ -15,7 +15,10 @@ import kotlinx.coroutines.sync.withLock import org.w3c.dom.* import org.w3c.dom.url.URL import space.kscience.dataforge.context.* -import space.kscience.dataforge.meta.* +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.MetaSerializer +import space.kscience.dataforge.meta.get +import space.kscience.dataforge.meta.int import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.parseAsName import space.kscience.visionforge.html.VisionTagConsumer @@ -29,9 +32,9 @@ import kotlin.time.Duration.Companion.milliseconds /** * A Kotlin-browser plugin that renders visions based on provided renderers and governs communication with the server. */ -public class VisionClient : AbstractPlugin() { +public class JsVisionClient : AbstractPlugin(), VisionClient { override val tag: PluginTag get() = Companion.tag - private val visionManager: VisionManager by require(VisionManager) + override val visionManager: VisionManager by require(VisionManager) /** * Up-going tree traversal in search for endpoint attribute. If element is null, return window URL @@ -69,7 +72,7 @@ public class VisionClient : AbstractPlugin() { /** * Communicate vision property changed from rendering engine to model */ - public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) { + override fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) { context.launch { mutex.withLock { changeCollector.propertyChanged(visionName, propertyName, item) @@ -85,7 +88,7 @@ public class VisionClient : AbstractPlugin() { /** * Send a custom feedback event */ - public suspend fun sendEvent(event: VisionEvent) { + override suspend fun sendEvent(event: VisionEvent) { eventCollector.emit(event) } @@ -252,37 +255,15 @@ public class VisionClient : AbstractPlugin() { textVisionRenderer(this), formVisionRenderer(this) ).associateByName() - } else super.content(target) + } else super.content(target) - public companion object : PluginFactory { - override fun build(context: Context, meta: Meta): VisionClient = VisionClient() + public companion object : PluginFactory { + override fun build(context: Context, meta: Meta): JsVisionClient = JsVisionClient() override val tag: PluginTag = PluginTag(name = "vision.client.js", group = PluginTag.DATAFORGE_GROUP) } } -public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) { - notifyPropertyChanged(visionName, propertyName.parseAsName(true), item) -} - -public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) { - notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) -} - -public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) { - notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) -} - -public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) { - notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) -} - -public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit { - context.launch { - sendEvent(VisionMetaEvent(visionName, event.toMeta())) - } -} - private fun whenDocumentLoaded(block: Document.() -> Unit): Unit { if (document.body != null) { block(document) @@ -294,7 +275,7 @@ private fun whenDocumentLoaded(block: Document.() -> Unit): Unit { /** * Fetch and render visions for all elements with [VisionTagConsumer.OUTPUT_CLASS] class inside given [element]. */ -public fun VisionClient.renderAllVisionsIn(element: Element) { +public fun JsVisionClient.renderAllVisionsIn(element: Element) { val elements = element.getElementsByClassName(VisionTagConsumer.OUTPUT_CLASS) logger.info { "Finished search for outputs. Found ${elements.length} items" } elements.asList().forEach { child -> @@ -305,7 +286,7 @@ public fun VisionClient.renderAllVisionsIn(element: Element) { /** * Render all visions in an element with a given [id] */ -public fun VisionClient.renderAllVisionsById(document: Document, id: String): Unit { +public fun JsVisionClient.renderAllVisionsById(document: Document, id: String): Unit { val element = document.getElementById(id) if (element != null) { renderAllVisionsIn(element) @@ -318,13 +299,13 @@ public fun VisionClient.renderAllVisionsById(document: Document, id: String): Un /** * Fetch visions from the server for all elements with [VisionTagConsumer.OUTPUT_CLASS] class in the document body */ -public fun VisionClient.renderAllVisions(): Unit = whenDocumentLoaded { +public fun JsVisionClient.renderAllVisions(): Unit = whenDocumentLoaded { val element = body ?: error("Document does not have a body") renderAllVisionsIn(element) } public class VisionClientApplication(public val context: Context) : Application { - private val client = context.request(VisionClient) + private val client = context.request(JsVisionClient) override fun start(document: Document, state: Map) { context.logger.info { @@ -348,7 +329,7 @@ public fun runVisionClient(contextBuilder: ContextBuilder.() -> Unit) { Global.logger.info { "Starting VisionForge context" } val context = Context("VisionForge") { - plugin(VisionClient) + plugin(JsVisionClient) contextBuilder() } diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt index faf82d13..ff84c403 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt @@ -20,7 +20,7 @@ import space.kscience.visionforge.html.VisionOfNumberField import space.kscience.visionforge.html.VisionOfTextField internal fun textVisionRenderer( - client: VisionClient, + client: JsVisionClient, ): ElementVisionRenderer = ElementVisionRenderer { name, vision, _ -> val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]" vision.label?.let { @@ -42,7 +42,7 @@ internal fun textVisionRenderer( } internal fun numberVisionRenderer( - client: VisionClient, + client: JsVisionClient, ): ElementVisionRenderer = ElementVisionRenderer { name, vision, _ -> val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]" vision.label?.let { @@ -87,7 +87,7 @@ internal fun FormData.toMeta(): Meta { } internal fun formVisionRenderer( - client: VisionClient, + client: JsVisionClient, ): ElementVisionRenderer = ElementVisionRenderer { name, vision, _ -> val form = document.getElementById(vision.formId) as? HTMLFormElement diff --git a/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt b/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt index 7f06c6ac..e095485c 100644 --- a/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt +++ b/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt @@ -8,14 +8,14 @@ import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.context.PluginTag import space.kscience.dataforge.meta.Meta -import space.kscience.visionforge.VisionClient +import space.kscience.visionforge.JsVisionClient import space.kscience.visionforge.renderAllVisions import space.kscience.visionforge.renderAllVisionsById import space.kscience.visionforge.renderAllVisionsIn @JsExport public class VFNotebookClient : AbstractPlugin() { - private val client by require(VisionClient) + private val client by require(JsVisionClient) public fun renderAllVisionsIn(element: Element) { client.renderAllVisionsIn(element) diff --git a/visionforge-markdown/src/jsMain/kotlin/space/kscience/visionforge/markup/MarkupPlugin.kt b/visionforge-markdown/src/jsMain/kotlin/space/kscience/visionforge/markup/MarkupPlugin.kt index aad66f3f..ef700466 100644 --- a/visionforge-markdown/src/jsMain/kotlin/space/kscience/visionforge/markup/MarkupPlugin.kt +++ b/visionforge-markdown/src/jsMain/kotlin/space/kscience/visionforge/markup/MarkupPlugin.kt @@ -18,7 +18,7 @@ import space.kscience.visionforge.markup.VisionOfMarkup.Companion.COMMONMARK_FOR import space.kscience.visionforge.markup.VisionOfMarkup.Companion.GFM_FORMAT public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer { - public val visionClient: VisionClient by require(VisionClient) + public val visionClient: JsVisionClient by require(JsVisionClient) override val tag: PluginTag get() = Companion.tag override val visionSerializersModule: SerializersModule get() = markupSerializersModule diff --git a/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt b/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt index 91518f34..074be6dc 100644 --- a/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt +++ b/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt @@ -11,12 +11,12 @@ import space.kscience.dataforge.names.asName import space.kscience.plotly.PlotlyConfig import space.kscience.plotly.plot import space.kscience.visionforge.ElementVisionRenderer +import space.kscience.visionforge.JsVisionClient import space.kscience.visionforge.Vision -import space.kscience.visionforge.VisionClient import space.kscience.visionforge.VisionPlugin public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer { - public val visionClient: VisionClient by require(VisionClient) + public val visionClient: JsVisionClient by require(JsVisionClient) override val tag: PluginTag get() = Companion.tag diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt index 65a1bcd5..3cc6ff61 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt @@ -15,6 +15,9 @@ public enum class CompositeType { SUBTRACT } +/** + * A CSG-based composite solid + */ @Serializable @SerialName("solid.composite") public class Composite( diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt index 4fa174ac..bd449ce8 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt @@ -5,6 +5,9 @@ import kotlinx.serialization.Serializable import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.setChild +/** + * A convex hull shape + */ @Serializable @SerialName("solid.convex") public class Convex(public val points: List) : SolidBase() diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt index 6064e6ed..9f970bf0 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt @@ -12,7 +12,7 @@ import space.kscience.dataforge.names.asName import space.kscience.visionforge.* @Serializable -public abstract class LightSource : SolidBase() { +public abstract class LightSource : MiscSolid() { override val descriptor: MetaDescriptor get() = LightSource.descriptor public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/MiscSolid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/MiscSolid.kt index f83f6cb9..99462802 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/MiscSolid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/MiscSolid.kt @@ -6,13 +6,19 @@ import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.setChild +/** + * Utility solids + */ public abstract class MiscSolid: SolidBase() +/** + * X-Y-Z axes + */ @Serializable @SerialName("solid.axes") public class AxesSolid(public val size: Double): MiscSolid(){ public companion object{ - public const val AXES_NAME: String = "@xes" + public const val AXES_NAME: String = "@axes" } } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt index 4f5d48a4..a73b97e0 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt @@ -7,6 +7,9 @@ import kotlin.math.sin public typealias Shape2D = List +/** + * A builder for 2D shapes + */ @Serializable public class Shape2DBuilder(private val points: ArrayList = ArrayList()) { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index 3972de83..a42427da 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -152,7 +152,10 @@ public var Vision.ignore: Boolean? // get() = getProperty(SELECTED_KEY).boolean // set(value) = setProperty(SELECTED_KEY, value) -internal fun float(name: Name, default: Number): ReadWriteProperty = +/** + *A [Float] solid property delegate + */ +internal fun float32(name: Name, default: Number): ReadWriteProperty = object : ReadWriteProperty { override fun getValue(thisRef: Solid, property: KProperty<*>): Number { return thisRef.properties.getValue(name)?.number ?: default @@ -163,7 +166,10 @@ internal fun float(name: Name, default: Number): ReadWriteProperty : AbstractVision(), Solid { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt index 14784065..40857b14 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt @@ -12,6 +12,9 @@ import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_K import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY +/** + * A scheme for vision material + */ @VisionBuilder public class SolidMaterial : Scheme() { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index a6aabe67..32e69520 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -21,6 +21,7 @@ import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD * Get a vision prototype if it is a [SolidReference] or vision itself if it is not. * Unref is recursive, so it always returns a non-reference. */ +@Suppress("RecursivePropertyAccessor") public val Vision.prototype: Solid get() = when (this) { is SolidReference -> prototype.prototype @@ -239,95 +240,4 @@ public fun SolidGroup.newRef( error("Can't add different prototype on top of existing one") } return children.ref(prototypeName, name?.parseAsName()) -} - - -// -// -///** -// * A reference [Solid] to reuse a template object -// */ -//@Serializable -//@SerialName("solid.ref") -//public class SolidReferenceGroup( -// public val refName: Name, -//) : VisionGroup(), SolidReference, VisionGroup, Solid { -// -// /** -// * Recursively search for defined template in the parent -// */ -// override val prototype: Solid by lazy { -// if (parent == null) error("No parent is present for SolidReferenceGroup") -// if (parent !is PrototypeHolder) error("Parent does not hold prototypes") -// (parent as? PrototypeHolder)?.getPrototype(refName) ?: error("Prototype with name $refName not found") -// } -// -// override val items: Map> -// get() = (prototype as? VisionGroup<*>)?.items -// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN } -// ?.mapValues { -// VisionGroupItem.Node(ReferenceChild(this, it.key.asName())) -// } ?: emptyMap() -// -// override val descriptor: MetaDescriptor get() = prototype.descriptor -// -// -// /** -// * A ProxyChild is created temporarily only to interact with properties, it does not store any values -// * (properties are stored in external cache) and created and destroyed on-demand). -// */ -// private class ReferenceChild( -// val owner: SolidReferenceGroup, -// private val refName: Name, -// ) : SolidReference, VisionGroup, Solid { -// -// override val prototype: Solid by lazy { -// if (refName.isEmpty()) { -// owner.prototype -// } else { -// val proto = (owner.prototype).children.get(refName) -// ?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}") -// proto as? Solid ?: error("Prototype with name $refName is ${proto::class} but expected Solid") -//// proto.unref as? Solid -//// ?: error("Prototype with name $refName is ${proto::class} but expected Solid") -// } -// } -// -// override val meta: ObservableMutableMeta by lazy { -// owner.meta.getOrCreate(childToken(refName).asName()) -// } -// -// override val items: Map> -// get() = (prototype as? VisionGroup<*>)?.items -// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN } -// ?.mapValues { (key, _) -> -// VisionGroupItem.Node(ReferenceChild(owner, refName + key.asName())) -// } ?: emptyMap() -// -// override var parent: VisionGroup<*>? -// get() { -// val parentName = refName.cutLast() -// return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName) -// } -// set(_) { -// error("Setting a parent for a reference child is not possible") -// } -// -// override fun invalidateProperty(propertyName: Name) { -// owner.invalidateProperty(childPropertyName(refName, propertyName)) -// } -// -// override fun update(change: VisionChange) { -// change.properties?.let { -// updateProperties(it, Name.EMPTY) -// } -// } -// -// override val descriptor: MetaDescriptor get() = prototype.descriptor -// -// } -// -// public companion object { -// public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child" -// } -//} +} \ No newline at end of file diff --git a/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt b/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt index 469d4af8..75977d79 100644 --- a/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt +++ b/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt @@ -12,13 +12,13 @@ import space.kscience.dataforge.meta.toDynamic import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName import space.kscience.visionforge.ElementVisionRenderer +import space.kscience.visionforge.JsVisionClient import space.kscience.visionforge.Vision -import space.kscience.visionforge.VisionClient import tabulator.Tabulator import tabulator.TabulatorFull public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer { - public val visionClient: VisionClient by require(VisionClient) + public val visionClient: JsVisionClient by require(JsVisionClient) public val tablesBase: TableVisionPlugin by require(TableVisionPlugin) override val tag: PluginTag get() = Companion.tag diff --git a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt index c692b88d..b65d1fce 100644 --- a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt +++ b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt @@ -123,8 +123,8 @@ public class ThreeCanvas( element.appendChild(canvas) updateSize() canvas.addEventListener("pointerdown", { - val picked = pick() - options.onSelect?.invoke(picked?.fullName()) + val newPicked = pick() + options.onSelect?.invoke(newPicked?.fullName()) }, false) //Attach listener to track mouse changes @@ -143,12 +143,12 @@ public class ThreeCanvas( addControls(canvas, options.controls) renderer.setAnimationLoop { - val picked = pick() + val newPicked = pick() - if (picked != null && this.picked != picked) { - this.picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) - picked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) - this.picked = picked + if (newPicked != null && picked !== newPicked) { + picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) + newPicked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) + picked = newPicked } renderer.render(scene, camera) @@ -326,7 +326,7 @@ public class ThreeCanvas( public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply { color.set(Colors.blue) - thickness = 2f + thickness = 1f cached = true } // diff --git a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt index c1c2cf4d..7051f887 100644 --- a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt +++ b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt @@ -7,12 +7,10 @@ import org.w3c.dom.HTMLElement import space.kscience.dataforge.context.* import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.names.* -import space.kscience.visionforge.ElementVisionRenderer -import space.kscience.visionforge.Vision -import space.kscience.visionforge.VisionChildren +import space.kscience.visionforge.* import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.specifications.Canvas3DOptions -import space.kscience.visionforge.visible +import space.kscience.visionforge.solid.three.set import three.core.Object3D import kotlin.collections.set import kotlin.reflect.KClass @@ -23,6 +21,8 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { public val solids: Solids by require(Solids) + public val client: VisionClient? get() = context.plugins.get() + private val objectFactories = HashMap, ThreeFactory<*>>() private val compositeFactory = ThreeCompositeFactory(this) @@ -90,6 +90,8 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { val child = vision.children.getChild(childName) + logger.debug { "Changing vision $childName to $child" } + //removing old object findChild(childName)?.let { oldChild -> oldChild.parent?.remove(oldChild)