Fix Plotly issues after refactoring
This commit is contained in:
@@ -3,6 +3,7 @@ kotlin.mpp.stability.nowarn=true
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
org.gradle.workers.max=4
|
||||
|
||||
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
|
||||
kotlin.native.enableKlibsCrossCompilation=true
|
||||
|
||||
@@ -15,20 +15,24 @@ import dev.datlag.kcef.KCEF
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
private val allowedPages = listOf(
|
||||
"Static",
|
||||
"Dynamic"
|
||||
)
|
||||
|
||||
val port = 7778
|
||||
|
||||
@Composable
|
||||
fun App() {
|
||||
var downloadProgress by remember { mutableStateOf(-1F) }
|
||||
var initialized by remember { mutableStateOf(false) } // if true, KCEF can be used to create clients, browsers etc
|
||||
|
||||
val scaleFlow = remember { MutableStateFlow(1f) }
|
||||
val scale by scaleFlow.collectAsState()
|
||||
val scope = rememberCoroutineScope()
|
||||
val server = remember {
|
||||
scope.servePlots(scaleFlow)
|
||||
scope.servePlots(scaleFlow, port)
|
||||
}
|
||||
|
||||
val state = rememberWebViewStateWithHTMLData(staticPlot())
|
||||
@@ -43,12 +47,50 @@ fun App() {
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) { // IO scope recommended but not required
|
||||
KCEF.init(
|
||||
builder = {
|
||||
progress {
|
||||
onDownloading {
|
||||
downloadProgress = it
|
||||
println("Downloading $it")
|
||||
// use this if you want to display a download progress for example
|
||||
}
|
||||
onInitialized {
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
},
|
||||
onError = {
|
||||
// error during initialization
|
||||
it?.printStackTrace()
|
||||
},
|
||||
onRestartRequired = {
|
||||
// all required CEF packages downloaded but the application needs a restart to load them (unlikely to happen)
|
||||
println("Restart required")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
KCEF.disposeBlocking()
|
||||
server.stop()
|
||||
}
|
||||
}
|
||||
|
||||
Row(Modifier.fillMaxSize()) {
|
||||
Column(Modifier.width(300.dp)) {
|
||||
Button({ navigator.loadHtml(staticPlot()) }, modifier = Modifier.fillMaxWidth()) {
|
||||
Button({
|
||||
val html = staticPlot()
|
||||
println(html)
|
||||
navigator.loadHtml(html)
|
||||
}, modifier = Modifier.fillMaxWidth()) {
|
||||
Text("Static")
|
||||
}
|
||||
Button({ navigator.loadUrl("http://localhost:7778/Dynamic") }, modifier = Modifier.fillMaxWidth()) {
|
||||
Button({ navigator.loadUrl("http://localhost:$port/Dynamic") }, modifier = Modifier.fillMaxWidth()) {
|
||||
Text("Dynamic")
|
||||
}
|
||||
|
||||
@@ -61,60 +103,25 @@ fun App() {
|
||||
}
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
|
||||
WebView(
|
||||
state = state,
|
||||
navigator = navigator,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
|
||||
if (initialized) {
|
||||
WebView(
|
||||
state = state,
|
||||
navigator = navigator,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
} else {
|
||||
Text("Downloading CEF: ${downloadProgress}%")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main() = application {
|
||||
Window(onCloseRequest = ::exitApplication) {
|
||||
var downloadProgress by remember { mutableStateOf(-1F) }
|
||||
var initialized by remember { mutableStateOf(false) } // if true, KCEF can be used to create clients, browsers etc
|
||||
val bundleLocation = System.getProperty("compose.application.resources.dir")?.let { File(it) } ?: File(".")
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) { // IO scope recommended but not required
|
||||
KCEF.init(
|
||||
builder = {
|
||||
installDir(File(bundleLocation, "kcef-bundle")) // recommended, but not necessary
|
||||
|
||||
progress {
|
||||
onDownloading {
|
||||
downloadProgress = it
|
||||
println("Downloading $it")
|
||||
// use this if you want to display a download progress for example
|
||||
}
|
||||
onInitialized {
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
},
|
||||
onError = {
|
||||
// error during initialization
|
||||
it?.printStackTrace()
|
||||
},
|
||||
onRestartRequired = {
|
||||
// all required CEF packages downloaded but the application needs a restart to load them (unlikely to happen)
|
||||
println("Restart required")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
MaterialTheme {
|
||||
App()
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
KCEF.disposeBlocking()
|
||||
}
|
||||
MaterialTheme {
|
||||
App()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import kotlinx.coroutines.launch
|
||||
import space.kscience.plotly.*
|
||||
import space.kscience.plotly.models.Scatter
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.makeString
|
||||
import space.kscience.visionforge.plotly.plotlyPage
|
||||
import kotlin.math.PI
|
||||
@@ -31,7 +32,7 @@ public fun Scatter(
|
||||
}
|
||||
|
||||
|
||||
fun staticPlot(): String = Plotly.page {
|
||||
internal fun staticPlot(): String = Plotly.plugin.visionManager.VisionPage(cdnPlotlyHeader) {
|
||||
val x = (0..100).map { it.toDouble() / 100.0 }.toDoubleArray()
|
||||
val y1 = x.map { sin(2.0 * PI * it) }.toDoubleArray()
|
||||
val y2 = x.map { cos(2.0 * PI * it) }.toDoubleArray()
|
||||
@@ -41,19 +42,17 @@ fun staticPlot(): String = Plotly.page {
|
||||
val trace2 = Scatter(x, y2) {
|
||||
name = "cos"
|
||||
}
|
||||
vision {
|
||||
plotly(config = PlotlyConfig { responsive = true }) {//static plot
|
||||
traces(trace1, trace2)
|
||||
layout {
|
||||
title = "First graph, row: 1, size: 8/12"
|
||||
xaxis.title = "x axis name"
|
||||
yaxis { title = "y axis name" }
|
||||
}
|
||||
staticPlot {
|
||||
traces(trace1, trace2)
|
||||
layout {
|
||||
title = "First graph, row: 1, size: 8/12"
|
||||
xaxis.title = "x axis name"
|
||||
yaxis { title = "y axis name" }
|
||||
}
|
||||
}
|
||||
}.makeString()
|
||||
|
||||
fun CoroutineScope.servePlots(scale: StateFlow<Number>): EmbeddedServer<*, *> = embeddedServer(CIO, port = 7777) {
|
||||
fun CoroutineScope.servePlots(scale: StateFlow<Number>, port: Int = 7778): EmbeddedServer<*, *> = embeddedServer(CIO, port = port) {
|
||||
|
||||
val x = (0..100).map { it.toDouble() / 100.0 }.toDoubleArray()
|
||||
|
||||
@@ -107,5 +106,5 @@ fun CoroutineScope.servePlots(scale: StateFlow<Number>): EmbeddedServer<*, *> =
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@ package contour
|
||||
|
||||
import space.kscience.plotly.Plotly
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.makePageFile
|
||||
import space.kscience.plotly.models.Contour
|
||||
import space.kscience.plotly.models.invoke
|
||||
import space.kscience.plotly.page
|
||||
import space.kscience.plotly.plot
|
||||
import space.kscience.visionforge.html.openInBrowser
|
||||
|
||||
|
||||
/**
|
||||
@@ -43,7 +42,7 @@ fun main() {
|
||||
connectgaps = true
|
||||
}
|
||||
|
||||
Plotly.page {
|
||||
Plotly.makePageFile {
|
||||
plot {
|
||||
traces(contour1)
|
||||
layout {
|
||||
@@ -61,5 +60,5 @@ fun main() {
|
||||
title = "Connected Gaps"
|
||||
}
|
||||
}
|
||||
}.openInBrowser()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import kotlinx.html.div
|
||||
import kotlinx.html.h1
|
||||
import kotlinx.html.hr
|
||||
import space.kscience.plotly.Plotly
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.*
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.plotly.models.invoke
|
||||
import space.kscience.plotly.page
|
||||
import space.kscience.plotly.staticPlot
|
||||
import space.kscience.visionforge.html.openInBrowser
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
@@ -21,8 +17,8 @@ fun main() {
|
||||
val trace1 = Trace(x1, y1) { name = "sin" }
|
||||
val trace2 = Trace(x1, y2) { name = "cos" }
|
||||
|
||||
Plotly.page {
|
||||
staticPlot{
|
||||
Plotly.makePageFile {
|
||||
plot {
|
||||
traces(trace1, trace2)
|
||||
layout {
|
||||
title = "The plot above"
|
||||
@@ -43,5 +39,5 @@ fun main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}.openInBrowser()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import space.kscience.plotly.*
|
||||
import space.kscience.plotly.models.ScatterMode
|
||||
import space.kscience.plotly.models.scatter
|
||||
import space.kscience.visionforge.html.openInBrowser
|
||||
|
||||
|
||||
/**
|
||||
@@ -9,7 +8,7 @@ import space.kscience.visionforge.html.openInBrowser
|
||||
* - Download plot as SVG using configuration button
|
||||
*/
|
||||
fun main() {
|
||||
val fragment = Plotly.page {
|
||||
Plotly.makePageFile {
|
||||
val plotConfig = PlotlyConfig{
|
||||
saveAsSvg()
|
||||
}
|
||||
@@ -34,5 +33,4 @@ fun main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
fragment.openInBrowser()
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import space.kscience.dataforge.meta.invoke
|
||||
import space.kscience.plotly.Plotly
|
||||
import space.kscience.plotly.ResourceLocation
|
||||
import space.kscience.plotly.openInBrowser
|
||||
import space.kscience.plotly.trace
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.sin
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ private class PlotGrid {
|
||||
|
||||
private fun Plotly.grid(block: PlotGrid.() -> Unit): VisionPage {
|
||||
val grid = PlotGrid().apply(block)
|
||||
return page(cdnBootstrap, cdnPlotlyHeader) {
|
||||
return plugin.visionManager.VisionPage(cdnBootstrap, cdnPlotlyHeader) {
|
||||
div("col") {
|
||||
grid.grid.forEach { row ->
|
||||
div("row") {
|
||||
|
||||
@@ -2,11 +2,10 @@ package heatmap
|
||||
|
||||
import space.kscience.plotly.Plotly
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.makePageFile
|
||||
import space.kscience.plotly.models.Heatmap
|
||||
import space.kscience.plotly.models.invoke
|
||||
import space.kscience.plotly.page
|
||||
import space.kscience.plotly.plot
|
||||
import space.kscience.visionforge.html.openInBrowser
|
||||
|
||||
|
||||
/**
|
||||
@@ -43,7 +42,7 @@ fun main() {
|
||||
connectgaps = true
|
||||
}
|
||||
|
||||
Plotly.page {
|
||||
Plotly.makePageFile {
|
||||
plot {
|
||||
traces(heatmap1)
|
||||
layout {
|
||||
@@ -61,5 +60,5 @@ fun main() {
|
||||
title = "Connected Gaps"
|
||||
}
|
||||
}
|
||||
}.openInBrowser()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@ package pie
|
||||
|
||||
import space.kscience.plotly.Plotly
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.makePageFile
|
||||
import space.kscience.plotly.models.Pie
|
||||
import space.kscience.plotly.models.invoke
|
||||
import space.kscience.plotly.page
|
||||
import space.kscience.plotly.plot
|
||||
import space.kscience.visionforge.html.openInBrowser
|
||||
|
||||
|
||||
fun main() {
|
||||
@@ -22,7 +21,7 @@ fun main() {
|
||||
hole = 0.4
|
||||
}
|
||||
|
||||
Plotly.page {
|
||||
Plotly.makePageFile {
|
||||
plot {
|
||||
traces(donut1)
|
||||
|
||||
@@ -42,5 +41,5 @@ fun main() {
|
||||
title = "CO2"
|
||||
}
|
||||
}
|
||||
}.openInBrowser()
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,10 @@ import space.kscience.plotly.*
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.plotly.models.invoke
|
||||
import space.kscience.plotly.palettes.T10
|
||||
import space.kscience.visionforge.html.*
|
||||
import space.kscience.visionforge.html.HtmlFragment
|
||||
import space.kscience.visionforge.html.VisionPage
|
||||
import space.kscience.visionforge.html.appendTo
|
||||
import space.kscience.visionforge.html.openInBrowser
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
@@ -29,12 +32,12 @@ public val cdnBootstrap: HtmlFragment = HtmlFragment {
|
||||
|
||||
|
||||
public class PlotTabs {
|
||||
public data class Tab(val title: String, val id: String, val content: HtmlVisionFragment)
|
||||
public data class Tab(val title: String, val id: String, val content: HtmlFragment)
|
||||
|
||||
private val _tabs = ArrayList<Tab>()
|
||||
public val tabs: List<Tab> get() = _tabs
|
||||
|
||||
public fun tab(title: String, id: String = title, fragment: HtmlVisionFragment) {
|
||||
public fun tab(title: String, id: String = title, fragment: HtmlFragment) {
|
||||
_tabs.add(Tab(title, id, fragment))
|
||||
}
|
||||
}
|
||||
@@ -42,7 +45,7 @@ public class PlotTabs {
|
||||
public fun Plotly.tabs(tabsID: String = "tabs", block: PlotTabs.() -> Unit): VisionPage {
|
||||
val grid = PlotTabs().apply(block)
|
||||
|
||||
return page(cdnBootstrap, cdnPlotlyHeader) {
|
||||
return plugin.visionManager.VisionPage(cdnBootstrap, cdnPlotlyHeader) {
|
||||
ul("nav nav-tabs") {
|
||||
role = "tablist"
|
||||
id = tabsID
|
||||
@@ -73,7 +76,7 @@ public fun Plotly.tabs(tabsID: String = "tabs", block: PlotTabs.() -> Unit): Vis
|
||||
id = tab.id
|
||||
role = "tabpanel"
|
||||
attributes["aria-labelledby"] = "${tab.id}-tab"
|
||||
visionFragment(visionManager, fragment = tab.content)
|
||||
tab.content.appendTo(consumer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,10 +108,10 @@ fun main() {
|
||||
responsive = true
|
||||
}
|
||||
|
||||
val plot = Plotly.tabs {
|
||||
val page = Plotly.tabs {
|
||||
|
||||
tab("First") {
|
||||
plot(config = responsive) {
|
||||
staticPlot(config = responsive) {
|
||||
traces(trace1)
|
||||
layout {
|
||||
title = "First graph"
|
||||
@@ -118,7 +121,7 @@ fun main() {
|
||||
}
|
||||
}
|
||||
tab("Second") {
|
||||
plot(config = responsive) {
|
||||
staticPlot(config = responsive) {
|
||||
traces(trace2)
|
||||
layout {
|
||||
title = "Second graph"
|
||||
@@ -129,5 +132,5 @@ fun main() {
|
||||
}
|
||||
}
|
||||
|
||||
plot.openInBrowser()
|
||||
page.openInBrowser()
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import space.kscience.dataforge.meta.Value
|
||||
import space.kscience.plotly.*
|
||||
import space.kscience.plotly.models.*
|
||||
import space.kscience.plotly.palettes.Xkcd
|
||||
import space.kscience.visionforge.html.openInBrowser
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.sin
|
||||
|
||||
@@ -42,7 +41,7 @@ fun main() {
|
||||
}
|
||||
}
|
||||
|
||||
Plotly.page(mathJaxHeader, cdnPlotlyHeader) {
|
||||
Plotly.makePageFile(additionalHeaders = mapOf("mathJax" to mathJaxHeader)) {
|
||||
plot {
|
||||
scatter { // sinus
|
||||
x.set(xValues)
|
||||
@@ -152,5 +151,5 @@ fun main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}.openInBrowser()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package space.kscience.plotly
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
@@ -21,6 +22,7 @@ import space.kscience.visionforge.*
|
||||
@Serializable
|
||||
public class Plot : AbstractVision(), MutableVisionGroup<Trace> {
|
||||
|
||||
@SerialName("data")
|
||||
private val _data = mutableListOf<Trace>()
|
||||
public val data: List<Trace> get() = _data
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.html.*
|
||||
import kotlin.js.JsName
|
||||
|
||||
@@ -93,24 +92,6 @@ public inline fun VisionOutput.plotly(
|
||||
return Plotly.plot(block)
|
||||
}
|
||||
|
||||
public fun Plotly.page(
|
||||
pageHeaders: Map<String, HtmlFragment> = emptyMap(),
|
||||
content: HtmlVisionFragment,
|
||||
): VisionPage = VisionPage(
|
||||
visionManager = context.request(VisionManager),
|
||||
pageHeaders = mapOf("plotly" to cdnPlotlyHeader) + pageHeaders,
|
||||
content = content
|
||||
)
|
||||
|
||||
public fun Plotly.page(
|
||||
vararg pageHeaders: HtmlFragment,
|
||||
content: HtmlVisionFragment,
|
||||
): VisionPage = VisionPage(
|
||||
visionManager = context.request(VisionManager),
|
||||
pageHeaders = mapOf("plotly" to cdnPlotlyHeader) + pageHeaders.associateBy { it.toString() },
|
||||
content = content
|
||||
)
|
||||
|
||||
context(rootConsumer: VisionTagConsumer<*>)
|
||||
public fun TagConsumer<*>.plot(
|
||||
config: PlotlyConfig = PlotlyConfig(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package space.kscience.plotly
|
||||
|
||||
import space.kscience.visionforge.html.HtmlFragment
|
||||
import space.kscience.visionforge.html.*
|
||||
import space.kscience.visionforge.visionManager
|
||||
import java.awt.Desktop
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
@@ -10,31 +11,6 @@ import javax.swing.filechooser.FileNameExtensionFilter
|
||||
|
||||
internal const val assetsDirectory = "assets"
|
||||
|
||||
/**
|
||||
* The location of resources for plot.
|
||||
*/
|
||||
public enum class ResourceLocation {
|
||||
/**
|
||||
* Use cdn or other remote source for assets
|
||||
*/
|
||||
REMOTE,
|
||||
|
||||
/**
|
||||
* Store assets in a sibling folder `plotly-assets` or in a system-wide folder if this is a default temporary file
|
||||
*/
|
||||
LOCAL,
|
||||
|
||||
/**
|
||||
* Store assets in a system-window `~/.plotly/plotly-assets` folder
|
||||
*/
|
||||
SYSTEM,
|
||||
|
||||
/**
|
||||
* Embed the asset into the html. Could produce very large files.
|
||||
*/
|
||||
EMBED
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a standalone html with the plot
|
||||
* @param path the reference to html file. If null, create a temporary file
|
||||
@@ -61,6 +37,28 @@ public fun Plot.openInBrowser(
|
||||
Desktop.getDesktop().browse(path.toFile().toURI())
|
||||
}
|
||||
|
||||
public fun Plotly.makePageFile(
|
||||
path: Path? = null,
|
||||
title: String = "VisionForge Plotly page",
|
||||
additionalHeaders: Map<String, HtmlFragment> = emptyMap(),
|
||||
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
|
||||
show: Boolean = true,
|
||||
content: HtmlVisionFragment,
|
||||
): Path {
|
||||
val actualPath = VisionPage(context.visionManager, content = content).makeFile(path) { actualPath ->
|
||||
mapOf(
|
||||
"title" to VisionPage.title(title),
|
||||
"plotly" to VisionPage.importScriptHeader(
|
||||
"js/plotly-kt.js",
|
||||
resourceLocation,
|
||||
actualPath
|
||||
),
|
||||
) + additionalHeaders
|
||||
}
|
||||
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
|
||||
return actualPath
|
||||
}
|
||||
|
||||
///**
|
||||
// * The same as [Plot.makeFile].
|
||||
// */
|
||||
|
||||
@@ -4,6 +4,7 @@ import kotlinx.html.link
|
||||
import kotlinx.html.script
|
||||
import kotlinx.html.unsafe
|
||||
import space.kscience.visionforge.html.HtmlFragment
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardOpenOption
|
||||
@@ -107,14 +108,15 @@ internal val embededPlotlyHeader = HtmlFragment {
|
||||
|
||||
internal fun inferPlotlyHeader(
|
||||
target: Path?,
|
||||
resourceLocation: ResourceLocation
|
||||
resourceLocation: ResourceLocation?
|
||||
): HtmlFragment = when (resourceLocation) {
|
||||
ResourceLocation.REMOTE -> cdnPlotlyHeader
|
||||
null -> cdnPlotlyHeader
|
||||
ResourceLocation.LOCAL -> if (target != null) {
|
||||
localPlotlyHeader(target)
|
||||
} else {
|
||||
systemPlotlyHeader
|
||||
}
|
||||
|
||||
ResourceLocation.SYSTEM -> systemPlotlyHeader
|
||||
ResourceLocation.EMBED -> embededPlotlyHeader
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ public data class VisionPage(
|
||||
public val pageHeaders: Map<String, HtmlFragment> = emptyMap(),
|
||||
public val content: HtmlVisionFragment,
|
||||
) {
|
||||
public companion object{
|
||||
public companion object {
|
||||
/**
|
||||
* Use a script with given [src] as a global header for all pages.
|
||||
*/
|
||||
public fun scriptHeader(src: String, block: SCRIPT.() -> Unit = {}): HtmlFragment = HtmlFragment{
|
||||
public fun scriptHeader(src: String, block: SCRIPT.() -> Unit = {}): HtmlFragment = HtmlFragment {
|
||||
script {
|
||||
type = "text/javascript"
|
||||
this.src = src
|
||||
@@ -28,7 +28,7 @@ public data class VisionPage(
|
||||
/**
|
||||
* Use css with the given stylesheet link as a global header for all pages.
|
||||
*/
|
||||
public fun styleSheetHeader(href: String, block: LINK.() -> Unit = {}): HtmlFragment = HtmlFragment{
|
||||
public fun styleSheetHeader(href: String, block: LINK.() -> Unit = {}): HtmlFragment = HtmlFragment {
|
||||
link {
|
||||
rel = "stylesheet"
|
||||
this.href = href
|
||||
@@ -36,8 +36,13 @@ public data class VisionPage(
|
||||
}
|
||||
}
|
||||
|
||||
public fun title(title:String): HtmlFragment = HtmlFragment{
|
||||
public fun title(title: String): HtmlFragment = HtmlFragment {
|
||||
title(title)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun VisionManager.VisionPage(
|
||||
vararg headers: HtmlFragment,
|
||||
content: HtmlVisionFragment
|
||||
): VisionPage = VisionPage(this, headers.associateBy { it.toString() }, content)
|
||||
@@ -2,6 +2,7 @@ package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.html.body
|
||||
import kotlinx.html.head
|
||||
import kotlinx.html.html
|
||||
import kotlinx.html.meta
|
||||
import kotlinx.html.stream.createHTML
|
||||
import java.awt.Desktop
|
||||
@@ -11,18 +12,22 @@ import java.nio.file.Path
|
||||
/**
|
||||
* Render given [VisionPage] to a string using a set of [additionalHeaders] that override current page headers.
|
||||
*/
|
||||
public fun VisionPage.makeString(additionalHeaders: Map<String, HtmlFragment> = emptyMap()): String = createHTML().apply {
|
||||
head {
|
||||
meta {
|
||||
charset = "utf-8"
|
||||
public fun VisionPage.makeString(
|
||||
additionalHeaders: Map<String, HtmlFragment> = emptyMap()
|
||||
): String = "<!DOCTYPE html>\n" + createHTML().apply {
|
||||
html {
|
||||
head {
|
||||
meta {
|
||||
charset = "utf-8"
|
||||
}
|
||||
(pageHeaders + additionalHeaders).values.forEach {
|
||||
appendFragment(it)
|
||||
}
|
||||
}
|
||||
(pageHeaders + additionalHeaders).values.forEach {
|
||||
appendFragment(it)
|
||||
body {
|
||||
visionFragment(visionManager, fragment = content)
|
||||
}
|
||||
}
|
||||
body {
|
||||
visionFragment(visionManager, fragment = content)
|
||||
}
|
||||
}.finalize()
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user