SimonDanisch / Bonito.jl

Serving JS to the browser
MIT License
204 stars 29 forks source link

Using MathJax for rendering LaTeX #206

Open timoleistner opened 8 months ago

timoleistner commented 8 months ago

Hi, As there is a way of wrapping JS libraries it should be possible to use MathJax somehow. I would like to use LaTeX like this for example:

DOM.p(L"$log(x_t)=A+C\cdot e^{−e^{(−B\cdot (t−M))}}$")

While the documentation gives one example, I am not sure how to make MathJax work.

MathJax states that: If you write your own HTML (directly or via a template/theme engine), you can include MathJax by adding this snippet to your page:

<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

Franklin.jl made it work too somehow

Any pointers would be appreciated.

SimonDanisch commented 8 months ago

Did you try by adding that snipped to the page with DOM.script?

timoleistner commented 8 months ago

I tried different things but to no avail.

App() do session
    jsmodule = ES6Module("https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js")::Asset

    DOM.script(src=jsmodule, type="module")
    return DOM.p(raw"$log(x_t)=A+C\cdot e^{−e^{(−B\cdot (t−M))}}$")
end
App() do session

    DOM.script("""
    <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
    <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
    """
    )
    return DOM.p(raw"$log(x_t)=A+C\cdot e^{−e^{(−B\cdot (t−M))}}$")
end
App() do session
    jsmodule = ES6Module("https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js")::Asset

    return DOM.p(js"$(jsmodule).then(jsmodule=> {
            $log(x_t)=A+C\cdot e^{−e^{(−B\cdot (t−M))}}$
    })")
end

I am also not sure if I should use a raw"" string or a latex string L"" or js"". I'm probably missing some fundamental thing :thinking:

Edit: There is also a CDN https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_SVG but the CDNSource() from the Docs Assets part isnt working anymore.

SimonDanisch commented 8 months ago

This should work:

App() do 
    polyfill = DOM.script(src="https://polyfill.io/v3/polyfill.min.js?features=es6")
    mthjax = DOM.script(id="MathJax-script", src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js", async=true)
    mathtex = raw"When \(a \ne 0\), there are two solutions to 
        \(ax^2 + bx + c = 0\) and they are
        \[x = {-b \pm \sqrt{b^2-4ac} \over 2a}.\]"
    return DOM.div(polyfill, mthjax, DOM.p_unesc(mathtex))
end

It only works on first display though... It should work on static sites like that, or when you serve the app via a server - just not with browser-display.

I guess it's because of: https://docs.mathjax.org/en/latest/advanced/typeset.html But doing mathjax.typeset() runs into: https://github.com/mathjax/MathJax/issues/3079

timoleistner commented 8 months ago

Very nice! I think it would be cool to have an example like this in the docs in the Wrapping JS libraries section. Like you said, it works when serving the app via server and doesn't work in Pluto (browser-display).

It would be nice to have a more accessible/intuitive way of doing this, like overloaded LatexStrings so that one could also use string interpolation or is this possible already somehow? I tried the following to no avail:

App() do 
    polyfill = DOM.script(src="https://polyfill.io/v3/polyfill.min.js?features=es6")
    mthjax = DOM.script(id="MathJax-script", src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js", async=true)
    mathtex = Observable(raw"When \(a \ne 0\), there are two solutions to 
        \(ax^2 + bx + c = 0\) and they are
        \[x = {-b \pm \sqrt{b^2-4ac} \over 2a}.\]")
    s_a = Bonito.Slider(range(1, 10, step=0.5), value=5)
    function texstring(var)
        mathtex[] = raw"When \(" * "$var" * raw"\)"
    end
    map(texstring, s_a.value)
    return DOM.div(polyfill, mthjax, DOM.p_unesc(mathtex))
end

Is there any information on DOM.p_unesc()? Because I couldn't find anything on this (Neither in the docs of Bonito.jl nor in its code or in Hyperscript.jl's code) but it seems to work without wrapping the mathtex string in it.

How did you try to use mathjax.typeset()? Just including it in the example like this

App() do 
    polyfill = DOM.script(src="https://polyfill.io/v3/polyfill.min.js?features=es6")
    mathjax = DOM.script(id="MathJax-script", src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js", async=true)
    mathtex = raw"When \(a \ne 0\), there are two solutions to 
        \(ax^2 + bx + c = 0\) and they are
        \[x = {-b \pm \sqrt{b^2-4ac} \over 2a}.\]"
    mathjax.typeset()
    return DOM.div(polyfill, mthjax, DOM.p_unesc(mathtex))
end

won't throw the mentioned error for me (but won't render latex in Pluto either).

Anyway it's cool that this functionality is basically there already. Thank you for this cool package!