diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 5dba0ab..1d634d1 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -18,7 +18,6 @@ jobs:
fail-fast: false
matrix:
version:
- - '1.6'
- '1'
os:
- ubuntu-latest
diff --git a/.gitignore b/.gitignore
index ba39cc5..3199bb7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
Manifest.toml
+test*.jl
\ No newline at end of file
diff --git a/Project.toml b/Project.toml
index a44f952..b407341 100644
--- a/Project.toml
+++ b/Project.toml
@@ -5,16 +5,19 @@ version = "0.3.9"
[deps]
AbstractPlutoDingetjes = "6e696c72-6542-2067-7265-42206c756150"
-Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
+BaseDirs = "18cc8868-cbac-4acf-b575-c8ff214dc66f"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
+Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
-LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
-PackageExtensionCompat = "65ce6f38-6b18-4e1d-a461-8949797d7930"
+Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
-PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
+SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
+TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
+LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
+Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
[weakdeps]
PlotlyKaleido = "f2990250-8cf9-495f-b13a-cce12b45703c"
@@ -24,11 +27,10 @@ PlotlyKaleidoExt = "PlotlyKaleido"
[compat]
AbstractPlutoDingetjes = "1"
+BaseDirs = "1"
Colors = "0.12"
-HypertextLiteral = "0.9"
+HypertextLiteral = "0.9.4"
LaTeXStrings = "1"
-PackageExtensionCompat = "1"
PlotlyBase = "0.8"
-PlutoUI = "0.7"
Reexport = "1"
-julia = "1.6"
+julia = "1.9"
diff --git a/notebooks/tests.jl b/notebooks/tests.jl
new file mode 100644
index 0000000..d5d0f7d
--- /dev/null
+++ b/notebooks/tests.jl
@@ -0,0 +1,860 @@
+### A Pluto.jl notebook ###
+# v0.19.27
+
+#> custom_attrs = ["hide-enabled"]
+
+using Markdown
+using InteractiveUtils
+
+# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
+macro bind(def, element)
+ quote
+ local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
+ local el = $(esc(element))
+ global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
+ el
+ end
+end
+
+# ╔═╡ 72c073fd-5f1b-4af0-901b-aaa901f0f273
+begin
+ using PlutoDevMacros
+ using PlutoUI
+ using PlutoExtras
+ using Dates
+ using Colors
+end
+
+# ╔═╡ 70dc8fa0-cc32-4ebe-af0d-62b5bb3a82ed
+@fromparent begin
+ using ^
+ using >.HypertextLiteral
+end
+
+# ╔═╡ 7bd46437-8af0-4a15-87e9-1508869e1600
+ExtendedTableOfContents()
+
+# ╔═╡ 0820a893-26a3-49e9-bbc9-13db0a6fccee
+PlutoPlotly._fromparent_dict_
+
+# ╔═╡ acba5003-a456-4c1a-a53f-71a3bec30251
+md"""
+# Tests
+"""
+
+# ╔═╡ 6d49055d-0347-4bce-a2c5-f1568596e2e6
+md"""
+## Image
+"""
+
+# ╔═╡ c56df6f6-865e-4af8-b8c0-429b021af1eb
+md"""
+This is testing the expected behavior of image traces as per [Issue #16](https://github.com/JuliaPluto/PlutoPlotly.jl/issues/16)
+"""
+
+# ╔═╡ 7ba8b496-f7c4-4fbc-a168-dc3d7af92d0c
+image_issue = image(;z = rand(3,5,3)*255)
+
+# ╔═╡ f6ed3a0a-e548-4b99-9cf7-085991a5c99e
+plot(image_issue)
+
+# ╔═╡ 0f9f50f8-95c8-4cb5-96f2-e4ce177ca2dd
+Plot(image_issue)
+
+# ╔═╡ 359d22e8-b13d-420b-b409-b18136c3ff3b
+md"""
+## Colors.jl colors
+"""
+
+# ╔═╡ e54cc4c4-2a93-4d44-90ed-5944edbf4b0f
+let
+ red = scatter(;y=rand(10), line_color = RGB(1,0,0))
+ green_transp = scatter(;y=rand(10), line_color = RGBA(0,1,0, .3))
+ plot([red, green_transp])
+end
+
+# ╔═╡ 3e5b09a9-6d18-4d2f-a37b-ac260ea36646
+md"""
+## Respect provided height/width
+"""
+
+# ╔═╡ 070820c5-082f-4428-8d5e-1fdd1ce29eba
+let
+ @htl """
+
+ $(plot(rand(10), Layout(
+ width = 400,
+ #height= 400
+ )))
+
+ """
+end
+
+# ╔═╡ 0c30855c-6542-4b1a-9427-3a8427e75210
+md"""
+## Slider + UIRevision
+"""
+
+# ╔═╡ de0cb780-ff4e-4236-89c4-4c3163337cfc
+@bind clk Clock()
+
+# ╔═╡ dd23fe10-a8d5-461a-85a8-e03468cdcd97
+@bind N Slider(50:50:250)
+# N =let
+# clk
+# rand(50:100)
+# end
+
+# ╔═╡ 8bf75ceb-e4ae-4c6c-8ab0-a81350f19bc7
+pp = Plot(scatter3d(x = rand(N), y = rand(N), z = rand(N), mode="markers"), Layout(
+ uirevision = 1,
+ scene = attr(
+ xaxis_range = [-1,2],
+ yaxis_range = [-1,2],
+ zaxis_range = [-1,2],
+ aspectmode = "cube",
+ ),
+ height = 550
+ # autosize = true,
+));
+
+# ╔═╡ ccf62e33-8fcf-45d9-83ed-c7de80800b76
+let
+ p = PlutoPlot(pp)
+ add_plotly_listener!(p, "plotly_relayout", htl_js("""
+ (e) => {
+
+ console.log(e)
+ //console.log(PLOT._fullLayout._preGUI)
+
+
+ var eye = e['scene.camera']?.eye;
+
+ if (eye) {
+ console.log('update: ', eye);
+ } else {
+ console.log(e)
+ }
+ console.log('div: ',PLOT._fullLayout.scene.camera.eye)
+ console.log('plot_obj: ',plot_obj.layout.scene?.camera?.eye)
+
+}
+ """))
+ PlutoPlotly._show(p)
+end
+
+# ╔═╡ 1460ece1-7828-4e93-ac37-e979b874b492
+md"""
+## @bind click
+"""
+
+# ╔═╡ 18c80ea2-0df4-40ea-bd87-f8fee463161e
+@bind asdasd let
+ p = PlutoPlot(Plot(scatter(y = rand(10), name = "test", showlegend=true)))
+ add_plotly_listener!(p,"plotly_click", "
+ (e) => {
+
+ console.log(e)
+ let dt = e.points[0]
+ PLOT.value = [dt.x, dt.y]
+ PLOT.dispatchEvent(new CustomEvent('input'))
+}
+ ")
+ p
+end
+
+# ╔═╡ ce29fa1f-0c52-4d38-acbd-0a96cb3b9ce6
+asdasd
+
+# ╔═╡ c3e29c94-941d-4a52-a358-c4ffbfc8cab8
+md"""
+## @bind filtering
+"""
+
+# ╔═╡ b0473b9a-2db5-4d03-8344-b8eaf8428d6c
+points = [(rand(),rand()) for _ in 1:10000]
+
+# ╔═╡ 73945da3-af45-41fb-9c5d-6fbba6362256
+@bind limits let
+ p = Plot(
+ scatter(x = first.(points), y = last.(points), mode = "markers")
+ )|> PlutoPlot
+ add_plotly_listener!(p, "plotly_relayout", "
+ e => {
+ //console.log(e)
+ let layout = PLOT.layout
+ let asd = {xaxis: layout.xaxis.range, yaxis: layout.yaxis.range}
+ PLOT.value = asd
+ PLOT.dispatchEvent(new CustomEvent('input'))
+ }
+ ")
+end
+
+# ╔═╡ ea9faecf-ecd7-483b-99ad-ede08ba05383
+visible_points = let
+ if ismissing(limits)
+ points
+ else
+ xrange = limits["xaxis"]
+ yrange = limits["yaxis"]
+ func(x,y) = x >= xrange[1] && x <= xrange[2] && y >= yrange[1] && y <= yrange[2]
+ filter(x -> func(x...), points)
+ end
+end
+
+# ╔═╡ 684ef6d7-c1ae-4af3-b1bd-f54bc29d7b53
+length(visible_points)
+
+# ╔═╡ f8f7b530-1ded-4ce0-a7d9-a8c92afb95c7
+md"""
+## Multiple Listeners
+"""
+
+# ╔═╡ c3b1a198-ef19-4a54-9c32-d9ea32a63812
+let
+ p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
+ add_plotly_listener!(p, "plotly_relayout", htl_js("""
+function(e) {
+
+ console.log('listener 1')
+
+}
+ """))
+ add_plotly_listener!(p, "plotly_relayout", htl_js("""
+function(e) {
+
+ console.log('listener 2')
+
+}
+ """))
+ @htl "$p"
+end
+
+# ╔═╡ e9fc2030-c2f0-48e9-a807-424039e796b2
+let
+ p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
+ add_plotly_listener!(p, "plotly_relayout", htl_js("""
+function(e) {
+
+ console.log('listener 1')
+
+}
+ """))
+ add_plotly_listener!(p, "plotly_relayout", htl_js("""
+function(e) {
+
+ console.log('listener 2')
+
+}
+ """))
+ p.plotly_listeners
+end
+
+# ╔═╡ de101f40-27db-43ea-91ed-238502ceaaf7
+md"""
+## JS Listener
+"""
+
+# ╔═╡ 6c709fa0-7a53-4554-ab2a-d8181267ec93
+lololol = 1
+
+# ╔═╡ 671296b9-6743-48d6-9c4d-1beac2b505b5
+let
+ lololol
+ p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
+ add_js_listener!(p, "mousedown", htl_js("""
+function(e) {
+
+ console.log('MOUSEDOWN!')
+
+}
+ """))
+end
+
+# ╔═╡ 6128ff76-3f1f-4144-bb3d-f44678210013
+md"""
+## flexbox
+"""
+
+# ╔═╡ a5823eb2-3aaa-4791-bdc8-196eac2ccf2e
+@htl """
+
+$(Plot(rand(10)) |> PlutoPlot)
+
+$(Plot(rand(10)) |> PlutoPlot)
+
+"""
+
+# ╔═╡ b45cc21d-bfff-4375-a524-95108661a2ef
+md"""
+## flexbox + bind
+"""
+
+# ╔═╡ 4ea48316-62d9-4b24-bb1d-c9fd1db044dc
+@htl """
+
+$(@bind asd plot(rand(10)))
+
+$(plot(rand(10)))
+
+
+"""
+
+# ╔═╡ e92a0cf8-f869-4737-a465-db17318498a2
+asd
+
+# ╔═╡ 62126774-e246-473b-9d0b-92e967cd36ac
+md"""
+## flexbox + PlutoUI.ExperimentalLayout.hbox
+"""
+
+# ╔═╡ cfa78790-aa4c-4c7b-8a9f-198987338516
+# Without bonds, the plots resize automatically inside hbox
+PlutoUI.ExperimentalLayout.hbox([plot(rand(10)), plot(rand(10))])
+
+# ╔═╡ 340262a2-c823-4e19-8f19-9a05f4504bb5
+# When you wrap plots in bonds, the subplots do not automatically resize to the cell width
+PlutoUI.ExperimentalLayout.hbox([(@bind asdasd2_val plot(rand(10))), plot(rand(10))])
+
+# ╔═╡ 21682322-13a7-4575-8846-19e61fb8667d
+# We need to specify flex-grow to allow resizing
+html"""
+
+"""
+
+# ╔═╡ a7ef3dfc-d6ad-41c2-bccb-a794e26e80bb
+PlutoUI.ExperimentalLayout.hbox([(@bind asdasd1_val plot(rand(10))), plot(rand(10))]; class="hbox_test")
+
+# ╔═╡ aaf0fe61-d5e6-4d93-8a22-7f97f1249b35
+md"""
+## flexbox + uirevision
+"""
+
+# ╔═╡ 6e12592d-01fe-455a-a19c-7544258b9791
+voila = 10
+
+# ╔═╡ 36c4a5b1-03f2-4f5f-b9af-822a8f7c8cdf
+let
+ voila
+ @htl """
+
+
+$(Plot(rand(10), Layout(uirevision = 1)) |> PlutoPlot)
+
+$(Plot(rand(10)) |> PlutoPlot)
+
+
+$(Plot(rand(10)) |> PlutoPlot)
+
+$(Plot(rand(10)) |> PlutoPlot)
+
+
+"""
+end
+
+# ╔═╡ 38a81414-0bcd-4d71-af1d-fe154d2ae09a
+md"""
+## custom class
+"""
+
+# ╔═╡ 2dd5534f-ce46-4770-b0f3-6e16005b3a90
+cl = ["test_css_class", "lol"]
+
+# ╔═╡ f69c6955-800c-461e-b464-cab4989913f6
+let
+ p = PlutoPlot(Plot(rand(10)))
+ for cn ∈ cl
+ add_class!(p, cn)
+ end
+ p
+end
+
+# ╔═╡ bfe5f717-4702-4316-808a-726fefef9e7e
+html"""
+
+"""
+
+# ╔═╡ cb3f5ee4-5504-4337-8a8d-d45784f54c85
+md"""
+## Sphere
+"""
+
+# ╔═╡ e0271a15-08b5-470f-a2d2-6f064cd3a2b2
+function sphere(radius, origin = [0,0,0]; N = 50)
+u = range(0, 2π; length = N)
+v = range(0, π, length = N)
+x = [radius * cos(u) * sin(v) + origin[1] for u ∈ u, v ∈ v]
+y = [radius * sin(u) * sin(v) + origin[2] for u ∈ u, v ∈ v]
+z = [radius * cos(v) + origin[3] for u ∈ u, v ∈ v]
+ surface(;x,y,z)
+end
+
+# ╔═╡ cb1f840f-8d99-4076-9554-7d8ba56e9865
+@bind M Slider(0:90)
+
+# ╔═╡ 22245242-80a6-4a5b-815e-39b469002f84
+let
+ s = sphere(1)
+ r = 2
+ i = 0
+ # M = 90
+ x = [r*cosd(M)]
+ y = [r*sind(M)]
+ z = [0]
+ sat = scatter3d(;x,y,z, mode = "markers")
+ data = [s,sat]
+ plot(data, Layout(
+ uirevision = 1,
+ scene = attr(
+ xaxis_range = [-3,3],
+ yaxis_range = [-3,3],
+ zaxis_range = [-3,3],
+ aspectmode = "cube",
+ ),
+ ))
+end
+
+# ╔═╡ ebdc0ebc-da58-49c8-a992-5924045c2cac
+md"""
+## Plot Dates
+"""
+
+# ╔═╡ 6d74e3fa-1806-40b0-9995-c1555519603d
+let
+ x = Date.(2000:2020)
+ y = rand(length(x))
+ plot(scatter(;x,y,name = "values", showlegend = true), Layout(
+ template = "none"
+ ))
+end
+
+# ╔═╡ 7054b9ce-cd00-42cf-b81c-bc27b29f4714
+md"""
+## Heatmap/Contour tests
+"""
+
+# ╔═╡ 5b5293bf-81b3-4e80-995a-f15f91971bd4
+md"""
+This is testing the expected behavior of heatmap and contour plots as per [https://github.com/JuliaPlots/PlotlyJS.jl/issues/355](https://github.com/JuliaPlots/PlotlyJS.jl/issues/355)
+"""
+
+# ╔═╡ 3612826c-0af0-4fef-aafe-112a2948f669
+let
+ plasma = [[0.0, "#0c0786"],
+ [0.1, "#40039c"],
+ [0.2, "#6a00a7"],
+ [0.3, "#8f0da3"],
+ [0.4, "#b02a8f"],
+ [0.5, "#cb4777"],
+ [0.6, "#e06461"],
+ [0.7, "#f2844b"],
+ [0.8, "#fca635"],
+ [0.9, "#fcce25"],
+ [1.0, "#eff821"]]
+ plot(heatmap(z=[1 24 30; 28 18 40; 36 54 7], colorscale=plasma), Layout(
+ template = "none",
+ yaxis = attr(
+ scaleanchor = "x",
+ scaleratio = 1,
+ )
+ ))
+end
+
+# ╔═╡ ce90eb60-98ed-4901-9218-ed8466bb03c7
+let
+ a, b = -1., 1.
+ c, d= 0., 1.
+ nx, ny= 200, 100
+ hx = (b-a)/(nx-1)
+ x = a:hx:b
+ hy = (d-c)/(ny-1)
+ y=c:hy:d
+ X = x' .* ones(length(y))
+ Y = ones(length(x))'.*y
+ Z= sin.(pi*pi*(X.*X+Y.*Y));
+ # print(size(Z))
+ plot(contour(x=x, y=y, z=Z), Layout(width=650, height=350, template = "none"))
+end
+
+# ╔═╡ 00000000-0000-0000-0000-000000000001
+PLUTO_PROJECT_TOML_CONTENTS = """
+[deps]
+Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
+Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
+PlutoDevMacros = "a0499f29-c39b-4c5c-807c-88074221b949"
+PlutoExtras = "ed5d0301-4775-4676-b788-cf71e66ff8ed"
+PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
+
+[compat]
+Colors = "~0.12.10"
+PlutoDevMacros = "~0.5.7"
+PlutoExtras = "~0.7.8"
+PlutoUI = "~0.7.37"
+"""
+
+# ╔═╡ 00000000-0000-0000-0000-000000000002
+PLUTO_MANIFEST_TOML_CONTENTS = """
+# This file is machine-generated - editing it directly is not advised
+
+[[AbstractPlutoDingetjes]]
+deps = ["Pkg"]
+git-tree-sha1 = "91bd53c39b9cbfb5ef4b015e8b582d344532bd0a"
+uuid = "6e696c72-6542-2067-7265-42206c756150"
+version = "1.2.0"
+
+[[ArgTools]]
+uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
+version = "1.1.1"
+
+[[Artifacts]]
+uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
+
+[[Base64]]
+uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
+
+[[ColorTypes]]
+deps = ["FixedPointNumbers", "Random"]
+git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4"
+uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
+version = "0.11.4"
+
+[[Colors]]
+deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
+git-tree-sha1 = "fc08e5930ee9a4e03f84bfb5211cb54e7769758a"
+uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
+version = "0.12.10"
+
+[[CompilerSupportLibraries_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
+version = "1.0.5+0"
+
+[[Dates]]
+deps = ["Printf"]
+uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
+
+[[Downloads]]
+deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
+uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
+version = "1.6.0"
+
+[[FileWatching]]
+uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
+
+[[FixedPointNumbers]]
+deps = ["Statistics"]
+git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
+uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
+version = "0.8.4"
+
+[[Hyperscript]]
+deps = ["Test"]
+git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
+uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
+version = "0.0.4"
+
+[[HypertextLiteral]]
+deps = ["Tricks"]
+git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9"
+uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
+version = "0.9.4"
+
+[[IOCapture]]
+deps = ["Logging", "Random"]
+git-tree-sha1 = "d75853a0bdbfb1ac815478bacd89cd27b550ace6"
+uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
+version = "0.2.3"
+
+[[InteractiveUtils]]
+deps = ["Markdown"]
+uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
+
+[[JSON]]
+deps = ["Dates", "Mmap", "Parsers", "Unicode"]
+git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a"
+uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
+version = "0.21.4"
+
+[[LibCURL]]
+deps = ["LibCURL_jll", "MozillaCACerts_jll"]
+uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
+version = "0.6.3"
+
+[[LibCURL_jll]]
+deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
+uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
+version = "7.84.0+0"
+
+[[LibGit2]]
+deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
+uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
+
+[[LibSSH2_jll]]
+deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
+uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
+version = "1.10.2+0"
+
+[[Libdl]]
+uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
+
+[[LinearAlgebra]]
+deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
+uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
+
+[[Logging]]
+uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
+
+[[MIMEs]]
+git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb"
+uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65"
+version = "0.1.4"
+
+[[MacroTools]]
+deps = ["Markdown", "Random"]
+git-tree-sha1 = "9ee1618cbf5240e6d4e0371d6f24065083f60c48"
+uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
+version = "0.5.11"
+
+[[Markdown]]
+deps = ["Base64"]
+uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
+
+[[MbedTLS_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
+version = "2.28.2+0"
+
+[[Mmap]]
+uuid = "a63ad114-7e13-5084-954f-fe012c677804"
+
+[[MozillaCACerts_jll]]
+uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
+version = "2022.10.11"
+
+[[NetworkOptions]]
+uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
+version = "1.2.0"
+
+[[OpenBLAS_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
+uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
+version = "0.3.21+4"
+
+[[OrderedCollections]]
+git-tree-sha1 = "2e73fe17cac3c62ad1aebe70d44c963c3cfdc3e3"
+uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
+version = "1.6.2"
+
+[[Parsers]]
+deps = ["Dates", "PrecompileTools", "UUIDs"]
+git-tree-sha1 = "716e24b21538abc91f6205fd1d8363f39b442851"
+uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
+version = "2.7.2"
+
+[[Pkg]]
+deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
+uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
+version = "1.9.2"
+
+[[PlutoDevMacros]]
+deps = ["HypertextLiteral", "InteractiveUtils", "MacroTools", "Markdown", "Pkg", "Random", "TOML"]
+git-tree-sha1 = "51e747644116b5806936ad355f1e32e124ec04b1"
+uuid = "a0499f29-c39b-4c5c-807c-88074221b949"
+version = "0.5.7"
+
+[[PlutoExtras]]
+deps = ["AbstractPlutoDingetjes", "HypertextLiteral", "InteractiveUtils", "Markdown", "OrderedCollections", "PlutoDevMacros", "PlutoUI", "REPL"]
+git-tree-sha1 = "2ce56cb64b4c346406a855105850e7ba68d2197c"
+uuid = "ed5d0301-4775-4676-b788-cf71e66ff8ed"
+version = "0.7.8"
+
+[[PlutoUI]]
+deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"]
+git-tree-sha1 = "e47cd150dbe0443c3a3651bc5b9cbd5576ab75b7"
+uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
+version = "0.7.52"
+
+[[PrecompileTools]]
+deps = ["Preferences"]
+git-tree-sha1 = "03b4c25b43cb84cee5c90aa9b5ea0a78fd848d2f"
+uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
+version = "1.2.0"
+
+[[Preferences]]
+deps = ["TOML"]
+git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1"
+uuid = "21216c6a-2e73-6563-6e65-726566657250"
+version = "1.4.0"
+
+[[Printf]]
+deps = ["Unicode"]
+uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
+
+[[REPL]]
+deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
+uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
+
+[[Random]]
+deps = ["SHA", "Serialization"]
+uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
+
+[[Reexport]]
+git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
+uuid = "189a3867-3050-52da-a836-e630ba90ab69"
+version = "1.2.2"
+
+[[SHA]]
+uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
+version = "0.7.0"
+
+[[Serialization]]
+uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
+
+[[Sockets]]
+uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
+
+[[SparseArrays]]
+deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
+uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
+
+[[Statistics]]
+deps = ["LinearAlgebra", "SparseArrays"]
+uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
+version = "1.9.0"
+
+[[SuiteSparse_jll]]
+deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"]
+uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
+version = "5.10.1+6"
+
+[[TOML]]
+deps = ["Dates"]
+uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
+version = "1.0.3"
+
+[[Tar]]
+deps = ["ArgTools", "SHA"]
+uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
+version = "1.10.0"
+
+[[Test]]
+deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
+uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
+
+[[Tricks]]
+git-tree-sha1 = "aadb748be58b492045b4f56166b5188aa63ce549"
+uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775"
+version = "0.1.7"
+
+[[URIs]]
+git-tree-sha1 = "b7a5e99f24892b6824a954199a45e9ffcc1c70f0"
+uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
+version = "1.5.0"
+
+[[UUIDs]]
+deps = ["Random", "SHA"]
+uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
+
+[[Unicode]]
+uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
+
+[[Zlib_jll]]
+deps = ["Libdl"]
+uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
+version = "1.2.13+0"
+
+[[libblastrampoline_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
+version = "5.8.0+0"
+
+[[nghttp2_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
+version = "1.48.0+0"
+
+[[p7zip_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
+version = "17.4.0+0"
+"""
+
+# ╔═╡ Cell order:
+# ╠═7bd46437-8af0-4a15-87e9-1508869e1600
+# ╠═72c073fd-5f1b-4af0-901b-aaa901f0f273
+# ╠═70dc8fa0-cc32-4ebe-af0d-62b5bb3a82ed
+# ╠═0820a893-26a3-49e9-bbc9-13db0a6fccee
+# ╟─acba5003-a456-4c1a-a53f-71a3bec30251
+# ╟─6d49055d-0347-4bce-a2c5-f1568596e2e6
+# ╟─c56df6f6-865e-4af8-b8c0-429b021af1eb
+# ╠═7ba8b496-f7c4-4fbc-a168-dc3d7af92d0c
+# ╠═f6ed3a0a-e548-4b99-9cf7-085991a5c99e
+# ╠═0f9f50f8-95c8-4cb5-96f2-e4ce177ca2dd
+# ╟─359d22e8-b13d-420b-b409-b18136c3ff3b
+# ╠═e54cc4c4-2a93-4d44-90ed-5944edbf4b0f
+# ╟─3e5b09a9-6d18-4d2f-a37b-ac260ea36646
+# ╠═070820c5-082f-4428-8d5e-1fdd1ce29eba
+# ╟─0c30855c-6542-4b1a-9427-3a8427e75210
+# ╠═8bf75ceb-e4ae-4c6c-8ab0-a81350f19bc7
+# ╠═de0cb780-ff4e-4236-89c4-4c3163337cfc
+# ╠═dd23fe10-a8d5-461a-85a8-e03468cdcd97
+# ╠═ccf62e33-8fcf-45d9-83ed-c7de80800b76
+# ╠═1460ece1-7828-4e93-ac37-e979b874b492
+# ╠═18c80ea2-0df4-40ea-bd87-f8fee463161e
+# ╠═ce29fa1f-0c52-4d38-acbd-0a96cb3b9ce6
+# ╟─c3e29c94-941d-4a52-a358-c4ffbfc8cab8
+# ╠═b0473b9a-2db5-4d03-8344-b8eaf8428d6c
+# ╠═73945da3-af45-41fb-9c5d-6fbba6362256
+# ╠═684ef6d7-c1ae-4af3-b1bd-f54bc29d7b53
+# ╠═ea9faecf-ecd7-483b-99ad-ede08ba05383
+# ╠═f8f7b530-1ded-4ce0-a7d9-a8c92afb95c7
+# ╠═c3b1a198-ef19-4a54-9c32-d9ea32a63812
+# ╠═e9fc2030-c2f0-48e9-a807-424039e796b2
+# ╟─de101f40-27db-43ea-91ed-238502ceaaf7
+# ╠═6c709fa0-7a53-4554-ab2a-d8181267ec93
+# ╠═671296b9-6743-48d6-9c4d-1beac2b505b5
+# ╟─6128ff76-3f1f-4144-bb3d-f44678210013
+# ╠═a5823eb2-3aaa-4791-bdc8-196eac2ccf2e
+# ╟─b45cc21d-bfff-4375-a524-95108661a2ef
+# ╠═4ea48316-62d9-4b24-bb1d-c9fd1db044dc
+# ╠═e92a0cf8-f869-4737-a465-db17318498a2
+# ╟─62126774-e246-473b-9d0b-92e967cd36ac
+# ╠═cfa78790-aa4c-4c7b-8a9f-198987338516
+# ╠═340262a2-c823-4e19-8f19-9a05f4504bb5
+# ╠═21682322-13a7-4575-8846-19e61fb8667d
+# ╠═a7ef3dfc-d6ad-41c2-bccb-a794e26e80bb
+# ╟─aaf0fe61-d5e6-4d93-8a22-7f97f1249b35
+# ╠═6e12592d-01fe-455a-a19c-7544258b9791
+# ╠═36c4a5b1-03f2-4f5f-b9af-822a8f7c8cdf
+# ╟─38a81414-0bcd-4d71-af1d-fe154d2ae09a
+# ╠═2dd5534f-ce46-4770-b0f3-6e16005b3a90
+# ╠═f69c6955-800c-461e-b464-cab4989913f6
+# ╠═bfe5f717-4702-4316-808a-726fefef9e7e
+# ╟─cb3f5ee4-5504-4337-8a8d-d45784f54c85
+# ╠═e0271a15-08b5-470f-a2d2-6f064cd3a2b2
+# ╠═cb1f840f-8d99-4076-9554-7d8ba56e9865
+# ╠═22245242-80a6-4a5b-815e-39b469002f84
+# ╟─ebdc0ebc-da58-49c8-a992-5924045c2cac
+# ╠═6d74e3fa-1806-40b0-9995-c1555519603d
+# ╟─7054b9ce-cd00-42cf-b81c-bc27b29f4714
+# ╟─5b5293bf-81b3-4e80-995a-f15f91971bd4
+# ╠═3612826c-0af0-4fef-aafe-112a2948f669
+# ╠═ce90eb60-98ed-4901-9218-ed8466bb03c7
+# ╟─00000000-0000-0000-0000-000000000001
+# ╟─00000000-0000-0000-0000-000000000002
diff --git a/notebooks/wrapper.jl b/notebooks/wrapper.jl
deleted file mode 100644
index ebb8d14..0000000
--- a/notebooks/wrapper.jl
+++ /dev/null
@@ -1,1628 +0,0 @@
-### A Pluto.jl notebook ###
-# v0.19.26
-
-using Markdown
-using InteractiveUtils
-
-# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
-macro bind(def, element)
- quote
- local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
- local el = $(esc(element))
- global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
- el
- end
-end
-
-# ╔═╡ 7b8a4360-aaa4-11ec-2efc-b1778f6d3a8c
-begin
- using PlotlyBase
- using HypertextLiteral
- using Colors
-end
-
-# ╔═╡ 810fb486-10b5-460f-a25a-1a7c9d84e256
-using LaTeXStrings
-
-# ╔═╡ 676d318f-b4a4-4949-a5db-1c3a5fd9fa68
-using AbstractPlutoDingetjes
-
-# ╔═╡ fc52e423-1370-4ca9-95dc-090815278a4a
-using PlutoUI
-
-# ╔═╡ a9e7c04a-2d60-4727-9e24-a6dd9a0ee73c
-using Dates
-
-# ╔═╡ 7bd46437-8af0-4a15-87e9-1508869e1600
-TableOfContents()
-
-# ╔═╡ 4a18fa5d-7c73-468b-bed2-3acff51e3981
-publish_to_js = if is_inside_pluto()
- PlutoRunner.publish_to_js
-else
- @warn "You are trying to show a PlutoPlot outside of Pluto, this is not the intended behavior and you should use either PlotlyBase or PlotlyJS directly.
- NOTE: If you receive this warning during pre-compilation or sysimage creation, you can ignore this warning."
- x -> x
-end
-
-# ╔═╡ 413ffc5c-c53f-48b0-922d-4c7f8718507c
-current_cell_id()::Base.UUID = if is_inside_pluto()
- Main.PlutoRunner.currently_running_cell_id[]
-else
- Base.UUID(zero(UInt128))
-end
-
-# ╔═╡ 0ae3f943-4f9b-4cfb-aa76-3bcdc7dc9963
-"""
- htl_js(x)
-Simple convenience constructor for `HypertextLiteral.JavaScript` objects, renamed and re-exported from HypertextLiteral for convenience in case HypertextLiteral is not explicitly loaded alongisde PlutoPlotly.
-
-See also: [`add_plotly_listeners!`](@ref)
-"""
-htl_js(x) = HypertextLiteral.JavaScript(x)
-
-# ╔═╡ 90fd960f-65b3-4d8c-b8a8-42d3be8c770f
-function Base.show(io::IO, mime::MIME"text/html", s::HypertextLiteral.JavaScript)
-if is_inside_pluto()
- show(io, mime, Markdown.MD(Markdown.Code("js",s.content)))
-else
- show(io, MIME"text/plain",s)
-end
-end
-
-# ╔═╡ e9d43bc6-390e-43c3-becb-d1584202da41
-# This is only used to simplify debugging (by setting this to false) the plotly internal functions using the developer console
-const LOAD_MINIFIED = Ref(true)
-
-# ╔═╡ 16f4b455-086b-4a8b-8767-26fb00a77aad
-md"""
-# Utility Functions
-"""
-
-# ╔═╡ 03bf1bc5-37a9-4b02-bff7-f8b42500c4fc
-const JS = HypertextLiteral.JavaScript
-
-# ╔═╡ c3dcd4d9-5e57-4189-a7f8-524afd6db1e6
-md"""
-## Hyperscript.content hack!
-"""
-
-# ╔═╡ 6a4a5cc2-dca5-4f5d-a7e2-9b1f2fbaa406
-md"""
-## ScriptContents struct
-"""
-
-# ╔═╡ 441b20b3-ef9a-4d8a-a6b0-6b6be151a3dd
-"""
- ScriptContents
-Wrapper around a vector of `HypertextLiteral.JavaScript` elements. It has a custom print implementation of `HypertextLiteral.print_script` in order to allow serialization of its various elements inside a script tag.
-
-It is used inside the PlutoPlot to allow modularity and ease customization of the script contents that is used to generate the plotlyjs plot in Javascript.
-"""
-struct ScriptContents
- vec::Vector{JS}
-end
-
-# ╔═╡ 271fd3a7-8347-407d-92d0-2d49758cb3f1
-function HypertextLiteral.print_script(io::IO, value::ScriptContents)
- for el ∈ value.vec
- print(io, el.content, '\n')
- end
-end
-
-# ╔═╡ 907d51fd-9aaf-43d0-a83b-879cae330a0b
-md"""
-## Plotly Version
-"""
-
-# ╔═╡ 10da78b9-9a67-4cd8-9453-c01ea4baabeb
-const PLOTLY_VERSION = Ref("2.16.1")
-
-# ╔═╡ ea88edae-c1a1-4cd3-95da-fd6d5cf337ff
-function change_plotly_version(ver::String)
- PLOTLY_VERSION[] = ver
-end
-
-# ╔═╡ 5e5cf476-609c-4669-bf5d-c3fc3b75b2fe
-get_plotly_version() = PLOTLY_VERSION[]
-
-# ╔═╡ 0c84069c-8362-43e7-8f0f-10f445ddc7fd
-check_plotly_version() = @htl """
-
-"""
-
-# ╔═╡ 83f2fe95-a6c2-42ec-ac86-72a4b4ec95c3
-md"""
-## Mathjax hack
-"""
-
-# ╔═╡ 4b1688b2-677e-41be-9446-e395925a7311
-const FORCE_MATHJAX_LOCAL = Ref(false)
-
-# ╔═╡ 49cf85b1-bf09-49de-8468-4e240dc621fa
-"""
- force_pluto_mathjax_local::Bool
- force_pluto_mathjax_local(flag::Bool)::Bool
-
-Returns `true` if the `PlutoPlot` `show` method forces svgs produced by MathJax to be locally cached and `false` otherwise.
-
-The flag can be set at package level by providing the intended boolean value as argument to the function
-
-Local svg caching is used to make mathjax in recent plolty versions (>2.10) work as expected. The default `global` caching in Pluto creates problems with the math display.
-"""
-force_pluto_mathjax_local() = FORCE_MATHJAX_LOCAL[]
-
-# ╔═╡ 997f1421-b2f7-40c2-bc5b-f8a21cb4b04a
-force_pluto_mathjax_local(flag::Bool) = FORCE_MATHJAX_LOCAL[] = flag
-
-# ╔═╡ e6b52b32-def4-4d71-80ca-e43530b1e704
-md"""
-## Preprocess data
-"""
-
-# ╔═╡ 77fe2c5d-f3dd-4779-92a4-e0ceadb639a9
-md"""
-This function is basically `_json_lower` from PlotlyBase, but we do it directly on the PlutoPlot to avoid the modifying the behavior of `_json_lower` for `Plot` objects (which is required to modify how matrices are passed to `publish_to_js`)
-"""
-
-# ╔═╡ 2380a265-700d-4fed-a52e-f6fa1ce41391
-# Defaults to JSON.lower for generic non-overloaded types
-_preprocess(x) = PlotlyBase.JSON.lower(x)
-
-# ╔═╡ 65638528-ed6b-4e67-9cda-70390db81f64
-_preprocess(x::TimeType) = sprint(print, x)
-
-# ╔═╡ bc727ded-8675-420d-806e-0b49357118e5
-begin
- _preprocess(x::Union{Bool,String,Number,Nothing,Missing}) = x
- _preprocess(x::Symbol) = string(x)
- _preprocess(x::Union{Tuple,AbstractArray}) = _preprocess.(x)
- _preprocess(A::AbstractArray{<:Number, N}) where N = if N == 1
- collect(A)
- else
- [_preprocess(collect(s)) for s ∈ eachslice(A; dims = ndims(A))]
- end
- _preprocess(d::Dict) = Dict{Any,Any}(k => _preprocess(v) for (k, v) in pairs(d))
- _preprocess(a::PlotlyBase.HasFields) = Dict{Any,Any}(k => _preprocess(v) for (k, v) in pairs(a.fields))
- _preprocess(c::PlotlyBase.Cycler) = c.vals
- function _preprocess(c::PlotlyBase.ColorScheme)::Vector{Tuple{Float64,String}}
- N = length(c.colors)
- map(ic -> ((ic[1] - 1) / (N - 1), _preprocess(ic[2])), enumerate(c.colors))
- end
-end
-
-# ╔═╡ f9c0a331-1f1c-4648-9c24-5e9e16d6be18
-_preprocess(t::PlotlyBase.Template) = Dict(
- :data => _preprocess(t.data),
- :layout => _preprocess(t.layout)
-)
-
-# ╔═╡ b0d77b4f-da8f-4a0b-a244-043b2e3bdfae
-function _preprocess(pc::PlotlyBase.PlotConfig)
- out = Dict{Symbol,Any}()
- for fn in fieldnames(PlotlyBase.PlotConfig)
- field = getfield(pc, fn)
- if !isnothing(field)
- out[fn] = field
- end
- end
- out
-end
-
-# ╔═╡ b8e1b177-6686-4b58-8c4c-991d9c148520
-# Escape latexstrings
-_preprocess(s::LaTeXString) = s.s
-
-# ╔═╡ d1a08479-2814-4d1c-8af9-510aaa4c9089
-begin
- # Process colors
- _preprocess(c::Color) = @views begin
- s = hex(c, :rrggbb)
- r = parse(Int, s[1:2]; base = 16)
- g = parse(Int, s[3:4]; base = 16)
- b = parse(Int, s[5:6]; base = 16)
- return "rgb($r,$g,$b)"
- end
- _preprocess(c::TransparentColor) = @views begin
- s = hex(c, :rrggbbaa)
- r = parse(Int, s[1:2]; base = 16)
- g = parse(Int, s[3:4]; base = 16)
- b = parse(Int, s[5:6]; base = 16)
- a = parse(Int, s[7:8]; base = 16)
- return "rgba($r,$g,$b,$(a/255))"
- end
-end
-
-# ╔═╡ a060a009-aee3-46f2-b70f-1811a27d06fa
-md"""
-## prepend\_cell\_selector
-"""
-
-# ╔═╡ f15f831f-6418-4656-80e5-47057662552d
-"""
- prepend_cell_selector(selector="")
- prepend_cell_selector(selectors)
-
-Prepends a CSS selector (represented by the argument `selector`) with a selector of the current pluto-cell (of the form `pluto-cell[id='cell_id']`, where `cell_id` is the currently running cell).
-
-It can be used to ease creating style sheets (using `@htl` from HypertextLiteral.jl) with selector that only apply to the cell where they are executed.
-
-When called with a vector of selectors as input, prepends each selector and joins them together using `,` as separator.
-
-`prepend_cell_selector("div") = pluto-cell[id='\$cell_id'] div`
-
-`prepend_cell_selector(["div", "span"]) = pluto-cell[id='\$cell_id'] div, pluto-cell[id='\$cell_id'] span`
-
-As example, one can create a plot and force its width to 400px in CSS by using the following snippet:
-```julia
-@htl \"\"\"
-\$(plot(rand(10)))
-
-\"\"\"
-```
-"""
-prepend_cell_selector(str::AbstractString="")::String = "pluto-cell[id='$(current_cell_id())'] $str" |> strip
-
-# ╔═╡ 3f6c98c6-879f-48f3-9885-52e0cc99295a
-prepend_cell_selector(selectors) = join(map(prepend_cell_selector, selectors), ",\n")
-
-# ╔═╡ 4e296bdd-cbd4-4d43-a769-0b4a80d7dec9
-md"""
-## Unique Counter
-"""
-
-# ╔═╡ 628c6e1f-03eb-43a2-8092-a2f61cf6bcbd
-function unique_io_counter(io::IO, identifier = "script_id")
- !get(io, :is_pluto, false) && return -1 # We simply return -1 if not inside pluto
- # By default pluto inserts a dict inside the IOContext under key :extra_items. See https://github.com/fonsp/Pluto.jl/blob/10747db7ed512c6b3a9881c5cdb2a4daadea766d/src/runner/PlutoRunner.jl#L786
- dict = io.dict[:extra_items]
- # The dict has key of type Tuple{ObjectID, Int64}, so we a custom key with our custom identifier where we will store the counter
- key = (objectid(identifier), 0)
- counter = get(dict, key, 0) + 1
- # Update the counter on the dict that is shared within this IOContext
- dict[key] = counter
-end
-
-# ╔═╡ ebcc9c42-9928-4a20-a307-02ee6ef726d0
-# Using the unique_io_counter inside the show3 method allows to have unique counters for plots within a same cell.
-# This does not ensure that the same plot object is always given the same unique script id if the plots are added to the cells with `if...end` blocks.
-function plotly_script_id(io::IO)
- counter = unique_io_counter(io, "plotly-plot")
- return "plot_$counter"
-end
-
-# ╔═╡ fa975cb6-4ec1-419a-bcd6-527c0762a533
-md"""
-# Plot Wrapper
-"""
-
-# ╔═╡ 8b57581f-65b3-4edf-abe3-9dfa4ed82ed5
-md"""
-We define a wrapper around the PlotlyBase.Plot object
-"""
-
-# ╔═╡ f5491a94-5ea8-4459-b6ee-5d37f2ba6188
-md"""
-## Default script contents
-"""
-
-# ╔═╡ 92f5a728-6c57-47b7-9929-e2e19f91da2f
-const _default_script_contents = htl_js.([
- """
- // Flag to check if this cell was manually ran or reactively ran
- const firstRun = this ? false : true
- const PLOT = this ?? document.createElement("div");
- const parent = currentScript.parentElement
- const isPlutoWrapper = parent.classList.contains('raw-html-wrapper')
- """,
- """
- if (firstRun) {
- // It seem plot divs would not autosize themself inside flexbox containers without this
- parent.appendChild(PLOT)
- }
- """,
- """
- // If width is not specified, set it to 100%
- PLOT.style.width = plot_obj.layout.width ? "" : "100%"
-
- // For the height we have to also put a fixed value in case the plot is put on a non-fixed-size container (like the default wrapper)
- PLOT.style.height = plot_obj.layout.height ? "" :
- (isPlutoWrapper || parent.clientHeight == 0) ? "400px" : "100%"
- """,
- """
-
-
- PLOT.classList.forEach(cn => {
- if (cn !== 'js-plotly-plot' && !custom_classlist.includes(cn)) {
- PLOT.classList.toggle(cn, false)
- }
- })
- for (const className of custom_classlist) {
- PLOT.classList.toggle(className, true)
- }
- """,
- """
-
- // Create the resizeObserver to make the plot even more responsive! :magic:
- const resizeObserver = new ResizeObserver(entries => {
- PLOT.style.height = plot_obj.layout.height ? "" :
- (isPlutoWrapper || parent.clientHeight == 0) ? "400px" : "100%"
- /*
- The addition of the invalid argument `plutoresize` seems to fix the problem with calling `relayout` simply with `{autosize: true}` as update breaking mouse relayout events tracking.
- See https://github.com/plotly/plotly.js/issues/6156 for details
- */
- Plotly.relayout(PLOT, {..._.pick(PLOT.layout, ['width','height']), autosize: true, plutoresize: true})
- })
-
- resizeObserver.observe(PLOT)
- """,
- """
-
- Plotly.react(PLOT, plot_obj).then(() => {
- // Assign the Plotly event listeners
- for (const [key, listener_vec] of Object.entries(plotly_listeners)) {
- for (const listener of listener_vec) {
- PLOT.on(key, listener)
- }
- }
- // Assign the JS event listeners
- for (const [key, listener_vec] of Object.entries(js_listeners)) {
- for (const listener of listener_vec) {
- PLOT.addEventListener(key, listener)
- }
- }
- }
- )
- """,
- """
-
- invalidation.then(() => {
- // Remove all plotly listeners
- PLOT.removeAllListeners()
- // Remove all JS listeners
- for (const [key, listener_vec] of Object.entries(js_listeners)) {
- for (const listener of listener_vec) {
- PLOT.removeEventListener(key, listener)
- }
- }
- // Remove the resizeObserver
- resizeObserver.disconnect()
- })
- """,
-])
-
-# ╔═╡ 656e982b-d805-4a75-b3e6-53a4444e5374
-md"""
-## Struct definition
-"""
-
-# ╔═╡ 0f088a21-7d5f-43f7-b99f-688338b61dc6
-begin
-"""
- PlutoPlot(p::Plot; kwargs...)
-
-A wrapper around `PlotlyBase.Plot` to provide optimized visualization within Pluto notebooks exploiting `@htl` from HypertextLiteral.
-
-# Fields
-- `Plot::PlotlyBase.Plot`
-- `plotly_listeners::Dict{String, Vector{HypertextLitera.JavaScript}}`
-- `js_listeners::Dict{String, Vector{HypertextLitera.JavaScript}}`
-- `classList::Vector{String}`
-- `script_contents::ScriptContents`
-
-Once the wrapper has been created, the underlying `Plot` object can be accessed from the `Plot` field of the `PlutoPlot` object.
-
-Custom listeners to [plotly events](https://plotly.com/javascript/plotlyjs-events/) are saved inside the `plotly_listeners` field and can be added to the `PlutoPlot` as *javascript* functions using the [`add_plotly_listener!`](@ref) function.
-
-Custom listeners to normal javascript events can instead be added to the `PlutoPlot` as *javascript* functions using the [`add_js_listener!`](@ref) function.
-
-Multiple listeners can be associated to each event, and they are executed in the order they are added.
-
-A list of custom CSS classes can be added to the PlutoPlot by using the [`add_class!`](@ref) and [`remove_class!`](@ref) functions.
-
-Finally, the contents of the script tag generating the plot are stored in the field `script_contents` which is of type [`ScriptContents`](@ref). The elements of `script_contents` are written serially inside the javascript script tag. The displayed plot can be customized by modifying the elements of this field.
-
-# Examples
-```julia
-p = PlutoPlot(Plot(rand(10)))
-add_plotly_listener!(p, "plotly_click", "e => console.log(e)")
-add_class!(p, "custom_class")
-```
-
-See also: [`ScriptContents`](@ref), [`add_js_listener!`](@ref), [`add_plotly_listener!`](@ref)
-"""
-Base.@kwdef struct PlutoPlot
- Plot::PlotlyBase.Plot
- plotly_listeners::Dict{String, Vector{JS}} = Dict{String, Vector{JS}}()
- js_listeners::Dict{String, Vector{JS}} = Dict{String, Vector{JS}}()
- classList::Vector{String} = String[]
- script_contents::ScriptContents = ScriptContents(deepcopy(_default_script_contents))
-end
-PlutoPlot(p::PlotlyBase.Plot; kwargs...) = PlutoPlot(;kwargs..., Plot = p)
-end
-
-# ╔═╡ 214cae09-fb98-4ca8-8475-62563e31f665
-# This is needed till next version of HypertextLiteral is out (current is 0.9.3). See https://github.com/JuliaPluto/HypertextLiteral.jl/issues/28 for details
-HypertextLiteral.content(p::PlutoPlot) = HypertextLiteral.Render(p)
-
-# ╔═╡ 1686debe-6d74-4ec5-bf25-12346c8045c2
-function push_script!(p::PlutoPlot, items::Vararg{String,N}) where N
- @nospecialize
- push_script!(p, htl_js.(items)...)
-end
-
-# ╔═╡ 64ce91b4-aaa3-45ec-b4d6-f24457167667
-function _preprocess(pp::PlutoPlot)
- p = pp.Plot
- out = Dict(
- :data => _preprocess(p.data),
- :layout => _preprocess(p.layout),
- :frames => _preprocess(p.frames),
- :config => _preprocess(p.config)
- )
-
- if templates.default !== "none" && PlotlyBase._isempty(get(out[:layout], :template, Dict()))
- out[:layout][:template] = _preprocess(templates[templates.default])
- end
- out
-end
-
-# ╔═╡ 4ebd0ae4-9f4f-42b2-980e-a25550d01b6b
-md"""
-## Add plotly listeners
-"""
-
-# ╔═╡ de2a547b-3ccd-4f56-96c0-81a7d9b2d272
-"""
- add_plotly_listener!(p::PlutoPlot, event_name::String, listener::HypertextLiteral.JavaScript)
- add_plotly_listener!(p::PlutoPlot, event_name::String, listener::String)
-
-Add a custom *javascript* `listener` (to be provided as `String` or directly as `HypertextLiteral.JavaScript`) to the `PlutoPlot` object `p`, and associated to the [plotly event](https://plotly.com/javascript/plotlyjs-events/) specified by `event_name`.
-
-The listeners are added to the HTML plot div after rendering. The div where the plot is inserted can be accessed using the variable named `PLOT` inside the listener code.
-
-# Differences with `add_js_listener!`
-This function adds a listener using the plotly internal events via the `on` function. These events differ from the standard javascript ones and provide data specific to the plot.
-
-See also: [`add_js_listener!`](@ref), [`htl_js`](@ref)
-
-# Examples:
-```julia
-p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
-add_plotly_listener!(p, "plotly_relayout", htl_js(\"\"\"
-function(e) {
-
-console.log(PLOT) // logs the plot div inside the developer console
-
-}
-\"\"\"
-```
-"""
-function add_plotly_listener!(p::PlutoPlot, event_name::String, listener::JS)
- ldict = p.plotly_listeners
- listeners_array = get!(ldict, event_name, JS[])
- push!(listeners_array, listener)
- return p
-end;
-
-# ╔═╡ 35e643ab-e3ea-427b-85f2-685b6b6103b8
-add_plotly_listener!(p::PlutoPlot, event_name, listener::String) = add_plotly_listener!(p, event_name, htl_js(listener))
-
-# ╔═╡ 3cc48426-1c39-4afe-bf3e-7f4aa2197fca
-md"""
-## Add JS listeners
-"""
-
-# ╔═╡ 67137f84-a284-4615-b7a8-729f0a412939
-"""
- add_js_listener!(p::PlutoPlot, event_name::String, listener::HypertextLiteral.JavaScript)
- add_js_listener!(p::PlutoPlot, event_name::String, listener::String)
-
-Add a custom *javascript* `listener` (to be provided as `String` or directly as `HypertextLiteral.JavaScript`) to the `PlutoPlot` object `p`, and associated to the javascript event specified by `event_name`.
-
-The listeners are added to the HTML plot div after rendering. The div where the plot is inserted can be accessed using the variable named `PLOT` inside the listener code.
-
-# Differences with `add_plotly_listener!`
-This function adds standard javascript events via the `addEventListener` function. These events differ from the plotly specific events.
-
-See also: [`add_plotly_listener!`](@ref), [`htl_js`](@ref)
-
-# Examples:
-```julia
-p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
-add_js_listener!(p, "mousedown", htl_js(\"\"\"
-function(e) {
-
-console.log(PLOT) // logs the plot div inside the developer console when pressing down the mouse
-
-}
-\"\"\"
-```
-"""
-function add_js_listener!(p::PlutoPlot, event_name::String, listener::JS)
- ldict = p.js_listeners
- listeners_array = get!(ldict, event_name, JS[])
- push!(listeners_array, listener)
- return p
-end;
-
-# ╔═╡ 83906aab-d4ac-4c2b-b7a4-718edb0c2a18
-add_js_listener!(p::PlutoPlot, event_name, listener::String) = add_js_listener!(p, event_name, htl_js(listener))
-
-# ╔═╡ 0215aea2-eb79-449e-8dee-a32ca3c5d5f9
-md"""
-## add_class!
-"""
-
-# ╔═╡ 4c6a1004-52ca-40c1-915a-081c0a3c5fbf
-"""
- add_class!(p::PlutoPlot, className::String)
-
-Add a CSS class with name `className` to the list of custom classes that are added to the PLOT div when displayed inside Pluto. This can be used to give custom CSS styles to certain plots.
-
-See also: [`remove_class!`](@ref)
-"""
-function add_class!(p::PlutoPlot, className::String)
- cl = p.classList
- if className ∉ cl
- push!(cl, className)
- end
- return p
-end
-
-# ╔═╡ 87af8c6f-3d6d-44c6-87bb-588e01829339
-md"""
-## remove_class!
-"""
-
-# ╔═╡ 50077612-a858-48a0-a187-a9de1489f34f
-"""
- remove_class!(p::PlutoPlot, className::String)
-
-Remove a CSS class with name `className` (if present) from the list of custom classes that are added to the PLOT div when displayed inside Pluto. This can be used to give custom CSS styles to certain plots.
-
-See also: [`add_class!`](@ref)
-"""
-function remove_class!(p::PlutoPlot, className::String)
- cl = p.classList
- idx = findfirst(x -> x === className, cl)
- if idx !== nothing
- deleteat!(cl, idx)
- end
- return p
-end
-
-# ╔═╡ 49fe75d5-844d-46d5-a251-7023706a7f92
-let
- p = PlutoPlot(Plot())
- add_class!(p, "lol")
- remove_class!(p, "lola")
- p.classList
-end
-
-# ╔═╡ 73290c37-481a-4f7d-a92d-038766702890
-md"""
-# plot Method
-"""
-
-# ╔═╡ c3fcc72a-389c-456a-aba5-cbfb4a798c9e
-function plot(args...;kwargs...)
- @nospecialize
- PlutoPlot(Plot(args...;kwargs...))
-end
-
-# ╔═╡ 18e74f8f-39b6-4c8f-a06f-214d4e9dc6fb
-plot(scatter(x = 1:10, y = rand(10)), Layout(title = "TITLE", template = "none"))
-
-# ╔═╡ 8a047414-cd5d-4491-a143-eb30578928ce
-md"""
-# Show Method
-"""
-
-# ╔═╡ f9d1e69f-7a07-486d-b43a-334c1c77790a
-function _show(pp::PlutoPlot, script_id = "pluto-plotly-div")
-ver = htl_js(PLOTLY_VERSION[])
-suffix = htl_js(LOAD_MINIFIED[] ? "min.js" : "js")
-@htl """
-
-"""
-end
-
-# ╔═╡ d42d4694-e05d-4e0e-a198-79a3a5cb688a
-function Base.show(io::IO, mime::MIME"text/html", plt::PlutoPlot)
- show(io, mime, _show(plt, plotly_script_id(io)))
- # show(io, mime, _show(plt))
-end
-
-# ╔═╡ acba5003-a456-4c1a-a53f-71a3bec30251
-md"""
-# Tests
-"""
-
-# ╔═╡ 6d49055d-0347-4bce-a2c5-f1568596e2e6
-md"""
-## Image
-"""
-
-# ╔═╡ c56df6f6-865e-4af8-b8c0-429b021af1eb
-md"""
-This is testing the expected behavior of image traces as per [Issue #16](https://github.com/JuliaPluto/PlutoPlotly.jl/issues/16)
-"""
-
-# ╔═╡ 464964d1-ada4-4ec3-8df1-eaeb8ea28e4a
-# We check that the new definition works as the old one for matrices
-let
- a = rand(5,6)
- t1 = _preprocess(a) == [collect(r) for r in eachcol(a)]
-end
-
-# ╔═╡ 7ba8b496-f7c4-4fbc-a168-dc3d7af92d0c
-image_issue = image(;z = rand(3,5,3)*255)
-
-# ╔═╡ f6ed3a0a-e548-4b99-9cf7-085991a5c99e
-plot(image_issue)
-
-# ╔═╡ 0f9f50f8-95c8-4cb5-96f2-e4ce177ca2dd
-Plot(image_issue)
-
-# ╔═╡ 359d22e8-b13d-420b-b409-b18136c3ff3b
-md"""
-## Colors.jl colors
-"""
-
-# ╔═╡ e54cc4c4-2a93-4d44-90ed-5944edbf4b0f
-let
- red = scatter(;y=rand(10), line_color = RGB(1,0,0))
- green_transp = scatter(;y=rand(10), line_color = RGBA(0,1,0, .3))
- plot([red, green_transp])
-end
-
-# ╔═╡ 3e5b09a9-6d18-4d2f-a37b-ac260ea36646
-md"""
-## Respect provided height/width
-"""
-
-# ╔═╡ 070820c5-082f-4428-8d5e-1fdd1ce29eba
-let
- @htl """
-
- $(plot(rand(10), Layout(
- width = 400,
- #height= 400
- )))
-
- """
-end
-
-# ╔═╡ 0c30855c-6542-4b1a-9427-3a8427e75210
-md"""
-## Slider + UIRevision
-"""
-
-# ╔═╡ de0cb780-ff4e-4236-89c4-4c3163337cfc
-@bind clk Clock()
-
-# ╔═╡ dd23fe10-a8d5-461a-85a8-e03468cdcd97
-@bind N Slider(50:50:250)
-# N =let
-# clk
-# rand(50:100)
-# end
-
-# ╔═╡ 6da3c910-a350-4a7e-b481-88942c97686b
-"""
- push_script!(p::PlutoPlot, items...)
-Add script contents contained in collection `items` at the end of the plot show method script.
-The `item` must either be a collection of `String` or `HypertextLiteral.JavaScript` elements
-"""
-function push_script!(p::PlutoPlot, items::Vararg{JS,N}) where N
- @nospecialize
- push!(p.script_contents.vec, items...)
- return p
-end
-
-# ╔═╡ fdc22972-b8aa-4202-bb4e-bfff92574814
-let
- p = plot(rand(4))
- push_script!(p, "console.log('PUSHED')")
-end
-
-# ╔═╡ f6a63433-553c-4857-b767-33465eb22934
-let
- p = plot(rand(10,4))
- push_script!(p,htl_js("console.log('MAGIC PUSH SCRIPT')"))
- p
-end
-
-# ╔═╡ 8bf75ceb-e4ae-4c6c-8ab0-a81350f19bc7
-pp = Plot(scatter3d(x = rand(N), y = rand(N), z = rand(N), mode="markers"), Layout(
- uirevision = 1,
- scene = attr(
- xaxis_range = [-1,2],
- yaxis_range = [-1,2],
- zaxis_range = [-1,2],
- aspectmode = "cube",
- ),
- height = 550
- # autosize = true,
-));
-
-# ╔═╡ ccf62e33-8fcf-45d9-83ed-c7de80800b76
-let
- p = PlutoPlot(pp)
- add_plotly_listener!(p, "plotly_relayout", htl_js("""
- (e) => {
-
- console.log(e)
- //console.log(PLOT._fullLayout._preGUI)
-
-
- var eye = e['scene.camera']?.eye;
-
- if (eye) {
- console.log('update: ', eye);
- } else {
- console.log(e)
- }
- console.log('div: ',PLOT._fullLayout.scene.camera.eye)
- console.log('plot_obj: ',plot_obj.layout.scene?.camera?.eye)
-
-}
- """))
- _show(p)
-end
-
-# ╔═╡ 1460ece1-7828-4e93-ac37-e979b874b492
-md"""
-## @bind click
-"""
-
-# ╔═╡ 18c80ea2-0df4-40ea-bd87-f8fee463161e
-@bind asdasd let
- p = PlutoPlot(Plot(scatter(y = rand(10), name = "test", showlegend=true)))
- add_plotly_listener!(p,"plotly_click", "
- (e) => {
-
- console.log(e)
- let dt = e.points[0]
- PLOT.value = [dt.x, dt.y]
- PLOT.dispatchEvent(new CustomEvent('input'))
-}
- ")
- p
-end
-
-# ╔═╡ ce29fa1f-0c52-4d38-acbd-0a96cb3b9ce6
-asdasd
-
-# ╔═╡ c3e29c94-941d-4a52-a358-c4ffbfc8cab8
-md"""
-## @bind filtering
-"""
-
-# ╔═╡ b0473b9a-2db5-4d03-8344-b8eaf8428d6c
-points = [(rand(),rand()) for _ in 1:10000]
-
-# ╔═╡ 73945da3-af45-41fb-9c5d-6fbba6362256
-@bind limits let
- p = Plot(
- scatter(x = first.(points), y = last.(points), mode = "markers")
- )|> PlutoPlot
- add_plotly_listener!(p, "plotly_relayout", "
- e => {
- //console.log(e)
- let layout = PLOT.layout
- let asd = {xaxis: layout.xaxis.range, yaxis: layout.yaxis.range}
- PLOT.value = asd
- PLOT.dispatchEvent(new CustomEvent('input'))
- }
- ")
-end
-
-# ╔═╡ ea9faecf-ecd7-483b-99ad-ede08ba05383
-visible_points = let
- if ismissing(limits)
- points
- else
- xrange = limits["xaxis"]
- yrange = limits["yaxis"]
- func(x,y) = x >= xrange[1] && x <= xrange[2] && y >= yrange[1] && y <= yrange[2]
- filter(x -> func(x...), points)
- end
-end
-
-# ╔═╡ 684ef6d7-c1ae-4af3-b1bd-f54bc29d7b53
-length(visible_points)
-
-# ╔═╡ f8f7b530-1ded-4ce0-a7d9-a8c92afb95c7
-md"""
-## Multiple Listeners
-"""
-
-# ╔═╡ c3b1a198-ef19-4a54-9c32-d9ea32a63812
-let
- p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
- add_plotly_listener!(p, "plotly_relayout", htl_js("""
-function(e) {
-
- console.log('listener 1')
-
-}
- """))
- add_plotly_listener!(p, "plotly_relayout", htl_js("""
-function(e) {
-
- console.log('listener 2')
-
-}
- """))
- @htl "$p"
-end
-
-# ╔═╡ e9fc2030-c2f0-48e9-a807-424039e796b2
-let
- p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
- add_plotly_listener!(p, "plotly_relayout", htl_js("""
-function(e) {
-
- console.log('listener 1')
-
-}
- """))
- add_plotly_listener!(p, "plotly_relayout", htl_js("""
-function(e) {
-
- console.log('listener 2')
-
-}
- """))
- p.plotly_listeners
-end
-
-# ╔═╡ de101f40-27db-43ea-91ed-238502ceaaf7
-md"""
-## JS Listener
-"""
-
-# ╔═╡ 6c709fa0-7a53-4554-ab2a-d8181267ec93
-lololol = 1
-
-# ╔═╡ 671296b9-6743-48d6-9c4d-1beac2b505b5
-let
- lololol
- p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
- add_js_listener!(p, "mousedown", htl_js("""
-function(e) {
-
- console.log('MOUSEDOWN!')
-
-}
- """))
-end
-
-# ╔═╡ 6128ff76-3f1f-4144-bb3d-f44678210013
-md"""
-## flexbox
-"""
-
-# ╔═╡ a5823eb2-3aaa-4791-bdc8-196eac2ccf2e
-@htl """
-
-$(Plot(rand(10)) |> PlutoPlot)
-
-$(Plot(rand(10)) |> PlutoPlot)
-
-"""
-
-# ╔═╡ b45cc21d-bfff-4375-a524-95108661a2ef
-md"""
-## flexbox + bind
-"""
-
-# ╔═╡ 4ea48316-62d9-4b24-bb1d-c9fd1db044dc
-@htl """
-
-$(@bind asd plot(rand(10)))
-
-$(plot(rand(10)))
-
-
-"""
-
-# ╔═╡ 62126774-e246-473b-9d0b-92e967cd36ac
-md"""
-## flexbox + PlutoUI.ExperimentalLayout.hbox
-"""
-
-# ╔═╡ cfa78790-aa4c-4c7b-8a9f-198987338516
-# Without bonds, the plots resize automatically inside hbox
-PlutoUI.ExperimentalLayout.hbox([plot(rand(10)), plot(rand(10))])
-
-# ╔═╡ 340262a2-c823-4e19-8f19-9a05f4504bb5
-# When you wrap plots in bonds, the subplots do not automatically resize to the cell width
-PlutoUI.ExperimentalLayout.hbox([(@bind asdasd2_val plot(rand(10))), plot(rand(10))])
-
-# ╔═╡ 21682322-13a7-4575-8846-19e61fb8667d
-# We need to specify flex-grow to allow resizing
-html"""
-
-"""
-
-# ╔═╡ a7ef3dfc-d6ad-41c2-bccb-a794e26e80bb
-PlutoUI.ExperimentalLayout.hbox([(@bind asdasd1_val plot(rand(10))), plot(rand(10))]; class="hbox_test")
-
-# ╔═╡ aaf0fe61-d5e6-4d93-8a22-7f97f1249b35
-md"""
-## flexbox + uirevision
-"""
-
-# ╔═╡ 6e12592d-01fe-455a-a19c-7544258b9791
-voila = 1
-
-# ╔═╡ 36c4a5b1-03f2-4f5f-b9af-822a8f7c8cdf
-let
- voila
- @htl """
-
-
-$(Plot(rand(10), Layout(uirevision = 1)) |> PlutoPlot)
-
-$(Plot(rand(10)) |> PlutoPlot)
-
-
-$(Plot(rand(10)) |> PlutoPlot)
-
-$(Plot(rand(10)) |> PlutoPlot)
-
-
-"""
-end
-
-# ╔═╡ 38a81414-0bcd-4d71-af1d-fe154d2ae09a
-md"""
-## custom class
-"""
-
-# ╔═╡ 2dd5534f-ce46-4770-b0f3-6e16005b3a90
-cl = ["test_css_class", "lol"]
-
-# ╔═╡ f69c6955-800c-461e-b464-cab4989913f6
-let
- p = PlutoPlot(Plot(rand(10)))
- for cn ∈ cl
- add_class!(p, cn)
- end
- p
-end
-
-# ╔═╡ bfe5f717-4702-4316-808a-726fefef9e7e
-html"""
-
-"""
-
-# ╔═╡ cb3f5ee4-5504-4337-8a8d-d45784f54c85
-md"""
-## Sphere
-"""
-
-# ╔═╡ e0271a15-08b5-470f-a2d2-6f064cd3a2b2
-function sphere(radius, origin = [0,0,0]; N = 50)
-u = range(0, 2π; length = N)
-v = range(0, π, length = N)
-x = [radius * cos(u) * sin(v) + origin[1] for u ∈ u, v ∈ v]
-y = [radius * sin(u) * sin(v) + origin[2] for u ∈ u, v ∈ v]
-z = [radius * cos(v) + origin[3] for u ∈ u, v ∈ v]
- surface(;x,y,z)
-end
-
-# ╔═╡ cb1f840f-8d99-4076-9554-7d8ba56e9865
-@bind M Slider(0:90)
-
-# ╔═╡ 22245242-80a6-4a5b-815e-39b469002f84
-let
- s = sphere(1)
- r = 2
- i = 0
- # M = 90
- x = [r*cosd(M)]
- y = [r*sind(M)]
- z = [0]
- sat = scatter3d(;x,y,z, mode = "markers")
- data = [s,sat]
- plot(data, Layout(
- uirevision = 1,
- scene = attr(
- xaxis_range = [-3,3],
- yaxis_range = [-3,3],
- zaxis_range = [-3,3],
- aspectmode = "cube",
- ),
- ))
-end
-
-# ╔═╡ ebdc0ebc-da58-49c8-a992-5924045c2cac
-md"""
-## Plot Dates
-"""
-
-# ╔═╡ 6d74e3fa-1806-40b0-9995-c1555519603d
-let
- x = Date.(2000:2020)
- y = rand(length(x))
- plot(scatter(;x,y,name = "values", showlegend = true), Layout(
- template = "none"
- ))
-end
-
-# ╔═╡ 7054b9ce-cd00-42cf-b81c-bc27b29f4714
-md"""
-## Heatmap/Contour tests
-"""
-
-# ╔═╡ 5b5293bf-81b3-4e80-995a-f15f91971bd4
-md"""
-This is testing the expected behavior of heatmap and contour plots as per [https://github.com/JuliaPlots/PlotlyJS.jl/issues/355](https://github.com/JuliaPlots/PlotlyJS.jl/issues/355)
-"""
-
-# ╔═╡ 3612826c-0af0-4fef-aafe-112a2948f669
-let
- plasma = [[0.0, "#0c0786"],
- [0.1, "#40039c"],
- [0.2, "#6a00a7"],
- [0.3, "#8f0da3"],
- [0.4, "#b02a8f"],
- [0.5, "#cb4777"],
- [0.6, "#e06461"],
- [0.7, "#f2844b"],
- [0.8, "#fca635"],
- [0.9, "#fcce25"],
- [1.0, "#eff821"]]
- plot(heatmap(z=[1 24 30; 28 18 40; 36 54 7], colorscale=plasma), Layout(
- template = "none",
- yaxis = attr(
- scaleanchor = "x",
- scaleratio = 1,
- )
- ))
-end
-
-# ╔═╡ ce90eb60-98ed-4901-9218-ed8466bb03c7
-let
- a, b = -1., 1.
- c, d= 0., 1.
- nx, ny= 200, 100
- hx = (b-a)/(nx-1)
- x = a:hx:b
- hy = (d-c)/(ny-1)
- y=c:hy:d
- X = x' .* ones(length(y))
- Y = ones(length(x))'.*y
- Z= sin.(pi*pi*(X.*X+Y.*Y));
- # print(size(Z))
- plot(contour(x=x, y=y, z=Z), Layout(width=650, height=350, template = "none"))
-end
-
-# ╔═╡ 2fa13939-eba2-4d25-b461-56be79fc1db6
-md"""
-# Re-execute errored cells
-"""
-
-# ╔═╡ 5a324fba-1033-4dcf-b10c-1fa4f231355c
-md"""
-Since we have functions defined at the bottom of the notebook, when first opening the notebook some of the tests above will error and would need to be re-executed after all the function definitions are loaded.
-
-To do this, we put at the bottom of the notebook a javascript function that re-executes all the errored cells
-"""
-
-# ╔═╡ 9f2c0123-7e1a-43b7-861a-d059bb28f776
-# # Not really needed anymore after putting the tests at the bottom
-
-# @htl """
-#
-# """
-
-# ╔═╡ 00000000-0000-0000-0000-000000000001
-PLUTO_PROJECT_TOML_CONTENTS = """
-[deps]
-AbstractPlutoDingetjes = "6e696c72-6542-2067-7265-42206c756150"
-Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
-Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
-HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
-LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
-PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
-PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
-
-[compat]
-AbstractPlutoDingetjes = "~1.1.4"
-Colors = "~0.12.8"
-HypertextLiteral = "~0.9.3"
-LaTeXStrings = "~1.3.0"
-PlotlyBase = "~0.8.18"
-PlutoUI = "~0.7.37"
-"""
-
-# ╔═╡ 00000000-0000-0000-0000-000000000002
-PLUTO_MANIFEST_TOML_CONTENTS = """
-# This file is machine-generated - editing it directly is not advised
-
-[[AbstractPlutoDingetjes]]
-deps = ["Pkg"]
-git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481"
-uuid = "6e696c72-6542-2067-7265-42206c756150"
-version = "1.1.4"
-
-[[ArgTools]]
-uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
-version = "1.1.1"
-
-[[Artifacts]]
-uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
-
-[[Base64]]
-uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
-
-[[ColorSchemes]]
-deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
-git-tree-sha1 = "12fc73e5e0af68ad3137b886e3f7c1eacfca2640"
-uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
-version = "3.17.1"
-
-[[ColorTypes]]
-deps = ["FixedPointNumbers", "Random"]
-git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
-uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
-version = "0.11.0"
-
-[[Colors]]
-deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
-git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
-uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
-version = "0.12.8"
-
-[[CompilerSupportLibraries_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
-version = "1.0.2+0"
-
-[[Dates]]
-deps = ["Printf"]
-uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
-
-[[DelimitedFiles]]
-deps = ["Mmap"]
-git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae"
-uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"
-version = "1.9.1"
-
-[[DocStringExtensions]]
-deps = ["LibGit2"]
-git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b"
-uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
-version = "0.8.6"
-
-[[Downloads]]
-deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
-uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
-version = "1.6.0"
-
-[[FileWatching]]
-uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
-
-[[FixedPointNumbers]]
-deps = ["Statistics"]
-git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
-uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
-version = "0.8.4"
-
-[[Hyperscript]]
-deps = ["Test"]
-git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
-uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
-version = "0.0.4"
-
-[[HypertextLiteral]]
-git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
-uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
-version = "0.9.3"
-
-[[IOCapture]]
-deps = ["Logging", "Random"]
-git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
-uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
-version = "0.2.2"
-
-[[InteractiveUtils]]
-deps = ["Markdown"]
-uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
-
-[[JSON]]
-deps = ["Dates", "Mmap", "Parsers", "Unicode"]
-git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e"
-uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
-version = "0.21.3"
-
-[[LaTeXStrings]]
-git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996"
-uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
-version = "1.3.0"
-
-[[LibCURL]]
-deps = ["LibCURL_jll", "MozillaCACerts_jll"]
-uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
-version = "0.6.3"
-
-[[LibCURL_jll]]
-deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
-uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
-version = "7.84.0+0"
-
-[[LibGit2]]
-deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
-uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
-
-[[LibSSH2_jll]]
-deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
-uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
-version = "1.10.2+0"
-
-[[Libdl]]
-uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
-
-[[LinearAlgebra]]
-deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
-uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
-
-[[Logging]]
-uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
-
-[[Markdown]]
-deps = ["Base64"]
-uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
-
-[[MbedTLS_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
-version = "2.28.2+0"
-
-[[Mmap]]
-uuid = "a63ad114-7e13-5084-954f-fe012c677804"
-
-[[MozillaCACerts_jll]]
-uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
-version = "2022.10.11"
-
-[[NetworkOptions]]
-uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
-version = "1.2.0"
-
-[[OpenBLAS_jll]]
-deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
-uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
-version = "0.3.21+4"
-
-[[OrderedCollections]]
-git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
-uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
-version = "1.4.1"
-
-[[Parameters]]
-deps = ["OrderedCollections", "UnPack"]
-git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
-uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
-version = "0.12.3"
-
-[[Parsers]]
-deps = ["Dates"]
-git-tree-sha1 = "621f4f3b4977325b9128d5fae7a8b4829a0c2222"
-uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
-version = "2.2.4"
-
-[[Pkg]]
-deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
-uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
-version = "1.9.0"
-
-[[PlotlyBase]]
-deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"]
-git-tree-sha1 = "180d744848ba316a3d0fdf4dbd34b77c7242963a"
-uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
-version = "0.8.18"
-
-[[PlutoUI]]
-deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
-git-tree-sha1 = "670e559e5c8e191ded66fa9ea89c97f10376bb4c"
-uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
-version = "0.7.38"
-
-[[Printf]]
-deps = ["Unicode"]
-uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
-
-[[REPL]]
-deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
-uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
-
-[[Random]]
-deps = ["SHA", "Serialization"]
-uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
-
-[[Reexport]]
-git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
-uuid = "189a3867-3050-52da-a836-e630ba90ab69"
-version = "1.2.2"
-
-[[Requires]]
-deps = ["UUIDs"]
-git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
-uuid = "ae029012-a4dd-5104-9daa-d747884805df"
-version = "1.3.0"
-
-[[SHA]]
-uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
-version = "0.7.0"
-
-[[Serialization]]
-uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
-
-[[Sockets]]
-uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
-
-[[SparseArrays]]
-deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
-uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
-
-[[Statistics]]
-deps = ["LinearAlgebra", "SparseArrays"]
-uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
-version = "1.9.0"
-
-[[SuiteSparse_jll]]
-deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"]
-uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
-version = "5.10.1+6"
-
-[[TOML]]
-deps = ["Dates"]
-uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
-version = "1.0.3"
-
-[[Tar]]
-deps = ["ArgTools", "SHA"]
-uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
-version = "1.10.0"
-
-[[Test]]
-deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
-uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
-
-[[UUIDs]]
-deps = ["Random", "SHA"]
-uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
-
-[[UnPack]]
-git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
-uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
-version = "1.0.2"
-
-[[Unicode]]
-uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
-
-[[Zlib_jll]]
-deps = ["Libdl"]
-uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
-version = "1.2.13+0"
-
-[[libblastrampoline_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
-version = "5.8.0+0"
-
-[[nghttp2_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
-version = "1.48.0+0"
-
-[[p7zip_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
-version = "17.4.0+0"
-"""
-
-# ╔═╡ Cell order:
-# ╠═7b8a4360-aaa4-11ec-2efc-b1778f6d3a8c
-# ╠═810fb486-10b5-460f-a25a-1a7c9d84e256
-# ╠═676d318f-b4a4-4949-a5db-1c3a5fd9fa68
-# ╠═fc52e423-1370-4ca9-95dc-090815278a4a
-# ╠═a9e7c04a-2d60-4727-9e24-a6dd9a0ee73c
-# ╠═7bd46437-8af0-4a15-87e9-1508869e1600
-# ╠═4a18fa5d-7c73-468b-bed2-3acff51e3981
-# ╠═413ffc5c-c53f-48b0-922d-4c7f8718507c
-# ╠═0ae3f943-4f9b-4cfb-aa76-3bcdc7dc9963
-# ╠═90fd960f-65b3-4d8c-b8a8-42d3be8c770f
-# ╠═e9d43bc6-390e-43c3-becb-d1584202da41
-# ╟─16f4b455-086b-4a8b-8767-26fb00a77aad
-# ╠═03bf1bc5-37a9-4b02-bff7-f8b42500c4fc
-# ╟─c3dcd4d9-5e57-4189-a7f8-524afd6db1e6
-# ╠═214cae09-fb98-4ca8-8475-62563e31f665
-# ╟─6a4a5cc2-dca5-4f5d-a7e2-9b1f2fbaa406
-# ╠═441b20b3-ef9a-4d8a-a6b0-6b6be151a3dd
-# ╠═271fd3a7-8347-407d-92d0-2d49758cb3f1
-# ╠═6da3c910-a350-4a7e-b481-88942c97686b
-# ╠═1686debe-6d74-4ec5-bf25-12346c8045c2
-# ╠═fdc22972-b8aa-4202-bb4e-bfff92574814
-# ╟─907d51fd-9aaf-43d0-a83b-879cae330a0b
-# ╠═10da78b9-9a67-4cd8-9453-c01ea4baabeb
-# ╠═ea88edae-c1a1-4cd3-95da-fd6d5cf337ff
-# ╠═5e5cf476-609c-4669-bf5d-c3fc3b75b2fe
-# ╠═0c84069c-8362-43e7-8f0f-10f445ddc7fd
-# ╟─83f2fe95-a6c2-42ec-ac86-72a4b4ec95c3
-# ╠═4b1688b2-677e-41be-9446-e395925a7311
-# ╠═49cf85b1-bf09-49de-8468-4e240dc621fa
-# ╠═997f1421-b2f7-40c2-bc5b-f8a21cb4b04a
-# ╟─e6b52b32-def4-4d71-80ca-e43530b1e704
-# ╟─77fe2c5d-f3dd-4779-92a4-e0ceadb639a9
-# ╠═2380a265-700d-4fed-a52e-f6fa1ce41391
-# ╠═65638528-ed6b-4e67-9cda-70390db81f64
-# ╠═bc727ded-8675-420d-806e-0b49357118e5
-# ╠═f9c0a331-1f1c-4648-9c24-5e9e16d6be18
-# ╠═b0d77b4f-da8f-4a0b-a244-043b2e3bdfae
-# ╠═64ce91b4-aaa3-45ec-b4d6-f24457167667
-# ╠═b8e1b177-6686-4b58-8c4c-991d9c148520
-# ╠═d1a08479-2814-4d1c-8af9-510aaa4c9089
-# ╟─a060a009-aee3-46f2-b70f-1811a27d06fa
-# ╠═f15f831f-6418-4656-80e5-47057662552d
-# ╠═3f6c98c6-879f-48f3-9885-52e0cc99295a
-# ╟─4e296bdd-cbd4-4d43-a769-0b4a80d7dec9
-# ╠═628c6e1f-03eb-43a2-8092-a2f61cf6bcbd
-# ╠═ebcc9c42-9928-4a20-a307-02ee6ef726d0
-# ╟─fa975cb6-4ec1-419a-bcd6-527c0762a533
-# ╟─8b57581f-65b3-4edf-abe3-9dfa4ed82ed5
-# ╠═f5491a94-5ea8-4459-b6ee-5d37f2ba6188
-# ╠═92f5a728-6c57-47b7-9929-e2e19f91da2f
-# ╟─656e982b-d805-4a75-b3e6-53a4444e5374
-# ╠═0f088a21-7d5f-43f7-b99f-688338b61dc6
-# ╟─4ebd0ae4-9f4f-42b2-980e-a25550d01b6b
-# ╠═de2a547b-3ccd-4f56-96c0-81a7d9b2d272
-# ╠═35e643ab-e3ea-427b-85f2-685b6b6103b8
-# ╠═3cc48426-1c39-4afe-bf3e-7f4aa2197fca
-# ╠═67137f84-a284-4615-b7a8-729f0a412939
-# ╠═83906aab-d4ac-4c2b-b7a4-718edb0c2a18
-# ╟─0215aea2-eb79-449e-8dee-a32ca3c5d5f9
-# ╠═4c6a1004-52ca-40c1-915a-081c0a3c5fbf
-# ╟─87af8c6f-3d6d-44c6-87bb-588e01829339
-# ╠═50077612-a858-48a0-a187-a9de1489f34f
-# ╠═49fe75d5-844d-46d5-a251-7023706a7f92
-# ╠═73290c37-481a-4f7d-a92d-038766702890
-# ╠═c3fcc72a-389c-456a-aba5-cbfb4a798c9e
-# ╠═f6a63433-553c-4857-b767-33465eb22934
-# ╠═18e74f8f-39b6-4c8f-a06f-214d4e9dc6fb
-# ╟─8a047414-cd5d-4491-a143-eb30578928ce
-# ╠═f9d1e69f-7a07-486d-b43a-334c1c77790a
-# ╠═d42d4694-e05d-4e0e-a198-79a3a5cb688a
-# ╟─acba5003-a456-4c1a-a53f-71a3bec30251
-# ╟─6d49055d-0347-4bce-a2c5-f1568596e2e6
-# ╟─c56df6f6-865e-4af8-b8c0-429b021af1eb
-# ╠═464964d1-ada4-4ec3-8df1-eaeb8ea28e4a
-# ╠═7ba8b496-f7c4-4fbc-a168-dc3d7af92d0c
-# ╠═f6ed3a0a-e548-4b99-9cf7-085991a5c99e
-# ╠═0f9f50f8-95c8-4cb5-96f2-e4ce177ca2dd
-# ╟─359d22e8-b13d-420b-b409-b18136c3ff3b
-# ╠═e54cc4c4-2a93-4d44-90ed-5944edbf4b0f
-# ╠═3e5b09a9-6d18-4d2f-a37b-ac260ea36646
-# ╠═070820c5-082f-4428-8d5e-1fdd1ce29eba
-# ╟─0c30855c-6542-4b1a-9427-3a8427e75210
-# ╠═8bf75ceb-e4ae-4c6c-8ab0-a81350f19bc7
-# ╠═de0cb780-ff4e-4236-89c4-4c3163337cfc
-# ╠═dd23fe10-a8d5-461a-85a8-e03468cdcd97
-# ╠═ccf62e33-8fcf-45d9-83ed-c7de80800b76
-# ╠═1460ece1-7828-4e93-ac37-e979b874b492
-# ╠═18c80ea2-0df4-40ea-bd87-f8fee463161e
-# ╠═ce29fa1f-0c52-4d38-acbd-0a96cb3b9ce6
-# ╟─c3e29c94-941d-4a52-a358-c4ffbfc8cab8
-# ╠═b0473b9a-2db5-4d03-8344-b8eaf8428d6c
-# ╠═73945da3-af45-41fb-9c5d-6fbba6362256
-# ╠═684ef6d7-c1ae-4af3-b1bd-f54bc29d7b53
-# ╠═ea9faecf-ecd7-483b-99ad-ede08ba05383
-# ╠═f8f7b530-1ded-4ce0-a7d9-a8c92afb95c7
-# ╠═c3b1a198-ef19-4a54-9c32-d9ea32a63812
-# ╠═e9fc2030-c2f0-48e9-a807-424039e796b2
-# ╟─de101f40-27db-43ea-91ed-238502ceaaf7
-# ╠═6c709fa0-7a53-4554-ab2a-d8181267ec93
-# ╠═671296b9-6743-48d6-9c4d-1beac2b505b5
-# ╟─6128ff76-3f1f-4144-bb3d-f44678210013
-# ╠═a5823eb2-3aaa-4791-bdc8-196eac2ccf2e
-# ╟─b45cc21d-bfff-4375-a524-95108661a2ef
-# ╠═4ea48316-62d9-4b24-bb1d-c9fd1db044dc
-# ╟─62126774-e246-473b-9d0b-92e967cd36ac
-# ╠═cfa78790-aa4c-4c7b-8a9f-198987338516
-# ╠═340262a2-c823-4e19-8f19-9a05f4504bb5
-# ╠═21682322-13a7-4575-8846-19e61fb8667d
-# ╠═a7ef3dfc-d6ad-41c2-bccb-a794e26e80bb
-# ╟─aaf0fe61-d5e6-4d93-8a22-7f97f1249b35
-# ╠═6e12592d-01fe-455a-a19c-7544258b9791
-# ╠═36c4a5b1-03f2-4f5f-b9af-822a8f7c8cdf
-# ╟─38a81414-0bcd-4d71-af1d-fe154d2ae09a
-# ╠═2dd5534f-ce46-4770-b0f3-6e16005b3a90
-# ╠═f69c6955-800c-461e-b464-cab4989913f6
-# ╠═bfe5f717-4702-4316-808a-726fefef9e7e
-# ╟─cb3f5ee4-5504-4337-8a8d-d45784f54c85
-# ╠═e0271a15-08b5-470f-a2d2-6f064cd3a2b2
-# ╠═cb1f840f-8d99-4076-9554-7d8ba56e9865
-# ╠═22245242-80a6-4a5b-815e-39b469002f84
-# ╟─ebdc0ebc-da58-49c8-a992-5924045c2cac
-# ╠═6d74e3fa-1806-40b0-9995-c1555519603d
-# ╟─7054b9ce-cd00-42cf-b81c-bc27b29f4714
-# ╟─5b5293bf-81b3-4e80-995a-f15f91971bd4
-# ╠═3612826c-0af0-4fef-aafe-112a2948f669
-# ╠═ce90eb60-98ed-4901-9218-ed8466bb03c7
-# ╟─2fa13939-eba2-4d25-b461-56be79fc1db6
-# ╟─5a324fba-1033-4dcf-b10c-1fa4f231355c
-# ╠═9f2c0123-7e1a-43b7-861a-d059bb28f776
-# ╟─00000000-0000-0000-0000-000000000001
-# ╟─00000000-0000-0000-0000-000000000002
diff --git a/src/PlutoPlotly.jl b/src/PlutoPlotly.jl
index d9c9852..4cb26a1 100644
--- a/src/PlutoPlotly.jl
+++ b/src/PlutoPlotly.jl
@@ -3,17 +3,34 @@ module PlutoPlotly
using Reexport
@reexport using PlotlyBase
-using PackageExtensionCompat
+using HypertextLiteral
+using AbstractPlutoDingetjes
+using Dates
+using BaseDirs
+using TOML
+using Colors
+using LaTeXStrings
+using Markdown
+using Downloads: download
-export PlutoPlot, get_plotly_version, change_plotly_version, check_plotly_version, force_pluto_mathjax_local, htl_js, add_plotly_listener!, add_class!, remove_class!, add_js_listener!
+export PlutoPlot, get_plotly_version, change_plotly_version,
+check_plotly_version, force_pluto_mathjax_local, htl_js, add_plotly_listener!,
+add_class!, remove_class!, add_js_listener!
export plot, push_script!, prepend_cell_selector
-include("../notebooks/wrapper.jl")
+
+include("local_plotly_library.jl")
+
+include("main_struct.jl")
+include("basics.jl")
+include("mathjax.jl")
+include("preprocess.jl")
+include("js_helpers.jl")
+include("show.jl")
function __init__()
# if !is_inside_pluto()
# @warn "You loaded this package outside of Pluto, this is not the intended behavior and you should use either PlotlyBase or PlotlyJS directly.\nNOTE: If you receive this warning during pre-compilation or sysimage creation, you can ignore this warning."
# end
- @require_extensions
end
end
\ No newline at end of file
diff --git a/src/basics.jl b/src/basics.jl
new file mode 100644
index 0000000..0890797
--- /dev/null
+++ b/src/basics.jl
@@ -0,0 +1,117 @@
+publish_to_js = if is_inside_pluto()
+ if isdefined(Main.PlutoRunner, :core_published_to_js)
+ Main.PlutoRunner.PublishedToJavascript
+ else
+ Main.PlutoRunner.publish_to_js
+ end
+else
+ x -> x
+end
+
+current_cell_id()::Base.UUID = if is_inside_pluto()
+ Main.PlutoRunner.currently_running_cell_id[]
+else
+ Base.UUID(zero(UInt128))
+end
+
+function Base.show(io::IO, mime::MIME"text/html", s::JS)
+ if is_inside_pluto()
+ show(io, mime, Markdown.MD(Markdown.Code("js",s.content)))
+ else
+ show(io, MIME"text/plain",s)
+ end
+end
+
+
+## Plotly Version ##
+function change_plotly_version(ver::String)
+ maybe_add_plotly_local(ver)
+ PLOTLY_VERSION[] = ver
+end
+
+get_plotly_version() = PLOTLY_VERSION[]
+
+check_plotly_version() = @htl """
+
+"""
+
+## Prepend Cell Selector ##
+"""
+ prepend_cell_selector(selector="")
+ prepend_cell_selector(selectors)
+
+Prepends a CSS selector (represented by the argument `selector`) with a selector
+of the current pluto-cell (of the form `pluto-cell[id='cell_id']`, where
+`cell_id` is the currently running cell).
+
+It can be used to ease creating style sheets (using `@htl` from
+HypertextLiteral.jl) with selector that only apply to the cell where they are
+executed.
+
+When called with a vector of selectors as input, prepends each selector and
+joins them together using `,` as separator.
+
+`prepend_cell_selector("div") = pluto-cell[id='\$cell_id'] div`
+
+`prepend_cell_selector(["div", "span"]) = pluto-cell[id='\$cell_id'] div, pluto-cell[id='\$cell_id'] span`
+
+As example, one can create a plot and force its width to 400px in CSS by using the following snippet:
+```julia
+@htl \"\"\"
+\$(plot(rand(10)))
+
+\"\"\"
+```
+"""
+prepend_cell_selector(str::AbstractString="")::String = "pluto-cell[id='$(current_cell_id())'] $str" |> strip
+prepend_cell_selector(selectors) = join(map(prepend_cell_selector, selectors), ",\n")
+
+const IO_DICT = Ref{Tuple{<:IO, Dict{UInt, Int}}}((IOBuffer(), Dict{UInt, Int}()))
+function get_IO_DICT(io::IO)
+ old_io = first(IO_DICT[])
+ dict = if old_io === io
+ last(IO_DICT[])
+ else
+ d = Dict{UInt, Int}()
+ IO_DICT[] = (io, d)
+ d
+ end
+ return dict
+end
+
+## Unique Counter ##
+function unique_io_counter(io::IO, identifier = "script_id")
+ !get(io, :is_pluto, false) && return -1 # We simply return -1 if not inside pluto
+ # We extract (or create if not existing) a dictionary that will keep track of instances of the same script name
+ dict = get_IO_DICT(io)
+ # We use the objectid as the key
+ key = objectid(identifier)
+ counter = get(dict, key, 0) + 1
+ # Update the counter on the dict that is shared within this IOContext
+ dict[key] = counter
+end
+
+# Using the unique_io_counter inside the show3 method allows to have unique counters for plots within a same cell.
+# This does not ensure that the same plot object is always given the same unique script id if the plots are added to the cells with `if...end` blocks.
+function plotly_script_id(io::IO)
+ counter = unique_io_counter(io, "plotly-plot")
+ return "plot_$counter"
+end
\ No newline at end of file
diff --git a/src/js_helpers.jl b/src/js_helpers.jl
new file mode 100644
index 0000000..5cb497d
--- /dev/null
+++ b/src/js_helpers.jl
@@ -0,0 +1,113 @@
+## add listeners ##
+"""
+ add_js_listener!(p::PlutoPlot, event_name::String, listener::HypertextLiteral.JavaScript)
+ add_js_listener!(p::PlutoPlot, event_name::String, listener::String)
+
+Add a custom *javascript* `listener` (to be provided as `String` or directly as `HypertextLiteral.JavaScript`) to the `PlutoPlot` object `p`, and associated to the javascript event specified by `event_name`.
+
+The listeners are added to the HTML plot div after rendering. The div where the plot is inserted can be accessed using the variable named `PLOT` inside the listener code.
+
+# Differences with `add_plotly_listener!`
+This function adds standard javascript events via the `addEventListener` function. These events differ from the plotly specific events.
+
+See also: [`add_plotly_listener!`](@ref), [`htl_js`](@ref)
+
+# Examples:
+```julia
+p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
+add_js_listener!(p, "mousedown", htl_js(\"\"\"
+function(e) {
+
+console.log(PLOT) // logs the plot div inside the developer console when pressing down the mouse
+
+}
+\"\"\"
+```
+"""
+function add_js_listener!(p::PlutoPlot, event_name::String, listener::JS)
+ ldict = p.js_listeners
+ listeners_array = get!(ldict, event_name, JS[])
+ push!(listeners_array, listener)
+ return p
+end
+add_js_listener!(p::PlutoPlot, event_name, listener::String) = add_js_listener!(p, event_name, htl_js(listener))
+
+## add class ##
+"""
+ add_class!(p::PlutoPlot, className::String)
+
+Add a CSS class with name `className` to the list of custom classes that are added to the PLOT div when displayed inside Pluto. This can be used to give custom CSS styles to certain plots.
+
+See also: [`remove_class!`](@ref)
+"""
+function add_class!(p::PlutoPlot, className::String)
+ cl = p.classList
+ if className ∉ cl
+ push!(cl, className)
+ end
+ return p
+end
+
+## remove class ##
+
+"""
+ remove_class!(p::PlutoPlot, className::String)
+
+Remove a CSS class with name `className` (if present) from the list of custom classes that are added to the PLOT div when displayed inside Pluto. This can be used to give custom CSS styles to certain plots.
+
+See also: [`add_class!`](@ref)
+"""
+function remove_class!(p::PlutoPlot, className::String)
+ cl = p.classList
+ idx = findfirst(x -> x === className, cl)
+ if idx !== nothing
+ deleteat!(cl, idx)
+ end
+ return p
+end
+
+## Push Script ##
+"""
+ push_script!(p::PlutoPlot, items...)
+Add script contents contained in collection `items` at the end of the plot show method script.
+The `item` must either be a collection of `String` or `HypertextLiteral.JavaScript` elements
+"""
+function push_script!(p::PlutoPlot, items::Vararg{JS,N}) where N
+ @nospecialize
+ push!(p.script_contents.vec, items...)
+ return p
+end
+
+## plotly listener ##
+"""
+ add_plotly_listener!(p::PlutoPlot, event_name::String, listener::HypertextLiteral.JavaScript)
+ add_plotly_listener!(p::PlutoPlot, event_name::String, listener::String)
+
+Add a custom *javascript* `listener` (to be provided as `String` or directly as `HypertextLiteral.JavaScript`) to the `PlutoPlot` object `p`, and associated to the [plotly event](https://plotly.com/javascript/plotlyjs-events/) specified by `event_name`.
+
+The listeners are added to the HTML plot div after rendering. The div where the plot is inserted can be accessed using the variable named `PLOT` inside the listener code.
+
+# Differences with `add_js_listener!`
+This function adds a listener using the plotly internal events via the `on` function. These events differ from the standard javascript ones and provide data specific to the plot.
+
+See also: [`add_js_listener!`](@ref), [`htl_js`](@ref)
+
+# Examples:
+```julia
+p = PlutoPlot(Plot(rand(10), Layout(uirevision = 1)))
+add_plotly_listener!(p, "plotly_relayout", htl_js(\"\"\"
+function(e) {
+
+console.log(PLOT) // logs the plot div inside the developer console
+
+}
+\"\"\"
+```
+"""
+function add_plotly_listener!(p::PlutoPlot, event_name::String, listener::JS)
+ ldict = p.plotly_listeners
+ listeners_array = get!(ldict, event_name, JS[])
+ push!(listeners_array, listener)
+ return p
+end
+add_plotly_listener!(p::PlutoPlot, event_name, listener::String) = add_plotly_listener!(p, event_name, htl_js(listener))
\ No newline at end of file
diff --git a/src/local_plotly_library.jl b/src/local_plotly_library.jl
new file mode 100644
index 0000000..f0ee444
--- /dev/null
+++ b/src/local_plotly_library.jl
@@ -0,0 +1,89 @@
+const DATA_FOLDER = BaseDirs.User.data("plutoplotly/")
+isdir(DATA_FOLDER) || mkdir(DATA_FOLDER)
+const VERSIONS_PATH = joinpath(DATA_FOLDER, "plotly_versions")
+const VERSIONS_DICT = Ref(
+ try
+ TOML.tryparsefile(VERSIONS_PATH)
+ catch
+ Dict{String, Any}()
+ end
+ )
+
+function pluto_server_folder()
+ is_inside_pluto() || return nothing
+ ml = methods(Main.PlutoRunner.embed_display)
+ m = first(ml)
+ plutorunner_path = string(m.file)
+ pluto_path = normpath(plutorunner_path, "../../..")
+end
+function maybe_put_plotly_in_pluto(v)
+ name = get_local_name(v)
+ pluto_path = pluto_server_folder()
+ pluto_path !== nothing || return false
+ maybe_add_plotly_local(v)
+ # We check whether the plotly library has been already loaded in this Pluto location, and we copy it otherwise
+ for subdir in ("frontend-dist", "frontend")
+ dist_path = joinpath(pluto_path, subdir)
+ isdir(dist_path) || (subdir === "frontend" ? error("Something went wrong") : continue)
+ file_path = joinpath(dist_path, "plotlyjs", "$name.min.js")
+ if !isfile(file_path)
+ isdir(joinpath(dist_path, "plotlyjs")) || mkdir(joinpath(dist_path, "plotlyjs"))
+ cp(get_local_path(v), file_path)
+ end
+ end
+ return true
+end
+
+function update_versions_file()
+ open(VERSIONS_PATH, "w") do io
+ TOML.print(io, VERSIONS_DICT[])
+ end
+end
+function get_esm_url(v)
+ v = string(v)
+ d = VERSIONS_DICT[]
+ url = if haskey(d, v)
+ d[v]
+ else
+ line = last(eachline(download("https://esm.sh/plotly.js-dist-min@$(v)")))
+ parsed_url = "https://esm.sh$(match(r"\".*\"", line).match[2:end-1])"
+ d[v] = parsed_url
+ update_versions_file()
+ parsed_url
+ end
+
+end
+
+get_plotly_cdn_url(v) = "https://cdn.plot.ly/plotly-$(VersionNumber(v)).min.js"
+get_local_pluto_src(v) = let
+ maybe_put_plotly_in_pluto(v) || error("Something wrong")
+ "./plotlyjs/$(get_local_name(v)).min.js"
+end
+
+get_local_path(v) = joinpath(DATA_FOLDER, "$(get_local_name(v)).min.js")
+get_local_name(v) = "plotlyjs-$(VersionNumber(v))"
+
+function maybe_add_plotly_local(v)
+ ver = VersionNumber(v)
+ # Check if the artifact already exists
+ path = get_local_path(v)
+ if !isfile(path)
+ # We download bundle and save locally
+ @info "Downloading a local version of plotly@$v"
+ base_url = get_esm_url(v)
+ bundle_url = replace(base_url, r".(\w+)$" => s".bundle.\1")
+ download(bundle_url, path)
+ end
+ nothing
+end
+
+function get_plotly_src(v, force = "local")
+ if lowercase(string(force)) === "esm"
+ get_esm_url(v)
+ elseif lowercase(string(force)) === "cdn"
+ get_plotly_cdn_url(v)
+ elseif lowercase(string(force)) === "local"
+ get_local_pluto_src(v)
+ end
+end
+
\ No newline at end of file
diff --git a/src/main_struct.jl b/src/main_struct.jl
new file mode 100644
index 0000000..99ff714
--- /dev/null
+++ b/src/main_struct.jl
@@ -0,0 +1,169 @@
+const PLOTLY_VERSION = Ref("2.25.2")
+const JS = HypertextLiteral.JavaScript
+
+"""
+ ScriptContents
+Wrapper around a vector of `HypertextLiteral.JavaScript` elements. It has a custom print implementation of `HypertextLiteral.print_script` in order to allow serialization of its various elements inside a script tag.
+
+It is used inside the PlutoPlot to allow modularity and ease customization of the script contents that is used to generate the plotlyjs plot in Javascript.
+"""
+struct ScriptContents
+ vec::Vector{JS}
+end
+
+function HypertextLiteral.print_script(io::IO, value::ScriptContents)
+ for el ∈ value.vec
+ print(io, el.content, '\n')
+ end
+end
+
+"""
+ htl_js(x)
+Simple convenience constructor for `HypertextLiteral.JavaScript` objects, renamed and re-exported from HypertextLiteral for convenience in case HypertextLiteral is not explicitly loaded alongisde PlutoPlotly.
+
+See also: [`add_plotly_listeners!`](@ref)
+"""
+htl_js(x) = HypertextLiteral.JavaScript(x)
+
+const _default_script_contents = htl_js.([
+ """
+ // Flag to check if this cell was manually ran or reactively ran
+ const firstRun = this ? false : true
+ const PLOT = this ?? document.createElement("div");
+ const parent = currentScript.parentElement
+ const isPlutoWrapper = parent.classList.contains('raw-html-wrapper')
+ """,
+ """
+ if (firstRun) {
+ // It seem plot divs would not autosize themself inside flexbox containers without this
+ parent.appendChild(PLOT)
+ }
+ """,
+ """
+ // If width is not specified, set it to 100%
+ PLOT.style.width = plot_obj.layout.width ? "" : "100%"
+
+ // For the height we have to also put a fixed value in case the plot is put on a non-fixed-size container (like the default wrapper)
+ PLOT.style.height = plot_obj.layout.height ? "" :
+ (isPlutoWrapper || parent.clientHeight == 0) ? "400px" : "100%"
+ """,
+ """
+
+
+ PLOT.classList.forEach(cn => {
+ if (cn !== 'js-plotly-plot' && !custom_classlist.includes(cn)) {
+ PLOT.classList.toggle(cn, false)
+ }
+ })
+ for (const className of custom_classlist) {
+ PLOT.classList.toggle(className, true)
+ }
+ """,
+ """
+
+ // Create the resizeObserver to make the plot even more responsive! :magic:
+ const resizeObserver = new ResizeObserver(entries => {
+ PLOT.style.height = plot_obj.layout.height ? "" :
+ (isPlutoWrapper || parent.clientHeight == 0) ? "400px" : "100%"
+ /*
+ The addition of the invalid argument `plutoresize` seems to fix the problem with calling `relayout` simply with `{autosize: true}` as update breaking mouse relayout events tracking.
+ See https://github.com/plotly/plotly.js/issues/6156 for details
+ */
+ Plotly.relayout(PLOT, {..._.pick(PLOT.layout, ['width','height']), autosize: true, plutoresize: true})
+ })
+
+ resizeObserver.observe(PLOT)
+ """,
+ """
+
+ Plotly.react(PLOT, plot_obj).then(() => {
+ // Assign the Plotly event listeners
+ for (const [key, listener_vec] of Object.entries(plotly_listeners)) {
+ for (const listener of listener_vec) {
+ PLOT.on(key, listener)
+ }
+ }
+ // Assign the JS event listeners
+ for (const [key, listener_vec] of Object.entries(js_listeners)) {
+ for (const listener of listener_vec) {
+ PLOT.addEventListener(key, listener)
+ }
+ }
+ }
+ )
+ """,
+ """
+
+ invalidation.then(() => {
+ // Remove all plotly listeners
+ PLOT.removeAllListeners()
+ // Remove all JS listeners
+ for (const [key, listener_vec] of Object.entries(js_listeners)) {
+ for (const listener of listener_vec) {
+ PLOT.removeEventListener(key, listener)
+ }
+ }
+ // Remove the resizeObserver
+ resizeObserver.disconnect()
+ })
+ """,
+])
+
+"""
+ PlutoPlot(p::Plot; kwargs...)
+
+A wrapper around `PlotlyBase.Plot` to provide optimized visualization within
+Pluto notebooks exploiting `@htl` from HypertextLiteral.
+
+# Fields
+- `Plot::PlotlyBase.Plot`
+- `plotly_listeners::Dict{String, Vector{HypertextLitera.JavaScript}}`
+- `js_listeners::Dict{String, Vector{HypertextLitera.JavaScript}}`
+- `classList::Vector{String}`
+- `script_contents::ScriptContents`
+
+Once the wrapper has been created, the underlying `Plot` object can be accessed
+from the `Plot` field of the `PlutoPlot` object.
+
+Custom listeners to [plotly
+events](https://plotly.com/javascript/plotlyjs-events/) are saved inside the
+`plotly_listeners` field and can be added to the `PlutoPlot` as *javascript*
+functions using the [`add_plotly_listener!`](@ref) function.
+
+Custom listeners to normal javascript events can instead be added to the
+`PlutoPlot` as *javascript* functions using the [`add_js_listener!`](@ref)
+function.
+
+Multiple listeners can be associated to each event, and they are executed in the
+order they are added.
+
+A list of custom CSS classes can be added to the PlutoPlot by using the
+[`add_class!`](@ref) and [`remove_class!`](@ref) functions.
+
+Finally, the contents of the script tag generating the plot are stored in the
+field `script_contents` which is of type [`ScriptContents`](@ref). The elements
+of `script_contents` are written serially inside the javascript script tag. The
+displayed plot can be customized by modifying the elements of this field.
+
+# Examples
+```julia
+p = PlutoPlot(Plot(rand(10)))
+add_plotly_listener!(p, "plotly_click", "e => console.log(e)")
+add_class!(p, "custom_class")
+```
+
+See also: [`ScriptContents`](@ref), [`add_js_listener!`](@ref), [`add_plotly_listener!`](@ref)
+"""
+Base.@kwdef struct PlutoPlot
+ Plot::PlotlyBase.Plot
+ plotly_listeners::Dict{String, Vector{JS}} = Dict{String, Vector{JS}}()
+ js_listeners::Dict{String, Vector{JS}} = Dict{String, Vector{JS}}()
+ classList::Vector{String} = String[]
+ script_contents::ScriptContents = ScriptContents(deepcopy(_default_script_contents))
+end
+PlutoPlot(p::PlotlyBase.Plot; kwargs...) = PlutoPlot(;kwargs..., Plot = p)
+
+function plot(args...;kwargs...)
+ @nospecialize
+ PlutoPlot(Plot(args...;kwargs...))
+end
\ No newline at end of file
diff --git a/src/mathjax.jl b/src/mathjax.jl
new file mode 100644
index 0000000..7998ab9
--- /dev/null
+++ b/src/mathjax.jl
@@ -0,0 +1,20 @@
+# This hack is necessary to force loading mathjax
+
+const FORCE_MATHJAX_LOCAL = Ref(false)
+
+"""
+ force_pluto_mathjax_local::Bool
+ force_pluto_mathjax_local(flag::Bool)::Bool
+
+Returns `true` if the `PlutoPlot` `show` method forces svgs produced by MathJax
+to be locally cached and `false` otherwise.
+
+The flag can be set at package level by providing the intended boolean value as
+argument to the function
+
+Local svg caching is used to make mathjax in recent plolty versions (>2.10) work
+as expected. The default `global` caching in Pluto creates problems with the
+math display.
+"""
+force_pluto_mathjax_local() = FORCE_MATHJAX_LOCAL[]
+force_pluto_mathjax_local(flag::Bool) = FORCE_MATHJAX_LOCAL[] = flag
\ No newline at end of file
diff --git a/src/preprocess.jl b/src/preprocess.jl
new file mode 100644
index 0000000..cd91563
--- /dev/null
+++ b/src/preprocess.jl
@@ -0,0 +1,77 @@
+#=
+This function is basically `_json_lower` from PlotlyBase, but we do it directly
+on the PlutoPlot to avoid the modifying the behavior of `_json_lower` for `Plot`
+objects (which is required to modify how matrices are passed to `publish_to_js`)
+=#
+
+# Main _preprocess for the PlutoPlot object
+function _preprocess(pp::PlutoPlot)
+ p = pp.Plot
+ out = Dict(
+ :data => _preprocess(p.data),
+ :layout => _preprocess(p.layout),
+ :frames => _preprocess(p.frames),
+ :config => _preprocess(p.config)
+ )
+
+ if templates.default !== "none" && PlotlyBase._isempty(get(out[:layout], :template, Dict()))
+ out[:layout][:template] = _preprocess(templates[templates.default])
+ end
+ out
+end
+
+# Defaults to JSON.lower for generic non-overloaded types
+_preprocess(x) = PlotlyBase.JSON.lower(x) # Default
+_preprocess(x::TimeType) = sprint(print, x) # For handling datetimes
+
+_preprocess(x::Union{Bool,String,Number,Nothing,Missing}) = x
+_preprocess(x::Symbol) = string(x)
+_preprocess(x::Union{Tuple,AbstractArray}) = _preprocess.(x)
+_preprocess(A::AbstractArray{<:Number, N}) where N = if N == 1
+ collect(A)
+else
+ [_preprocess(collect(s)) for s ∈ eachslice(A; dims = ndims(A))]
+end
+_preprocess(d::Dict) = Dict{Any,Any}(k => _preprocess(v) for (k, v) in pairs(d))
+_preprocess(a::PlotlyBase.HasFields) = Dict{Any,Any}(k => _preprocess(v) for (k, v) in pairs(a.fields))
+_preprocess(c::PlotlyBase.Cycler) = c.vals
+function _preprocess(c::PlotlyBase.ColorScheme)::Vector{Tuple{Float64,String}}
+ N = length(c.colors)
+ map(ic -> ((ic[1] - 1) / (N - 1), _preprocess(ic[2])), enumerate(c.colors))
+end
+
+_preprocess(t::PlotlyBase.Template) = Dict(
+ :data => _preprocess(t.data),
+ :layout => _preprocess(t.layout)
+)
+
+function _preprocess(pc::PlotlyBase.PlotConfig)
+ out = Dict{Symbol,Any}()
+ for fn in fieldnames(PlotlyBase.PlotConfig)
+ field = getfield(pc, fn)
+ if !isnothing(field)
+ out[fn] = field
+ end
+ end
+ out
+end
+
+# Files that will be later moved to an extension. At the moment it's pointless because PlotlyBase uses those internally anyway.
+_preprocess(s::LaTeXString) = s.s
+
+# Colors, they can be put inside an extension
+_preprocess(c::Color) = @views begin
+ s = hex(c, :rrggbb)
+ r = parse(Int, s[1:2]; base = 16)
+ g = parse(Int, s[3:4]; base = 16)
+ b = parse(Int, s[5:6]; base = 16)
+ return "rgb($r,$g,$b)"
+end
+_preprocess(c::TransparentColor) = @views begin
+ s = hex(c, :rrggbbaa)
+ r = parse(Int, s[1:2]; base = 16)
+ g = parse(Int, s[3:4]; base = 16)
+ b = parse(Int, s[5:6]; base = 16)
+ a = parse(Int, s[7:8]; base = 16)
+ return "rgba($r,$g,$b,$(a/255))"
+end
\ No newline at end of file
diff --git a/src/show.jl b/src/show.jl
new file mode 100644
index 0000000..6fb5f95
--- /dev/null
+++ b/src/show.jl
@@ -0,0 +1,42 @@
+function _show(pp::PlutoPlot; script_id = "pluto-plotly-div", ver = PLOTLY_VERSION[])
+@htl """
+
+"""
+end
+
+# ╔═╡ d42d4694-e05d-4e0e-a198-79a3a5cb688a
+function Base.show(io::IO, mime::MIME"text/html", plt::PlutoPlot)
+ show(io, mime, _show(plt; script_id = plotly_script_id(io)))
+ # show(io, mime, _show(plt))
+end
\ No newline at end of file
diff --git a/test/plotlykaleido.jl b/test/plotlykaleido.jl
index 1233469..7549134 100644
--- a/test/plotlykaleido.jl
+++ b/test/plotlykaleido.jl
@@ -2,6 +2,8 @@ using PlutoPlotly
using PlotlyKaleido
using Test
+PlotlyKaleido.start()
+
mktempdir() do dir
cd() do
p = plot(rand(10,4))