New properties #34

Merged
altavir merged 19 commits from new-properties into dev 2020-12-29 13:35:01 +03:00
19 changed files with 211 additions and 140 deletions
Showing only changes of commit 56481933ed - Show all commits

View File

@ -17,5 +17,5 @@ fun main() {
} }
} }
fragment.makeFile(resourceLocation = ResourceLocation.LOCAL) fragment.makeFile(resourceLocation = ResourceLocation.SYSTEM)
} }

View File

@ -0,0 +1,37 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.fragment
import hep.dataforge.vision.three.server.makeFile
import hep.dataforge.vision.three.server.solid
import kotlinx.html.h1
import java.nio.file.Paths
import kotlin.random.Random
@OptIn(DFExperimental::class)
fun main() {
val random = Random(112233)
val fragment = VisionManager.fragment {
h1 { +"Happy new year!" }
vision {
solid {
repeat(100) {
sphere(5) {
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())
specularColor(random.nextInt())
}
detail = 16
}
}
}
}
}
fragment.makeFile(Paths.get("stars.html"), resourceLocation = ResourceLocation.EMBED)
}

View File

@ -32,7 +32,7 @@ public external interface PropertyEditorProps : RProps {
public var provider: MutableItemProvider public var provider: MutableItemProvider
/** /**
* Provide default item (greyed out if used * Provide default item (greyed out if used)
*/ */
public var defaultProvider: ItemProvider? public var defaultProvider: ItemProvider?
@ -65,11 +65,12 @@ private val PropertyEditorItem: FunctionalComponent<PropertyEditorProps> =
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) { private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
var expanded: Boolean by useState { true } var expanded: Boolean by useState { true }
val itemName = useMemo( { props.name ?: Name.EMPTY }, arrayOf(props.name)) val itemName = props.name ?: Name.EMPTY
var item: MetaItem? by useState { props.provider.getItem(itemName) }
val descriptorItem: ItemDescriptor? = val descriptorItem: ItemDescriptor? =
useMemo({ props.descriptor?.get(itemName) }, arrayOf(props.descriptor, itemName)) useMemo({ props.descriptor?.get(itemName) }, arrayOf(props.descriptor, itemName))
var item: MetaItem? by useState { props.provider.getItem(itemName) }
if (descriptorItem?.hidden == true) return //fail fast for hidden property if (descriptorItem?.hidden == true) return //fail fast for hidden property
var actualItem: MetaItem? by useState { var actualItem: MetaItem? by useState {

View File

@ -9,12 +9,10 @@ import hep.dataforge.vision.widgetType
import kotlinx.html.InputType import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onKeyDownFunction import kotlinx.html.js.onKeyDownFunction
import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.events.Event import org.w3c.dom.events.Event
import react.* import react.*
import react.dom.defaultValue
import react.dom.option import react.dom.option
import styled.styledInput import styled.styledInput
import styled.styledSelect import styled.styledSelect
@ -25,116 +23,142 @@ public external interface ValueChooserProps : RProps {
public var valueChanged: ((Value?) -> Unit)? public var valueChanged: ((Value?) -> Unit)?
} }
public external interface ValueChooserState : RState { @JsExport
public var rawInput: Boolean? public val StringValueChooser: FunctionalComponent<ValueChooserProps> =
} functionalComponent("StringValueChooser") { props ->
var value by useState(props.item.string ?: "")
val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
value = (event.target as HTMLInputElement).value
if(value!= props.item.string) {
props.valueChanged?.invoke(value.asValue())
}
}
}
val handleChange: (Event) -> Unit = {
value = (it.target as HTMLInputElement).value
}
styledInput(type = InputType.text) {
attrs {
this.value = value
onKeyDownFunction = keyDown
onChangeFunction = handleChange
}
}
}
@JsExport @JsExport
public class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserProps, ValueChooserState>(props) { public val BooleanValueChooser: FunctionalComponent<ValueChooserProps> =
private val element = createRef<HTMLElement>() functionalComponent("BooleanValueChooser") { props ->
var checkedValue by useState(props.item.boolean ?: false)
private fun getValue(): Value? { val handleChange: (Event) -> Unit = {
val element = element.current ?: return null//state.element ?: return null val newValue = (it.target as HTMLInputElement).checked
return when (element) { checkedValue = newValue
is HTMLInputElement -> if (element.type == "checkbox") { props.valueChanged?.invoke(newValue.asValue())
if (element.checked) True else False
} else {
element.value.asValue()
} }
is HTMLSelectElement -> element.value.asValue()
else -> error("Unknown event target: $element")
}
}
private val commit: (Event) -> Unit = { _ ->
props.valueChanged?.invoke(getValue())
}
private val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
commit(event)
}
}
override fun shouldComponentUpdate(
nextProps: ValueChooserProps,
nextState: ValueChooserState
): Boolean = nextProps.item !== props.item
override fun componentDidUpdate(prevProps: ValueChooserProps, prevState: ValueChooserState, snapshot: Any) {
(element.current as? HTMLInputElement)?.let { element ->
if (element.type == "checkbox") {
element.defaultChecked = props.item?.boolean ?: false
} else {
element.defaultValue = props.item?.string ?: ""
}
element.indeterminate = props.item == null
}
}
private fun RBuilder.stringInput() = styledInput(type = InputType.text) {
attrs {
this.defaultValue = props.item?.string ?: ""
onKeyDownFunction = keyDown
}
ref = element
}
override fun RBuilder.render() {
val descriptor = props.descriptor
val type = descriptor?.type?.firstOrNull()
when {
state.rawInput == true -> stringInput()
descriptor?.widgetType == "color" -> styledInput(type = InputType.color) {
ref = element
attrs {
this.defaultValue = props.item?.value?.let { value ->
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
else value.string
} ?: "#000000"
onChangeFunction = commit
}
}
type == ValueType.BOOLEAN -> {
styledInput(type = InputType.checkBox) { styledInput(type = InputType.checkBox) {
ref = element
attrs { attrs {
defaultChecked = props.item?.boolean ?: false this.attributes["indeterminate"] = (checkedValue == null).toString()
onChangeFunction = commit checked = checkedValue
onChangeFunction = handleChange
} }
} }
} }
type == ValueType.NUMBER -> styledInput(type = InputType.number) {
ref = element @JsExport
public val NumberValueChooser: FunctionalComponent<ValueChooserProps> =
functionalComponent("NumberValueChooser") { props ->
var value by useState(props.item.string ?: "")
val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
value = (event.target as HTMLInputElement).value
val number = value.toDoubleOrNull()
if (number == null) {
console.error("The input value $value is not a number")
} else {
props.valueChanged?.invoke(number.asValue())
}
}
}
val handleChange: (Event) -> Unit = {
value = (it.target as HTMLInputElement).value
}
styledInput(type = InputType.number) {
attrs { attrs {
descriptor.attributes["step"].string?.let { this.value = value
onKeyDownFunction = keyDown
onChangeFunction = handleChange
props.descriptor?.attributes?.get("step").string?.let {
step = it step = it
} }
descriptor.attributes["min"].string?.let { props.descriptor?.attributes?.get("min").string?.let {
min = it min = it
} }
descriptor.attributes["max"].string?.let { props.descriptor?.attributes?.get("max").string?.let {
max = it max = it
} }
defaultValue = props.item?.string ?: ""
onKeyDownFunction = keyDown
} }
} }
descriptor?.allowedValues?.isNotEmpty() ?: false -> styledSelect { }
descriptor!!.allowedValues.forEach {
@JsExport
public val ComboValueChooser: FunctionalComponent<ValueChooserProps> =
functionalComponent("ComboValueChooser") { props ->
var selected by useState(props.item.string ?: "")
val handleChange: (Event) -> Unit = {
selected = (it.target as HTMLSelectElement).value
props.valueChanged?.invoke(selected.asValue())
}
styledSelect {
props.descriptor?.allowedValues?.forEach {
option { option {
+it.string +it.string
} }
} }
ref = element
attrs { attrs {
this.value = props.item?.string ?: "" this.value = props.item?.string ?: ""
multiple = false multiple = false
onChangeFunction = commit onChangeFunction = handleChange
} }
} }
else -> stringInput()
} }
@JsExport
public val ColorValueChooser: FunctionalComponent<ValueChooserProps> =
functionalComponent("ColorValueChooser") { props ->
var value by useState(
props.item.value?.let { value ->
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
else value.string
} ?: "#000000"
)
val handleChange: (Event) -> Unit = {
value = (it.target as HTMLInputElement).value
props.valueChanged?.invoke(value.asValue())
}
styledInput(type = InputType.color) {
attrs {
this.value = value
onChangeFunction = handleChange
}
}
}
@JsExport
public val ValueChooser: FunctionalComponent<ValueChooserProps> = functionalComponent("ValueChooser") { props ->
val rawInput by useState(false)
val descriptor = props.descriptor
val type = descriptor?.type?.firstOrNull()
when {
rawInput -> child(StringValueChooser, props)
descriptor?.widgetType == "color" -> child(ColorValueChooser, props)
type == ValueType.BOOLEAN -> child(BooleanValueChooser, props)
type == ValueType.NUMBER -> child(NumberValueChooser, props)
descriptor?.allowedValues?.isNotEmpty() ?: false -> child(ComboValueChooser, props)
//TODO handle lists
else -> child(StringValueChooser, props)
} }
} }
@ -142,9 +166,9 @@ internal fun RBuilder.valueChooser(
name: Name, name: Name,
item: MetaItem?, item: MetaItem?,
descriptor: ValueDescriptor? = null, descriptor: ValueDescriptor? = null,
callback: (Value?) -> Unit callback: (Value?) -> Unit,
) { ) {
child(ValueChooserComponent::class) { child(ValueChooser) {
attrs { attrs {
key = name.toString() key = name.toString()
this.item = item this.item = item

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision package hep.dataforge.vision
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MutableItemProvider import hep.dataforge.meta.MutableItemProvider
@ -73,6 +74,7 @@ public interface Vision : Described {
* Flow of property invalidation events. It does not contain property values after invalidation since it is not clear * Flow of property invalidation events. It does not contain property values after invalidation since it is not clear
* if it should include inherited properties etc. * if it should include inherited properties etc.
*/ */
@DFExperimental
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
public val propertyChanges: Flow<Name> public val propertyChanges: Flow<Name>
get() = callbackFlow<Name> { get() = callbackFlow<Name> {

View File

@ -73,7 +73,7 @@ public abstract class VisionTagConsumer<R>(
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
public inline fun <T> TagConsumer<T>.vision( public inline fun <T> TagConsumer<T>.vision(
name: String, name: String = DEFAULT_VISION_NAME,
visionProvider: VisionOutput.() -> Vision, visionProvider: VisionOutput.() -> Vision,
): T = vision(name.toName(), visionProvider) ): T = vision(name.toName(), visionProvider)
@ -103,5 +103,7 @@ public abstract class VisionTagConsumer<R>(
public const val OUTPUT_NAME_ATTRIBUTE: String = "data-output-name" public const val OUTPUT_NAME_ATTRIBUTE: String = "data-output-name"
public const val OUTPUT_ENDPOINT_ATTRIBUTE: String = "data-output-endpoint" public const val OUTPUT_ENDPOINT_ATTRIBUTE: String = "data-output-endpoint"
public const val DEFAULT_ENDPOINT: String = "." public const val DEFAULT_ENDPOINT: String = "."
public const val DEFAULT_VISION_NAME = "vision"
} }
} }

View File

@ -18,9 +18,10 @@ public fun FlowContent.embedVisionFragment(
val consumer = object : VisionTagConsumer<Any?>(consumer, idPrefix) { val consumer = object : VisionTagConsumer<Any?>(consumer, idPrefix) {
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) { override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
script { script {
type = "text/json"
attributes["class"] = OUTPUT_DATA_CLASS attributes["class"] = OUTPUT_DATA_CLASS
unsafe { unsafe {
+manager.encodeToString(vision) +"\n${manager.encodeToString(vision)}\n"
} }
} }
} }

View File

@ -35,7 +35,7 @@ public enum class ResourceLocation {
EMBED EMBED
} }
internal const val DATAFORGE_ASSETS_PATH = ".dataforge/assets" internal const val VISIONFORGE_ASSETS_PATH = ".dataforge/vision/assets"
/** /**
@ -43,14 +43,14 @@ internal const val DATAFORGE_ASSETS_PATH = ".dataforge/assets"
* @param * @param
*/ */
internal fun checkOrStoreFile(basePath: Path, filePath: Path, resource: String): Path { internal fun checkOrStoreFile(basePath: Path, filePath: Path, resource: String): Path {
val fullPath = basePath.resolveSibling(filePath).toAbsolutePath() val fullPath = basePath.resolveSibling(filePath).toAbsolutePath().resolve(resource)
if (Files.exists(fullPath)) { if (Files.exists(fullPath)) {
//TODO checksum //TODO checksum
} else { } else {
//TODO add logging //TODO add logging
val bytes = VisionManager::class.java.getResourceAsStream(resource).readAllBytes() val bytes = VisionManager::class.java.getResourceAsStream("/$resource").readAllBytes()
Files.createDirectories(fullPath.parent) Files.createDirectories(fullPath.parent)
Files.write(fullPath, bytes, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE) Files.write(fullPath, bytes, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)
} }
@ -58,7 +58,7 @@ internal fun checkOrStoreFile(basePath: Path, filePath: Path, resource: String):
return if (basePath.isAbsolute && fullPath.startsWith(basePath)) { return if (basePath.isAbsolute && fullPath.startsWith(basePath)) {
basePath.relativize(fullPath) basePath.relativize(fullPath)
} else { } else {
filePath fullPath
} }
} }
@ -78,7 +78,7 @@ internal fun embedScriptHeader(resource: String): HtmlFragment = {
script { script {
type = "text/javascript" type = "text/javascript"
unsafe { unsafe {
val bytes = VisionManager::class.java.getResourceAsStream(resource).readAllBytes() val bytes = VisionManager::class.java.getResourceAsStream("/$resource").readAllBytes()
+bytes.toString(Charsets.UTF_8) +bytes.toString(Charsets.UTF_8)
} }
} }
@ -108,12 +108,12 @@ public fun Context.Companion.scriptHeader(
val targetPath = when (resourceLocation) { val targetPath = when (resourceLocation) {
ResourceLocation.LOCAL -> checkOrStoreFile( ResourceLocation.LOCAL -> checkOrStoreFile(
basePath, basePath,
Path.of(DATAFORGE_ASSETS_PATH), Path.of(VISIONFORGE_ASSETS_PATH),
scriptResource scriptResource
) )
ResourceLocation.SYSTEM -> checkOrStoreFile( ResourceLocation.SYSTEM -> checkOrStoreFile(
Path.of("."), Path.of("."),
Path.of(System.getProperty("user.home")).resolve(DATAFORGE_ASSETS_PATH), Path.of(System.getProperty("user.home")).resolve(VISIONFORGE_ASSETS_PATH),
scriptResource scriptResource
) )
ResourceLocation.EMBED -> null ResourceLocation.EMBED -> null

View File

@ -20,8 +20,10 @@ public fun HtmlVisionFragment.makeFile(
title: String = "VisionForge page", title: String = "VisionForge page",
show: Boolean = true, show: Boolean = true,
) { ) {
val actualFile = path ?: Files.createTempFile("tempPlot", ".html") val actualFile = path?.let {
Files.createDirectories(actualFile.parent) Path.of(System.getProperty("user.home")).resolve(path)
} ?: Files.createTempFile("tempPlot", ".html")
//Files.createDirectories(actualFile.parent)
val htmlString = createHTML().apply { val htmlString = createHTML().apply {
head { head {
meta { meta {

View File

@ -130,7 +130,7 @@ class FX3DPlugin : AbstractPlugin() {
} }
companion object : PluginFactory<FX3DPlugin> { companion object : PluginFactory<FX3DPlugin> {
override val tag = PluginTag("visual.fx3D", PluginTag.DATAFORGE_GROUP) override val tag = PluginTag("vision.fx3D", PluginTag.DATAFORGE_GROUP)
override val type = FX3DPlugin::class override val type = FX3DPlugin::class
override fun invoke(meta: Meta, context: Context) = FX3DPlugin() override fun invoke(meta: Meta, context: Context) = FX3DPlugin()
} }

View File

@ -44,13 +44,13 @@ public interface Solid : Vision {
public val Y_POSITION_KEY: Name = POSITION_KEY + Y_KEY public val Y_POSITION_KEY: Name = POSITION_KEY + Y_KEY
public val Z_POSITION_KEY: Name = POSITION_KEY + Z_KEY public val Z_POSITION_KEY: Name = POSITION_KEY + Z_KEY
public val ROTATION: Name = "rotation".asName() public val ROTATION_KEY: Name = "rotation".asName()
public val X_ROTATION_KEY: Name = ROTATION + X_KEY public val X_ROTATION_KEY: Name = ROTATION_KEY + X_KEY
public val Y_ROTATION_KEY: Name = ROTATION + Y_KEY public val Y_ROTATION_KEY: Name = ROTATION_KEY + Y_KEY
public val Z_ROTATION_KEY: Name = ROTATION + Z_KEY public val Z_ROTATION_KEY: Name = ROTATION_KEY + Z_KEY
public val ROTATION_ORDER_KEY: Name = ROTATION + "order" public val ROTATION_ORDER_KEY: Name = ROTATION_KEY + "order"
public val SCALE_KEY: Name = "scale".asName() public val SCALE_KEY: Name = "scale".asName()

View File

@ -35,6 +35,6 @@ internal fun Meta.toVector(default: Float = 0f) = Point3D(
internal fun Solid.updatePosition(meta: Meta?) { internal fun Solid.updatePosition(meta: Meta?) {
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it } meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
meta[Solid.ROTATION].node?.toVector()?.let { rotation = it } meta[Solid.ROTATION_KEY].node?.toVector()?.let { rotation = it }
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it } meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
} }

View File

@ -33,7 +33,7 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
} }
public companion object : PluginFactory<SolidManager> { public companion object : PluginFactory<SolidManager> {
override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP) override val tag: PluginTag = PluginTag(name = "vision.solid", group = PluginTag.DATAFORGE_GROUP)
override val type: KClass<out SolidManager> = SolidManager::class override val type: KClass<out SolidManager> = SolidManager::class
override fun invoke(meta: Meta, context: Context): SolidManager = SolidManager(meta) override fun invoke(meta: Meta, context: Context): SolidManager = SolidManager(meta)

View File

@ -19,12 +19,12 @@ public class SolidMaterial : Scheme() {
/** /**
* Primary web-color for the material * Primary web-color for the material
*/ */
public var color: ColorAccessor = ColorAccessor(this, COLOR_KEY) public val color: ColorAccessor = ColorAccessor(this, COLOR_KEY)
/** /**
* Specular color for phong material * Specular color for phong material
*/ */
public var specularColor: ColorAccessor = ColorAccessor(this, SPECULAR_COLOR_KEY) public val specularColor: ColorAccessor = ColorAccessor(this, SPECULAR_COLOR_KEY)
/** /**
* Opacity * Opacity

View File

@ -1,9 +1,12 @@
package hep.dataforge.vision.solid.specifications package hep.dataforge.vision.solid.specifications
import hep.dataforge.meta.* import hep.dataforge.meta.Scheme
import hep.dataforge.meta.SchemeSpec
import hep.dataforge.meta.boolean
import hep.dataforge.meta.double
public class Axes : Scheme() { public class Axes : Scheme() {
public var visible: Boolean by boolean(rootNode?.isEmpty() != false) public var visible: Boolean by boolean(false)
public var size: Double by double(AXIS_SIZE) public var size: Double by double(AXIS_SIZE)
public var width: Double by double(AXIS_WIDTH) public var width: Double by double(AXIS_WIDTH)

View File

@ -20,6 +20,7 @@ import info.laht.threekt.external.controls.OrbitControls
import info.laht.threekt.external.controls.TrackballControls import info.laht.threekt.external.controls.TrackballControls
import info.laht.threekt.geometries.EdgesGeometry import info.laht.threekt.geometries.EdgesGeometry
import info.laht.threekt.helpers.AxesHelper import info.laht.threekt.helpers.AxesHelper
import info.laht.threekt.lights.AmbientLight
import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.LineBasicMaterial
import info.laht.threekt.math.Vector2 import info.laht.threekt.math.Vector2
import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.LineSegments
@ -50,8 +51,11 @@ public class ThreeCanvas(
public var axes: AxesHelper = AxesHelper(options.axes.size.toInt()).apply { visible = options.axes.visible } public var axes: AxesHelper = AxesHelper(options.axes.size.toInt()).apply { visible = options.axes.visible }
private set private set
private val light = AmbientLight(0x404040)
private val scene: Scene = Scene().apply { private val scene: Scene = Scene().apply {
add(axes) add(axes)
add(light)
} }
public var camera: PerspectiveCamera = buildCamera(options.camera) public var camera: PerspectiveCamera = buildCamera(options.camera)
@ -66,6 +70,7 @@ public class ThreeCanvas(
} }
private val canvas = (renderer.domElement as HTMLCanvasElement).apply { private val canvas = (renderer.domElement as HTMLCanvasElement).apply {
className += "three-canvas"
width = 600 width = 600
height = 600 height = 600
style.apply { style.apply {
@ -131,7 +136,7 @@ public class ThreeCanvas(
} }
internal fun attach(element: Element) { internal fun attach(element: Element) {
check(element.children.length == 0){"The element for Three canvas is not empty"} check(element.getElementsByClassName("three-canvas").length == 0){"Three canvas already created in this element"}
element.appendChild(canvas) element.appendChild(canvas)
updateSize() updateSize()
} }

View File

@ -49,7 +49,7 @@ public fun Object3D.updateProperty(source: Vision, propertyName: Name) {
updateMaterialProperty(source, propertyName) updateMaterialProperty(source, propertyName)
} else if ( } else if (
propertyName.startsWith(Solid.POSITION_KEY) propertyName.startsWith(Solid.POSITION_KEY)
|| propertyName.startsWith(Solid.ROTATION) || propertyName.startsWith(Solid.ROTATION_KEY)
|| propertyName.startsWith(Solid.SCALE_KEY) || propertyName.startsWith(Solid.SCALE_KEY)
) { ) {
//update position of mesh using this object //update position of mesh using this object

View File

@ -70,7 +70,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
obj.onPropertyChange(updateScope) { name -> obj.onPropertyChange(updateScope) { name ->
if ( if (
name.startsWith(Solid.POSITION_KEY) || name.startsWith(Solid.POSITION_KEY) ||
name.startsWith(Solid.ROTATION) || name.startsWith(Solid.ROTATION_KEY) ||
name.startsWith(Solid.SCALE_KEY) name.startsWith(Solid.SCALE_KEY)
) { ) {
//update position of mesh using this object //update position of mesh using this object
@ -81,14 +81,6 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
} }
obj.structureChanges.onEach { (nameToken, _, child) -> obj.structureChanges.onEach { (nameToken, _, child) ->
// if (name.isEmpty()) {
// logger.error { "Children change with empty name on $group" }
// return@onChildrenChange
// }
// val parentName = name.cutLast()
// val childName = name.last()!!
//removing old object //removing old object
findChild(nameToken.asName())?.let { oldChild -> findChild(nameToken.asName())?.let { oldChild ->
oldChild.parent?.remove(oldChild) oldChild.parent?.remove(oldChild)
@ -153,7 +145,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
} }
public companion object : PluginFactory<ThreePlugin> { public companion object : PluginFactory<ThreePlugin> {
override val tag: PluginTag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP) override val tag: PluginTag = PluginTag("vision.threejs", PluginTag.DATAFORGE_GROUP)
override val type: KClass<ThreePlugin> = ThreePlugin::class override val type: KClass<ThreePlugin> = ThreePlugin::class
override fun invoke(meta: Meta, context: Context): ThreePlugin = ThreePlugin() override fun invoke(meta: Meta, context: Context): ThreePlugin = ThreePlugin()
} }

View File

@ -39,7 +39,9 @@ public fun HtmlVisionFragment.makeFile(
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM, resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true, show: Boolean = true,
) { ) {
val actualPath = path ?: Files.createTempFile("tempPlot", ".html") val actualPath = path?.let {
val scriptHeader = Context.scriptHeader("/js/visionforge-three.js", actualPath, resourceLocation) Path.of(System.getProperty("user.home")).resolve(path)
} ?: Files.createTempFile("tempPlot", ".html")
val scriptHeader = Context.scriptHeader("js/visionforge-three.js", actualPath, resourceLocation)
makeFile(visionManager, path = path, show = show, title = title, headers = arrayOf(scriptHeader)) makeFile(visionManager, path = path, show = show, title = title, headers = arrayOf(scriptHeader))
} }