Compare commits
60 Commits
master
...
beta/1.9.0
Author | SHA1 | Date | |
---|---|---|---|
25c3a19eed | |||
ea9d37b9a1 | |||
a695e5e7c9 | |||
140c59497e | |||
23cb8765b6 | |||
a872f10523 | |||
be52551564 | |||
c4b866f5b5 | |||
d32dc3fa08 | |||
18c39fc076 | |||
f6f74b54f6 | |||
33778801b6 | |||
c48e5aac25 | |||
c921d5541b | |||
4ec611eda3 | |||
35fc7a7042 | |||
2bdaea2e82 | |||
d28873e796 | |||
fef1df3ab4 | |||
fd8f693151 | |||
c8141c6338 | |||
20b20a621f | |||
d6c974fcbc | |||
4ceffef67a | |||
279b848039 | |||
b2624cb10b | |||
eae1316de5 | |||
3c51060e2e | |||
960d17855b | |||
81aa5d2fcc | |||
f0a6e12358 | |||
56d577453a | |||
25fc143363 | |||
75540a078f | |||
40b784f551 | |||
67afa4e45b | |||
cb25dca34c | |||
98bb935de5 | |||
e2f281debe | |||
ac651c4d50 | |||
846e87a44b | |||
34fbb23c60 | |||
eeec89f0e6 | |||
43362f51f5 | |||
c586a2ea14 | |||
ecf4a6a198 | |||
0ea1ee056a | |||
9221df785d | |||
47bde02488 | |||
c71042ae06 | |||
9b1ca8332b | |||
791d6d7a81 | |||
4b1149b99b | |||
86935ce52a | |||
ce02a18c09 | |||
212d729afb | |||
3198bad094 | |||
9648533ac8 | |||
7ee40679b9 | |||
f828f86e29 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@ build/
|
||||
data/
|
||||
|
||||
!gradle-wrapper.jar
|
||||
|
||||
/kotlin-js-store/yarn.lock
|
||||
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -2,8 +2,18 @@
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Context receivers flag
|
||||
- MeshLine for thick lines
|
||||
|
||||
### Changed
|
||||
- API update for server and pages
|
||||
- Edges moved to solids module for easier construction
|
||||
- Visions **must** be rooted in order to subscribe to updates.
|
||||
- Visions use flows instead of direct subscriptions.
|
||||
- Radical change of inner workings of vision children and properties.
|
||||
- Three package changed to `three`.
|
||||
- Naming of Canvas3D options.
|
||||
- Lights are added to the scene instead of 3D options.
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
@ -1,29 +1,58 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile
|
||||
import space.kscience.gradle.isInDevelopment
|
||||
import space.kscience.gradle.useApache2Licence
|
||||
import space.kscience.gradle.useSPCTeam
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.project")
|
||||
id("org.jetbrains.kotlinx.kover") version "0.5.0-RC"
|
||||
id("space.kscience.gradle.project")
|
||||
// id("org.jetbrains.kotlinx.kover") version "0.5.0"
|
||||
}
|
||||
|
||||
val dataforgeVersion by extra("0.5.2")
|
||||
val dataforgeVersion by extra("0.6.1")
|
||||
val fxVersion by extra("11")
|
||||
|
||||
allprojects{
|
||||
allprojects {
|
||||
group = "space.kscience"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0-dev-9"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
if (name.startsWith("visionforge")) apply<MavenPublishPlugin>()
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
maven("https://maven.jzy3d.org/releases")
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<KotlinJsCompile>{
|
||||
kotlinOptions{
|
||||
useEsClasses = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ksciencePublish {
|
||||
github("visionforge")
|
||||
space()
|
||||
pom("https://github.com/SciProgCentre/visionforge") {
|
||||
useApache2Licence()
|
||||
useSPCTeam()
|
||||
}
|
||||
github(githubProject = "visionforge", githubOrg = "SciProgCentre")
|
||||
space(
|
||||
if (isInDevelopment) {
|
||||
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
|
||||
} else {
|
||||
"https://maven.pkg.jetbrains.space/spc/p/sci/maven"
|
||||
}
|
||||
)
|
||||
sonatype()
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,14 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
kscience{
|
||||
jvm()
|
||||
js()
|
||||
dependencies {
|
||||
api(projects.visionforgeSolid)
|
||||
}
|
||||
useSerialization {
|
||||
json()
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
api(project(":visionforge-solid"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.misc.Named
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.values.doubleArray
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
|
||||
public fun MetaProvider.doubleArray(
|
||||
|
@ -2,9 +2,11 @@ package ru.mipt.npm.root
|
||||
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.dataforge.values.doubleArray
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.isEmpty
|
||||
import space.kscience.visionforge.set
|
||||
import space.kscience.visionforge.solid.*
|
||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
||||
import kotlin.math.*
|
||||
@ -20,7 +22,9 @@ private fun degToRad(d: Double) = d * PI / 180.0
|
||||
private data class RootToSolidContext(
|
||||
val prototypeHolder: PrototypeHolder,
|
||||
val currentLayer: Int = 0,
|
||||
val maxLayer: Int = 5
|
||||
val maxLayer: Int = 5,
|
||||
val ignoreRootColors: Boolean = false,
|
||||
val colorCache: MutableMap<Meta, String> = mutableMapOf(),
|
||||
)
|
||||
|
||||
// converting to XYZ to Tait–Bryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
|
||||
@ -42,14 +46,17 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
|
||||
"TGeoIdentity" -> {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
"TGeoTranslation" -> {
|
||||
val fTranslation by matrix.meta.doubleArray()
|
||||
translate(fTranslation)
|
||||
}
|
||||
|
||||
"TGeoRotation" -> {
|
||||
val fRotationMatrix by matrix.meta.doubleArray()
|
||||
rotate(fRotationMatrix)
|
||||
}
|
||||
|
||||
"TGeoCombiTrans" -> {
|
||||
val fTranslation by matrix.meta.doubleArray()
|
||||
|
||||
@ -58,6 +65,7 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
|
||||
rotate(it.doubleArray)
|
||||
}
|
||||
}
|
||||
|
||||
"TGeoHMatrix" -> {
|
||||
val fTranslation by matrix.meta.doubleArray()
|
||||
val fRotationMatrix by matrix.meta.doubleArray()
|
||||
@ -73,7 +81,7 @@ private fun SolidGroup.addShape(
|
||||
shape: DGeoShape,
|
||||
context: RootToSolidContext,
|
||||
name: String? = shape.fName.ifEmpty { null },
|
||||
block: Solid.() -> Unit = {}
|
||||
block: Solid.() -> Unit = {},
|
||||
) {
|
||||
when (shape.typename) {
|
||||
"TGeoCompositeShape" -> {
|
||||
@ -94,6 +102,7 @@ private fun SolidGroup.addShape(
|
||||
}
|
||||
}.apply(block)
|
||||
}
|
||||
|
||||
"TGeoXtru" -> {
|
||||
val fNvert by shape.meta.int(0)
|
||||
val fX by shape.meta.doubleArray()
|
||||
@ -121,6 +130,7 @@ private fun SolidGroup.addShape(
|
||||
}
|
||||
}.apply(block)
|
||||
}
|
||||
|
||||
"TGeoTube" -> {
|
||||
val fRmax by shape.meta.double(0.0)
|
||||
val fDz by shape.meta.double(0.0)
|
||||
@ -134,6 +144,7 @@ private fun SolidGroup.addShape(
|
||||
block = block
|
||||
)
|
||||
}
|
||||
|
||||
"TGeoTubeSeg" -> {
|
||||
val fRmax by shape.meta.double(0.0)
|
||||
val fDz by shape.meta.double(0.0)
|
||||
@ -151,6 +162,7 @@ private fun SolidGroup.addShape(
|
||||
block = block
|
||||
)
|
||||
}
|
||||
|
||||
"TGeoPcon" -> {
|
||||
val fDphi by shape.meta.double(0.0)
|
||||
val fNz by shape.meta.int(2)
|
||||
@ -176,6 +188,7 @@ private fun SolidGroup.addShape(
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
"TGeoPgon" -> {
|
||||
//TODO add a inner polygone layer
|
||||
val fDphi by shape.meta.double(0.0)
|
||||
@ -206,15 +219,18 @@ private fun SolidGroup.addShape(
|
||||
}
|
||||
}.apply(block)
|
||||
}
|
||||
|
||||
"TGeoShapeAssembly" -> {
|
||||
val fVolume by shape.dObject(::DGeoVolume)
|
||||
fVolume?.let { volume ->
|
||||
addRootVolume(volume, context, block = block)
|
||||
}
|
||||
}
|
||||
|
||||
"TGeoBBox" -> {
|
||||
box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = name, block = block)
|
||||
}
|
||||
|
||||
"TGeoTrap" -> {
|
||||
val fTheta by shape.meta.double(0.0)
|
||||
val fPhi by shape.meta.double(0.0)
|
||||
@ -242,17 +258,19 @@ private fun SolidGroup.addShape(
|
||||
val node8 = Point3D(-fTl2, fH2, fDz)
|
||||
hexagon(node1, node2, node3, node4, node5, node6, node7, node8, name)
|
||||
}
|
||||
|
||||
"TGeoScaledShape" -> {
|
||||
val fShape by shape.dObject(::DGeoShape)
|
||||
val fScale by shape.dObject(::DGeoScale)
|
||||
fShape?.let { scaledShape ->
|
||||
group(name?.let { Name.parse(it) }) {
|
||||
solidGroup(name?.let { Name.parse(it) }) {
|
||||
scale = Point3D(fScale?.x ?: 1.0, fScale?.y ?: 1.0, fScale?.z ?: 1.0)
|
||||
addShape(scaledShape, context)
|
||||
apply(block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
TODO("A shape with type ${shape.typename} not implemented")
|
||||
}
|
||||
@ -267,6 +285,7 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
|
||||
val fMatrix by obj.dObject(::DGeoMatrix)
|
||||
this.useMatrix(fMatrix)
|
||||
}
|
||||
|
||||
"TGeoNodeOffset" -> {
|
||||
val fOffset by obj.meta.double(0.0)
|
||||
x = fOffset
|
||||
@ -276,12 +295,12 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
|
||||
}
|
||||
|
||||
private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid? {
|
||||
val group = SolidGroup {
|
||||
val group = SolidGroup().apply {
|
||||
//set current layer
|
||||
layer = context.currentLayer
|
||||
val nodes = volume.fNodes
|
||||
|
||||
if (nodes.isEmpty() || context.currentLayer >= context.maxLayer) {
|
||||
if (volume.typename != "TGeoVolumeAssembly" && (nodes.isEmpty() || context.currentLayer >= context.maxLayer)) {
|
||||
//TODO add smart filter
|
||||
volume.fShape?.let { shape ->
|
||||
addShape(shape, context)
|
||||
@ -301,12 +320,22 @@ private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid?
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (group.isEmpty()) {
|
||||
return if (group.children.isEmpty()) {
|
||||
null
|
||||
} else if (group.children.size == 1 && group.meta.isEmpty()) {
|
||||
(group.children.values.first() as Solid).apply { parent = null }
|
||||
} else if (group.items.size == 1 && group.properties.own == null) {
|
||||
group.items.values.first().apply { parent = null }
|
||||
} else {
|
||||
group
|
||||
}.apply {
|
||||
volume.fMedium?.let { medium ->
|
||||
color.set(context.colorCache.getOrPut(medium.meta) { RootColors[11 + context.colorCache.size] })
|
||||
}
|
||||
|
||||
if (!context.ignoreRootColors) {
|
||||
volume.fFillColor?.let {
|
||||
properties[MATERIAL_COLOR_KEY] = RootColors[it]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,8 +346,9 @@ private fun SolidGroup.addRootVolume(
|
||||
context: RootToSolidContext,
|
||||
name: String? = null,
|
||||
cache: Boolean = true,
|
||||
block: Solid.() -> Unit = {}
|
||||
block: Solid.() -> Unit = {},
|
||||
) {
|
||||
|
||||
val combinedName = if (volume.fName.isEmpty()) {
|
||||
name
|
||||
} else if (name == null) {
|
||||
@ -328,35 +358,30 @@ private fun SolidGroup.addRootVolume(
|
||||
}
|
||||
|
||||
if (!cache) {
|
||||
val group = buildVolume(volume, context)?.apply {
|
||||
volume.fFillColor?.let {
|
||||
meta[MATERIAL_COLOR_KEY] = RootColors[it]
|
||||
}
|
||||
block()
|
||||
}
|
||||
set(combinedName?.let { Name.parse(it) }, group)
|
||||
val group = buildVolume(volume, context)?.apply(block)
|
||||
setChild(combinedName?.let { Name.parse(it) }, group)
|
||||
} else {
|
||||
val templateName = volumesName + volume.name
|
||||
val existing = getPrototype(templateName)
|
||||
if (existing == null) {
|
||||
context.prototypeHolder.prototypes {
|
||||
val group = buildVolume(volume, context)
|
||||
set(templateName, group)
|
||||
setChild(templateName, group)
|
||||
}
|
||||
}
|
||||
|
||||
ref(templateName, name).apply {
|
||||
volume.fFillColor?.let {
|
||||
meta[MATERIAL_COLOR_KEY] = RootColors[it]
|
||||
}
|
||||
block()
|
||||
}
|
||||
ref(templateName, name).apply(block)
|
||||
}
|
||||
}
|
||||
|
||||
public fun DGeoManager.toSolid(): SolidGroup = SolidGroup {
|
||||
val context = RootToSolidContext(this)
|
||||
fNodes.forEach { node ->
|
||||
public fun MutableVisionContainer<Solid>.rootGeo(
|
||||
dGeoManager: DGeoManager,
|
||||
name: String? = null,
|
||||
maxLayer: Int = 5,
|
||||
ignoreRootColors: Boolean = false,
|
||||
): SolidGroup = solidGroup(name = name?.parseAsName()) {
|
||||
val context = RootToSolidContext(this, maxLayer = maxLayer, ignoreRootColors = ignoreRootColors)
|
||||
dGeoManager.fNodes.forEach { node ->
|
||||
addRootNode(node, context)
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
public object RootColors {
|
||||
private val colorMap = Array<String>(924) { "white" }
|
||||
private val colorMap = MutableList(924) { "white" }
|
||||
|
||||
//colorMap[110] = "white"
|
||||
|
||||
|
@ -14,7 +14,7 @@ import kotlinx.serialization.modules.subclass
|
||||
|
||||
private fun <T> jsonRootDeserializer(
|
||||
tSerializer: KSerializer<T>,
|
||||
builder: (JsonElement) -> T
|
||||
builder: (JsonElement) -> T,
|
||||
): DeserializationStrategy<T> = object :
|
||||
DeserializationStrategy<T> {
|
||||
private val jsonElementSerializer = JsonElement.serializer()
|
||||
@ -46,6 +46,7 @@ private object RootDecoder {
|
||||
private val refCache: List<RefEntry>,
|
||||
) : KSerializer<T> by tSerializer {
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
val input = decoder as JsonDecoder
|
||||
@ -90,9 +91,8 @@ private object RootDecoder {
|
||||
|
||||
private fun <T> KSerializer<T>.unref(refCache: List<RefEntry>): KSerializer<T> = RootUnrefSerializer(this, refCache)
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun unrefSerializersModule(
|
||||
refCache: List<RefEntry>
|
||||
refCache: List<RefEntry>,
|
||||
): SerializersModule = SerializersModule {
|
||||
|
||||
contextual(TObjArray::class) {
|
||||
@ -118,7 +118,7 @@ private object RootDecoder {
|
||||
subclass(TGeoCompositeShape.serializer().unref(refCache))
|
||||
subclass(TGeoShapeAssembly.serializer().unref(refCache))
|
||||
|
||||
default {
|
||||
defaultDeserializer {
|
||||
if (it == null) {
|
||||
TGeoShape.serializer().unref(refCache)
|
||||
} else {
|
||||
@ -136,7 +136,7 @@ private object RootDecoder {
|
||||
|
||||
|
||||
val unrefed = TGeoMatrix.serializer().unref(refCache)
|
||||
default {
|
||||
defaultDeserializer {
|
||||
if (it == null) {
|
||||
unrefed
|
||||
} else {
|
||||
@ -149,7 +149,7 @@ private object RootDecoder {
|
||||
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
|
||||
|
||||
val unrefed = TGeoVolume.serializer().unref(refCache)
|
||||
default {
|
||||
defaultDeserializer {
|
||||
if (it == null) {
|
||||
unrefed
|
||||
} else {
|
||||
@ -163,7 +163,7 @@ private object RootDecoder {
|
||||
subclass(TGeoNodeOffset.serializer().unref(refCache))
|
||||
|
||||
val unrefed = TGeoNode.serializer().unref(refCache)
|
||||
default {
|
||||
defaultDeserializer {
|
||||
if (it == null) {
|
||||
unrefed
|
||||
} else {
|
||||
@ -197,11 +197,13 @@ private object RootDecoder {
|
||||
fillCache(it)
|
||||
}
|
||||
}
|
||||
|
||||
is JsonArray -> {
|
||||
element.forEach {
|
||||
fillCache(it)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
//ignore primitives
|
||||
}
|
||||
@ -216,6 +218,7 @@ private object RootDecoder {
|
||||
|
||||
var value: Any? = null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> getOrPutValue(builder: (JsonElement) -> T): T {
|
||||
if (value == null) {
|
||||
value = builder(element)
|
||||
|
@ -3,6 +3,7 @@ package ru.mipt.npm.root.serialization
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.solid.*
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.atan2
|
||||
@ -132,7 +133,7 @@ private fun buildGroup(volume: TGeoVolume): SolidGroup {
|
||||
return if (volume is TGeoVolumeAssemblyRef) {
|
||||
buildGroup(volume.value)
|
||||
} else {
|
||||
SolidGroup {
|
||||
SolidGroup().apply {
|
||||
volume.fShape?.let { addShape(it) }
|
||||
volume.fNodes?.let {
|
||||
it.arr.forEach { obj ->
|
||||
@ -160,7 +161,7 @@ private fun SolidGroup.volume(volume: TGeoVolume, name: String? = null, cache: B
|
||||
name = combinedName,
|
||||
obj = group,
|
||||
prototypeHolder = rootPrototypes,
|
||||
templateName = volumesName + Name.parse(combinedName ?: "volume[${group.hashCode()}]")
|
||||
prototypeName = volumesName + Name.parse(combinedName ?: "volume[${group.hashCode()}]")
|
||||
)
|
||||
}
|
||||
|
||||
@ -180,8 +181,8 @@ private fun SolidGroup.volume(volume: TGeoVolume, name: String? = null, cache: B
|
||||
// }
|
||||
|
||||
|
||||
public fun TGeoManager.toSolid(): SolidGroup = SolidGroup {
|
||||
fNodes.arr.forEach {
|
||||
public fun MutableVisionContainer<Solid>.rootGeo(tGeoManager: TGeoManager): SolidGroup = solidGroup {
|
||||
tGeoManager.fNodes.arr.forEach {
|
||||
node(it)
|
||||
}
|
||||
}
|
11
demo/build.gradle.kts
Normal file
11
demo/build.gradle.kts
Normal file
@ -0,0 +1,11 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
|
||||
|
||||
subprojects {
|
||||
plugins.withType<KotlinPluginWrapper> {
|
||||
configure<KotlinProjectExtension> {
|
||||
explicitApi = ExplicitApiMode.Disabled
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +1,68 @@
|
||||
import ru.mipt.npm.gradle.DependencyConfiguration
|
||||
import ru.mipt.npm.gradle.FXModule
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
application
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
group = "demo"
|
||||
|
||||
kscience {
|
||||
val fxVersion: String by rootProject.extra
|
||||
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
|
||||
application()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
withJava()
|
||||
}
|
||||
|
||||
jvm()
|
||||
js {
|
||||
useCommonJs()
|
||||
browser {
|
||||
binaries.executable()
|
||||
commonWebpackConfig {
|
||||
cssSupport.enabled = false
|
||||
cssSupport {
|
||||
enabled.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation(project(":visionforge-solid"))
|
||||
implementation(project(":visionforge-gdml"))
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation(project(":visionforge-fx"))
|
||||
implementation("ch.qos.logback:logback-classic:1.2.5")
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation(project(":ui:ring"))
|
||||
implementation(project(":visionforge-threejs"))
|
||||
implementation(npm("react-file-drop", "3.0.6"))
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation(projects.visionforgeSolid)
|
||||
implementation(projects.visionforgeGdml)
|
||||
}
|
||||
jvmMain {
|
||||
// implementation(project(":visionforge-fx"))
|
||||
implementation(spclibs.logback.classic)
|
||||
}
|
||||
jsMain {
|
||||
implementation(projects.ui.ring)
|
||||
implementation(projects.visionforgeThreejs)
|
||||
implementation(npm("react-file-drop", "3.0.6"))
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("space.kscience.visionforge.gdml.demo.GdmlFxDemoAppKt")
|
||||
kotlin {
|
||||
explicitApi = null
|
||||
}
|
||||
|
||||
val convertGdmlToJson by tasks.creating(JavaExec::class) {
|
||||
group = "application"
|
||||
classpath = sourceSets["main"].runtimeClasspath
|
||||
mainClass.set("space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt")
|
||||
}
|
||||
//kotlin {
|
||||
//
|
||||
// sourceSets {
|
||||
// commonMain {
|
||||
// dependencies {
|
||||
// implementation(project(":visionforge-solid"))
|
||||
// implementation(project(":visionforge-gdml"))
|
||||
// }
|
||||
// }
|
||||
// jvmMain {
|
||||
// dependencies {
|
||||
//// implementation(project(":visionforge-fx"))
|
||||
// implementation("ch.qos.logback:logback-classic:1.2.11")
|
||||
// }
|
||||
// }
|
||||
// jsMain {
|
||||
// dependencies {
|
||||
// implementation(project(":ui:ring"))
|
||||
// implementation(project(":visionforge-threejs"))
|
||||
// implementation(npm("react-file-drop", "3.0.6"))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//val convertGdmlToJson by tasks.creating(JavaExec::class) {
|
||||
// group = "application"
|
||||
// classpath = sourceSets["main"].runtimeClasspath
|
||||
// mainClass.set("space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt")
|
||||
//}
|
@ -1,13 +1,11 @@
|
||||
package space.kscience.visionforge.gdml
|
||||
|
||||
import space.kscience.dataforge.meta.asValue
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.values.asValue
|
||||
import space.kscience.dataforge.values.string
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.computeProperties
|
||||
import space.kscience.visionforge.get
|
||||
import space.kscience.visionforge.setProperty
|
||||
import space.kscience.visionforge.getChild
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.SolidMaterial
|
||||
import space.kscience.visionforge.solid.material
|
||||
@ -20,8 +18,8 @@ class GDMLVisionTest {
|
||||
|
||||
@Test
|
||||
fun testCubesStyles(){
|
||||
val segment = cubes["composite-000.segment-0"] as Solid
|
||||
println(segment.computeProperties().getValue(Vision.STYLE_KEY))
|
||||
val segment = cubes.children.getChild("composite-000.segment-0") as Solid
|
||||
println(segment.properties.getValue(Vision.STYLE_KEY))
|
||||
// println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY))
|
||||
// println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY))
|
||||
|
||||
@ -35,7 +33,7 @@ class GDMLVisionTest {
|
||||
fun testPrototypeProperty() {
|
||||
val child = cubes[Name.of("composite-000","segment-0")]
|
||||
assertNotNull(child)
|
||||
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
||||
assertEquals("red", child.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.string)
|
||||
child.properties.setValue(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
||||
assertEquals("red", child.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||
}
|
||||
}
|
@ -10,13 +10,11 @@ import org.w3c.files.get
|
||||
import react.Props
|
||||
import react.dom.h2
|
||||
import react.fc
|
||||
import react.useMemo
|
||||
import react.useState
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.gdml.Gdml
|
||||
import space.kscience.gdml.decodeFromString
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.gdml.markLayers
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.ring.ThreeCanvasWithControls
|
||||
@ -24,18 +22,19 @@ import space.kscience.visionforge.ring.tab
|
||||
import space.kscience.visionforge.setAsRoot
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.set
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
external interface GDMLAppProps : Props {
|
||||
var context: Context
|
||||
var solids: Solids
|
||||
var vision: Solid?
|
||||
var selected: Name?
|
||||
}
|
||||
|
||||
@JsExport
|
||||
val GDMLApp = fc<GDMLAppProps>("GDMLApp") { props ->
|
||||
val visionManager = useMemo(props.context) { props.context.fetch(Solids).visionManager }
|
||||
var deferredVision: Deferred<Solid?> by useState {
|
||||
CompletableDeferred(props.vision)
|
||||
}
|
||||
@ -50,12 +49,15 @@ val GDMLApp = fc<GDMLAppProps>("GDMLApp") { props ->
|
||||
name.endsWith(".gdml") || name.endsWith(".xml") -> {
|
||||
val gdml = Gdml.decodeFromString(data)
|
||||
gdml.toVision().apply {
|
||||
setAsRoot(visionManager)
|
||||
setAsRoot(props.solids.visionManager)
|
||||
console.info("Marking layers for file $name")
|
||||
markLayers()
|
||||
ambientLight {
|
||||
color.set(Colors.white)
|
||||
}
|
||||
}
|
||||
}
|
||||
name.endsWith(".json") -> visionManager.decodeFromString(data)
|
||||
name.endsWith(".json") -> props.solids.visionManager.decodeFromString(data)
|
||||
else -> {
|
||||
window.alert("File extension is not recognized: $name")
|
||||
error("File extension is not recognized: $name")
|
||||
@ -76,7 +78,7 @@ val GDMLApp = fc<GDMLAppProps>("GDMLApp") { props ->
|
||||
}
|
||||
child(ThreeCanvasWithControls) {
|
||||
attrs {
|
||||
this.context = props.context
|
||||
this.solids = props.solids
|
||||
this.builderOfSolid = deferredVision
|
||||
this.selected = props.selected
|
||||
tab("Load") {
|
||||
|
@ -1,12 +1,18 @@
|
||||
package space.kscience.visionforge.gdml.demo
|
||||
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.css.*
|
||||
import react.dom.render
|
||||
import org.w3c.dom.Document
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.Application
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.react.createRoot
|
||||
import space.kscience.visionforge.react.render
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.set
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.startApplication
|
||||
import styled.injectGlobal
|
||||
@ -14,7 +20,7 @@ import styled.injectGlobal
|
||||
|
||||
private class GDMLDemoApp : Application {
|
||||
|
||||
override fun start(state: Map<String, Any>) {
|
||||
override fun start(document: Document, state: Map<String, Any>) {
|
||||
val context = Context("gdml-demo"){
|
||||
plugin(ThreePlugin)
|
||||
}
|
||||
@ -39,12 +45,16 @@ private class GDMLDemoApp : Application {
|
||||
|
||||
val element = document.getElementById("application") ?: error("Element with id 'application' not found on page")
|
||||
|
||||
render(element) {
|
||||
createRoot(element).render {
|
||||
child(GDMLApp) {
|
||||
val vision = GdmlShowCase.cubes().toVision()
|
||||
val vision = GdmlShowCase.cubes().toVision().apply {
|
||||
ambientLight {
|
||||
color.set(Colors.white)
|
||||
}
|
||||
}
|
||||
//println(context.plugins.fetch(VisionManager).encodeToString(vision))
|
||||
attrs {
|
||||
this.context = context
|
||||
this.solids = context.request(Solids)
|
||||
this.vision = vision
|
||||
}
|
||||
}
|
||||
|
@ -1,83 +1,83 @@
|
||||
package space.kscience.visionforge.gdml.demo
|
||||
|
||||
import javafx.geometry.Orientation
|
||||
import javafx.scene.Parent
|
||||
import javafx.stage.FileChooser
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.editor.VisionEditorFragment
|
||||
import space.kscience.visionforge.editor.VisionTreeFragment
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.solid.FX3DPlugin
|
||||
import space.kscience.visionforge.solid.FXCanvas3D
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.SolidMaterial
|
||||
import tornadofx.*
|
||||
|
||||
class GDMLDemoApp : App(GDMLView::class)
|
||||
|
||||
class GDMLView : View() {
|
||||
private val context = Context {
|
||||
plugin(FX3DPlugin)
|
||||
}
|
||||
|
||||
private val fx3d = context.fetch(FX3DPlugin)
|
||||
private val visionManager = context.fetch(VisionManager)
|
||||
private val canvas = FXCanvas3D(fx3d)
|
||||
|
||||
private val treeFragment = VisionTreeFragment().apply {
|
||||
this.itemProperty.bind(canvas.rootObjectProperty)
|
||||
}
|
||||
|
||||
private val propertyEditor = VisionEditorFragment().apply {
|
||||
descriptorProperty.set(SolidMaterial.descriptor)
|
||||
visionProperty.bind(treeFragment.selectedProperty)
|
||||
}
|
||||
|
||||
override val root: Parent = borderpane {
|
||||
top {
|
||||
buttonbar {
|
||||
button("Load GDML/json") {
|
||||
action {
|
||||
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
|
||||
if (file != null) {
|
||||
runAsync {
|
||||
visionManager.readFile(file) as Solid
|
||||
} ui {
|
||||
canvas.render(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
center {
|
||||
splitpane(Orientation.HORIZONTAL, treeFragment.root, canvas.root, propertyEditor.root) {
|
||||
setDividerPositions(0.2, 0.6, 0.2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
runAsync {
|
||||
GdmlShowCase.cubes().toVision()
|
||||
} ui {
|
||||
canvas.render(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val fileNameFilter = arrayOf(
|
||||
FileChooser.ExtensionFilter("GDML", "*.gdml", "*.xml"),
|
||||
FileChooser.ExtensionFilter("JSON", "*.json"),
|
||||
FileChooser.ExtensionFilter("JSON.ZIP", "*.json.zip"),
|
||||
FileChooser.ExtensionFilter("JSON.GZ", "*.json.gz")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
launch<GDMLDemoApp>()
|
||||
}
|
||||
//package space.kscience.visionforge.gdml.demo
|
||||
//
|
||||
//import javafx.geometry.Orientation
|
||||
//import javafx.scene.Parent
|
||||
//import javafx.stage.FileChooser
|
||||
//import space.kscience.dataforge.context.Context
|
||||
//import space.kscience.dataforge.context.fetch
|
||||
//import space.kscience.gdml.GdmlShowCase
|
||||
//import space.kscience.visionforge.VisionManager
|
||||
//import space.kscience.visionforge.editor.VisionEditorFragment
|
||||
//import space.kscience.visionforge.editor.VisionTreeFragment
|
||||
//import space.kscience.visionforge.gdml.toVision
|
||||
//import space.kscience.visionforge.solid.FX3DPlugin
|
||||
//import space.kscience.visionforge.solid.FXCanvas3D
|
||||
//import space.kscience.visionforge.solid.Solid
|
||||
//import space.kscience.visionforge.solid.SolidMaterial
|
||||
//import tornadofx.*
|
||||
//
|
||||
//class GDMLDemoApp : App(GDMLView::class)
|
||||
//
|
||||
//class GDMLView : View() {
|
||||
// private val context = Context {
|
||||
// plugin(FX3DPlugin)
|
||||
// }
|
||||
//
|
||||
// private val fx3d = context.fetch(FX3DPlugin)
|
||||
// private val visionManager = context.fetch(VisionManager)
|
||||
// private val canvas = FXCanvas3D(fx3d)
|
||||
//
|
||||
// private val treeFragment = VisionTreeFragment().apply {
|
||||
// this.itemProperty.bind(canvas.rootObjectProperty)
|
||||
// }
|
||||
//
|
||||
// private val propertyEditor = VisionEditorFragment().apply {
|
||||
// descriptorProperty.set(SolidMaterial.descriptor)
|
||||
// visionProperty.bind(treeFragment.selectedProperty)
|
||||
// }
|
||||
//
|
||||
// override val root: Parent = borderpane {
|
||||
// top {
|
||||
// buttonbar {
|
||||
// button("Load GDML/json") {
|
||||
// action {
|
||||
// val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
|
||||
// if (file != null) {
|
||||
// runAsync {
|
||||
// visionManager.readFile(file) as Solid
|
||||
// } ui {
|
||||
// canvas.render(it)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// center {
|
||||
// splitpane(Orientation.HORIZONTAL, treeFragment.root, canvas.root, propertyEditor.root) {
|
||||
// setDividerPositions(0.2, 0.6, 0.2)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// init {
|
||||
// runAsync {
|
||||
// GdmlShowCase.cubes().toVision()
|
||||
// } ui {
|
||||
// canvas.render(it)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// companion object {
|
||||
// private val fileNameFilter = arrayOf(
|
||||
// FileChooser.ExtensionFilter("GDML", "*.gdml", "*.xml"),
|
||||
// FileChooser.ExtensionFilter("JSON", "*.json"),
|
||||
// FileChooser.ExtensionFilter("JSON.ZIP", "*.json.zip"),
|
||||
// FileChooser.ExtensionFilter("JSON.GZ", "*.json.gz")
|
||||
// )
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//fun main() {
|
||||
// launch<GDMLDemoApp>()
|
||||
//}
|
@ -1,18 +1,20 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.js")
|
||||
id("space.kscience.gradle.js")
|
||||
}
|
||||
|
||||
kscience{
|
||||
useCoroutines()
|
||||
application()
|
||||
}
|
||||
|
||||
kotlin{
|
||||
js(IR){
|
||||
useCommonJs()
|
||||
browser {
|
||||
binaries.executable()
|
||||
commonWebpackConfig {
|
||||
cssSupport.enabled = false
|
||||
cssSupport{
|
||||
enabled.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.css.*
|
||||
import react.child
|
||||
import react.dom.render
|
||||
import org.w3c.dom.Document
|
||||
import ringui.SmartTabs
|
||||
import ringui.Tab
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.request
|
||||
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.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.react.createRoot
|
||||
import space.kscience.visionforge.react.render
|
||||
import space.kscience.visionforge.ring.ThreeCanvasWithControls
|
||||
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
|
||||
import space.kscience.visionforge.ring.solid
|
||||
@ -28,7 +30,7 @@ fun Trace.appendXYLatest(x: Number, y: Number, history: Int = 400, xErr: Number?
|
||||
|
||||
private class JsPlaygroundApp : Application {
|
||||
|
||||
override fun start(state: Map<String, Any>) {
|
||||
override fun start(document: Document, state: Map<String, Any>) {
|
||||
|
||||
val playgroundContext = Context {
|
||||
plugin(ThreeWithControlsPlugin)
|
||||
@ -38,7 +40,7 @@ private class JsPlaygroundApp : Application {
|
||||
|
||||
val element = document.getElementById("playground") ?: error("Element with id 'playground' not found on page")
|
||||
|
||||
render(element) {
|
||||
createRoot(element).render {
|
||||
styledDiv {
|
||||
css {
|
||||
padding(0.pt)
|
||||
@ -48,9 +50,9 @@ private class JsPlaygroundApp : Application {
|
||||
}
|
||||
SmartTabs("gravity") {
|
||||
Tab("gravity") {
|
||||
GravityDemo{
|
||||
GravityDemo {
|
||||
attrs {
|
||||
this.context = playgroundContext
|
||||
this.solids = playgroundContext.request(Solids)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,15 +73,18 @@ private class JsPlaygroundApp : Application {
|
||||
child(ThreeCanvasWithControls) {
|
||||
val random = Random(112233)
|
||||
attrs {
|
||||
context = playgroundContext
|
||||
solids = playgroundContext.request(Solids)
|
||||
solid {
|
||||
ambientLight {
|
||||
color.set(Colors.white)
|
||||
}
|
||||
repeat(100) {
|
||||
sphere(5, name = "sphere[$it]") {
|
||||
x = random.nextDouble(-300.0, 300.0)
|
||||
y = random.nextDouble(-300.0, 300.0)
|
||||
z = random.nextDouble(-300.0, 300.0)
|
||||
material {
|
||||
color(random.nextInt())
|
||||
color.set(random.nextInt())
|
||||
}
|
||||
detail = 16
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.css.*
|
||||
import react.Props
|
||||
import react.fc
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.markup.VisionOfMarkup
|
||||
import space.kscience.visionforge.react.flexRow
|
||||
import space.kscience.visionforge.ring.ThreeCanvasWithControls
|
||||
@ -17,14 +17,14 @@ import styled.styledDiv
|
||||
import kotlin.math.sqrt
|
||||
|
||||
external interface DemoProps : Props {
|
||||
var context: Context
|
||||
var solids: Solids
|
||||
}
|
||||
|
||||
val GravityDemo = fc<DemoProps> { props ->
|
||||
val velocityTrace = Trace{
|
||||
val velocityTrace = Trace {
|
||||
name = "velocity"
|
||||
}
|
||||
val energyTrace = Trace{
|
||||
val energyTrace = Trace {
|
||||
name = "energy"
|
||||
}
|
||||
val markup = VisionOfMarkup()
|
||||
@ -39,14 +39,19 @@ val GravityDemo = fc<DemoProps> { props ->
|
||||
}
|
||||
child(ThreeCanvasWithControls) {
|
||||
attrs {
|
||||
context = props.context
|
||||
solids = props.solids
|
||||
solid {
|
||||
pointLight(200, 200, 200, name = "light"){
|
||||
color.set(Colors.white)
|
||||
}
|
||||
ambientLight()
|
||||
|
||||
sphere(5.0, "ball") {
|
||||
detail = 16
|
||||
color("red")
|
||||
color.set("red")
|
||||
val h = 100.0
|
||||
y = h
|
||||
context.launch {
|
||||
solids.context.launch {
|
||||
val g = 10.0
|
||||
val dt = 0.1
|
||||
var time = 0.0
|
||||
@ -91,7 +96,7 @@ val GravityDemo = fc<DemoProps> { props ->
|
||||
height = 50.vh - 50.pt
|
||||
}
|
||||
plotly {
|
||||
traces(velocityTrace,energyTrace)
|
||||
traces(velocityTrace, energyTrace)
|
||||
layout {
|
||||
xaxis.title = "time"
|
||||
}
|
||||
|
@ -20,9 +20,9 @@ val Plotly = fc<PlotlyProps>("Plotly") { props ->
|
||||
useEffect(props.plot, elementRef) {
|
||||
val element = elementRef.current as? HTMLElement ?: error("Plotly element not found")
|
||||
props.plot?.let {
|
||||
element.plot(it, PlotlyConfig {
|
||||
element.plot(PlotlyConfig {
|
||||
responsive = true
|
||||
})
|
||||
}, it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,61 +1,42 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
id("space.kscience.gradle.mpp")
|
||||
application
|
||||
}
|
||||
|
||||
group = "ru.mipt.npm"
|
||||
|
||||
val ktorVersion: String = npmlibs.versions.ktor.get()
|
||||
val ktorVersion: String = spclibs.versions.ktor.get()
|
||||
|
||||
kscience {
|
||||
useCoroutines()
|
||||
useSerialization()
|
||||
application()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
withJava()
|
||||
}
|
||||
js {
|
||||
useCommonJs()
|
||||
browser {
|
||||
commonWebpackConfig {
|
||||
cssSupport.enabled = false
|
||||
useKtor()
|
||||
fullStack(
|
||||
"muon-monitor.js",
|
||||
jvmConfig = { withJava() },
|
||||
jsConfig = { useCommonJs() }
|
||||
) {
|
||||
commonWebpackConfig {
|
||||
cssSupport {
|
||||
enabled.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
val jsBrowserDistribution by tasks.getting
|
||||
|
||||
tasks.getByName<ProcessResources>("jvmProcessResources") {
|
||||
dependsOn(jsBrowserDistribution)
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
from(jsBrowserDistribution)
|
||||
}
|
||||
commonMain {
|
||||
implementation(projects.visionforgeSolid)
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation(project(":visionforge-solid"))
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation("org.apache.commons:commons-math3:3.6.1")
|
||||
implementation(npmlibs.ktor.server.cio)
|
||||
implementation(npmlibs.ktor.serialization)
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation(project(":ui:ring"))
|
||||
implementation(project(":visionforge-threejs"))
|
||||
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
implementation("org.apache.commons:commons-math3:3.6.1")
|
||||
implementation("io.ktor:ktor-server-cio:${ktorVersion}")
|
||||
implementation("io.ktor:ktor-server-content-negotiation:${ktorVersion}")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:${ktorVersion}")
|
||||
implementation("ch.qos.logback:logback-classic:1.2.11")
|
||||
}
|
||||
jsMain {
|
||||
implementation(projects.ui.ring)
|
||||
implementation(projects.visionforgeThreejs)
|
||||
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,6 +44,7 @@ application {
|
||||
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
||||
}
|
||||
|
||||
|
||||
//distributions {
|
||||
// main {
|
||||
// contents {
|
||||
|
@ -3,19 +3,19 @@ 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.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.removeAll
|
||||
import space.kscience.visionforge.setAsRoot
|
||||
import space.kscience.visionforge.setProperty
|
||||
import space.kscience.visionforge.solid.*
|
||||
import kotlin.collections.set
|
||||
import kotlin.math.PI
|
||||
|
||||
class Model(val manager: VisionManager) {
|
||||
private val map = HashMap<String, SolidGroup>()
|
||||
private val events = HashSet<Event>()
|
||||
|
||||
private fun SolidGroup.pixel(pixel: SC1) {
|
||||
val group = group(pixel.name) {
|
||||
private fun MutableVisionContainer<Solid>.pixel(pixel: SC1) {
|
||||
val group = solidGroup(pixel.name) {
|
||||
position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z)
|
||||
box(pixel.xSize, pixel.ySize, pixel.zSize)
|
||||
label(pixel.name) {
|
||||
@ -27,7 +27,7 @@ class Model(val manager: VisionManager) {
|
||||
}
|
||||
|
||||
private fun SolidGroup.detector(detector: SC16) {
|
||||
group(detector.name) {
|
||||
solidGroup(detector.name) {
|
||||
detector.pixels.forEach {
|
||||
pixel(it)
|
||||
}
|
||||
@ -39,40 +39,39 @@ class Model(val manager: VisionManager) {
|
||||
val root: SolidGroup = SolidGroup().apply {
|
||||
setAsRoot(this@Model.manager)
|
||||
material {
|
||||
wireframe
|
||||
color("darkgreen")
|
||||
color.set("darkgreen")
|
||||
}
|
||||
rotationX = PI / 2
|
||||
group("bottom") {
|
||||
solidGroup("bottom") {
|
||||
Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach {
|
||||
detector(it)
|
||||
}
|
||||
}
|
||||
|
||||
group("middle") {
|
||||
solidGroup("middle") {
|
||||
Monitor.detectors.filter { it.center.z == CENTRAL_LAYER_Z }.forEach {
|
||||
detector(it)
|
||||
}
|
||||
}
|
||||
|
||||
group("top") {
|
||||
solidGroup("top") {
|
||||
Monitor.detectors.filter { it.center.z == UPPER_LAYER_Z }.forEach {
|
||||
detector(it)
|
||||
}
|
||||
}
|
||||
tracks = group("tracks")
|
||||
tracks = solidGroup("tracks")
|
||||
}
|
||||
|
||||
private fun highlight(pixel: String) {
|
||||
println("highlight $pixel")
|
||||
map[pixel]?.color?.invoke("blue")
|
||||
map[pixel]?.color.set("blue")
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
map.values.forEach {
|
||||
it.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
|
||||
it.properties.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
|
||||
}
|
||||
tracks.removeAll()
|
||||
tracks.children.clear()
|
||||
}
|
||||
|
||||
fun displayEvent(event: Event) {
|
||||
@ -83,8 +82,7 @@ class Model(val manager: VisionManager) {
|
||||
}
|
||||
event.track?.let {
|
||||
tracks.polyline(*it.toTypedArray(), name = "track[${event.id}]") {
|
||||
thickness = 4
|
||||
color("red")
|
||||
color.set("red")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,12 @@ import space.kscience.visionforge.solid.plus
|
||||
class SC1(
|
||||
val name: String,
|
||||
val center: Point3D,
|
||||
val xSize: Float = PIXEL_XY_SIZE, val ySize: Float = PIXEL_XY_SIZE, val zSize: Float = PIXEL_Z_SIZE
|
||||
val xSize: Float = PIXEL_XY_SIZE, val ySize: Float = PIXEL_XY_SIZE, val zSize: Float = PIXEL_Z_SIZE,
|
||||
)
|
||||
|
||||
class SC16(
|
||||
val name: String,
|
||||
val center: Point3D
|
||||
val center: Point3D,
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -28,73 +28,86 @@ class SC16(
|
||||
val y: Double
|
||||
when (index) {
|
||||
7 -> {
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
4 -> {
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
6 -> {
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
5 -> {
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
3 -> {
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
0 -> {
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
2 -> {
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
1 -> {
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
11 -> {
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
8 -> {
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
10 -> {
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
9 -> {
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
15 -> {
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
12 -> {
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -1.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
14 -> {
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 1.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
|
||||
13 -> {
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING;
|
||||
x = 0.5 * Monitor.PIXEL_XY_SPACING
|
||||
y = -0.5 * Monitor.PIXEL_XY_SPACING
|
||||
}
|
||||
else -> throw Error();
|
||||
|
||||
else -> throw Error()
|
||||
}
|
||||
val offset = Point3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0));
|
||||
val pixelName = "${name}_${index}"
|
||||
@ -137,7 +150,7 @@ object Monitor {
|
||||
.mapNotNull { line ->
|
||||
if (line.startsWith(" ")) {
|
||||
val split = line.trim().split("\\s+".toRegex())
|
||||
val detectorName = split[1];
|
||||
val detectorName = split[1]
|
||||
val x = split[4].toDouble() - 500
|
||||
val y = split[5].toDouble() - 500
|
||||
val z = 180 - split[6].toDouble()
|
||||
|
@ -16,15 +16,18 @@ import react.dom.p
|
||||
import react.fc
|
||||
import react.useMemo
|
||||
import react.useState
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.meta.invoke
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.react.flexColumn
|
||||
import space.kscience.visionforge.react.flexRow
|
||||
import space.kscience.visionforge.ring.ThreeCanvasWithControls
|
||||
import space.kscience.visionforge.ring.tab
|
||||
import space.kscience.visionforge.solid.specifications.Camera
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.edges
|
||||
import space.kscience.visionforge.solid.set
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
import space.kscience.visionforge.solid.three.edges
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
import styled.styledSpan
|
||||
@ -32,7 +35,7 @@ import kotlin.math.PI
|
||||
|
||||
external interface MMAppProps : Props {
|
||||
var model: Model
|
||||
var context: Context
|
||||
var solids: Solids
|
||||
var selected: Name?
|
||||
}
|
||||
|
||||
@ -42,17 +45,21 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
|
||||
|
||||
val mmOptions = useMemo {
|
||||
Canvas3DOptions {
|
||||
camera = Camera {
|
||||
camera {
|
||||
distance = 2100.0
|
||||
latitude = PI / 6
|
||||
azimuth = PI + PI / 6
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
val root = useMemo(props.model) {
|
||||
props.model.root.apply {
|
||||
edges()
|
||||
ambientLight{
|
||||
color.set(Colors.white)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +71,7 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
|
||||
}
|
||||
child(ThreeCanvasWithControls) {
|
||||
attrs {
|
||||
this.context = props.context
|
||||
this.solids = props.solids
|
||||
this.builderOfSolid = CompletableDeferred(root)
|
||||
this.selected = props.selected
|
||||
this.options = mmOptions
|
||||
@ -75,7 +82,7 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
|
||||
+"Next"
|
||||
attrs {
|
||||
onClickFunction = {
|
||||
context.launch {
|
||||
solids.context.launch {
|
||||
val event = window.fetch(
|
||||
"http://localhost:8080/event",
|
||||
RequestInit("GET")
|
||||
|
@ -1,31 +1,34 @@
|
||||
package ru.mipt.npm.muon.monitor
|
||||
|
||||
import kotlinx.browser.document
|
||||
import react.dom.render
|
||||
import org.w3c.dom.Document
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.visionforge.Application
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.react.createRoot
|
||||
import space.kscience.visionforge.react.render
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.startApplication
|
||||
|
||||
private class MMDemoApp : Application {
|
||||
|
||||
override fun start(state: Map<String, Any>) {
|
||||
override fun start(document: Document, state: Map<String, Any>) {
|
||||
|
||||
val context = Context("MM-demo") {
|
||||
plugin(ThreePlugin)
|
||||
}
|
||||
val visionManager = context.fetch(VisionManager)
|
||||
|
||||
val visionManager = context.request(VisionManager)
|
||||
|
||||
val model = Model(visionManager)
|
||||
|
||||
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
|
||||
render(element) {
|
||||
createRoot(element).render {
|
||||
child(MMApp) {
|
||||
attrs {
|
||||
this.model = model
|
||||
this.context = context
|
||||
this.solids = context.request(Solids)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
|
||||
<title>Three js demo for particle physics</title>
|
||||
<script type="text/javascript" src="muon-monitor.js"></script>
|
||||
<link rel="stylesheet" href="css/custom-bootstrap.css">
|
||||
</head>
|
||||
<body class="application">
|
||||
<div class="container-fluid max-vh-100" id = "app"> </div>
|
||||
|
@ -1,31 +1,29 @@
|
||||
package ru.mipt.npm.muon.monitor.server
|
||||
|
||||
|
||||
import io.ktor.application.Application
|
||||
import io.ktor.application.call
|
||||
import io.ktor.application.install
|
||||
import io.ktor.application.log
|
||||
import io.ktor.features.CallLogging
|
||||
import io.ktor.features.ContentNegotiation
|
||||
import io.ktor.features.DefaultHeaders
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.content.resources
|
||||
import io.ktor.http.content.static
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.response.respondText
|
||||
import io.ktor.routing.Routing
|
||||
import io.ktor.routing.get
|
||||
import io.ktor.serialization.json
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import io.ktor.server.application.Application
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.application.install
|
||||
import io.ktor.server.application.log
|
||||
import io.ktor.server.cio.CIO
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.http.content.resources
|
||||
import io.ktor.server.http.content.static
|
||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.response.respondText
|
||||
import io.ktor.server.routing.Routing
|
||||
import io.ktor.server.routing.get
|
||||
import org.apache.commons.math3.random.JDKRandomGenerator
|
||||
import ru.mipt.npm.muon.monitor.Model
|
||||
import ru.mipt.npm.muon.monitor.sim.Cos2TrackGenerator
|
||||
import ru.mipt.npm.muon.monitor.sim.simulateOne
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import java.awt.Desktop
|
||||
@ -38,10 +36,8 @@ private val generator = Cos2TrackGenerator(JDKRandomGenerator(223))
|
||||
fun Application.module(context: Context = Global) {
|
||||
val currentDir = File(".").absoluteFile
|
||||
environment.log.info("Current directory: $currentDir")
|
||||
val solidManager = context.fetch(Solids)
|
||||
val solidManager = context.request(Solids)
|
||||
|
||||
install(DefaultHeaders)
|
||||
install(CallLogging)
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ plugins {
|
||||
kotlin("multiplatform")
|
||||
kotlin("jupyter.api")
|
||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||
// application
|
||||
}
|
||||
|
||||
repositories {
|
||||
@ -16,23 +17,25 @@ kotlin {
|
||||
useCommonJs()
|
||||
browser {
|
||||
webpackTask {
|
||||
this.outputFileName = "js/visionforge-playground.js"
|
||||
outputFileName = "js/visionforge-playground.js"
|
||||
}
|
||||
commonWebpackConfig {
|
||||
sourceMaps = true
|
||||
cssSupport.enabled = false
|
||||
cssSupport{
|
||||
enabled.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
binaries.executable()
|
||||
}
|
||||
|
||||
jvm {
|
||||
withJava()
|
||||
// withJava()
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
freeCompilerArgs =
|
||||
freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy"
|
||||
freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" + "-Xcontext-receivers"
|
||||
}
|
||||
}
|
||||
testRuns["test"].executionTask.configure {
|
||||
@ -64,7 +67,7 @@ kotlin {
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
implementation(projects.visionforgeServer)
|
||||
implementation("ch.qos.logback:logback-classic:1.2.3")
|
||||
implementation(spclibs.logback.classic)
|
||||
implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
||||
}
|
||||
}
|
||||
@ -87,4 +90,8 @@ val processJupyterApiResources by tasks.getting(org.jetbrains.kotlinx.jupyter.ap
|
||||
libraryProducers = listOf("space.kscience.visionforge.examples.VisionForgePlayGroundForJupyter")
|
||||
}
|
||||
|
||||
tasks.findByName("shadowJar")?.dependsOn(processJupyterApiResources)
|
||||
tasks.findByName("shadowJar")?.dependsOn(processJupyterApiResources)
|
||||
|
||||
//application{
|
||||
// mainClass.set("space.kscience.visionforge.examples.ShapesKt")
|
||||
//}
|
130
demo/playground/notebooks/dynamic-demo.ipynb
Normal file
130
demo/playground/notebooks/dynamic-demo.ipynb
Normal file
@ -0,0 +1,130 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"tags": [],
|
||||
"pycharm": {
|
||||
"is_executing": true
|
||||
},
|
||||
"ExecuteTime": {
|
||||
"end_time": "2023-05-29T15:22:37.933397300Z",
|
||||
"start_time": "2023-05-29T15:22:37.913872100Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2023-05-29T15:22:50.486483300Z",
|
||||
"start_time": "2023-05-29T15:22:50.457485500Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Line_2.jupyter.kts (1:1 - 3) Unresolved reference: vf"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"vf.startServer()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"jupyter": {
|
||||
"outputs_hidden": false
|
||||
},
|
||||
"ExecuteTime": {
|
||||
"end_time": "2023-05-29T15:22:51.410680600Z",
|
||||
"start_time": "2023-05-29T15:22:51.250779400Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Line_3.jupyter.kts (1:16 - 26) Unresolved reference: coroutines\n",
|
||||
"Line_3.jupyter.kts (4:1 - 7) Unresolved reference: Plotly\n",
|
||||
"Line_3.jupyter.kts (5:5 - 12) Unresolved reference: scatter\n",
|
||||
"Line_3.jupyter.kts (6:9 - 10) Unresolved reference: x\n",
|
||||
"Line_3.jupyter.kts (7:9 - 10) Unresolved reference: y\n",
|
||||
"Line_3.jupyter.kts (8:12 - 14) Unresolved reference: vf\n",
|
||||
"Line_3.jupyter.kts (9:13 - 15) Unresolved reference: vf\n",
|
||||
"Line_3.jupyter.kts (10:23 - 31) Unresolved reference: isActive\n",
|
||||
"Line_3.jupyter.kts (11:21 - 26) Unresolved reference: delay\n",
|
||||
"Line_3.jupyter.kts (12:21 - 22) Unresolved reference: y"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import kotlinx.coroutines.*\n",
|
||||
"import kotlin.random.Random\n",
|
||||
"\n",
|
||||
"Plotly.plot{\n",
|
||||
" scatter{\n",
|
||||
" x(1,2,3)\n",
|
||||
" y(1,2,3)\n",
|
||||
" if(vf.isServerRunning()){\n",
|
||||
" vf.launch{\n",
|
||||
" while(isActive){\n",
|
||||
" delay(500)\n",
|
||||
" y(Random.nextDouble(), Random.nextDouble(), Random.nextDouble())\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"vf.stopServer()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Kotlin",
|
||||
"language": "kotlin",
|
||||
"name": "kotlin"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "text/x-kotlin",
|
||||
"file_extension": ".kt",
|
||||
"mimetype": "text/x-kotlin",
|
||||
"name": "kotlin",
|
||||
"nbconvert_exporter": "",
|
||||
"pygments_lexer": "kotlin",
|
||||
"version": "1.8.0-dev-3517"
|
||||
},
|
||||
"ktnbPluginMetadata": {
|
||||
"isAddProjectLibrariesToClasspath": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.jupyter.VFNotebookPlugin
|
||||
import space.kscience.visionforge.markup.MarkupPlugin
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
|
||||
@ -11,4 +12,5 @@ fun main() = runVisionClient {
|
||||
plugin(PlotlyPlugin)
|
||||
plugin(MarkupPlugin)
|
||||
plugin(TableVisionJsPlugin)
|
||||
plugin(VFNotebookPlugin)
|
||||
}
|
@ -6,17 +6,18 @@ import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.gdml.Gdml
|
||||
import space.kscience.plotly.Plot
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.jupyter.JupyterPluginBase
|
||||
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 : JupyterPluginBase(
|
||||
internal class VisionForgePlayGroundForJupyter : VFIntegrationBase(
|
||||
Context("VisionForge") {
|
||||
plugin(Solids)
|
||||
plugin(PlotlyPlugin)
|
||||
}
|
||||
}.visionManager
|
||||
) {
|
||||
|
||||
override fun Builder.afterLoaded() {
|
||||
|
@ -1,7 +1,8 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import kotlinx.html.h2
|
||||
import space.kscience.dataforge.values.ValueType
|
||||
import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.dataforge.meta.invoke
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.models.ScatterMode
|
||||
import space.kscience.plotly.models.TextPosition
|
||||
@ -12,13 +13,14 @@ import space.kscience.visionforge.markup.markdown
|
||||
import space.kscience.visionforge.plotly.plotly
|
||||
import space.kscience.visionforge.solid.box
|
||||
import space.kscience.visionforge.solid.solid
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
import space.kscience.visionforge.solid.z
|
||||
import space.kscience.visionforge.tables.columnTable
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.Path
|
||||
|
||||
|
||||
fun main() = makeVisionFile(
|
||||
Paths.get("VisionForgeDemo.html"),
|
||||
Path("VisionForgeDemo.html"),
|
||||
resourceLocation = ResourceLocation.EMBED
|
||||
) {
|
||||
markdown {
|
||||
@ -32,8 +34,15 @@ fun main() = makeVisionFile(
|
||||
|
||||
h2 { +"3D visualization with Three-js" }
|
||||
vision("3D") {
|
||||
solid {
|
||||
box(100, 100, 100, name = "aBox"){
|
||||
solid(
|
||||
Canvas3DOptions {
|
||||
axes {
|
||||
size = 200.0
|
||||
visible = true
|
||||
}
|
||||
}
|
||||
) {
|
||||
box(100, 100, 100, name = "aBox") {
|
||||
z = 50.0
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,42 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import io.ktor.server.cio.CIO
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.http.content.staticResources
|
||||
import io.ktor.server.routing.routing
|
||||
import kotlinx.html.*
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.Page
|
||||
import space.kscience.visionforge.html.formFragment
|
||||
import space.kscience.visionforge.html.VisionOfHtmlForm
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.bindForm
|
||||
import space.kscience.visionforge.onPropertyChange
|
||||
import space.kscience.visionforge.server.close
|
||||
import space.kscience.visionforge.server.openInBrowser
|
||||
import space.kscience.visionforge.server.serve
|
||||
import space.kscience.visionforge.server.visionPage
|
||||
|
||||
@Suppress("ExtractKtorModule")
|
||||
fun main() {
|
||||
val visionManager = Global.fetch(VisionManager)
|
||||
val visionManager = Global.request(VisionManager)
|
||||
|
||||
val server = visionManager.serve {
|
||||
page(header = Page.scriptHeader("js/visionforge-playground.js")) {
|
||||
val form = formFragment("form") {
|
||||
val server = embeddedServer(CIO) {
|
||||
|
||||
routing {
|
||||
staticResources("/", null)
|
||||
}
|
||||
|
||||
val form = VisionOfHtmlForm("form").apply {
|
||||
onPropertyChange(visionManager.context) {
|
||||
println(values)
|
||||
}
|
||||
}
|
||||
|
||||
visionPage(
|
||||
visionManager,
|
||||
VisionPage.scriptHeader("js/visionforge-playground.js"),
|
||||
) {
|
||||
bindForm(form) {
|
||||
label {
|
||||
htmlFor = "fname"
|
||||
+"First name:"
|
||||
@ -47,13 +67,11 @@ fun main() {
|
||||
value = "Submit"
|
||||
}
|
||||
}
|
||||
|
||||
vision("form") { form }
|
||||
form.onPropertyChange {
|
||||
println(this)
|
||||
}
|
||||
println(form.values)
|
||||
vision(form)
|
||||
}
|
||||
}
|
||||
|
||||
}.start(false)
|
||||
|
||||
server.openInBrowser()
|
||||
|
||||
|
@ -5,7 +5,7 @@ import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
|
||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM){
|
||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
vision("canvas") {
|
||||
requirePlugin(Solids)
|
||||
GdmlShowCase.cubes().toVision()
|
||||
|
@ -7,7 +7,7 @@ import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.color
|
||||
import space.kscience.visionforge.solid.invoke
|
||||
import space.kscience.visionforge.solid.set
|
||||
import space.kscience.visionforge.visible
|
||||
import java.nio.file.Path
|
||||
|
||||
@ -223,13 +223,13 @@ fun main() = makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceL
|
||||
}
|
||||
}
|
||||
}.toVision {
|
||||
configure { _, solid, _ ->
|
||||
solids { _, solid, _ ->
|
||||
//disable visibility for the world box
|
||||
if(solid.name == "world"){
|
||||
visible = false
|
||||
}
|
||||
if(solid.name.startsWith("gas")){
|
||||
color("green")
|
||||
color.set("green")
|
||||
} else {
|
||||
//make all solids semi-transparent
|
||||
transparent()
|
||||
|
@ -1,12 +1,15 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.gdml.gdml
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.solid
|
||||
|
||||
fun main() = makeVisionFile {
|
||||
vision("canvas") {
|
||||
requirePlugin(Solids)
|
||||
GdmlShowCase.babyIaxo().toVision()
|
||||
solid {
|
||||
gdml(GdmlShowCase.babyIaxo(), "D0")
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import kotlinx.serialization.json.Json
|
||||
import space.kscience.visionforge.solid.SolidGroup
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
private val json = Json {
|
||||
serializersModule = Solids.serializersModuleForSolids
|
||||
prettyPrintIndent = " "
|
||||
|
@ -1,15 +1,92 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.plotly.scatter
|
||||
import space.kscience.dataforge.meta.Value
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.models.*
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.plotly.plotly
|
||||
|
||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
vision {
|
||||
val trace1 = Violin {
|
||||
text("sample length: 32")
|
||||
marker {
|
||||
line {
|
||||
width = 2
|
||||
color("#bebada")
|
||||
}
|
||||
symbol = Symbol.valueOf("line-ns")
|
||||
}
|
||||
orientation = Orientation.h
|
||||
hoveron = ViolinHoveron.`points+kde`
|
||||
meanline {
|
||||
visible = true
|
||||
}
|
||||
legendgroup = "F"
|
||||
scalegroup = "F"
|
||||
points = ViolinPoints.all
|
||||
pointpos = 1.2
|
||||
jitter = 0
|
||||
box {
|
||||
visible = true
|
||||
}
|
||||
scalemode = ViolinScaleMode.count
|
||||
showlegend = false
|
||||
side = ViolinSide.positive
|
||||
y0 = Value.of(0)
|
||||
line {
|
||||
color("#bebada")
|
||||
}
|
||||
name = "F"
|
||||
|
||||
x(10.07, 34.83, 10.65, 12.43, 24.08, 13.42, 12.48, 29.8, 14.52, 11.38,
|
||||
20.27, 11.17, 12.26, 18.26, 8.51, 10.33, 14.15, 13.16, 17.47, 27.05, 16.43,
|
||||
8.35, 18.64, 11.87, 19.81, 43.11, 13.0, 12.74, 13.0, 16.4, 16.47, 18.78)
|
||||
}
|
||||
|
||||
val trace2 = Violin {
|
||||
text("sample length: 32")
|
||||
marker {
|
||||
line {
|
||||
width = 2
|
||||
color("#8dd3c7")
|
||||
}
|
||||
symbol = Symbol.valueOf("line-ns")
|
||||
}
|
||||
orientation = Orientation.h
|
||||
hoveron = ViolinHoveron.`points+kde`
|
||||
meanline {
|
||||
visible = true
|
||||
}
|
||||
legendgroup = "M"
|
||||
scalegroup = "M"
|
||||
points = ViolinPoints.all
|
||||
pointpos = -1.2
|
||||
jitter = 0
|
||||
box {
|
||||
visible = true
|
||||
}
|
||||
scalemode = ViolinScaleMode.count
|
||||
showlegend = false
|
||||
side = ViolinSide.negative
|
||||
y0 = Value.of(0)
|
||||
|
||||
line {
|
||||
color("#8dd3c7")
|
||||
}
|
||||
name = "M"
|
||||
|
||||
x(27.2, 22.76, 17.29, 19.44, 16.66, 32.68, 15.98, 13.03, 18.28, 24.71,
|
||||
21.16, 11.69, 14.26, 15.95, 8.52, 22.82, 19.08, 16.0, 34.3, 41.19, 9.78,
|
||||
7.51, 28.44, 15.48, 16.58, 7.56, 10.34, 13.51, 18.71, 20.53)
|
||||
}
|
||||
|
||||
plotly {
|
||||
scatter {
|
||||
x(1, 2, 3)
|
||||
y(5, 8, 7)
|
||||
traces(trace1, trace2)
|
||||
layout {
|
||||
width = 800
|
||||
height = 800
|
||||
title = "Advanced Violin Plot"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package space.kscience.visionforge.examples
|
||||
|
||||
import kotlinx.html.div
|
||||
import kotlinx.html.h1
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.solid.*
|
||||
import java.nio.file.Paths
|
||||
@ -17,13 +18,16 @@ fun main() = makeVisionFile(
|
||||
div {
|
||||
vision {
|
||||
solid {
|
||||
ambientLight {
|
||||
color.set(Colors.white)
|
||||
}
|
||||
repeat(100) {
|
||||
sphere(5, name = "sphere[$it]") {
|
||||
x = random.nextDouble(-300.0, 300.0)
|
||||
y = random.nextDouble(-300.0, 300.0)
|
||||
z = random.nextDouble(-300.0, 300.0)
|
||||
material {
|
||||
color(random.nextInt())
|
||||
color.set(random.nextInt())
|
||||
}
|
||||
detail = 16
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import ru.mipt.npm.root.DGeoManager
|
||||
import ru.mipt.npm.root.rootGeo
|
||||
import ru.mipt.npm.root.serialization.TGeoManager
|
||||
import ru.mipt.npm.root.toSolid
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.isLeaf
|
||||
import space.kscience.dataforge.values.string
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import java.nio.file.Paths
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.set
|
||||
import space.kscience.visionforge.solid.solid
|
||||
import java.util.zip.ZipInputStream
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.writeText
|
||||
|
||||
|
||||
@ -34,73 +39,17 @@ fun main() {
|
||||
println(it)
|
||||
}
|
||||
|
||||
val solid = geo.toSolid()
|
||||
|
||||
Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid))
|
||||
//println(Solids.encodeToString(solid))
|
||||
|
||||
makeVisionFile {
|
||||
makeVisionFile(path = Path("data/output.html"), resourceLocation = ResourceLocation.EMBED) {
|
||||
vision("canvas") {
|
||||
requirePlugin(Solids)
|
||||
solid
|
||||
solid {
|
||||
ambientLight {
|
||||
color.set(Colors.white)
|
||||
}
|
||||
rootGeo(geo,"BM@N", maxLayer = 3, ignoreRootColors = true).also {
|
||||
Path("data/BM@N.vf.json").writeText(Solids.encodeToString(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* SolidGroup {
|
||||
set(
|
||||
"Coil",
|
||||
solid.getPrototype("Coil".asName())!!.apply {
|
||||
parent = null
|
||||
}
|
||||
)
|
||||
*//* group("Shade") {
|
||||
y = 200
|
||||
color("red")
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(79.6, 0, -122.1)
|
||||
rotation = Point3D(-1.5707964, 0, 0)
|
||||
}
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(-79.6, 0, -122.1)
|
||||
rotation = Point3D(1.5707964, 0, -3.1415927)
|
||||
}
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(79.6, 0, 122.1)
|
||||
rotation = Point3D(1.5707964, 0, 0)
|
||||
}
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(-79.6, 0, 122.1)
|
||||
rotation = Point3D(-1.5707964, 0, -3.1415927)
|
||||
}
|
||||
}*//*
|
||||
}*/
|
||||
}
|
@ -1,11 +1,8 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.visionforge.html.HtmlVisionFragment
|
||||
import space.kscience.visionforge.html.Page
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
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
|
||||
|
||||
@ -16,10 +13,14 @@ public fun makeVisionFile(
|
||||
show: Boolean = true,
|
||||
content: HtmlVisionFragment,
|
||||
): Unit {
|
||||
val actualPath = Page(Global, content = content).makeFile(path) { actualPath ->
|
||||
val actualPath = VisionPage(Global.visionManager, content = content).makeFile(path) { actualPath ->
|
||||
mapOf(
|
||||
"title" to Page.title(title),
|
||||
"playground" to Page.importScriptHeader("js/visionforge-playground.js", resourceLocation, actualPath),
|
||||
"title" to VisionPage.title(title),
|
||||
"playground" to VisionPage.importScriptHeader(
|
||||
"js/visionforge-playground.js",
|
||||
resourceLocation,
|
||||
actualPath
|
||||
),
|
||||
)
|
||||
}
|
||||
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
|
||||
|
40
demo/playground/src/jvmMain/kotlin/shapes.kt
Normal file
40
demo/playground/src/jvmMain/kotlin/shapes.kt
Normal file
@ -0,0 +1,40 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.solid.*
|
||||
import kotlin.math.PI
|
||||
|
||||
fun main() = makeVisionFile {
|
||||
vision("canvas") {
|
||||
solid {
|
||||
ambientLight()
|
||||
box(100.0, 100.0, 100.0) {
|
||||
z = -110.0
|
||||
color.set("teal")
|
||||
}
|
||||
sphere(50.0) {
|
||||
x = 110
|
||||
detail = 16
|
||||
color.set("red")
|
||||
}
|
||||
tube(50, height = 10, innerRadius = 25, angle = PI) {
|
||||
y = 110
|
||||
detail = 16
|
||||
rotationX = PI / 4
|
||||
color.set("blue")
|
||||
}
|
||||
sphereLayer(50, 40, theta = PI / 2) {
|
||||
rotationX = -PI * 3 / 4
|
||||
z = 110
|
||||
color.set(Colors.pink)
|
||||
}
|
||||
|
||||
|
||||
cylinder(30,20, name = "cylinder"){
|
||||
detail = 31
|
||||
y = -220
|
||||
z = 15
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@ package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.solid.box
|
||||
import space.kscience.visionforge.solid.invoke
|
||||
import space.kscience.visionforge.solid.material
|
||||
import space.kscience.visionforge.solid.set
|
||||
import space.kscience.visionforge.solid.solid
|
||||
|
||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
@ -11,7 +11,7 @@ fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
solid {
|
||||
box(100, 100, 100)
|
||||
material {
|
||||
emissiveColor("red")
|
||||
emissiveColor.set("red")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.dataforge.values.ValueType
|
||||
import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.tables.ColumnHeader
|
||||
import space.kscience.tables.valueRow
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
|
@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.jvm")
|
||||
id("space.kscience.gradle.jvm")
|
||||
application
|
||||
}
|
||||
|
||||
@ -8,16 +8,14 @@ kscience {
|
||||
// useSerialization {
|
||||
// json()
|
||||
// }
|
||||
application()
|
||||
dependencies{
|
||||
implementation(projects.visionforgeThreejs.visionforgeThreejsServer)
|
||||
implementation("ch.qos.logback:logback-classic:1.4.5")
|
||||
}
|
||||
}
|
||||
|
||||
group = "ru.mipt.npm"
|
||||
|
||||
dependencies{
|
||||
implementation(project(":visionforge-threejs:visionforge-threejs-server"))
|
||||
implementation("ch.qos.logback:logback-classic:1.2.3")
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("ru.mipt.npm.sat.SatServerKt")
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import space.kscience.visionforge.style
|
||||
import space.kscience.visionforge.useStyle
|
||||
import kotlin.math.PI
|
||||
|
||||
internal fun visionOfSatellite(
|
||||
internal fun Solids.visionOfSatellite(
|
||||
layers: Int = 10,
|
||||
layerHeight: Number = 10,
|
||||
xSegments: Int = 3,
|
||||
@ -14,8 +14,8 @@ internal fun visionOfSatellite(
|
||||
xSegmentSize: Number = 30,
|
||||
ySegmentSize: Number = xSegmentSize,
|
||||
fiberDiameter: Number = 1.0,
|
||||
): SolidGroup = SolidGroup {
|
||||
color("darkgreen")
|
||||
): SolidGroup = solidGroup {
|
||||
color.set("darkgreen")
|
||||
val transparent by style {
|
||||
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
|
||||
}
|
||||
@ -31,7 +31,7 @@ internal fun visionOfSatellite(
|
||||
val totalXSize = xSegments * xSegmentSize.toDouble()
|
||||
val totalYSize = ySegments * ySegmentSize.toDouble()
|
||||
for (layer in 1..layers) {
|
||||
group("layer[$layer]") {
|
||||
solidGroup("layer[$layer]") {
|
||||
for (i in 1..xSegments) {
|
||||
for (j in 1..ySegments) {
|
||||
box(xSegmentSize, ySegmentSize, layerHeight, name = "segment[$i,$j]") {
|
||||
@ -42,7 +42,7 @@ internal fun visionOfSatellite(
|
||||
}
|
||||
}
|
||||
}
|
||||
group("fibers") {
|
||||
solidGroup("fibers") {
|
||||
for (i in 1..xSegments) {
|
||||
cylinder(fiberDiameter, totalYSize) {
|
||||
useStyle(red)
|
||||
|
@ -1,38 +1,57 @@
|
||||
package ru.mipt.npm.sat
|
||||
|
||||
|
||||
import io.ktor.server.cio.CIO
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.http.content.staticResources
|
||||
import io.ktor.server.routing.routing
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.html.div
|
||||
import kotlinx.html.h1
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.meta.Null
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.html.Page
|
||||
import space.kscience.visionforge.html.plus
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.server.close
|
||||
import space.kscience.visionforge.server.openInBrowser
|
||||
import space.kscience.visionforge.server.serve
|
||||
import space.kscience.visionforge.server.visionPage
|
||||
import space.kscience.visionforge.solid.*
|
||||
import space.kscience.visionforge.three.threeJsHeader
|
||||
import space.kscience.visionforge.visionManager
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
@Suppress("ExtractKtorModule")
|
||||
fun main() {
|
||||
val satContext = Context("sat") {
|
||||
plugin(Solids)
|
||||
}
|
||||
|
||||
//Create a geometry
|
||||
val sat = visionOfSatellite(ySegments = 3)
|
||||
val solids = satContext.request(Solids)
|
||||
|
||||
val server = satContext.visionManager.serve {
|
||||
page(header = Page.threeJsHeader + Page.styleSheetHeader("css/styles.css")) {
|
||||
//Create a geometry
|
||||
val sat = solids.visionOfSatellite(ySegments = 3).apply {
|
||||
ambientLight {
|
||||
color.set(Colors.white)
|
||||
}
|
||||
}
|
||||
val server = embeddedServer(CIO, port = 7777) {
|
||||
routing {
|
||||
staticResources("", null, null)
|
||||
}
|
||||
|
||||
visionPage(
|
||||
solids.visionManager, VisionPage.threeJsHeader,
|
||||
VisionPage.styleSheetHeader("css/styles.css")
|
||||
) {
|
||||
div("flex-column") {
|
||||
h1 { +"Satellite detector demo" }
|
||||
vision { sat }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}.start(false)
|
||||
|
||||
server.openInBrowser()
|
||||
|
||||
@ -44,9 +63,10 @@ fun main() {
|
||||
val randomJ = Random.nextInt(1, 4)
|
||||
val target = Name.parse("layer[$randomLayer].segment[$randomI,$randomJ]")
|
||||
val targetVision = sat[target] as Solid
|
||||
targetVision.color("red")
|
||||
targetVision.color.set("red")
|
||||
delay(1000)
|
||||
targetVision.color.clear()
|
||||
//use to ensure that color is cleared
|
||||
targetVision.color.value = Null
|
||||
delay(500)
|
||||
}
|
||||
}
|
||||
|
21
demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/static.kt
Normal file
21
demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/static.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package ru.mipt.npm.sat
|
||||
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.solid.box
|
||||
import space.kscience.visionforge.solid.material
|
||||
import space.kscience.visionforge.solid.set
|
||||
import space.kscience.visionforge.solid.solid
|
||||
import space.kscience.visionforge.three.makeThreeJsFile
|
||||
|
||||
@OptIn(DFExperimental::class)
|
||||
fun main() = makeThreeJsFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||
vision ("canvas") {
|
||||
solid {
|
||||
box(100, 100, 100)
|
||||
material {
|
||||
emissiveColor.set("red")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +1,24 @@
|
||||
import ru.mipt.npm.gradle.DependencyConfiguration
|
||||
import ru.mipt.npm.gradle.FXModule
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
id("space.kscience.gradle.mpp")
|
||||
application
|
||||
}
|
||||
|
||||
kscience {
|
||||
useCoroutines()
|
||||
val fxVersion: String by rootProject.extra
|
||||
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
|
||||
application()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
||||
jvm {
|
||||
withJava()
|
||||
}
|
||||
js()
|
||||
dependencies {
|
||||
implementation(projects.visionforgeSolid)
|
||||
implementation(projects.visionforgeGdml)
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation(project(":visionforge-solid"))
|
||||
// implementation(project(":visionforge-gdml"))
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation(project(":visionforge-fx"))
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation(project(":visionforge-threejs"))
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
implementation(projects.visionforgeThreejs)
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
mainClassName = "space.kscience.visionforge.solid.demo.FXDemoAppKt"
|
||||
mainClass.set("space.kscience.visionforge.solid.demo.FXDemoAppKt")
|
||||
}
|
@ -3,7 +3,10 @@ package space.kscience.visionforge.solid.demo
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
|
||||
public interface VisionLayout<in V: Vision> {
|
||||
public fun render(name: Name, vision: V, meta: Meta = Meta.EMPTY)
|
||||
interface VisionLayout<in V: Vision> {
|
||||
val solids: Solids
|
||||
|
||||
fun render(name: Name, vision: V, meta: Meta = Meta.EMPTY)
|
||||
}
|
@ -18,7 +18,12 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
|
||||
val meta = Meta {
|
||||
"title" put title
|
||||
}
|
||||
val vision = SolidGroup(block)
|
||||
val vision = solids.solidGroup {
|
||||
block()
|
||||
ambientLight {
|
||||
color.set(Colors.white)
|
||||
}
|
||||
}
|
||||
render(Name.parse(name), vision, meta)
|
||||
}
|
||||
|
||||
@ -39,30 +44,31 @@ val canvasOptions = Canvas3DOptions {
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun VisionLayout<Solid>.showcase() {
|
||||
demo("shapes", "Basic shapes") {
|
||||
ambientLight()
|
||||
box(100.0, 100.0, 100.0) {
|
||||
z = -110.0
|
||||
color("teal")
|
||||
color.set("teal")
|
||||
}
|
||||
sphere(50.0) {
|
||||
x = 110
|
||||
detail = 16
|
||||
color("red")
|
||||
color.set("red")
|
||||
}
|
||||
tube(50, height = 10, innerRadius = 25, angle = PI) {
|
||||
y = 110
|
||||
detail = 16
|
||||
rotationX = PI / 4
|
||||
color("blue")
|
||||
color.set("blue")
|
||||
}
|
||||
sphereLayer(50, 40, theta = PI / 2) {
|
||||
rotationX = -PI * 3 / 4
|
||||
z = 110
|
||||
color(Colors.pink)
|
||||
color.set(Colors.pink)
|
||||
}
|
||||
}
|
||||
|
||||
demo("dynamic", "Dynamic properties") {
|
||||
val group = group {
|
||||
val group = solidGroup {
|
||||
box(100, 100, 100) {
|
||||
z = 110.0
|
||||
opacity = 0.5
|
||||
@ -72,7 +78,7 @@ fun VisionLayout<Solid>.showcase() {
|
||||
visible = false
|
||||
x = 110.0
|
||||
//override color for this cube
|
||||
color(1530)
|
||||
color.set(1530)
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
while (isActive) {
|
||||
@ -87,19 +93,19 @@ fun VisionLayout<Solid>.showcase() {
|
||||
val random = Random(111)
|
||||
while (isActive) {
|
||||
delay(1000)
|
||||
group.color(random.nextInt(0, Int.MAX_VALUE))
|
||||
group.color.set(random.nextInt(0, Int.MAX_VALUE))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
demo("rotation", "Rotations") {
|
||||
box(100, 100, 100)
|
||||
group {
|
||||
solidGroup {
|
||||
x = 200
|
||||
rotationY = PI / 4
|
||||
box(100, 100, 100) {
|
||||
rotationZ = PI / 4
|
||||
color(Colors.red)
|
||||
color.set(Colors.red)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,7 +118,7 @@ fun VisionLayout<Solid>.showcase() {
|
||||
for (i in 0..100) {
|
||||
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
|
||||
}
|
||||
color(Colors.teal)
|
||||
color.set(Colors.teal)
|
||||
rotationX = -PI / 2
|
||||
}
|
||||
}
|
||||
@ -121,13 +127,13 @@ fun VisionLayout<Solid>.showcase() {
|
||||
sphere(100) {
|
||||
detail = 32
|
||||
opacity = 0.4
|
||||
color(Colors.blue)
|
||||
color.set(Colors.blue)
|
||||
}
|
||||
repeat(20) {
|
||||
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
|
||||
thickness = 3.0
|
||||
rotationX = it * PI2 / 20
|
||||
color(Colors.green)
|
||||
color.set(Colors.green)
|
||||
//rotationY = it * PI2 / 20
|
||||
}
|
||||
}
|
||||
@ -154,7 +160,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
||||
detail = 32
|
||||
}
|
||||
material {
|
||||
color(Colors.pink)
|
||||
color.set(Colors.pink)
|
||||
}
|
||||
}
|
||||
composite(CompositeType.UNION) {
|
||||
@ -164,7 +170,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
||||
sphere(50) {
|
||||
detail = 32
|
||||
}
|
||||
color("lightgreen")
|
||||
color.set("lightgreen")
|
||||
opacity = 0.7
|
||||
}
|
||||
composite(CompositeType.SUBTRACT) {
|
||||
@ -175,7 +181,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
||||
sphere(50) {
|
||||
detail = 32
|
||||
}
|
||||
color("teal")
|
||||
color.set("teal")
|
||||
opacity = 0.7
|
||||
}
|
||||
}
|
||||
@ -186,7 +192,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
||||
detail = 32
|
||||
}
|
||||
box(100, 100, 100)
|
||||
color("red")
|
||||
color.set("red")
|
||||
opacity = 0.5
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package space.kscience.visionforge.solid.demo
|
||||
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import org.w3c.dom.Document
|
||||
import space.kscience.visionforge.Application
|
||||
import space.kscience.visionforge.solid.x
|
||||
import space.kscience.visionforge.solid.y
|
||||
@ -12,7 +12,7 @@ import kotlin.random.Random
|
||||
|
||||
private class ThreeDemoApp : Application {
|
||||
|
||||
override fun start(state: Map<String, Any>) {
|
||||
override fun start(document: Document, state: Map<String, Any>) {
|
||||
|
||||
val element = document.getElementById("demo") ?: error("Element with id 'demo' not found on page")
|
||||
|
||||
|
@ -10,12 +10,13 @@ import org.w3c.dom.Element
|
||||
import org.w3c.dom.HTMLDivElement
|
||||
import org.w3c.dom.HTMLElement
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.three.ThreeCanvas
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
|
||||
@ -25,7 +26,9 @@ class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
|
||||
|
||||
private val outputs: MutableMap<Name, ThreeCanvas> = HashMap()
|
||||
|
||||
private val three = Global.fetch(ThreePlugin)
|
||||
private val three = Global.request(ThreePlugin)
|
||||
|
||||
override val solids: Solids get() = three.solids
|
||||
|
||||
init {
|
||||
element.clear()
|
||||
|
@ -1,20 +1,19 @@
|
||||
package space.kscience.visionforge.solid.demo
|
||||
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.BoxGeometry
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.asValue
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.number
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.startsWith
|
||||
import space.kscience.dataforge.values.asValue
|
||||
import space.kscience.visionforge.onPropertyChange
|
||||
import space.kscience.visionforge.set
|
||||
import space.kscience.visionforge.setProperty
|
||||
import space.kscience.visionforge.setChild
|
||||
import space.kscience.visionforge.solid.SolidGroup
|
||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.EDGES_KEY
|
||||
import space.kscience.visionforge.solid.layer
|
||||
import space.kscience.visionforge.solid.three.*
|
||||
import three.core.Object3D
|
||||
import three.geometries.BoxGeometry
|
||||
import three.objects.Mesh
|
||||
import kotlin.math.max
|
||||
|
||||
internal fun SolidGroup.varBox(
|
||||
@ -22,7 +21,7 @@ internal fun SolidGroup.varBox(
|
||||
ySize: Number,
|
||||
name: String = "",
|
||||
action: VariableBox.() -> Unit = {},
|
||||
): VariableBox = VariableBox(xSize, ySize).apply(action).also { set(name, it) }
|
||||
): VariableBox = VariableBox(xSize, ySize).apply(action).also { setChild(name, it) }
|
||||
|
||||
internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision() {
|
||||
|
||||
@ -44,13 +43,13 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
|
||||
it.layers.enable(this@VariableBox.layer)
|
||||
}
|
||||
}
|
||||
mesh.scale.z = meta[VALUE].number?.toDouble() ?: 1.0
|
||||
mesh.scale.z = properties.getValue(VALUE)?.number?.toDouble() ?: 1.0
|
||||
|
||||
//add listener to object properties
|
||||
onPropertyChange { name ->
|
||||
when {
|
||||
name == VALUE -> {
|
||||
val value = meta.get(VALUE).int ?: 0
|
||||
val value = properties.getValue(VALUE)?.int ?: 0
|
||||
val size = value.toFloat() / 255f * 20f
|
||||
mesh.scale.z = size.toDouble()
|
||||
mesh.position.z = size.toDouble() / 2
|
||||
@ -61,7 +60,8 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
|
||||
material.color.setRGB(r.toFloat() / 256, g.toFloat() / 256, b.toFloat() / 256)
|
||||
mesh.updateMatrix()
|
||||
}
|
||||
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
|
||||
|
||||
name.startsWith(EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
|
||||
else -> mesh.updateProperty(this@VariableBox, name)
|
||||
}
|
||||
}
|
||||
@ -70,9 +70,9 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
|
||||
}
|
||||
|
||||
var value: Int
|
||||
get() = meta[VALUE].int ?: 0
|
||||
get() = properties.getValue(VALUE)?.int ?: 0
|
||||
set(value) {
|
||||
setProperty(VALUE, value.asValue())
|
||||
properties.setValue(VALUE, value.asValue())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -10,9 +10,11 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.solid.FX3DPlugin
|
||||
import space.kscience.visionforge.solid.FXCanvas3D
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import tornadofx.*
|
||||
|
||||
class FXDemoGrid : View(title = "DataForge-vis FX demo"), VisionLayout<Solid> {
|
||||
|
||||
private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>()
|
||||
|
||||
override val root: Parent = borderpane {
|
||||
@ -24,6 +26,9 @@ class FXDemoGrid : View(title = "DataForge-vis FX demo"), VisionLayout<Solid> {
|
||||
}
|
||||
|
||||
private val fx3d = Global.fetch(FX3DPlugin)
|
||||
override val solids: Solids get() = fx3d.solids
|
||||
|
||||
|
||||
|
||||
override fun render(name: Name, vision: Solid, meta: Meta) {
|
||||
outputs.getOrPut(name) { FXCanvas3D(fx3d, canvasOptions) }.render(vision)
|
@ -2,10 +2,10 @@ package space.kscience.visionforge.demo
|
||||
|
||||
import javafx.geometry.Orientation
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.node
|
||||
import space.kscience.dataforge.meta.descriptors.value
|
||||
import space.kscience.dataforge.values.ValueType
|
||||
import space.kscience.visionforge.editor.FXMetaModel
|
||||
import space.kscience.visionforge.editor.MetaViewer
|
||||
import space.kscience.visionforge.editor.MutableMetaEditor
|
@ -3,7 +3,7 @@
|
||||
![](../docs/images/hierarchy.png)
|
||||
|
||||
### Vision
|
||||
* function `getPropertyValue(name: Name, inherit: Boolean = false, includeStyles: Boolean = true, includeDefaults: Boolean = true)` - get property value with given layer flags.
|
||||
* function `getProperty(name: Name, inherit: Boolean = false, includeStyles: Boolean = true, includeDefaults: Boolean = true)` - get property value with given layer flags.
|
||||
|
||||
* function `setProperty(name: Name, item: Any?)` - a convenient method to set property node or value. If `item` is null, then node is removed, not a value
|
||||
Sets the `item` property to the element with the `name` identification.
|
||||
|
@ -7,7 +7,7 @@ Properties, which can be inherited by objects, are `styles`, `prototypes` (if th
|
||||
All values of `styles` property are contained in class `StyleSheet`, where they all are defined at `Group`s level. The `prototypes` property tree is defined in `SolidGroup` class via `PrototypeHolder` interface, and
|
||||
`SolidReference` class helps to reuse a template object.
|
||||
|
||||
The order of inheritance of properties is set in function `getPropertyValue` in `VisionBase` class.
|
||||
The order of inheritance of properties is set in function `getProperty` in `VisionBase` class.
|
||||
The order is this:
|
||||
* own styles
|
||||
* prototypes
|
||||
|
@ -59,7 +59,7 @@ box(10, 10, 10, name = "small box"){
|
||||
rotation = Point3D(0, 0, 0)
|
||||
}
|
||||
```
|
||||
![](../docs/images/small-box.png)
|
||||
![](../images/small-box.png)
|
||||
|
||||
The `big box` will have properties with custom values.
|
||||
```kotlin
|
||||
@ -72,7 +72,7 @@ box(40, 40, 40, name = "big box"){
|
||||
rotation = Point3D(60, 80, 0)
|
||||
}
|
||||
```
|
||||
![](../docs/images/big-rotated-box.png)
|
||||
![](../images/big-rotated-box.png)
|
||||
If we compare these boxes, we will see all differences.
|
||||
|
||||
Here is the function `main` with both boxes.
|
||||
@ -111,8 +111,8 @@ fun main(){
|
||||
}
|
||||
}
|
||||
```
|
||||
![](../docs/images/two-boxes-1.png)
|
||||
![](../docs/images/two-boxes-2.png)
|
||||
![](../images/two-boxes-1.png)
|
||||
![](../images/two-boxes-2.png)
|
||||
|
||||
***There is plenty of other properties, especially those, which you can create by yourself. Here we mention just a small part.***
|
||||
|
||||
@ -142,8 +142,8 @@ polyline(Point3D(30, 20, 10), Point3D(30, -100, 30), Point3D(30, -100, 30), Poin
|
||||
}
|
||||
```
|
||||
|
||||
![](../docs/images/polyline-points.png)
|
||||
![](../docs/images/polyline-points-2.png)
|
||||
![](../images/polyline-points.png)
|
||||
![](../images/polyline-points-2.png)
|
||||
|
||||
### 2) Box
|
||||
|
||||
@ -165,7 +165,7 @@ Let's create just usual `box` with equal ribs.
|
||||
color("pink")
|
||||
}
|
||||
```
|
||||
![](../docs/images/box.png)
|
||||
![](../images/box.png)
|
||||
|
||||
Now, let's make `box` with bigger `y` value.
|
||||
```kotlin
|
||||
@ -175,7 +175,7 @@ Now, let's make `box` with bigger `y` value.
|
||||
```
|
||||
As you can see, only the rib of `y-axis` differs from other ribs.
|
||||
|
||||
![](../docs/images/high-box.png)
|
||||
![](../images/high-box.png)
|
||||
|
||||
For a final trial, let's create a `box` with a bigger `x` value.
|
||||
|
||||
@ -189,7 +189,7 @@ For a final trial, let's create a `box` with a bigger `x` value.
|
||||
```
|
||||
Predictably, only the `x-axis` rib is bigger than other ribs.
|
||||
|
||||
![](../docs/images/wide-box.png)
|
||||
![](../images/wide-box.png)
|
||||
|
||||
### 3) Sphere
|
||||
|
||||
@ -206,7 +206,7 @@ As for `radius`, it has `Float` type, and, as you can guess, it sets the radius
|
||||
color("blue")
|
||||
}
|
||||
```
|
||||
![](../docs/images/sphere.png)
|
||||
![](../images/sphere.png)
|
||||
|
||||
### 4) Hexagon
|
||||
|
||||
@ -220,7 +220,7 @@ It is solid which has six edges. It is set by eight values: `node1`,..., `node8`
|
||||
5) Edge with vertices `node1`, `node5`, `node8`, `node4`
|
||||
6) Edge with vertices `node8`, `node5`, `node6`, `node7`
|
||||
|
||||
![](../docs/images/scheme.png)
|
||||
![](../images/scheme.png)
|
||||
|
||||
As the hexagon takes in specific points, we understand that this solid cannot be moved, it is fixed in space, and it can't make pivots.
|
||||
|
||||
@ -239,7 +239,7 @@ Let's make classic parallelepiped.
|
||||
color("green")
|
||||
}
|
||||
```
|
||||
![](../docs/images/classic-hexagon.png)
|
||||
![](../images/classic-hexagon.png)
|
||||
|
||||
Now, let's make a custom hexagon.
|
||||
|
||||
@ -258,7 +258,7 @@ hexagon(
|
||||
color("brown")
|
||||
}
|
||||
```
|
||||
![](../docs/images/custom-hexagon.png)
|
||||
![](../images/custom-hexagon.png)
|
||||
### 3) Cone
|
||||
It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`.
|
||||
|
||||
@ -274,8 +274,8 @@ Let's build a classic cone:
|
||||
color("beige")
|
||||
}
|
||||
```
|
||||
![](../docs/images/cone-1.png)
|
||||
![](../docs/images/cone-2.png)
|
||||
![](../images/cone-1.png)
|
||||
![](../images/cone-2.png)
|
||||
|
||||
First of all, we have to try to build a frustum cone:
|
||||
```kotlin
|
||||
@ -283,7 +283,7 @@ cone(60, 80, name = "cone") {
|
||||
color(0u, 40u, 0u)
|
||||
}
|
||||
```
|
||||
![](../docs/images/frustum-cone.png)
|
||||
![](../images/frustum-cone.png)
|
||||
|
||||
Now, we need to make a try to build a cone segment:
|
||||
|
||||
@ -292,8 +292,8 @@ cone(60, 80, angle = PI, name = "cone") {
|
||||
color(0u, 0u, 200u)
|
||||
}
|
||||
```
|
||||
![](../docs/images/cone-segment-1.png)
|
||||
![](../docs/images/cone-segment-2.png)
|
||||
![](../images/cone-segment-1.png)
|
||||
![](../images/cone-segment-2.png)
|
||||
|
||||
Finally, the segment of frustum cone is left for a try:
|
||||
```kotlin
|
||||
@ -301,7 +301,7 @@ cone(60, 100, 20, PI*3/4, angle = PI/3, name = "cone") {
|
||||
color(190u, 0u, 0u)
|
||||
}
|
||||
```
|
||||
![](../docs/images/frustum-cone-segment.png)
|
||||
![](../images/frustum-cone-segment.png)
|
||||
|
||||
### 4) Cone Surface
|
||||
This solid is set by seven values:`bottomOuterRadius`, `bottomInnerRadius`, `height`, `topOuterRadius`, `topInnerRadius`, `startAngle`, and `angle`.
|
||||
@ -318,8 +318,8 @@ Let's build usual cone surface with almost all properties set:
|
||||
rotation = Point3D(2, 50, -9)
|
||||
}
|
||||
```
|
||||
![](../docs/images/cone-surface-1.png)
|
||||
![](../docs/images/cone-surface-2.png)
|
||||
![](../images/cone-surface-1.png)
|
||||
![](../images/cone-surface-2.png)
|
||||
|
||||
Now, let's create a cone surface and set all it's properties:
|
||||
|
||||
@ -329,8 +329,8 @@ coneSurface(30, 25, 10, 10, 8,0f, pi*3/4, name = "cone surface") {
|
||||
rotation = Point3D(2, 50, -9)
|
||||
}
|
||||
```
|
||||
![](../docs/images/cone-surface-fragment.png)
|
||||
![](../docs/images/cone-surface-fragment-2.png)
|
||||
![](../images/cone-surface-fragment.png)
|
||||
![](../images/cone-surface-fragment-2.png)
|
||||
|
||||
### 5) Cylinder
|
||||
|
||||
@ -344,8 +344,8 @@ cylinder(40, 100, "cylinder"){
|
||||
color("indigo")
|
||||
}
|
||||
```
|
||||
![](../docs/images/cylinder-1.png)
|
||||
![](../docs/images/cylinder-2.png)
|
||||
![](../images/cylinder-1.png)
|
||||
![](../images/cylinder-2.png)
|
||||
### 6) Tube
|
||||
|
||||
`tube` takes in `radius`, `height`, `innerRadius`, `startAngle`, `angle`, and `name`. *All values are familiar from `cone`, and `coneSurface` solids.*
|
||||
@ -356,7 +356,7 @@ tube(50, 40, 20, name = "usual tube"){
|
||||
opacity = 0.4
|
||||
}
|
||||
```
|
||||
![](../docs/images/tube.png)
|
||||
![](../images/tube.png)
|
||||
|
||||
This is an example of tube fragment:
|
||||
|
||||
@ -365,7 +365,7 @@ tube(50, 40, 20, 0f, PI, name = "fragmented tube"){
|
||||
color("white")
|
||||
}
|
||||
```
|
||||
![](../docs/images/tube-fragment.png)
|
||||
![](../images/tube-fragment.png)
|
||||
### 7) Extruded
|
||||
|
||||
`extruded` is set by two values: `shape`, and `layer`.
|
@ -3,7 +3,7 @@
|
||||
|
||||
interface Vision{
|
||||
val parent: VisionGroup?
|
||||
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
|
||||
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
|
||||
}
|
||||
|
||||
interface Solid{
|
||||
@ -81,7 +81,7 @@ Solid <--- Composite
|
||||
|
||||
interface SolidReference{
|
||||
val prototype: Solid
|
||||
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
|
||||
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
|
||||
}
|
||||
VisionGroup <---- SolidReference
|
||||
SolidReferenceGroup -- SolidReference
|
||||
@ -91,7 +91,7 @@ class SolidReferenceGroup{
|
||||
var properties: MutableMeta?
|
||||
val prototype: Solid
|
||||
val children: Map<NameToken, Vision>
|
||||
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
|
||||
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
|
||||
}
|
||||
VisionBase <-- SolidReferenceGroup
|
||||
VisionGroup <-- SolidReferenceGroup
|
||||
|
@ -1,12 +1,13 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
kotlin.js.compiler=ir
|
||||
kotlin.incremental.js.ir=true
|
||||
|
||||
kotlin.jupyter.add.scanner=false
|
||||
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
|
||||
org.gradle.parallel=true
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
|
||||
publishing.github=false
|
||||
publishing.sonatype=false
|
||||
org.jetbrains.compose.experimental.jscanvas.enabled=true
|
||||
|
||||
toolsVersion=0.11.1-kotlin-1.6.10
|
||||
toolsVersion=0.14.9-kotlin-1.9.0-RC-dev-1
|
||||
kotlin.experimental.tryK2=true
|
||||
#kscience.wasm.disabled=true
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -1,25 +1,22 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
id("org.jetbrains.kotlin.jupyter.api")
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
description = "Common visionforge jupyter module"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain{
|
||||
dependencies{
|
||||
api(projects.visionforgeCore)
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
api(projects.visionforgeServer)
|
||||
}
|
||||
}
|
||||
kscience {
|
||||
jvm()
|
||||
js()
|
||||
jupyterLibrary()
|
||||
dependencies {
|
||||
api(projects.visionforgeCore)
|
||||
}
|
||||
dependencies(jvmMain){
|
||||
api(projects.visionforgeServer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
readme {
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
48
jupyter/src/jsMain/kotlin/VFNotebookPlugin.kt
Normal file
48
jupyter/src/jsMain/kotlin/VFNotebookPlugin.kt
Normal file
@ -0,0 +1,48 @@
|
||||
package space.kscience.visionforge.jupyter
|
||||
|
||||
import kotlinx.browser.window
|
||||
import org.w3c.dom.Element
|
||||
import space.kscience.dataforge.context.AbstractPlugin
|
||||
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.renderAllVisions
|
||||
import space.kscience.visionforge.renderAllVisionsById
|
||||
import space.kscience.visionforge.renderAllVisionsIn
|
||||
|
||||
@JsExport
|
||||
public class VFNotebookPlugin : AbstractPlugin() {
|
||||
private val client by require(VisionClient)
|
||||
|
||||
public fun renderAllVisionsIn(element: Element) {
|
||||
client.renderAllVisionsIn(element)
|
||||
}
|
||||
|
||||
public fun renderAllVisionsById(id: String) {
|
||||
client.renderAllVisionsById(id)
|
||||
}
|
||||
|
||||
public fun renderAllVisions() {
|
||||
client.renderAllVisions()
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
//register VisionForge in the browser window
|
||||
window.asDynamic().vf = this
|
||||
window.asDynamic().VisionForge = this
|
||||
}
|
||||
|
||||
@Suppress("NON_EXPORTABLE_TYPE")
|
||||
override val tag: PluginTag get() = Companion.tag
|
||||
|
||||
@Suppress("NON_EXPORTABLE_TYPE")
|
||||
public companion object : PluginFactory<VFNotebookPlugin> {
|
||||
override fun build(context: Context, meta: Meta): VFNotebookPlugin = VFNotebookPlugin()
|
||||
|
||||
override val tag: PluginTag = PluginTag(name = "vision.notebook", group = PluginTag.DATAFORGE_GROUP)
|
||||
}
|
||||
|
||||
}
|
144
jupyter/src/jvmMain/kotlin/VFForNotebook.kt
Normal file
144
jupyter/src/jvmMain/kotlin/VFForNotebook.kt
Normal file
@ -0,0 +1,144 @@
|
||||
package space.kscience.visionforge.jupyter
|
||||
|
||||
import io.ktor.http.URLProtocol
|
||||
import io.ktor.server.application.install
|
||||
import io.ktor.server.cio.CIO
|
||||
import io.ktor.server.engine.ApplicationEngine
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.util.url
|
||||
import io.ktor.server.websocket.WebSockets
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.html.*
|
||||
import kotlinx.html.stream.createHTML
|
||||
import org.jetbrains.kotlinx.jupyter.api.HTML
|
||||
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.ContextAware
|
||||
import space.kscience.dataforge.context.info
|
||||
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.HtmlVisionFragment
|
||||
import space.kscience.visionforge.html.visionFragment
|
||||
import space.kscience.visionforge.server.VisionRoute
|
||||
import space.kscience.visionforge.server.serveVisionData
|
||||
import space.kscience.visionforge.visionManager
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextUInt
|
||||
|
||||
internal fun TagConsumer<*>.renderScriptForId(id: String) {
|
||||
script {
|
||||
type = "text/javascript"
|
||||
unsafe { +"VisionForge.renderAllVisionsById(\"$id\");" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A handler class that includes a server and common utilities
|
||||
*/
|
||||
public class VFForNotebook(override val context: Context) : ContextAware, CoroutineScope {
|
||||
|
||||
public val visionManager: VisionManager = context.visionManager
|
||||
|
||||
private var counter = 0
|
||||
|
||||
private var engine: ApplicationEngine? = null
|
||||
|
||||
public var isolateFragments: Boolean = false
|
||||
|
||||
override val coroutineContext: CoroutineContext get() = context.coroutineContext
|
||||
|
||||
public fun legacyMode() {
|
||||
isolateFragments = true
|
||||
}
|
||||
|
||||
public fun isServerRunning(): Boolean = engine != null
|
||||
|
||||
public fun html(block: TagConsumer<*>.() -> Unit): MimeTypedResult = HTML(createHTML().apply(block).finalize())
|
||||
|
||||
public fun startServer(
|
||||
host: String = context.properties["visionforge.host"].string ?: "localhost",
|
||||
port: Int = context.properties["visionforge.port"].int ?: VisionRoute.DEFAULT_PORT,
|
||||
): MimeTypedResult = html {
|
||||
if (engine != null) {
|
||||
p {
|
||||
style = "color: red;"
|
||||
+"Stopping current VisionForge server"
|
||||
}
|
||||
}
|
||||
|
||||
//val connector: EngineConnectorConfig = EngineConnectorConfig(host, port)
|
||||
|
||||
engine?.stop(1000, 2000)
|
||||
engine = context.embeddedServer(CIO, port, host) {
|
||||
install(WebSockets)
|
||||
}.start(false)
|
||||
|
||||
p {
|
||||
style = "color: blue;"
|
||||
+"Starting VisionForge server on http://$host:$port"
|
||||
}
|
||||
}
|
||||
|
||||
public fun stopServer() {
|
||||
engine?.apply {
|
||||
logger.info { "Stopping VisionForge server" }
|
||||
stop(1000, 2000)
|
||||
engine = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun produceHtmlString(
|
||||
fragment: HtmlVisionFragment,
|
||||
): String = createHTML().apply {
|
||||
val id = "fragment[${fragment.hashCode()}/${Random.nextUInt()}]"
|
||||
div {
|
||||
this.id = id
|
||||
val engine = engine
|
||||
if (engine != null) {
|
||||
//if server exist, serve dynamically
|
||||
//server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment)
|
||||
val cellRoute = "content-${counter++}"
|
||||
|
||||
val collector: MutableMap<Name, Vision> = mutableMapOf()
|
||||
|
||||
val url = engine.environment.connectors.first().let {
|
||||
url {
|
||||
protocol = URLProtocol.WS
|
||||
host = it.host
|
||||
port = it.port
|
||||
pathSegments = listOf(cellRoute, "ws")
|
||||
}
|
||||
}
|
||||
|
||||
engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector)
|
||||
|
||||
visionFragment(
|
||||
visionManager,
|
||||
embedData = true,
|
||||
updatesUrl = url,
|
||||
onVisionRendered = { name, vision -> collector[name] = vision },
|
||||
fragment = fragment
|
||||
)
|
||||
} else {
|
||||
//if not, use static rendering
|
||||
visionFragment(visionManager, fragment = fragment)
|
||||
}
|
||||
}
|
||||
renderScriptForId(id)
|
||||
}.finalize()
|
||||
|
||||
public fun produceHtml(isolated: Boolean? = null, fragment: HtmlVisionFragment): MimeTypedResult =
|
||||
HTML(produceHtmlString(fragment), isolated ?: isolateFragments)
|
||||
|
||||
public fun fragment(body: HtmlVisionFragment): MimeTypedResult = produceHtml(fragment = body)
|
||||
public fun page(body: HtmlVisionFragment): MimeTypedResult = produceHtml(true, body)
|
||||
|
||||
public fun form(builder: FORM.() -> Unit): HtmlFormFragment =
|
||||
HtmlFormFragment("form[${counter++}]", builder = builder)
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
package space.kscience.visionforge.jupyter
|
||||
|
||||
import kotlinx.html.p
|
||||
import kotlinx.html.*
|
||||
import kotlinx.html.stream.createHTML
|
||||
import kotlinx.html.style
|
||||
import org.jetbrains.kotlinx.jupyter.api.HTML
|
||||
import org.jetbrains.kotlinx.jupyter.api.declare
|
||||
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
|
||||
@ -10,12 +9,21 @@ 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
|
||||
|
||||
/**
|
||||
* A base class for different Jupyter VF integrations
|
||||
*/
|
||||
@DFExperimental
|
||||
public abstract class JupyterPluginBase(final override val context: Context) : JupyterIntegration(), ContextAware {
|
||||
public abstract class VFIntegrationBase(
|
||||
public val visionManager: VisionManager,
|
||||
) : JupyterIntegration(), ContextAware {
|
||||
|
||||
protected val handler: VisionForgeForNotebook = VisionForgeForNotebook(context)
|
||||
override val context: Context get() = visionManager.context
|
||||
protected val handler: VFForNotebook = VFForNotebook(visionManager.context)
|
||||
|
||||
protected abstract fun Builder.afterLoaded()
|
||||
|
||||
@ -44,13 +52,30 @@ public abstract class JupyterPluginBase(final override val context: Context) : J
|
||||
|
||||
render<Vision> { vision ->
|
||||
handler.produceHtml {
|
||||
vision { vision }
|
||||
vision(vision)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render<Page> { page ->
|
||||
HTML(page.render(createHTML()), true)
|
||||
render<VisionPage> { page ->
|
||||
HTML(createHTML().apply {
|
||||
head {
|
||||
meta {
|
||||
charset = "utf-8"
|
||||
}
|
||||
page.pageHeaders.values.forEach {
|
||||
fragment(it)
|
||||
}
|
||||
}
|
||||
body {
|
||||
val id = "fragment[${page.hashCode()}/${Random.nextUInt()}]"
|
||||
div {
|
||||
this.id = id
|
||||
visionFragment(visionManager, fragment = page.content)
|
||||
}
|
||||
renderScriptForId(id)
|
||||
}
|
||||
}.finalize(), true)
|
||||
}
|
||||
|
||||
render<HtmlFormFragment> { fragment ->
|
||||
@ -62,7 +87,7 @@ public abstract class JupyterPluginBase(final override val context: Context) : J
|
||||
}
|
||||
}
|
||||
fragment(fragment.formBody)
|
||||
vision { fragment.vision }
|
||||
vision(fragment.vision)
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +0,0 @@
|
||||
package space.kscience.visionforge.jupyter
|
||||
|
||||
import io.ktor.server.engine.ApplicationEngine
|
||||
import kotlinx.html.FORM
|
||||
import kotlinx.html.TagConsumer
|
||||
import kotlinx.html.p
|
||||
import kotlinx.html.stream.createHTML
|
||||
import kotlinx.html.style
|
||||
import org.jetbrains.kotlinx.jupyter.api.HTML
|
||||
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.ContextAware
|
||||
import space.kscience.dataforge.context.info
|
||||
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.visionforge.html.HtmlFormFragment
|
||||
import space.kscience.visionforge.html.HtmlVisionFragment
|
||||
import space.kscience.visionforge.html.visionFragment
|
||||
import space.kscience.visionforge.server.VisionServer
|
||||
import space.kscience.visionforge.server.serve
|
||||
import space.kscience.visionforge.visionManager
|
||||
|
||||
/**
|
||||
* A handler class that includes a server and common utilities
|
||||
*/
|
||||
public class VisionForgeForNotebook(override val context: Context) : ContextAware {
|
||||
private var counter = 0
|
||||
|
||||
private var engine: ApplicationEngine? = null
|
||||
private var server: VisionServer? = null
|
||||
|
||||
public var isolateFragments: Boolean = false
|
||||
|
||||
public fun legacyMode() {
|
||||
isolateFragments = true
|
||||
}
|
||||
|
||||
public fun isServerRunning(): Boolean = server != null
|
||||
|
||||
public fun html(block: TagConsumer<*>.() -> Unit): MimeTypedResult = HTML(createHTML().apply(block).finalize())
|
||||
|
||||
public fun startServer(
|
||||
host: String = context.properties["visionforge.host"].string ?: "localhost",
|
||||
port: Int = context.properties["visionforge.port"].int ?: VisionServer.DEFAULT_PORT,
|
||||
configuration: VisionServer.() -> Unit = {},
|
||||
): MimeTypedResult = html {
|
||||
if (server != null) {
|
||||
p {
|
||||
style = "color: red;"
|
||||
+"Stopping current VisionForge server"
|
||||
}
|
||||
}
|
||||
|
||||
engine?.stop(1000, 2000)
|
||||
engine = context.visionManager.serve(host, port) {
|
||||
configuration()
|
||||
server = this
|
||||
}.start()
|
||||
|
||||
p {
|
||||
style = "color: blue;"
|
||||
+"Starting VisionForge server on http://$host:$port"
|
||||
}
|
||||
}
|
||||
|
||||
public fun stopServer() {
|
||||
engine?.apply {
|
||||
logger.info { "Stopping VisionForge server" }
|
||||
}?.stop(1000, 2000)
|
||||
}
|
||||
|
||||
private fun produceHtmlString(
|
||||
fragment: HtmlVisionFragment,
|
||||
): String = server?.serveVisionsFromFragment("content[${counter++}]", fragment)
|
||||
?: createHTML().apply {
|
||||
visionFragment(context, fragment = fragment)
|
||||
}.finalize()
|
||||
|
||||
public fun produceHtml(isolated: Boolean? = null, fragment: HtmlVisionFragment): MimeTypedResult =
|
||||
HTML(produceHtmlString(fragment), isolated ?: isolateFragments)
|
||||
|
||||
public fun fragment(body: HtmlVisionFragment): MimeTypedResult = produceHtml(fragment = body)
|
||||
public fun page(body: HtmlVisionFragment): MimeTypedResult = produceHtml(true, body)
|
||||
|
||||
public fun form(builder: FORM.() -> Unit): HtmlFormFragment =
|
||||
HtmlFormFragment("form[${counter++}]", builder = builder)
|
||||
}
|
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()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +1,38 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
description = "Jupyter api artifact for GDML rendering"
|
||||
|
||||
kotlin {
|
||||
explicitApi = null
|
||||
js {
|
||||
useCommonJs()
|
||||
browser {
|
||||
webpackTask {
|
||||
this.outputFileName = "js/gdml-jupyter.js"
|
||||
}
|
||||
commonWebpackConfig {
|
||||
sourceMaps = false
|
||||
cssSupport.enabled = false
|
||||
}
|
||||
}
|
||||
binaries.executable()
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
val jsBrowserDistribution by tasks.getting
|
||||
|
||||
tasks.getByName<ProcessResources>("jvmProcessResources") {
|
||||
dependsOn(jsBrowserDistribution)
|
||||
from(jsBrowserDistribution)
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation(projects.visionforgeSolid)
|
||||
implementation(projects.jupyter)
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation(projects.visionforgeGdml)
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation(projects.visionforgeThreejs)
|
||||
implementation(projects.ui.ring)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
kscience {
|
||||
fullStack("js/gdml-jupyter.js",
|
||||
jsConfig = { useCommonJs() }
|
||||
) {
|
||||
commonWebpackConfig {
|
||||
sourceMaps = false
|
||||
cssSupport {
|
||||
enabled.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies{
|
||||
implementation(projects.visionforgeSolid)
|
||||
implementation(projects.jupyter)
|
||||
}
|
||||
|
||||
dependencies(jvmMain){
|
||||
implementation(projects.visionforgeGdml)
|
||||
}
|
||||
|
||||
dependencies(jsMain){
|
||||
implementation(projects.visionforgeThreejs)
|
||||
implementation(projects.ui.ring)
|
||||
}
|
||||
|
||||
jupyterLibrary("space.kscience.visionforge.gdml.jupyter.GdmlForJupyter")
|
||||
}
|
||||
|
||||
readme {
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
@ -6,7 +6,7 @@ import space.kscience.visionforge.runVisionClient
|
||||
|
||||
@DFExperimental
|
||||
@JsExport
|
||||
fun main(): Unit = runVisionClient {
|
||||
public fun main(): Unit = runVisionClient {
|
||||
plugin(ThreeWithControlsPlugin)
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,15 @@ import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.gdml.Gdml
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.jupyter.JupyterPluginBase
|
||||
import space.kscience.visionforge.jupyter.VFIntegrationBase
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.visionManager
|
||||
|
||||
@DFExperimental
|
||||
internal class GdmlForJupyter : JupyterPluginBase(
|
||||
internal class GdmlForJupyter : VFIntegrationBase(
|
||||
Context("GDML") {
|
||||
plugin(Solids)
|
||||
}
|
||||
}.visionManager
|
||||
) {
|
||||
|
||||
override fun Builder.afterLoaded() {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,6 @@
|
||||
rootProject.name = "visionforge"
|
||||
|
||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
enableFeaturePreview("VERSION_CATALOGS")
|
||||
|
||||
pluginManagement {
|
||||
|
||||
@ -12,13 +11,14 @@ pluginManagement {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.project") version toolsVersion
|
||||
id("ru.mipt.npm.gradle.mpp") version toolsVersion
|
||||
id("ru.mipt.npm.gradle.jvm") version toolsVersion
|
||||
id("ru.mipt.npm.gradle.js") version toolsVersion
|
||||
id("space.kscience.gradle.project") version toolsVersion
|
||||
id("space.kscience.gradle.mpp") version toolsVersion
|
||||
id("space.kscience.gradle.jvm") version toolsVersion
|
||||
id("space.kscience.gradle.js") version toolsVersion
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,8 +33,8 @@ dependencyResolutionManagement {
|
||||
}
|
||||
|
||||
versionCatalogs {
|
||||
create("npmlibs") {
|
||||
from("ru.mipt.npm:version-catalog:$toolsVersion")
|
||||
create("spclibs") {
|
||||
from("space.kscience:version-catalog:$toolsVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,9 +45,10 @@ include(
|
||||
":ui:ring",
|
||||
// ":ui:material",
|
||||
":ui:bootstrap",
|
||||
// ":ui:compose",
|
||||
":visionforge-core",
|
||||
":visionforge-solid",
|
||||
":visionforge-fx",
|
||||
// ":visionforge-fx",
|
||||
":visionforge-threejs",
|
||||
":visionforge-threejs:visionforge-threejs-server",
|
||||
":visionforge-gdml",
|
||||
@ -61,7 +62,7 @@ include(
|
||||
":demo:muon-monitor",
|
||||
":demo:sat-demo",
|
||||
":demo:playground",
|
||||
":demo:plotly-fx",
|
||||
// ":demo:plotly-fx",
|
||||
":demo:js-playground",
|
||||
":jupyter",
|
||||
":jupyter:visionforge-jupyter-gdml"
|
||||
|
@ -1,15 +1,19 @@
|
||||
plugins {
|
||||
kotlin("js")
|
||||
id("ru.mipt.npm.gradle.js")
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
val dataforgeVersion: String by rootProject.extra
|
||||
|
||||
dependencies {
|
||||
api(project(":visionforge-solid"))
|
||||
api(project(":ui:react"))
|
||||
implementation(npm("file-saver", "2.0.2"))
|
||||
implementation(npm("bootstrap","4.6.0"))
|
||||
implementation(npm("jquery","3.5.1"))
|
||||
implementation(npm("popper.js","1.16.1"))
|
||||
kscience{
|
||||
js()
|
||||
jsMain{
|
||||
dependencies {
|
||||
api(project(":visionforge-solid"))
|
||||
api(project(":ui:react"))
|
||||
implementation(npm("file-saver", "2.0.2"))
|
||||
implementation(npm("bootstrap","4.6.0"))
|
||||
implementation(npm("jquery","3.5.1"))
|
||||
implementation(npm("popper.js","1.16.1"))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
package space.kscience.visionforge.bootstrap
|
||||
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.css.BorderStyle
|
||||
import kotlinx.css.Color
|
||||
import kotlinx.css.padding
|
||||
import kotlinx.css.properties.border
|
||||
import kotlinx.css.px
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import org.w3c.dom.events.Event
|
||||
import kotlinx.html.org.w3c.dom.events.Event
|
||||
import org.w3c.files.Blob
|
||||
import org.w3c.files.BlobPropertyBag
|
||||
import react.FC
|
||||
@ -15,7 +17,6 @@ import react.RBuilder
|
||||
import react.dom.attrs
|
||||
import react.dom.button
|
||||
import react.fc
|
||||
import space.kscience.dataforge.meta.withDefault
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.encodeToString
|
||||
import space.kscience.visionforge.react.flexColumn
|
||||
@ -47,6 +48,7 @@ public external interface CanvasControlsProps : Props {
|
||||
public var vision: Vision?
|
||||
}
|
||||
|
||||
|
||||
public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
|
||||
flexColumn {
|
||||
flexRow {
|
||||
@ -68,9 +70,10 @@ public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { prop
|
||||
}
|
||||
}
|
||||
}
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
propertyEditor(
|
||||
ownProperties = props.canvasOptions.meta,
|
||||
allProperties = props.canvasOptions.meta.withDefault(Canvas3DOptions.descriptor.defaultNode),
|
||||
scope = props.vision?.manager?.context ?: GlobalScope,
|
||||
properties = props.canvasOptions.meta,
|
||||
descriptor = Canvas3DOptions.descriptor,
|
||||
expanded = false
|
||||
)
|
@ -30,7 +30,7 @@ public external interface TabPaneProps : PropsWithChildren {
|
||||
public val TabPane: FC<TabPaneProps> = fc("TabPane") { props ->
|
||||
var activeTab: String? by useState(props.activeTab)
|
||||
|
||||
val children: Array<out ReactElement?> = Children.map(props.children) {
|
||||
val children: Array<out ReactElement<*>?> = Children.map(props.children) {
|
||||
it.asElementOrNull()
|
||||
} ?: emptyArray()
|
||||
|
@ -10,8 +10,8 @@ import react.fc
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.isEmpty
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionGroup
|
||||
import space.kscience.visionforge.react.visionTree
|
||||
import space.kscience.visionforge.solid.SolidGroup
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
@ -51,7 +51,7 @@ public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
|
||||
val selectedObject: Vision? = when {
|
||||
selected == null -> null
|
||||
selected.isEmpty() -> props.vision
|
||||
else -> (props.vision as? VisionGroup)?.get(selected)
|
||||
else -> (props.vision as? SolidGroup)?.get(selected)
|
||||
}
|
||||
if (selectedObject != null) {
|
||||
visionPropertyEditor(selectedObject, key = selected)
|
@ -2,13 +2,15 @@ package space.kscience.visionforge.bootstrap
|
||||
|
||||
import org.w3c.dom.Element
|
||||
import react.RBuilder
|
||||
import react.dom.render
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.isEmpty
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.computeProperties
|
||||
import space.kscience.visionforge.getStyle
|
||||
import space.kscience.visionforge.react.EditorPropertyState
|
||||
import space.kscience.visionforge.react.PropertyEditor
|
||||
import space.kscience.visionforge.react.metaViewer
|
||||
import space.kscience.visionforge.react.propertyEditor
|
||||
import space.kscience.visionforge.react.render
|
||||
import space.kscience.visionforge.root
|
||||
import space.kscience.visionforge.solid.SolidReference
|
||||
import space.kscience.visionforge.styles
|
||||
|
||||
@ -19,12 +21,26 @@ public fun RBuilder.visionPropertyEditor(
|
||||
) {
|
||||
|
||||
card("Properties") {
|
||||
propertyEditor(
|
||||
ownProperties = vision.meta,
|
||||
allProperties = vision.computeProperties(),
|
||||
descriptor = descriptor,
|
||||
key = key
|
||||
)
|
||||
child(PropertyEditor) {
|
||||
attrs {
|
||||
this.key = key?.toString()
|
||||
this.meta = vision.properties.root()
|
||||
this.updates = vision.properties.changes
|
||||
this.descriptor = descriptor
|
||||
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
|
||||
this.getPropertyState = { name ->
|
||||
val ownMeta = vision.properties.own?.getMeta(name)
|
||||
if (ownMeta != null && !ownMeta.isEmpty()) {
|
||||
EditorPropertyState.Defined
|
||||
} else if (vision.properties.root().getValue(name) != null) {
|
||||
// TODO differentiate
|
||||
EditorPropertyState.Default()
|
||||
} else {
|
||||
EditorPropertyState.Undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val styles = if (vision is SolidReference) {
|
||||
(vision.styles + vision.prototype.styles).distinct()
|
||||
@ -50,6 +66,6 @@ public fun RBuilder.visionPropertyEditor(
|
||||
public fun Element.visionPropertyEditor(
|
||||
item: Vision,
|
||||
descriptor: MetaDescriptor? = item.descriptor,
|
||||
): Unit = render(this) {
|
||||
): Unit = space.kscience.visionforge.react.createRoot(this).render {
|
||||
visionPropertyEditor(item, descriptor = descriptor)
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package space.kscience.visionforge.compose
|
||||
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
public fun ThreeJs(){
|
||||
Surface {
|
||||
|
||||
}
|
||||
}
|
@ -1,11 +1,16 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.js")
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
dependencies{
|
||||
api(project(":visionforge-solid"))
|
||||
api("org.jetbrains.kotlin-wrappers:kotlin-styled")
|
||||
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
|
||||
kscience {
|
||||
js()
|
||||
jsMain {
|
||||
dependencies {
|
||||
api(projects.visionforgeSolid)
|
||||
api("org.jetbrains.kotlin-wrappers:kotlin-styled")
|
||||
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
|
||||
// implementation(npm("react-select","4.3.0"))
|
||||
implementation(project(":visionforge-threejs"))
|
||||
api(projects.visionforgeThreejs)
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package space.kscience.visionforge.react
|
||||
import kotlinx.css.Align
|
||||
import kotlinx.css.alignItems
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import org.w3c.dom.events.Event
|
||||
import kotlinx.html.org.w3c.dom.events.Event
|
||||
import react.*
|
||||
import react.dom.a
|
||||
import react.dom.attrs
|
@ -1,31 +1,31 @@
|
||||
package space.kscience.visionforge.react
|
||||
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import kotlinx.html.org.w3c.dom.events.Event
|
||||
import org.w3c.dom.HTMLOptionElement
|
||||
import org.w3c.dom.HTMLSelectElement
|
||||
import org.w3c.dom.asList
|
||||
import org.w3c.dom.events.Event
|
||||
import react.FC
|
||||
import react.dom.attrs
|
||||
import react.dom.option
|
||||
import react.dom.select
|
||||
import react.fc
|
||||
import space.kscience.dataforge.meta.asValue
|
||||
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||
import space.kscience.dataforge.values.asValue
|
||||
import space.kscience.dataforge.values.string
|
||||
import space.kscience.dataforge.meta.string
|
||||
|
||||
@JsExport
|
||||
public val MultiSelectChooser: FC<ValueChooserProps> = fc("MultiSelectChooser") { props ->
|
||||
val onChange: (Event) -> Unit = { event: Event ->
|
||||
val newSelected = (event.target as HTMLSelectElement).selectedOptions.asList()
|
||||
.map { (it as HTMLOptionElement).value.asValue() }
|
||||
props.meta.value = newSelected.asValue()
|
||||
props.onValueChange(newSelected.asValue())
|
||||
}
|
||||
|
||||
select {
|
||||
attrs {
|
||||
multiple = true
|
||||
values = (props.actual.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
|
||||
values = (props.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
|
||||
onChangeFunction = onChange
|
||||
}
|
||||
props.descriptor?.allowedValues?.forEach { optionValue ->
|
@ -1,17 +1,25 @@
|
||||
package space.kscience.visionforge.react
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.css.*
|
||||
import kotlinx.css.properties.TextDecoration
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.events.Event
|
||||
import kotlinx.html.org.w3c.dom.events.Event
|
||||
import react.*
|
||||
import react.dom.attrs
|
||||
import react.dom.render
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.ValueRequirement
|
||||
import space.kscience.dataforge.meta.descriptors.get
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.remove
|
||||
import space.kscience.dataforge.names.*
|
||||
import space.kscience.visionforge.hidden
|
||||
import styled.css
|
||||
@ -19,17 +27,30 @@ import styled.styledButton
|
||||
import styled.styledDiv
|
||||
import styled.styledSpan
|
||||
|
||||
/**
|
||||
* The display state of a property
|
||||
*/
|
||||
public sealed class EditorPropertyState {
|
||||
public object Defined : EditorPropertyState()
|
||||
public class Default(public val source: String = "unknown") : EditorPropertyState()
|
||||
|
||||
public object Undefined : EditorPropertyState()
|
||||
|
||||
}
|
||||
|
||||
|
||||
public external interface PropertyEditorProps : Props {
|
||||
|
||||
/**
|
||||
* Root config object - always non-null
|
||||
*/
|
||||
public var meta: ObservableMutableMeta
|
||||
public var meta: MutableMeta
|
||||
|
||||
/**
|
||||
* Provide default item (greyed out if used)
|
||||
*/
|
||||
public var withDefault: MetaProvider
|
||||
public var getPropertyState: (Name) -> EditorPropertyState
|
||||
|
||||
public var scope: CoroutineScope
|
||||
|
||||
public var updates: Flow<Name>
|
||||
|
||||
/**
|
||||
* Full path to the displayed node in [meta]. Could be empty
|
||||
@ -54,7 +75,9 @@ private val PropertyEditorItem: FC<PropertyEditorProps> = fc("PropertyEditorItem
|
||||
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
var expanded: Boolean by useState { props.expanded ?: true }
|
||||
val descriptor: MetaDescriptor? = useMemo(props.descriptor, props.name) { props.descriptor?.get(props.name) }
|
||||
var ownProperty: ObservableMutableMeta by useState { props.meta.getOrCreate(props.name) }
|
||||
var property: MutableMeta by useState { props.meta.getOrCreate(props.name) }
|
||||
var editorPropertyState: EditorPropertyState by useState { props.getPropertyState(props.name) }
|
||||
|
||||
|
||||
val keys = useMemo(descriptor) {
|
||||
buildSet {
|
||||
@ -70,17 +93,19 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
val token = props.name.lastOrNull()?.toString() ?: "Properties"
|
||||
|
||||
fun update() {
|
||||
ownProperty = props.meta.getOrCreate(props.name)
|
||||
property = props.meta.getOrCreate(props.name)
|
||||
editorPropertyState = props.getPropertyState(props.name)
|
||||
}
|
||||
|
||||
useEffect(props.meta) {
|
||||
props.meta.onChange(props) { updatedName ->
|
||||
val job = props.updates.onEach { updatedName ->
|
||||
if (updatedName == props.name) {
|
||||
update()
|
||||
}
|
||||
}
|
||||
}.launchIn(props.scope)
|
||||
|
||||
cleanup {
|
||||
props.meta.removeListener(props)
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +140,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
styledSpan {
|
||||
css {
|
||||
+TreeStyles.treeLabel
|
||||
if (ownProperty.isEmpty()) {
|
||||
if (editorPropertyState != EditorPropertyState.Defined) {
|
||||
+TreeStyles.treeLabelInactive
|
||||
}
|
||||
}
|
||||
@ -131,8 +156,12 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
ValueChooser {
|
||||
attrs {
|
||||
this.descriptor = descriptor
|
||||
this.meta = ownProperty
|
||||
this.actual = props.withDefault.getMeta(props.name) ?: ownProperty
|
||||
this.state = editorPropertyState
|
||||
this.value = property.value
|
||||
this.onValueChange = {
|
||||
property.value = it
|
||||
editorPropertyState = props.getPropertyState(props.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -156,7 +185,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
}
|
||||
+"\u00D7"
|
||||
attrs {
|
||||
if (ownProperty.isEmpty()) {
|
||||
if (editorPropertyState!= EditorPropertyState.Defined) {
|
||||
disabled = true
|
||||
} else {
|
||||
onClickFunction = removeClick
|
||||
@ -179,9 +208,11 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
attrs {
|
||||
this.key = props.name.toString()
|
||||
this.meta = props.meta
|
||||
this.withDefault = props.withDefault
|
||||
this.name = props.name + token
|
||||
this.descriptor = props.descriptor
|
||||
this.scope = props.scope
|
||||
this.getPropertyState = { props.getPropertyState(props.name + token) }
|
||||
this.updates = props.updates
|
||||
}
|
||||
}
|
||||
//configEditor(props.root, props.name + token, props.descriptor, props.default)
|
||||
@ -197,44 +228,51 @@ public val PropertyEditor: FC<PropertyEditorProps> = fc("PropertyEditor") { prop
|
||||
attrs {
|
||||
this.key = ""
|
||||
this.meta = props.meta
|
||||
this.withDefault = props.withDefault
|
||||
this.name = Name.EMPTY
|
||||
this.descriptor = props.descriptor
|
||||
this.expanded = props.expanded
|
||||
this.scope = props.scope
|
||||
this.getPropertyState = props.getPropertyState
|
||||
this.updates = props.updates
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
public fun RBuilder.propertyEditor(
|
||||
ownProperties: ObservableMutableMeta,
|
||||
allProperties: MetaProvider = ownProperties,
|
||||
scope: CoroutineScope,
|
||||
properties: ObservableMutableMeta,
|
||||
descriptor: MetaDescriptor? = null,
|
||||
key: Any? = null,
|
||||
expanded: Boolean? = null,
|
||||
) {
|
||||
child(PropertyEditor) {
|
||||
attrs {
|
||||
this.meta = ownProperties
|
||||
this.withDefault = allProperties
|
||||
this.meta = properties
|
||||
this.descriptor = descriptor
|
||||
this.key = key?.toString() ?: ""
|
||||
this.expanded = expanded
|
||||
this.scope = scope
|
||||
this.getPropertyState = { name ->
|
||||
if (properties[name] != null) {
|
||||
EditorPropertyState.Defined
|
||||
} else if (descriptor?.get(name)?.defaultValue != null) {
|
||||
EditorPropertyState.Default("descriptor")
|
||||
} else {
|
||||
EditorPropertyState.Undefined
|
||||
}
|
||||
}
|
||||
this.updates = callbackFlow {
|
||||
properties.onChange(scope) { name ->
|
||||
scope.launch {
|
||||
send(name)
|
||||
}
|
||||
}
|
||||
|
||||
invokeOnClose {
|
||||
properties.removeListener(scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun RBuilder.configEditor(
|
||||
config: ObservableMutableMeta,
|
||||
default: MetaProvider = config,
|
||||
descriptor: MetaDescriptor? = null,
|
||||
key: Any? = null,
|
||||
): Unit = propertyEditor(config, default, descriptor, key = key)
|
||||
|
||||
public fun Element.configEditor(
|
||||
config: ObservableMutableMeta,
|
||||
default: Meta = config,
|
||||
descriptor: MetaDescriptor? = null,
|
||||
key: Any? = null,
|
||||
): Unit = render(this) {
|
||||
configEditor(config, default, descriptor, key = key)
|
||||
}
|
@ -4,38 +4,40 @@ import kotlinx.css.pct
|
||||
import kotlinx.css.width
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import kotlinx.html.org.w3c.dom.events.Event
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.events.Event
|
||||
import react.FC
|
||||
import react.dom.attrs
|
||||
import react.fc
|
||||
import react.useState
|
||||
import space.kscience.dataforge.meta.asValue
|
||||
import space.kscience.dataforge.meta.descriptors.ValueRequirement
|
||||
import space.kscience.dataforge.meta.double
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.values.asValue
|
||||
import styled.css
|
||||
import styled.styledInput
|
||||
|
||||
@JsExport
|
||||
public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") { props ->
|
||||
var innerValue by useState(props.actual.double)
|
||||
var rangeDisabled: Boolean by useState(props.meta.value == null)
|
||||
var innerValue by useState(props.value?.double)
|
||||
var rangeDisabled: Boolean by useState(props.state != EditorPropertyState.Defined)
|
||||
|
||||
val handleDisable: (Event) -> Unit = {
|
||||
val checkBoxValue = (it.target as HTMLInputElement).checked
|
||||
rangeDisabled = !checkBoxValue
|
||||
props.meta.value = if (!checkBoxValue) {
|
||||
null
|
||||
} else {
|
||||
innerValue?.asValue()
|
||||
}
|
||||
props.onValueChange(
|
||||
if (!checkBoxValue) {
|
||||
null
|
||||
} else {
|
||||
innerValue?.asValue()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val handleChange: (Event) -> Unit = {
|
||||
val newValue = (it.target as HTMLInputElement).value
|
||||
props.meta.value = newValue.toDoubleOrNull()?.asValue()
|
||||
props.onValueChange(newValue.toDoubleOrNull()?.asValue())
|
||||
innerValue = newValue.toDoubleOrNull()
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import org.w3c.dom.Element
|
||||
import org.w3c.dom.HTMLElement
|
||||
import react.*
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
@ -25,7 +25,7 @@ public val ThreeCanvasComponent: FC<ThreeCanvasProps> = fc("ThreeCanvasComponent
|
||||
val elementRef = useRef<Element>(null)
|
||||
var canvas by useState<ThreeCanvas?>(null)
|
||||
|
||||
val three: ThreePlugin = useMemo(props.context) { props.context.fetch(ThreePlugin) }
|
||||
val three: ThreePlugin = useMemo(props.context) { props.context.request(ThreePlugin) }
|
||||
|
||||
useEffect(props.solid, props.options, elementRef) {
|
||||
if (canvas == null) {
|
@ -7,7 +7,7 @@ import kotlinx.css.cursor
|
||||
import kotlinx.css.properties.TextDecorationLine
|
||||
import kotlinx.css.properties.textDecoration
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import org.w3c.dom.events.Event
|
||||
import kotlinx.html.org.w3c.dom.events.Event
|
||||
import react.*
|
||||
import react.dom.attrs
|
||||
import space.kscience.dataforge.names.Name
|
||||
@ -16,6 +16,7 @@ import space.kscience.dataforge.names.plus
|
||||
import space.kscience.dataforge.names.startsWith
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionGroup
|
||||
import space.kscience.visionforge.asSequence
|
||||
import space.kscience.visionforge.isEmpty
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
@ -61,7 +62,7 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
|
||||
//display as node if any child is visible
|
||||
if (obj is VisionGroup) {
|
||||
flexRow {
|
||||
if (obj.children.any { !it.key.body.startsWith("@") }) {
|
||||
if (obj.children.keys.any { !it.body.startsWith("@") }) {
|
||||
styledSpan {
|
||||
css {
|
||||
+TreeStyles.treeCaret
|
||||
@ -81,9 +82,9 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
|
||||
css {
|
||||
+TreeStyles.tree
|
||||
}
|
||||
obj.children.entries
|
||||
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
||||
.sortedBy { (it.value as? VisionGroup)?.isEmpty() ?: true } // ignore empty groups
|
||||
obj.children.asSequence()
|
||||
.filter { !it.first.toString().startsWith("@") } // ignore statics and other hidden children
|
||||
.sortedBy { (it.second as? VisionGroup)?.children?.isEmpty() ?: true } // ignore empty groups
|
||||
.forEach { (childToken, child) ->
|
||||
styledDiv {
|
||||
css {
|
@ -0,0 +1,17 @@
|
||||
|
||||
@file:JsModule("react-dom/client")
|
||||
@file:JsNonModule
|
||||
|
||||
package space.kscience.visionforge.react
|
||||
|
||||
import org.w3c.dom.Element
|
||||
import react.dom.client.Root
|
||||
import react.dom.client.RootOptions
|
||||
|
||||
/**
|
||||
* Compatibility method to work with old browser API
|
||||
*/
|
||||
public external fun createRoot(
|
||||
container: Element,
|
||||
options: RootOptions = definedExternally,
|
||||
): Root
|
@ -0,0 +1,10 @@
|
||||
package space.kscience.visionforge.react
|
||||
|
||||
import react.Props
|
||||
import react.RBuilder
|
||||
import react.createElement
|
||||
import react.dom.client.Root
|
||||
|
||||
public fun Root.render(block: RBuilder.() -> Unit) {
|
||||
render(createElement<Props>(block))
|
||||
}
|
@ -7,9 +7,9 @@ import kotlinx.css.width
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import kotlinx.html.js.onKeyDownFunction
|
||||
import kotlinx.html.org.w3c.dom.events.Event
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.HTMLSelectElement
|
||||
import org.w3c.dom.events.Event
|
||||
import react.FC
|
||||
import react.Props
|
||||
import react.dom.attrs
|
||||
@ -19,29 +19,27 @@ import react.useState
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||
import space.kscience.dataforge.values.ValueType
|
||||
import space.kscience.dataforge.values.asValue
|
||||
import space.kscience.dataforge.values.int
|
||||
import space.kscience.dataforge.values.string
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.widgetType
|
||||
import styled.css
|
||||
import styled.styledInput
|
||||
import styled.styledSelect
|
||||
import three.math.Color
|
||||
|
||||
public external interface ValueChooserProps : Props {
|
||||
public var descriptor: MetaDescriptor?
|
||||
public var meta: ObservableMutableMeta
|
||||
public var actual: Meta
|
||||
public var state: EditorPropertyState
|
||||
public var value: Value?
|
||||
public var onValueChange: (Value?) -> Unit
|
||||
}
|
||||
|
||||
@JsExport
|
||||
public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser") { props ->
|
||||
var value by useState(props.actual.string ?: "")
|
||||
var value by useState(props.value?.string ?: "")
|
||||
val keyDown: (Event) -> Unit = { event ->
|
||||
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
|
||||
value = (event.target as HTMLInputElement).value
|
||||
props.meta.value = value.asValue()
|
||||
props.onValueChange(value.asValue())
|
||||
}
|
||||
}
|
||||
val handleChange: (Event) -> Unit = {
|
||||
@ -63,7 +61,7 @@ public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser")
|
||||
public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser") { props ->
|
||||
val handleChange: (Event) -> Unit = {
|
||||
val newValue = (it.target as HTMLInputElement).checked
|
||||
props.meta.value = newValue.asValue()
|
||||
props.onValueChange(newValue.asValue())
|
||||
}
|
||||
styledInput(type = InputType.checkBox) {
|
||||
css {
|
||||
@ -71,7 +69,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
|
||||
}
|
||||
attrs {
|
||||
//this.attributes["indeterminate"] = (props.item == null).toString()
|
||||
checked = props.actual.boolean ?: false
|
||||
checked = props.value?.boolean ?: false
|
||||
onChangeFunction = handleChange
|
||||
}
|
||||
}
|
||||
@ -79,7 +77,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
|
||||
|
||||
@JsExport
|
||||
public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser") { props ->
|
||||
var innerValue by useState(props.actual.string ?: "")
|
||||
var innerValue by useState(props.value?.string ?: "")
|
||||
val keyDown: (Event) -> Unit = { event ->
|
||||
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
|
||||
innerValue = (event.target as HTMLInputElement).value
|
||||
@ -87,7 +85,7 @@ public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser")
|
||||
if (number == null) {
|
||||
console.error("The input value $innerValue is not a number")
|
||||
} else {
|
||||
props.meta.value = number.asValue()
|
||||
props.onValueChange(number.asValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,10 +115,10 @@ public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser")
|
||||
|
||||
@JsExport
|
||||
public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") { props ->
|
||||
var selected by useState(props.actual.string ?: "")
|
||||
var selected by useState(props.value?.string ?: "")
|
||||
val handleChange: (Event) -> Unit = {
|
||||
selected = (it.target as HTMLSelectElement).value
|
||||
props.meta.value = selected.asValue()
|
||||
props.onValueChange(selected.asValue())
|
||||
}
|
||||
styledSelect {
|
||||
css {
|
||||
@ -132,7 +130,7 @@ public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") {
|
||||
}
|
||||
}
|
||||
attrs {
|
||||
this.value = props.actual.string ?: ""
|
||||
this.value = props.value?.string ?: ""
|
||||
multiple = false
|
||||
onChangeFunction = handleChange
|
||||
}
|
||||
@ -142,7 +140,7 @@ public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") {
|
||||
@JsExport
|
||||
public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") { props ->
|
||||
val handleChange: (Event) -> Unit = {
|
||||
props.meta.value = (it.target as HTMLInputElement).value.asValue()
|
||||
props.onValueChange((it.target as HTMLInputElement).value.asValue())
|
||||
}
|
||||
styledInput(type = InputType.color) {
|
||||
css {
|
||||
@ -150,9 +148,9 @@ public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") {
|
||||
margin(0.px)
|
||||
}
|
||||
attrs {
|
||||
this.value = props.actual.value?.let { value ->
|
||||
this.value = props.value?.let { value ->
|
||||
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
|
||||
else value.string
|
||||
else "#" + Color(value.string).getHexString()
|
||||
} ?: "#000000"
|
||||
onChangeFunction = handleChange
|
||||
}
|
@ -1,24 +1,25 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.js")
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
val dataforgeVersion: String by rootProject.extra
|
||||
|
||||
kotlin{
|
||||
kscience{
|
||||
js{
|
||||
useCommonJs()
|
||||
browser {
|
||||
commonWebpackConfig {
|
||||
cssSupport.enabled = false
|
||||
cssSupport{
|
||||
enabled.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
jsMain{
|
||||
api(projects.ui.react)
|
||||
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
|
||||
|
||||
dependencies{
|
||||
api(project(":ui:react"))
|
||||
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
|
||||
|
||||
implementation(npm("core-js","3.12.1"))
|
||||
implementation(npm("file-saver", "2.0.2"))
|
||||
implementation(npm("core-js","3.12.1"))
|
||||
implementation(npm("file-saver", "2.0.2"))
|
||||
}
|
||||
}
|
@ -5,39 +5,46 @@ import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.css.*
|
||||
import react.*
|
||||
import react.dom.b
|
||||
import react.dom.div
|
||||
import react.dom.p
|
||||
import react.dom.span
|
||||
import ringui.*
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.isEmpty
|
||||
import space.kscience.dataforge.names.length
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.react.ThreeCanvasComponent
|
||||
import space.kscience.visionforge.react.flexColumn
|
||||
import space.kscience.visionforge.react.flexRow
|
||||
import space.kscience.visionforge.react.propertyEditor
|
||||
import space.kscience.visionforge.react.*
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.SolidGroup
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.solidGroup
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
public external interface ThreeCanvasWithControlsProps : Props {
|
||||
public var context: Context
|
||||
public var solids: Solids
|
||||
public var builderOfSolid: Deferred<Solid?>
|
||||
public var selected: Name?
|
||||
public var options: Canvas3DOptions?
|
||||
public var additionalTabs: Map<String, RBuilder.() -> Unit>?
|
||||
}
|
||||
|
||||
private val ThreeCanvasWithControlsProps.context get() = solids.context
|
||||
|
||||
public fun ThreeCanvasWithControlsProps.solid(block: SolidGroup.() -> Unit) {
|
||||
builderOfSolid = context.async {
|
||||
SolidGroup(block)
|
||||
solids.solidGroup(null, block)
|
||||
}
|
||||
}
|
||||
|
||||
public fun ThreeCanvasWithControlsProps.options(block: Canvas3DOptions.() -> Unit) {
|
||||
options = Canvas3DOptions(block)
|
||||
}
|
||||
|
||||
public fun ThreeCanvasWithControlsProps.tab(title: String, block: RBuilder.() -> Unit) {
|
||||
additionalTabs = (additionalTabs ?: emptyMap()) + (title to block)
|
||||
}
|
||||
@ -77,14 +84,14 @@ public fun RBuilder.nameCrumbs(name: Name?, link: (Name) -> Unit): Unit = styled
|
||||
|
||||
@JsExport
|
||||
public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("ThreeViewWithControls") { props ->
|
||||
var selected by useState { props.selected }
|
||||
var selected: Name? by useState { props.selected }
|
||||
var solid: Solid? by useState(null)
|
||||
|
||||
useEffect {
|
||||
props.context.launch {
|
||||
solid = props.builderOfSolid.await()
|
||||
//ensure that the solid is properly rooted
|
||||
if(solid?.parent == null){
|
||||
if (solid?.parent == null) {
|
||||
solid?.setAsRoot(props.context.visionManager)
|
||||
}
|
||||
}
|
||||
@ -104,7 +111,7 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
|
||||
selected?.let {
|
||||
when {
|
||||
it.isEmpty() -> solid
|
||||
else -> (solid as? VisionGroup)?.get(it)
|
||||
else -> (solid as? SolidGroup)?.get(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,12 +167,31 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
|
||||
nameCrumbs(selected) { selected = it }
|
||||
}
|
||||
IslandContent {
|
||||
propertyEditor(
|
||||
ownProperties = vision.meta,
|
||||
allProperties = vision.computeProperties(),
|
||||
descriptor = vision.descriptor,
|
||||
key = selected
|
||||
)
|
||||
child(PropertyEditor) {
|
||||
attrs {
|
||||
this.key = selected.toString()
|
||||
this.meta = vision.properties.root()
|
||||
this.updates = vision.properties.changes
|
||||
this.descriptor = vision.descriptor
|
||||
this.scope = props.context
|
||||
this.getPropertyState = { name ->
|
||||
if (vision.properties.own?.get(name) != null) {
|
||||
EditorPropertyState.Defined
|
||||
} else if (vision.properties.root()[name] != null) {
|
||||
// TODO differentiate
|
||||
EditorPropertyState.Default()
|
||||
} else {
|
||||
EditorPropertyState.Undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vision.styles.takeIf { it.isNotEmpty() }?.let { styles ->
|
||||
p {
|
||||
b { +"Styles: " }
|
||||
+styles.joinToString(separator = ", ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ package space.kscience.visionforge.ring
|
||||
|
||||
import kotlinx.coroutines.async
|
||||
import org.w3c.dom.Element
|
||||
import react.child
|
||||
import space.kscience.dataforge.context.AbstractPlugin
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.PluginFactory
|
||||
@ -12,9 +11,9 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.visionforge.ElementVisionRenderer
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.react.render
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
public val three: ThreePlugin by require(ThreePlugin)
|
||||
@ -24,11 +23,11 @@ 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) {
|
||||
react.dom.render(element) {
|
||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||
space.kscience.visionforge.react.createRoot(element).render {
|
||||
child(ThreeCanvasWithControls) {
|
||||
attrs {
|
||||
this.context = this@ThreeWithControlsPlugin.context
|
||||
this.solids = three.solids
|
||||
this.builderOfSolid = context.async { vision as Solid}
|
||||
}
|
||||
}
|
||||
@ -44,7 +43,7 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
|
||||
public companion object : PluginFactory<ThreeWithControlsPlugin> {
|
||||
override val tag: PluginTag = PluginTag("vision.threejs.withControls", PluginTag.DATAFORGE_GROUP)
|
||||
override val type: KClass<ThreeWithControlsPlugin> = ThreeWithControlsPlugin::class
|
||||
override fun invoke(meta: Meta, context: Context): ThreeWithControlsPlugin = ThreeWithControlsPlugin()
|
||||
|
||||
override fun build(context: Context, meta: Meta): ThreeWithControlsPlugin = ThreeWithControlsPlugin()
|
||||
}
|
||||
}
|
@ -3,17 +3,15 @@ package space.kscience.visionforge.ring
|
||||
import org.w3c.dom.Element
|
||||
import react.RBuilder
|
||||
import react.dom.p
|
||||
import react.dom.render
|
||||
import ringui.Island
|
||||
import ringui.SmartTabs
|
||||
import ringui.Tab
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.computeProperties
|
||||
import space.kscience.visionforge.getStyle
|
||||
import space.kscience.visionforge.react.flexColumn
|
||||
import space.kscience.visionforge.react.metaViewer
|
||||
import space.kscience.visionforge.react.propertyEditor
|
||||
import space.kscience.visionforge.react.*
|
||||
import space.kscience.visionforge.root
|
||||
import space.kscience.visionforge.solid.SolidReference
|
||||
import space.kscience.visionforge.styles
|
||||
|
||||
@ -30,12 +28,25 @@ public fun RBuilder.ringPropertyEditor(
|
||||
|
||||
flexColumn {
|
||||
Island("Properties") {
|
||||
propertyEditor(
|
||||
ownProperties = vision.meta,
|
||||
allProperties = vision.computeProperties(),
|
||||
descriptor = descriptor,
|
||||
key = key
|
||||
)
|
||||
child(PropertyEditor) {
|
||||
attrs {
|
||||
this.key = key?.toString()
|
||||
this.meta = vision.properties.root()
|
||||
this.updates = vision.properties.changes
|
||||
this.descriptor = descriptor
|
||||
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
|
||||
this.getPropertyState = {name->
|
||||
if(vision.properties.own?.get(name)!= null){
|
||||
EditorPropertyState.Defined
|
||||
} else if(vision.properties.root()[name] != null){
|
||||
// TODO differentiate
|
||||
EditorPropertyState.Default()
|
||||
} else {
|
||||
EditorPropertyState.Undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (styles.isNotEmpty()) {
|
||||
@ -72,6 +83,6 @@ public fun RBuilder.ringPropertyEditor(
|
||||
public fun Element.ringPropertyEditor(
|
||||
item: Vision,
|
||||
descriptor: MetaDescriptor? = item.descriptor,
|
||||
): Unit = render(this) {
|
||||
): Unit = createRoot(this).render {
|
||||
ringPropertyEditor(item, descriptor = descriptor)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user