forked from kscience/visionforge
Static export fix
This commit is contained in:
parent
1e183107cf
commit
56481933ed
@ -17,5 +17,5 @@ fun main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment.makeFile(resourceLocation = ResourceLocation.LOCAL)
|
fragment.makeFile(resourceLocation = ResourceLocation.SYSTEM)
|
||||||
}
|
}
|
@ -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)
|
||||||
|
}
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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> {
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user