MathJax inside SVG

风流意气都作罢 提交于 2019-12-03 10:56:37

问题


I'm doing some writing where I use MathJax to render the math. I also occasionally include SVG diagrams which are generated dynamically by javascript. Those SVG diagrams occasionally include math.

I'd like the text elements in those SVG diagrams to be rendered using MathJax. I know how to cause the dynamic math to be rendered. However, the mathjax output is in <span>s which aren't valid SVG and don't show up.

This persists when I configure MathJax to use SVG output mode, though this is perhaps due to an improper use of SVG output mode. I changed by MathJax CDN link to http://cdn.mathjax.org/mathjax/2.1-latest/MathJax.js?config=TeX-AMS-MML_SVG, which did not produce SVG output. I haven't been able to coax MathJax into actually outputting SVG elements yet.

I've considered using an SVG <foreignObject> tag which is non-ideal because (to my knowledge) I must specify a width and height, which is inconvenient.

Is there a better way to include MathJax rendered text inside SVG inside HTML?


回答1:


Currently, the only way to include MathJax within an SVG diagram is through <foreignObject>. Yes, it is not ideal, not only because you need to provide a size, but also because IE9+ doesn't support <foreignObject>.

As for the SVG output, if you have used the MathJax contextual menu to select a math render, that will override the renderer choice in the document, so you may still be seeing HTML-CSS output for that reason. The value is stored in a cookie, so that it will be remembered from session to session. You can delete the cookie to remove the setting, or use the MathJax menu again to select SVG rendering.

Note, however, that this isn't going to help you either, as MathJax's SVG output is not just an SVG snippet that can be included into a larger SVG file, but include some HTML and the <svg> element itself. Moreover, MathJax needs the surrounding HTML to determine things like the font-size to use, and some other factors, so it is not going to be able to placed directly into your SVG diagram.

The <foreignObject> approach is really the only reliable way at the moment.

Edit: Here is a full example:

<!DOCTYPE html>
<html>
<head>
<title>MathJax in SVG diagram</title>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG"></script>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1000" height="500">
  <circle cx="100" cy="100" r="99" fill="yellow" stroke="red" />
  <circle cx="100" cy="100" r="3" fill="blue" />
  <foreignObject x="100" y="100" width="100" height="100">
    <div xmlns="http://www.w3.org/1999/xhtml" style="font-family:Times; font-size:15px">
    \(\displaystyle{x+1\over y-1}\)
    </div>
  </foreignObject>
</svg>
</body>
</html>



回答2:


There is a way to include MathJax SVG elements in an SVG diagram, without requiring foreignObject. A full demonstration of the technique is at http://puzlet.com/m/b00b3.

Say you have an SVG diagram like this (and containing any SVG elements) in your web page:

<svg id="diagram" xmlns='http://www.w3.org/2000/svg' 
    xmlns:xlink="http://www.w3.org/1999/xlink"
    version='1.1' width='720' height='100'>
</svg>

and the following MathJax:

<div id="mathjaxSource">
$\Omega$
</div>

Use this CoffeeScript (plus jQuery) to integrate the MathJax element into your SVG diagram:

diagram = $("#diagram")  # SVG diagram
obj = new MathJaxObject "mathjaxSource"  # MathJax object (see class definition below)
obj.appendTo diagram  # Append MathJax object to diagram
obj.translate 100, 200  # Position MathJax object within diagram

You can also use the width() and height() methods for centering and vertical alignment.

class MathJaxObject

    constructor: (@divId, @scale=0.02) ->
        @source = $("##{@divId}").find ".MathJax_SVG"
        @svg = @source.find "svg"
        g = @svg.find "g"
        @group = $(g[0]).clone()
        @translate 0, 0

    viewBox: -> @svg[0].viewBox

    width: -> @scale * @viewBox().baseVal.width

    height: -> @scale * @viewBox().baseVal.height

    translate: (@dx, @dy) ->
        dy = @dy + (-@scale * @viewBox().baseVal.y)
        @group[0].setAttribute "transform", 
            "translate(#{@dx} #{dy}) scale(#{@scale}) matrix(1 0 0 -1 0 0)"

    appendTo: (diagram) ->
        diagram.append @group



回答3:


I've used the following, which defines a function that takes latex code as input and appends the MathJax processed svg to a target SVG element.

// First create a new element to hold the initial Latex code
// and eventual MathJax generated SVG. This element isn't added
// to the main docuemnt, so it's never seen.
let mathBuffer = document.createElement("div");

// Then define a function that takes LaTeX source code
// and places the resulting generated SVG in a target SVG element.
mathSVG = function (latex, target) {
  // Update the buffer with the source latex.
  mathBuffer.textContent = latex;
  // Get MathJax to process and typeset.
  MathJax.Hub.Queue(["Typeset", MathJax.Hub, mathBuffer]);
  // Queue a callback function that will execute once it's finished typesetting.
  MathJax.Hub.Queue(function () {
    // This (svg) is the generated graphics.
    const svg = mathBuffer.childNodes[1].childNodes[0];
    // The next line is optional, play with positioning as you see fit.
    svg.setAttribute("y", "-11pt");
    // Move the generated svg from the buffer to the target element.
    target.appendChild(svg);
    // Clear the buffer.
    mathBuffer.textContent = "";
  });
};

In the above, I'm assuming an html host document with svg elements within. It should also work in a svg host document too.



来源:https://stackoverflow.com/questions/15962325/mathjax-inside-svg

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!