From 389f357f8425a1ddf9d687a6cca473671b672eda Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 25 Jun 2023 14:24:58 +0300 Subject: [PATCH] Add event support to JS --- .../space/kscience/plotly/jsdemo/main.kt | 5 ++- .../kscience/plotly/events/PlotlyEvent.kt | 34 ++++++++----------- .../space/kscience/plotly/PlotlyElement.kt | 26 +++++++++----- .../kotlin/space/kscience/plotly/PlotlyJs.kt | 7 ++++ 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/examples/js-demo/src/main/kotlin/space/kscience/plotly/jsdemo/main.kt b/examples/js-demo/src/main/kotlin/space/kscience/plotly/jsdemo/main.kt index 6bf7b488..039ac038 100644 --- a/examples/js-demo/src/main/kotlin/space/kscience/plotly/jsdemo/main.kt +++ b/examples/js-demo/src/main/kotlin/space/kscience/plotly/jsdemo/main.kt @@ -14,6 +14,7 @@ import org.w3c.dom.events.Event import space.kscience.dataforge.meta.MetaSerializer import space.kscience.dataforge.meta.toMutableMeta import space.kscience.plotly.* +import space.kscience.plotly.events.PlotlyEventListenerType import space.kscience.plotly.models.ScatterMode import space.kscience.plotly.models.TraceType import kotlin.random.Random @@ -133,7 +134,9 @@ fun main(): Unit = withCanvas { val serialized = plot.toJsonString() console.log(serialized) val deserialized = Plot(Json.decodeFromString(MetaSerializer, serialized).toMutableMeta()) - plotDiv(plot = deserialized) + plotDiv(plot = deserialized).on(PlotlyEventListenerType.CLICK){ + console.info(it.toString()) + } } } diff --git a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/events/PlotlyEvent.kt b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/events/PlotlyEvent.kt index 8e2798ed..e96a00f2 100644 --- a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/events/PlotlyEvent.kt +++ b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/events/PlotlyEvent.kt @@ -1,10 +1,9 @@ package space.kscience.plotly.events -import space.kscience.dataforge.meta.* -import space.kscience.plotly.list -import space.kscience.plotly.models.Trace +import kotlinx.serialization.json.JsonElement +import space.kscience.dataforge.meta.Value -public enum class PlotlyEventListenerType(public val typeName: String){ +public enum class PlotlyEventListenerType(public val eventType: String){ CLICK("plotly_click"), HOVER("plotly_hover"), UNHOVER("plotly_unhover"), @@ -12,23 +11,18 @@ public enum class PlotlyEventListenerType(public val typeName: String){ SELECTED("plotly_selected") } -public class PlotlyEventPoint : Scheme() { - public val curveNumber: Int by int(1) - public val pointNumber: Int? by int() - public val x: Value? by value() - public val y: Value? by value() +public data class PlotlyEventPoint( + public val curveNumber: Int, + public val data: JsonElement, + public val pointNumber: Int? = null, + public val x: Value? = null, + public val y: Value? = null, +// +// public var data: Trace by spec(Trace) +// public var fullData: Trace by spec(Trace) +) - public val data: Trace by spec(Trace) - public val fullData: Trace by spec(Trace) - public companion object : SchemeSpec(::PlotlyEventPoint) -} - - -public class PlotlyEvent : Scheme() { - public val points: List by list(PlotlyEventPoint) - - public companion object : SchemeSpec(::PlotlyEvent) -} +public data class PlotlyEvent(public val points: List) diff --git a/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyElement.kt b/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyElement.kt index 6360d208..329c1776 100644 --- a/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyElement.kt +++ b/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyElement.kt @@ -4,18 +4,20 @@ import kotlinx.html.TagConsumer import kotlinx.html.div import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromDynamic import kotlinx.serialization.json.encodeToDynamic import org.w3c.dom.Element import org.w3c.dom.HTMLElement -import org.w3c.dom.events.Event -import space.kscience.dataforge.meta.DynamicMeta +import org.w3c.dom.events.MouseEvent import space.kscience.dataforge.meta.MetaSerializer import space.kscience.dataforge.meta.Scheme +import space.kscience.dataforge.meta.Value import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.firstOrNull import space.kscience.dataforge.names.startsWith import space.kscience.plotly.events.PlotlyEvent import space.kscience.plotly.events.PlotlyEventListenerType +import space.kscience.plotly.events.PlotlyEventPoint @OptIn(ExperimentalSerializationApi::class) private fun Scheme.toDynamic(): dynamic = Json.encodeToDynamic(MetaSerializer, meta) @@ -87,10 +89,18 @@ public inline fun TagConsumer.plotDiv( plotBuilder: Plot.() -> Unit, ): PlotlyElement = PlotlyElement(div("plotly-kt-plot").apply { plot(plotlyConfig, plotBuilder) }) -public fun PlotlyElement.on(eventType: PlotlyEventListenerType, block: (PlotlyEvent) -> Unit) { - div.addEventListener(eventType.typeName, { event: Event-> - val meta = DynamicMeta(event.asDynamic()) - val plotlyEvent = PlotlyEvent.read(meta) - block(plotlyEvent) - }) +@OptIn(ExperimentalSerializationApi::class) +public fun PlotlyElement.on(eventType: PlotlyEventListenerType, block: MouseEvent.(PlotlyEvent) -> Unit) { + div.asDynamic().on(eventType.eventType) { event: PlotMouseEvent -> + val eventData = PlotlyEvent(event.points.map { + PlotlyEventPoint( + curveNumber = it.curveNumber as Int, + pointNumber = it.pointNumber as? Int, + x = Value.of(it.x), + y = Value.of(it.y), + data = Json.decodeFromDynamic(it.data) + ) + }) + event.event.block(eventData) + } } diff --git a/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyJs.kt b/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyJs.kt index d95af7a0..19822b2e 100644 --- a/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyJs.kt +++ b/plotlykt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyJs.kt @@ -1,6 +1,7 @@ package space.kscience.plotly import org.w3c.dom.Element +import org.w3c.dom.events.MouseEvent import kotlin.js.Promise public external interface ToImgOpts { @@ -47,3 +48,9 @@ public external object PlotlyJs { public fun toImage(root: Element, opts: ToImgOpts): Promise public fun downloadImage(root: Element, opts: DownloadImgOpts): Promise } + + +public external interface PlotMouseEvent { + public val points : Array + public val event: MouseEvent +}