There are some good ideas here in the thread, but I think the best way of doing this goes like this:
using WGLMakie, Bonito
# Maybe should be in bonito?
function as_html(io, session, app)
dom = Bonito.session_dom(session, app)
show(io, MIME"text/html"(), Bonito.Pretty(dom))
end
# For a single plot, we can just do this:
open("test.html", "w") do io
# Do you own header etc
println(io, "<!doctype html>")
app = App(contour(rand(10, 10, 10)))
# Page(exportable=true, offline=true) creates pretty much just the below Session
session = Session(NoConnection(); asset_server=NoServer())
# This should only create a `div` with all imports and the plot:
as_html(io, session, app)
end
For multiple plots, we need to use a Subsession, which skips uploading similar assets/data and setup.
This is pretty much what Page
does, but for direct export, Page is a bit cumbersome to work with, so I recommend just creating the subsession manually:
open("test.html", "w") do io
println(io, "<!doctype html>")
app = App(contour(rand(10, 10, 10)))
# Page(exportable=true, offline=true) creates pretty much just the below Session
session = Session(NoConnection(); asset_server=NoServer())
println(io, "<h2>First plot</h2>")
as_html(io, session, app)
app2 = App(volume(rand(10, 10, 10)))
# Create a new session with the same connection, but skip uploading assets/data
println(io, "<h2>Second plot</h2>")
sub = Session(session)
as_html(io, sub, app2)
end
If you use a static site, which supports serving files (like github.io), you can also use Bonito.AssetFolder
, instead of NoServer()
.
NoServer uses Base64 encoded urls for all assets, which is slower and leads to worse stack traces, while AssetFolder writes out all dependencies and uses relative urls to include them:
root = "root-of-server"
mkdir(root)
# First argument is the root of the server
# Second argument is the location of the current html file that gets exported
# Which is required for generating urls for assets correctly
# e.g. you could want to generate `/root/plots/plot.html`, then the second argument would need to be
# "root-of-server/plots"
asset_server = Bonito.AssetFolder(root, root)
open(joinpath(root, "index.html"), "w") do io
println(io, "<!doctype html>")
app = App(contour(rand(10, 10, 10)))
# Page(exportable=true, offline=true) creates pretty much just the below Session
session = Session(NoConnection(); asset_server=asset_server)
println(io, "<h2>First plot</h2>")
as_html(io, session, app)
app2 = App(volume(rand(10, 10, 10)))
# Create a new session with the same connection, but skip uploading assets/data
println(io, "<h2>Second plot</h2>")
sub = Session(session)
as_html(io, sub, app2)
end
You will see that a few files and folders are created in the root folder, which contain the assets used by index.html
. The index.html
then uses something like ./bonito/someasset.js
to include those.
You will need e.g. LiveServer
, to look at index.html
now, since it needs a full file server to display things:
using LiveServer
LiveServer.serve(dir=root)
This is actually how makie.org is created - if you don’t already use e.g. Jekyll, Bonito has some tools to create the whole site, avoiding the whole manual export above:
And the make.jl.
Would be nice to update the Bonito docs with all of this.
Btw, record_states
is not completely deprecated, but it’s quite buggy, and I’m not sure if I’d recommend it anymore.
Maybe for very simple stuff, but the size also balloons pretty quickly, and the last refactor of it, made it even worse sadly (I tried to improve correctness, but mainly just increased size)
But I guess if it works for you and doesn’t become too big, there’s no reason against using it. Not sure, if it’s worth putting more time into it, but maybe I’ll find some low hanging fruits to decrease size and make it work better.
Currently, I’m thinking it’s better to just improve the javascript interface, making it easier to update plots via sliders in javascript, and then maybe make it easier to hook those up with precalculated data from Julia.