Fix plotly update problem

This commit is contained in:
Alexander Nozik 2024-03-14 14:54:16 +03:00
parent 1145483a90
commit 6dc1b9f349
9 changed files with 63 additions and 49 deletions

View File

@ -1,7 +1,6 @@
kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.js.compiler=ir
#kotlin.incremental.js.ir=true
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4G

View File

@ -147,7 +147,7 @@ private fun CoroutineScope.collectChange(
) {
//Collect properties change
source.properties.flowChanges().onEach { propertyName ->
source.properties.changes.onEach { propertyName ->
val newItem = source.properties.own[propertyName]
collector.propertyChanged(name, propertyName, newItem)
}.launchIn(this)

View File

@ -40,7 +40,11 @@ public interface VisionProperties : MetaProvider {
override fun get(name: Name): Meta? = get(name, null, null)
public fun flowChanges(): Flow<Name>
public val changes: Flow<Name>
@Deprecated("Replace with property", ReplaceWith("changes"))
public fun flowChanges(): Flow<Name> = changes
/**
* Notify all listeners that a property has been changed and should be invalidated.
@ -64,7 +68,7 @@ public interface MutableVisionProperties : VisionProperties, MutableMetaProvider
public fun set(
name: Name,
node: Meta?,
item: Meta?,
notify: Boolean,
)
@ -186,28 +190,28 @@ public open class AbstractVisionProperties(
return descriptor?.defaultValue
}
override fun set(name: Name, node: Meta?, notify: Boolean) {
override fun set(name: Name, item: Meta?, notify: Boolean) {
//ignore if the value is the same as existing
if (own[name] == node) return
if (own[name] == item) return
if (name.isEmpty()) {
if (node == null) {
if (item == null) {
own.items.keys.forEach {
remove(it.asName())
}
} else {
(own.items.keys - node.items.keys).forEach {
(own.items.keys - item.items.keys).forEach {
remove(it.asName())
}
node.items.forEach { (token, item) ->
item.items.forEach { (token, item) ->
set(token, item)
}
}
} else if (node == null) {
own[name] = node
} else if (item == null) {
own[name] = item
} else {
own[name] = node
own[name] = item
}
if (notify) {
invalidate(name)
@ -231,7 +235,8 @@ public open class AbstractVisionProperties(
@Transient
protected val changesInternal: MutableSharedFlow<Name> = MutableSharedFlow()
override fun flowChanges(): Flow<Name> = changesInternal
override val changes: Flow<Name>
get() = changesInternal
override fun invalidate(propertyName: Name) {
//send update signal

View File

@ -18,7 +18,7 @@ public fun Vision.flowProperty(
): Flow<Meta> = flow {
//Pass initial value.
emit(properties.get(propertyName, inherit, includeStyles))
properties.flowChanges().collect { name ->
properties.changes.collect { name ->
if (name.startsWith(propertyName)) {
emit(properties.get(propertyName, inherit, includeStyles))
}
@ -41,7 +41,7 @@ public fun Vision.flowPropertyValue(
): Flow<Value?> = flow {
//Pass initial value.
emit(properties.getValue(propertyName, inherit, includeStyles))
properties.flowChanges().collect { name ->
properties.changes.collect { name ->
if (name.startsWith(propertyName)) {
emit(properties.getValue(propertyName, inherit, includeStyles))
}

View File

@ -25,7 +25,7 @@ public fun Vision.useProperty(
): Job {
//Pass initial value.
callback(properties.get(propertyName, inherit, includeStyles))
return properties.flowChanges().onEach { name ->
return properties.changes.onEach { name ->
if (name.startsWith(propertyName)) {
callback(properties.get(propertyName, inherit, includeStyles))
}
@ -47,7 +47,7 @@ public fun <V : Vision, T> V.useProperty(
): Job {
//Pass initial value.
callback(property.get(this))
return properties.flowChanges().onEach { name ->
return properties.changes.onEach { name ->
if (name.startsWith(property.name.asName())) {
callback(property.get(this@useProperty))
}
@ -60,7 +60,7 @@ public fun <V : Vision, T> V.useProperty(
public fun Vision.onPropertyChange(
scope: CoroutineScope = manager?.context ?: error("Orphan Vision can't observe properties. Use explicit scope."),
callback: suspend (Name) -> Unit,
): Job = properties.flowChanges().onEach {
): Job = properties.changes.onEach {
callback(it)
}.launchIn(scope)
@ -71,6 +71,6 @@ public fun <V : Vision, T> V.onPropertyChange(
property: KProperty1<V, T>,
scope: CoroutineScope = manager?.context ?: error("Orphan Vision can't observe properties. Use explicit scope."),
callback: suspend V.(T) -> Unit,
): Job = properties.flowChanges().filter { it.startsWith(property.name.asName()) }.onEach {
): Job = properties.changes.filter { it.startsWith(property.name.asName()) }.onEach {
callback(property.get(this))
}.launchIn(scope)

View File

@ -1,23 +1,17 @@
package space.kscience.visionforge.plotly
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.MutableMetaSerializer
import space.kscience.dataforge.meta.ObservableMeta
import space.kscience.dataforge.meta.asObservable
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name
import space.kscience.plotly.Plot
import space.kscience.plotly.Plotly
import space.kscience.plotly.PlotlyConfig
import space.kscience.visionforge.AbstractVisionProperties
import space.kscience.visionforge.MutableVisionProperties
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionBuilder
@ -26,36 +20,52 @@ import space.kscience.visionforge.html.VisionOutput
@Serializable
@SerialName("vision.plotly")
public class VisionOfPlotly private constructor(
@Serializable(MutableMetaSerializer::class) public val meta: MutableMeta,
@Serializable(MutableMetaSerializer::class) private val meta: MutableMeta,
) : Vision {
public constructor(plot: Plot) : this(plot.meta)
public val plot: Plot get() = Plot(meta.asObservable())
@Transient
public val plot: Plot = Plot(meta.asObservable())
@Transient
override var parent: Vision? = null
@Transient
override val properties: MutableVisionProperties = object : AbstractVisionProperties(this, meta) {
override val properties: MutableVisionProperties = object : MutableVisionProperties {
override val own: Meta get() = plot.meta
override fun flowChanges(): Flow<Name> = if (meta is ObservableMeta) {
callbackFlow {
meta.onChange(this) {
override val changes = callbackFlow {
plot.meta.onChange(this) {
println(it)
launch {
send(it)
}
}
awaitClose {
meta.removeListener(this)
plot.meta.removeListener(this)
}
}
} else emptyFlow()
override fun invalidate(propertyName: Name) {
// Do nothing
//do nothing, updates to source already counted
// manager?.context?.launch {
// changes.emit(propertyName)
// }
}
override fun getValue(name: Name, inherit: Boolean?, includeStyles: Boolean?): Value? = plot.meta[name]?.value
override fun set(name: Name, item: Meta?, notify: Boolean) {
plot.meta[name] = item
if (notify) invalidate(name)
}
override fun setValue(name: Name, value: Value?, notify: Boolean) {
plot.meta[name] = value
if (notify) invalidate(name)
}
override val descriptor: MetaDescriptor get() = plot.descriptor
}

View File

@ -166,16 +166,16 @@ internal class SolidReferenceChild(
includeStyles: Boolean?,
): Value? = own.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
override fun set(name: Name, node: Meta?, notify: Boolean) {
own[name] = node
override fun set(name: Name, item: Meta?, notify: Boolean) {
own[name] = item
}
override fun setValue(name: Name, value: Value?, notify: Boolean) {
own.setValue(name, value)
}
override fun flowChanges(): Flow<Name> =
owner.properties.flowChanges().filter { it.startsWith(childToken(childName)) }
override val changes: Flow<Name>
get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) }
override fun invalidate(propertyName: Name) {
owner.properties.invalidate(childPropertyName(childName, propertyName))

View File

@ -89,7 +89,7 @@ public class ThreePlugin : AbstractPlugin(), ComposeHtmlVisionRenderer {
updatePosition(vision)
//obj.onChildrenChange()
if (observe) {
vision.properties.flowChanges().onEach { name ->
vision.properties.changes.onEach { name ->
if (
name.startsWith(Solid.POSITION_KEY) ||
name.startsWith(Solid.ROTATION_KEY) ||

View File

@ -147,7 +147,7 @@ public fun ThreeView(
}
},
name = Name.EMPTY,
updates = vision.properties.flowChanges(),
updates = vision.properties.changes,
rootDescriptor = vision.descriptor
)
vision.styles.takeIf { it.isNotEmpty() }?.let { styles ->