Feed Subscribe
Exception has been thrown by the target of an invocation.


Displaying math in web applications and font embedding

by ondrejsv 6. September 2010 18:08

When some math creeps into requirements list for your new web application, you get a bad feeling. It’s a problem because although the MathML standard has been there for years, only Gecko based browsers and Opera support it natively (WebKit based browsers in their latest builds, KHTML with no support) and the biggest problem – Internet Explorer still does not support it in 8th version and MathML support in IE9 has still not been confirmed. You have a few options:

  • force your IE users to download and use an ActiveX MathML player – not quite a pretty solution,
  • do some magic and convert (La)TeX formulas into images (Wikipedia approach) – there is mimeTeX and also an ASP.NET wrapper (but they render low quality GIF images),
  • buy a commercial software (I found Equation Server for .NET, however, I didn’t try it),
  • use jsMath!

jsMath

jsMath is a fantastic open source javascript library that renders any TeX formula into a series of positioned spans. If the user has TeX CM fonts installed, it uses them directly; if not, it has a fallback to displaying basic glyphs as images but this process is transparent to you as a web developer.

Deployment is simple. Download jsMath package from its homepage together with image fonts. Unpack image fonts into a subfolder called “fonts” of the jsMath folder. Now create a new ASP.NET web project/site and copy the jsMath folder to the root folder. Set any permanent port number in the project properties in Visual Studio because we need a fixed URL.

Open the jsMath/easy/load.js file and set root property to the full URL of the jsMath folder. If your web site runs on the 6500 port on localhost, for example, it will loke like this:

root: "http://localhost:6500/jsMath/",

(Of course, do not forget to edit also after deploy to your production environment.)

Now include this javascript into your .aspx file – I included it in my master page because I’m going to do math on almost all pages:


<script type="text/javascript" src='<%= ResolveUrl("~/jsMath/easy/load.js") %>'></script>

and let’s start doing math:


Some inline math: \(\sqrt{1-x^2}\) or \(ax^2+bx+c\),

jsMath will render this instantly:

image

If you wonder about the formula format, read any TeX or LaTeX manual.

Font embedding

With releases of Firefox 3.5, Safari 3.1 and Opera 10, web developers can use a feature called font embedding. It means that we don’t need to rely only on web-safe fonts and we can use any font by using the @font-face technique.

A common myth is that Internet Explorer does not support this technique. It’s false and the truth is that Internet Explorer has supported font embedding long before Firefox or Safari even existed – since IE4 (1997!). It supports, however, only one of formats specified in the CSS standard, called Embedded OpenType (.eot) but this usually is not a problem since conversion tools from TrueType exist.

Using the technique, we can almost always prevent the image-font fallback of our formulas even without requiring users to manually download and install CM fonts. Just copy all TTF and converted EOT fonts and include proper CSS stylesheets with EOT font for IE and TTF for all other browsers:

@font-face {
 font-family: jsMath-cmex10;
 src: url("jsMathFonts/jsMath-cmex10.eot") /* EOT file for IE */
}
@font-face {
 font-family: "jsMath-cmex10";
 src: url("jsMathFonts/jsMath-cmex10.ttf") /* TTF file for CSS3 browsers */
}

(this is just one font of 6 required by jsMath)

To make it easier for you, you may download the fonts together with the CSS file. Just include the CSS file in your pages or master like me:


<link href="../../Content/jsMath.css" rel="stylesheet" type="text/css" />

Now almost all your users will benefit from formulas rendered by CM fonts (at least IE, Firefox, Chrome, Safari and Opera! – that’s the vast majority).

As you can see, it’s all plain text – I can select it with no problems:

image

If you are curious, the first formula is converted to this HTML:


<SPAN class=typeset alt="\sqrt{1-x^2}"><NOBR><SPAN class=scale><SPAN style="POSITION: relative; DISPLAY: inline-block"><SPAN style="POSITION: absolute; TOP: 0em; LEFT: 0em"><SPAN style="POSITION: relative; WIDTH: 0.83em; TOP: -0.84em; LEFT: 0em"><SPAN class=cmsy10>p</SPAN></SPAN><SPAN style="POSITION: relative; WIDTH: 2.63em; TOP: -0.81em; LEFT: 0em"><SPAN style="BORDER-LEFT: 2.63em solid; HEIGHT: 1.5px" class=blank></SPAN></SPAN><SPAN style="WIDTH: 1px; DISPLAY: inline-block; MARGIN-RIGHT: -1px"></SPAN><SPAN style="MARGIN-LEFT: -2.63em" class=spacer></SPAN><SPAN class=cmr10>1</SPAN><SPAN style="WIDTH: 1px; DISPLAY: inline-block; MARGIN-RIGHT: -1px"></SPAN><SPAN style="MARGIN-LEFT: 0.22em" class=spacer></SPAN><SPAN class=cmsy10>À</SPAN><SPAN style="WIDTH: 1px; DISPLAY: inline-block; MARGIN-RIGHT: -1px"></SPAN><SPAN style="MARGIN-LEFT: 0.22em" class=spacer></SPAN><SPAN class=cmmi10>x</SPAN><SPAN style="POSITION: relative; WIDTH: 0.39em; TOP: -0.28em; LEFT: 0em"><SPAN class=size2><SPAN class=cmr10>2</SPAN></SPAN><SPAN style="WIDTH: 1px; DISPLAY: inline-block; MARGIN-RIGHT: -1px"></SPAN><SPAN style="MARGIN-LEFT: 0.05em" class=spacer></SPAN></SPAN>&nbsp;</SPAN><SPAN style="WIDTH: 3.47em; HEIGHT: 0.83em" class=blank></SPAN></SPAN><SPAN style="HEIGHT: 1.18em; VERTICAL-ALIGN: -0.16em" class=blank></SPAN></SPAN></NOBR></SPAN>

But remember. It’s all automatic and on-the-fly, you won’t even see this markup in View->Source.

Firefox and Chrome bug

There’s one more small glitch. Firefox and Chrome (and possibly also Safari) use an optimization which does not download and apply fonts specified by the @font-face rules if you don’t use them directly in the page markup. Since our formulas are parsed and converted by javascript and does not use directly any “font-family: jsMath-cmex10”, you end with fall-backed image fonts when using these browsers. This optimization is buggy because it does not take into account that you can set font-family css property also by javascript. My workaround is to use a dummy span with font-family set to jsMath-cmex10 (this is the font jsMath uses for testing whether the user has CM fonts) and some non-visible character:


<span style="font-family: jsMath-cmex10;">&nbsp;</span>

Note that you can’t hide it by display:none because the font won’t be loaded.

Place it somewhere to your masterpage where it won’t get in the way to other content.

Tags: