diff --git a/.gitignore b/.gitignore index 1eecbb0..c20255a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ /Manifest.toml /docs/Manifest.toml /docs/build/ -testdebug.jl \ No newline at end of file +testdebug.jl + +.vscode/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f8b2a22 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.2.0] - 2025-01-02 + +### Added + +- DocumenterVitepress extension to circumvent the limitation of raw javascript code in Vue. + +### Changed + +- The `to_documenter` function no longer directly returns HTML, but rather an object for which `Base.show(::MIME"text/html")` is defined. diff --git a/Project.toml b/Project.toml index 42e79bc..fc2fb4b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PlotlyDocumenter" uuid = "9b90f1cd-2639-4507-8b17-2fbe371ceceb" authors = ["Alberto Mengali "] -version = "0.1.3" +version = "0.2.0" [deps] Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" @@ -10,25 +10,28 @@ PackageExtensionCompat = "65ce6f38-6b18-4e1d-a461-8949797d7930" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [weakdeps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterVitepress = "4710194d-e776-4893-9690-8d956a29c365" PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" -PlotlyLight = "ca7969ec-10b3-423e-8d99-40f33abb42bf" PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" +PlotlyLight = "ca7969ec-10b3-423e-8d99-40f33abb42bf" [extensions] +DocumenterVitepressPlotsExt = ["DocumenterVitepress", "Documenter"] PlotlyBaseExt = "PlotlyBase" PlotlyJSExt = "PlotlyJS" PlotlyLightExt = "PlotlyLight" [compat] +Downloads = "1" HypertextLiteral = "0.9" PackageExtensionCompat = "1" -Downloads = "1" julia = "1.6" [extras] PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" -PlotlyLight = "ca7969ec-10b3-423e-8d99-40f33abb42bf" PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" +PlotlyLight = "ca7969ec-10b3-423e-8d99-40f33abb42bf" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] diff --git a/docs/make.jl b/docs/make.jl index 9c40bed..1eecc7d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -18,6 +18,7 @@ makedocs(; ), pages=[ "Home" => "index.md", + "DocumenterVitepress" => "vitepress.md", ], ) diff --git a/docs/src/index.md b/docs/src/index.md index 9f47976..a3fbac0 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -6,14 +6,20 @@ CurrentModule = PlotlyDocumenter Documentation for [PlotlyDocumenter](https://github.com/disberd/PlotlyDocumenter.jl). -```@index -``` +This package provides a function `to_documenter` that returns a wrapped plot object. This object will be rendered interactively by Documenter. +If you are using DocumenterVitepress, see [here](vitepress.md) for more information. + +!!! note + To prevent `to_documenter` from showing up in the documentation, add `#hide` to the end of the line. + See [Documenter.jl](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-example) for more information. +## API ```@autodocs Modules = [PlotlyDocumenter] ``` -## PlotlyBase +## Examples +### PlotlyBase ```@example using PlotlyDocumenter using PlotlyBase @@ -22,7 +28,7 @@ p = Plot(scatter(;y = rand(5))) to_documenter(p) ``` -## PlotlyJS +### PlotlyJS ```@example using PlotlyDocumenter using PlotlyJS @@ -31,7 +37,7 @@ p = plot(scatter(;y = rand(5)), Layout(height = 700)) to_documenter(p) ``` -## PlotlyLight +### PlotlyLight ```@example using PlotlyDocumenter using PlotlyLight diff --git a/docs/src/vitepress.md b/docs/src/vitepress.md new file mode 100644 index 0000000..6ecf3ad --- /dev/null +++ b/docs/src/vitepress.md @@ -0,0 +1,30 @@ +# Usage with DocumenterVitepress + +PlotlyDocumenter provides an extension to work with DocumenterVitepress. As raw javascript code cannot be executed in Vue, an alternate approach is required. +For this reason, when using DocumenterVitepress, the custom plot object will be rendered as the `` component from the [vue3-plotly-ts](https://github.com/boscoh/vue3-plotly-ts) package. + +!!! warning + The keyword arguments for `to_documenter` are ignored when using DocumenterVitepress. + +To make this work, first install the `vue3-plotly-ts` package in your project: + +```bash +npm install vue3-plotly-ts +``` + +Then, add the `VuePlotly` component to your `.vitepress/theme/index.ts` file: + +```typescript +import VuePlotly from "vue3-plotly-ts" + +export default { +... +enhanceApp({ app, router, siteData }) { + ... + app.component('VuePlotly', VuePlotly); + ... +} +} satisfies Theme +``` +In your `make.jl`, make sure you call `using PlotlyDocumenter` before `makedocs`. + \ No newline at end of file diff --git a/ext/DocumenterVitepressPlotsExt.jl b/ext/DocumenterVitepressPlotsExt.jl new file mode 100644 index 0000000..5acb094 --- /dev/null +++ b/ext/DocumenterVitepressPlotsExt.jl @@ -0,0 +1,24 @@ +module DocumenterVitepressPlotsExt + +using Documenter +using DocumenterVitepress +using HypertextLiteral +using PlotlyDocumenter + +DocumenterVitepress.mime_priority(::MIME"text/vnd.plotlydocumenter.plot") = 2.5; +DocumenterVitepress.render_mime(io::IO, mime::MIME"text/vnd.plotlydocumenter.plot", node, element, page, doc; kwargs...) = println(io, element) + +function Documenter.display_dict(x::PlotlyDocumenterPlot; context = nothing) + base_dict = invoke(Documenter.display_dict, Tuple{Any}, x; context) + rendered = @htl(""" + + """) + base_dict[MIME"text/vnd.plotlydocumenter.plot"()] = repr(MIME"text/html"(), rendered, context = context) + return base_dict +end + +end diff --git a/ext/PlotlyBaseExt.jl b/ext/PlotlyBaseExt.jl index c180abe..cf80cf3 100644 --- a/ext/PlotlyBaseExt.jl +++ b/ext/PlotlyBaseExt.jl @@ -6,6 +6,6 @@ module PlotlyBaseExt data = json(p.data) layout = json(p.layout) config = json(p.config) - return PlotlyDocumenter._to_documenter(;kwargs..., data, layout, config) + return PlotlyDocumenterPlot(data, layout, config, kwargs...) end end \ No newline at end of file diff --git a/ext/PlotlyLightExt.jl b/ext/PlotlyLightExt.jl index 3b2131a..5bcd755 100644 --- a/ext/PlotlyLightExt.jl +++ b/ext/PlotlyLightExt.jl @@ -15,6 +15,6 @@ module PlotlyLightExt data = JSON3.write(p.data) layout = JSON3.write(merge(settings.layout, p.layout)) config = JSON3.write(merge(settings.config, p.config)) - return PlotlyDocumenter._to_documenter(;kwargs..., data, layout, config) + return PlotlyDocumenterPlot(data, layout, config, kwargs...) end end \ No newline at end of file diff --git a/src/PlotlyDocumenter.jl b/src/PlotlyDocumenter.jl index a103bdf..6bc1835 100644 --- a/src/PlotlyDocumenter.jl +++ b/src/PlotlyDocumenter.jl @@ -6,6 +6,30 @@ using Random using Downloads: download export to_documenter +export PlotlyDocumenterPlot + +""" + PlotlyDocumenterPlot + +A wrapper type for Plotly plot data that enables flexible rendering in different contexts. + +The plot data is stored as strings containing the JSON representation of the plot's data, layout and config. + +The `options` field contains rendering options that control how the plot is displayed. For the default +`text/html` MIME output, see [`to_documenter`](@ref) for more information. +""" +struct PlotlyDocumenterPlot + data::AbstractString + layout::AbstractString + config::AbstractString + options::Dict{Symbol,Any} + + function PlotlyDocumenterPlot(data, layout, config, kwargs...) + options = Dict{Symbol,Any}(kwargs...) + return new(data, layout, config, options) + end +end + # Taken from PlotlyLight get_semver(x) = VersionNumber(match(r"v(\d+)\.(\d+)\.(\d+)", x).match[2:end]) @@ -16,6 +40,7 @@ function latest_plotlyjs_version() get_semver(read(file, String)) end + const DEFAULT_VERSION = v"2.24.2" const PLOTLY_VERSION = Ref(DEFAULT_VERSION) @@ -25,15 +50,22 @@ Change the plotly version that is used by default to render Plotly plots using [ """ change_default_plotly_version(v) = PLOTLY_VERSION[] = VersionNumber(string(v)) -function _to_documenter(;data, layout, config, version = PLOTLY_VERSION[], id = randstring(10), classes = [], style = (;)) +function Base.show(io::IO, ::MIME"text/html", x::PlotlyDocumenterPlot) js = HypertextLiteral.JavaScript + + version = get(x.options, :version, PLOTLY_VERSION[]) + id = get(x.options, :id, randstring(10)) + classes = get(x.options, :classes, []) + style = get(x.options, :style, (;)) + v = js(string(version)) plot_obj = (; - data = js(data), - layout = js(layout), - config = js(config), + data = js(x.data), + layout = js(x.layout), + config = js(x.config), ) - return @htl(""" + + rendered = @htl("""
""") + Base.show(io, MIME"text/html"(), rendered) end # Define the function name. Methods are added in the extension packages diff --git a/test/runtests.jl b/test/runtests.jl index 11d7717..12a6e8c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,9 +7,7 @@ import PlotlyJS @testset "PlotlyDocumenter.jl" begin function to_str(o) - io = IOBuffer() - show(io, o) - String(take!(io)) + repr(MIME"text/html"(), o) end