Skip to content

Instantly share code, notes, and snippets.

@jason-s
Created June 29, 2022 13:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jason-s/15e8d676408a17c98508e0860a1593f7 to your computer and use it in GitHub Desktop.
Save jason-s/15e8d676408a17c98508e0860a1593f7 to your computer and use it in GitHub Desktop.
MathJax in SVG

SVG_MathJax

This replaces MathJax inline markup in an <svg> element with SVG-rendered MathJax.

Usage is easy:

<html>
    <head>
    <script type="text/javascript"
      src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG">
    </script>
    <script type="text/javascript" src="svg_mathjax.js">
    </script>
    <script type="text/javascript">
        new Svg_MathJax().install();
    </script>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300">
     <!-- center-align at x,y point: -->
     <text font-size="11" x="100" y="175">\( a^2 + b^2 = c^2 \)</text>
     <!-- left-align at x,y point: -->
     <text font-size="11" x="100" y="205">L\( a^2 + b^2 = c^2 \)</text>
     <!-- right-align at x,y point: -->
     <text font-size="11" x="100" y="235">R\( a^2 + b^2 = c^2 \)</text>
  </svg>
</body>
</html>
/*
* SVG_MathJax
*
* Copyright 2014 Jason M. Sachs
* Based loosely on an approach outlined by Martin Clark
* in http://stackoverflow.com/a/21923030/44330
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Svg_MathJax = (function() {
// apply a function to elements of an array x
function forEach(x,f) {
var n = x.length; for (var i = 0; i < n; ++i) { f(x[i]); }
}
// find all the SVG text elements that are delimited by
// \( \) or $ $ MathJax delimiters
// (with optional whitespace before/after)
function findSVGMathJax(f, context)
{
var re = /^\s*([LlRrCc]?)(\\\(.*\\\)|\$.*\$)\s*$/;
context = context || document;
forEach(context.getElementsByTagName('svg'), function(svg) {
forEach(svg.getElementsByTagName('text'), function(t) {
var m = t.textContent.match(re);
if (m)
{
f(svg, t, m);
}
});
});
}
function _install(options) {
var items = [];
// Move the raw MathJax items to a temporary element
MathJax.Hub.Register.StartupHook("Begin Typeset",function () {
var mathbucket = document.createElement('div');
mathbucket.setAttribute('id','mathjax_svg_bucket');
document.body.appendChild(mathbucket);
findSVGMathJax(function(svg, t, m) {
var d = document.createElement('div');
mathbucket.appendChild(d);
var mathmarkup = m[2].replace(/^\$(.*)\$$/,'\\($1\\)');
d.appendChild(document.createTextNode(mathmarkup));
t.textContent = '';
items.push([t,d,m[1]]);
});
});
MathJax.Hub.Register.StartupHook("End Typeset",function() {
forEach(items, function(x) {
var svgdest = x[0];
var mathjaxdiv = x[1];
var justification = x[2];
var svgmath =
mathjaxdiv.getElementsByClassName('MathJax_SVG')[0]
.getElementsByTagName('svg')[0];
var svgmathinfo = {
width: svgmath.viewBox.baseVal.width,
height: svgmath.viewBox.baseVal.height
};
// get graphics nodes
var gnodes =
svgmath.getElementsByTagName('g')[0].cloneNode(true);
var fontsize = svgdest.getAttribute('font-size');
var scale = options.scale*fontsize;
var x = +svgdest.getAttribute('x');
var y = +svgdest.getAttribute('y');
var x0 = x;
var y0 = y;
var x1;
switch (justification.toUpperCase())
{
case 'L': x1 = 0; break;
case 'R': x1 = -svgmathinfo.width; break;
case 'C': // default to center
default: x1 = -svgmathinfo.width * 0.5; break;
}
var y1 = svgmathinfo.height*0;
gnodes.setAttribute('transform', 'translate('+x0+' '+y0+')'
+' scale('+scale+') translate('+x1+' '+y1+')'
+' matrix(1 0 0 -1 0 0)');
if (options.escape_clip)
svgdest.parentNode.removeAttribute('clip-path');
svgdest.parentNode.replaceChild(gnodes,svgdest);
});
// remove the temporary items
var mathbucket = document.getElementById('mathjax_svg_bucket');
mathbucket.parentNode.removeChild(mathbucket);
});
}
var F = function()
{
this.scale = 0.0016;
this.escape_clip = false;
};
F.prototype.install = function() { _install(this); }
return F;
})();
<html>
<head>
<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG">
</script>
<script type="text/javascript" src="svg_mathjax.js">
</script>
<script type="text/javascript">
new Svg_MathJax().install();
</script>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">
<!-- center-align at x,y point: -->
<text font-size="11" x="100" y="75">\( a^2 + b^2 = c^2 \)</text>
<!-- left-align at x,y point: -->
<text font-size="11" x="100" y="105">L\( a^2 + b^2 = c^2 \)</text>
<!-- right-align at x,y point: -->
<text font-size="11" x="100" y="135">R\( a^2 + b^2 = c^2 \)</text>
</svg>
</body>
</html>
<html>
<head>
<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG">
</script>
<script type="text/javascript" src="svg_mathjax.js">
</script>
<script type="text/javascript">
new Svg_MathJax().install();
</script>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="600">
<defs id="defs_block">
<filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
<feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
</filter>
</defs>
<title>blockdiag</title>
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="46" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="259" y="46" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="451" y="46" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="451" y="126" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="643" y="126" />
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="40" />
<text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="110" y="65">plain text</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="256" y="40" />
<text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="320" y="65">\( e^{-sT} \)</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="448" y="40" />
<text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="512" y="65">R\( \frac{3}{s^2+1} \)</text>
<text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="470" y="95">aligned at the right</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="448" y="120" />
<text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="512" y="145">L\( H(s) \)</text>
<text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="470" y="175">aligned at the left</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="640" y="120" />
<text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="704" y="145">$ K_p + \left( 1 + {1 \over T s} \right) $</text>
<path d="M 192 60 L 248 60" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="255,60 248,56 248,64 255,60" stroke="rgb(0,0,0)" />
<path d="M 384 60 L 440 60" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="447,60 440,56 440,64 447,60" stroke="rgb(0,0,0)" />
<path d="M 384 60 L 416 60" fill="none" stroke="rgb(0,0,0)" />
<path d="M 416 60 L 416 140" fill="none" stroke="rgb(0,0,0)" />
<path d="M 416 140 L 440 140" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="447,140 440,136 440,144 447,140" stroke="rgb(0,0,0)" />
<path d="M 576 140 L 632 140" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="639,140 632,136 632,144 639,140" stroke="rgb(0,0,0)" />
<path d="M 768 140 L 784 140" fill="none" stroke="rgb(0,0,0)" />
<path d="M 784 140 L 784 25" fill="none" stroke="rgb(0,0,0)" />
<path d="M 320 25 L 784 25" fill="none" stroke="rgb(0,0,0)" />
<path d="M 320 25 L 320 32" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="320,39 316,32 324,32 320,39" stroke="rgb(0,0,0)" />
</svg>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment