Skip to content

Commit e708caf

Browse files
committed
Add manual coroutine scope for plotly JS render.
1 parent bae747b commit e708caf

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

plotly-kt/plotly-kt-core/src/commonMain/kotlin/space/kscience/plotly/Plot.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ public class Plot : AbstractVision(), MutableVisionGroup<Trace> {
8080
*/
8181
@UnstablePlotlyAPI
8282
@JvmSynchronized
83-
internal fun removeTrace(index: Int) {
83+
public fun removeTrace(index: Int) {
8484
_data.removeAt(index)
85+
emitEvent(VisionGroupCompositionChangedEvent(NameToken("trace", _data.size.toString()), null))
8586
}
8687

8788
override val descriptor: MetaDescriptor get() = Companion.descriptor

plotly-kt/plotly-kt-core/src/commonMain/kotlin/space/kscience/plotly/Plotly.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import space.kscience.dataforge.context.ContextAware
88
import space.kscience.dataforge.context.request
99
import space.kscience.dataforge.meta.*
1010
import space.kscience.dataforge.names.Name
11+
import space.kscience.dataforge.names.asName
1112
import space.kscience.plotly.models.Trace
1213
import space.kscience.visionforge.VisionBuilder
13-
import space.kscience.visionforge.html.*
14+
import space.kscience.visionforge.html.VisionOutput
15+
import space.kscience.visionforge.html.VisionTagConsumer
1416
import kotlin.js.JsName
1517

1618
/**
@@ -65,6 +67,18 @@ public class PlotlyConfig : Scheme() {
6567
public var responsive: Boolean? by boolean()
6668
public var imageFormat: String? by string(Name.parse("toImageButtonOptions.format"))
6769

70+
/**
71+
* A list of class names applied to the output `div` in the generated HTML for the plot.
72+
*
73+
* This property allows customization of the CSS classes assigned to the `div` element
74+
* that contains the rendered plot. It can be utilized to add custom styling or specific
75+
* class-based behaviors to the output.
76+
*
77+
* By default, this property is initialized as an empty list and can be updated to include
78+
* necessary class names as strings.
79+
*/
80+
public var classes: List<String> by stringList(default = emptyArray(), key = VisionTagConsumer.OUTPUT_DIV_CLASSES_KEY.asName())
81+
6882
public fun withEditorButton() {
6983
showEditInChartStudio = true
7084
plotlyServerURL = "https://chart-studio.plotly.com"

plotly-kt/plotly-kt-core/src/jsMain/kotlin/space/kscience/plotly/PlotlyElement.kt

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package space.kscience.plotly
22

3+
import kotlinx.coroutines.CoroutineScope
34
import kotlinx.coroutines.DelicateCoroutinesApi
45
import kotlinx.coroutines.GlobalScope
56
import kotlinx.coroutines.flow.filterIsInstance
@@ -32,7 +33,11 @@ private fun List<MetaRepr>.toDynamic(): Array<dynamic> = map { it.toDynamic() }.
3233
* Attach a plot to this element or update the existing plot
3334
*/
3435
@OptIn(DelicateCoroutinesApi::class)
35-
public fun Element.plot(plotlyConfig: PlotlyConfig = PlotlyConfig(), plot: Plot) {
36+
public fun Element.plot(
37+
plotlyConfig: PlotlyConfig,
38+
plot: Plot,
39+
scope: CoroutineScope = plot.manager?.context ?: GlobalScope
40+
) {
3641

3742
// console.info("""
3843
// Plotly.react(
@@ -51,7 +56,7 @@ public fun Element.plot(plotlyConfig: PlotlyConfig = PlotlyConfig(), plot: Plot)
5156
)
5257

5358
//start updates
54-
val listenJob = (plot.manager?.context ?: GlobalScope).launch {
59+
val listenJob = scope.launch {
5560
plot.data.forEachIndexed { index, trace ->
5661
trace.eventFlow.filterIsInstance<VisionPropertyChangedEvent>().onEach { event ->
5762
val traceData = trace.toDynamic()
@@ -92,27 +97,34 @@ public fun Element.plot(plot: Plot, plotlyConfig: PlotlyConfig = PlotlyConfig())
9297
/**
9398
* Create a plot in this element
9499
*/
95-
public inline fun Element.plot(plotlyConfig: PlotlyConfig = PlotlyConfig(), plotBuilder: Plot.() -> Unit) {
96-
plot(plotlyConfig, Plot().apply(plotBuilder))
100+
public inline fun Element.plot(
101+
scope: CoroutineScope,
102+
plotlyConfig: PlotlyConfig = PlotlyConfig(),
103+
plotBuilder: Plot.() -> Unit
104+
) {
105+
plot(plotlyConfig, Plot().apply(plotBuilder), scope)
97106
}
98107

99108
public class PlotlyElement(public val div: HTMLElement)
100109

101110
/**
102-
* Create a div element and render plot in it
111+
* Create a div element and render the plot in it
103112
*/
113+
@OptIn(DelicateCoroutinesApi::class)
104114
public fun TagConsumer<HTMLElement>.plotDiv(
105-
plotlyConfig: PlotlyConfig = PlotlyConfig(),
115+
plotlyConfig: PlotlyConfig,
106116
plot: Plot,
117+
scope: CoroutineScope = plot.manager?.context ?: GlobalScope,
107118
): PlotlyElement = PlotlyElement(div("plotly-kt-plot").apply { plot(plotlyConfig, plot) })
108119

109120
/**
110121
* Render plot in the HTML element using direct plotly API.
111122
*/
112123
public inline fun TagConsumer<HTMLElement>.plotDiv(
124+
scope: CoroutineScope,
113125
plotlyConfig: PlotlyConfig = PlotlyConfig(),
114126
plotBuilder: Plot.() -> Unit,
115-
): PlotlyElement = PlotlyElement(div("plotly-kt-plot").apply { plot(plotlyConfig, plotBuilder) })
127+
): PlotlyElement = PlotlyElement(div("plotly-kt-plot").apply { plot(scope, plotlyConfig, plotBuilder) })
116128

117129
@OptIn(ExperimentalSerializationApi::class)
118130
public fun PlotlyElement.on(eventType: PlotlyEventListenerType, block: MouseEvent.(PlotlyEvent) -> Unit) {

0 commit comments

Comments
 (0)