Expressions et équations mathématiques en HTML avec MathJax et AsciiMath

Introduction

L'écriture d'expressions et d'équations mathématiques dans des articles, même si l'usage n'est pas du tout courant, voire exceptionnel, a toujours été problématique. Mais parfois il est nécessaire de représenter une formule surtout si les statistiques sont abordées avec le langage R.

Soit l'expression est brute de fonderie, peu ergonomique et difficilement lisible, notamment avec la présence de fractions, exemple :

Taille d'un cylindre (Mb) = ("sectors/cylinder" * "bytes/sector") / 1024000

Soit une image est créée à partir d'outils comme Formule Math dans LibreOffice, image qui doit être recréée si la formule doit être modifiée et pour laquelle le texte ne peut pas être copié par l'internaute :Equation format image

HTML 5 devait intégrer le standard MathML pour l'écriture d'expressions mathématiques en HTML. Mais les éditeurs de navigateurs en ont décidément autrement. Le support de MathML entre les navigateurs (Chrome, FireFox, MS Internet Explorer...) est trop disparate et il y a trop de désaccords entre eux sur ce sujet.

Google, l'éditeur de Chrome, a probablement raison d'ailleurs en décidant de ne pas porter MathML en standard dans son navigateur. Les arguments avancés sont l'usage de MathML restreint à un public de scientifiques et l'existence de librairies Javascript très puissantes qui sont en mesure de répondre au besoin.

Et effectivement, MathJax est une librairie Javascript, compatible avec tous les navigateurs, simple et très évoluée pour les expressions mathématiques en HTML. Le rendu est impressionnant, le codage simple et le contenu des expressions devient ainsi aisément modifiable en cas d'erreur ou de besoin. Les 2 exemples ci-dessus deviennent avec MathJax :

`text{Taille d'un cylindre (Mb)}=frac(text{"sectors/cylinder"} xx text{"bytes/sector"})(1024000)` `R=text{CHAIN_CNT}/text{NUM_ROWS} >= 0,05`

Cet article n'est pas un tutoriel sur l'utilisation de MathJax pour écrire des équations de physique. Cette librairie est très riche (Tex, Latex...) et la documentation est de très bonne qualité. Il s'agit ici d'un simple aide mémoire pour inclure MathJax automatiquement dans des articles si des expressions mathématiques y sont présentes avec quelques exemples simples pour écrire rapidement des équations courantes (fractions, symboles grecs, expressions statistiques...).

Installation de MathJax

Il est possible d'utiliser la librairie MathJax en ligne mais si vous préférez l'installer en local sur votre site web, la dernière version de MathJax est disponible en téléchargement au format zip depuis le site www.mathjax.org : MathJax Download

La librairie MathJax fait environ 50 Mb (version 2.6 en août 2017). Décompresser l'archive zip et installer MathJax dans le répertoire contenant les librairies Javascript du site Web. Ici MathJax est installé dans le répertoire wwwroot/js/mathjax.

Dans la suite, les articles *.html sont installés dans le répertoire wwwroot/docs.

Appel de MathJax en natif

La librairie MathJax est très riche, plusieurs options sont possibles : Latex, MathML, AsciiMath... AsciiMath est l'option la plus simple pour un usage courant, LaTex et les autres sont plus destinés aux purs mathématiciens, physiciens et statisticiens. Pour appeler en natif MathJax avec l'option AsciiMath depuis une page HTML, appeler dans le l'entête de la page le script wwwroot/js/mathjax/MathJax.js.

<head>
...
<script type="text/javascript" 
           src="../js/mathjax/MathJax.js?config=AM_HTMLorMML-full">
</script>
...
</head>

L'acronyme AM correspond à AsciiMath.

Et le tour est joué, vous pouvez commencer à écrire des expressions mathématiques. Il suffit d'encapsuler l'expression mathématique entre les caractères `.

<div>
           `x^2 + 2x + 1`
<br>
           `d/dxf(x) = lim_(h->0)(f(x+h)-f(x))/h`
<br>
           `sum_(n=0)^oo`
<br>
           `root3x`
</div>
`x^2 + 2x + 1`
`d/dxf(x) = lim_(h->0)(f(x+h)-f(x))/h`
`sum_(n=0)^oo`
`root3 x`

Les expressions sont écrites ici dans des blocs div, mais rien n'empêche d'écrire des expressions "in line" au sein d'une ligne grâce aux balises span.

<p>Une expression : <span> `sum_(i=1)^n i^3=((n(n+1))/2)^2`</span> au sein d'une phrase.</p>

Une expression : `sum_(i=1)^n i^3=((n(n+1))/2)^2` au sein d'une phrase.

Appeler MathJax si besoin dans une page HTML grâce aux classes

Les pages HTML n'incluent pas forcément des expressions mathématiques et il n'est pas nécessaire de charger MathJax, qui a un surcoût non négligeable, si une page n'en a pas besoin. Donner une classe CSS particulière pour les blocs div et span qui contiennent des expressions mathématiques est une solution simple pour appeler dans ce cas la librairie MathJax.js. Cette solution présente le double avantage de charger la librairie et de formater en même temps le style des blocs qui contiennent les expressions.

Par exemple, la classe asciimath est appliquées aux blocs div et span comportant des formules :

<span class="asciimath"> `x^2 + 2x +1` </span>
<div class="asciimath"> `(a + b)^2 = a^2 + 2ab + b^2` </div>

Avec la méthode Javascript getElementsByClassName sur la classe asciimath, la librairie MathJax.js est chargée si le nombre d'éléments ayant la classe asciimath est supérieur à 0. La méthode appendChild  est utilisée pour le chargement :

if (document.getElementsByClassName('asciimath').length > 0) 
{ 
  v_head = document.getElementsByTagName("head")[0]; 
  v_script_js = document.createElement ("script"); 
  v_script_js.setAttribute("type","text/javascript"); 
  v_script_js.setAttribute("src","../js/mathjax/MathJax.js?config=AM_HTMLorMML-full");
  v_head.appendChild(v_script_js);
}

Même si les blocs div ou span ont plusieurs classes (ex : <span class="bg-fluojaune asciimath">), la méthode getElementsByClassName fonctionne sans problème.

Cette cinématique est encapsulée dans une fonction run_asciimath, fonction qui est appelée lorsque la page est chargée grâce à la méthode addEventListener de l'objet window.

<head>
...
<script type="text/javascript">

  run_asciimath = function() {
    if (document.getElementsByClassName('asciimath').length > 0) 
    { 
     v_head = document.getElementsByTagName("head")[0]; 
     v_script_js = document.createElement ("script"); 
     v_script_js.setAttribute("type","text/javascript"); 
     v_script_js.setAttribute("src","../js/mathjax/MathJax.js?config=AM_HTMLorMML-full");
     v_head.appendChild(v_script_js);
    }
  };

  if(window.addEventListener) { 
   window.addEventListener("load",run_asciimath, false); // IE9, Chrome, FireFox
  } 
  
</script>
...
</head>

Bien entendu, pour être encore plus générique pour chaque article, inclure ce code javascript dans un script générique lib.js chargé en entête de la page.

<head>
...
<script type="text/javascript" src="../js/lib.js"></script>
...
</head>
lib.js
  run_asciimath = function() {
    if (document.getElementsByClassName('asciimath').length > 0) 
    { 
     v_head = document.getElementsByTagName("head")[0]; 
     v_script_js = document.createElement ("script"); 
     v_script_js.setAttribute("type","text/javascript"); 
     v_script_js.setAttribute("src","../js/mathjax/MathJax.js?config=AM_HTMLorMML-full");
     v_head.appendChild(v_script_js);
    }
  };

  if(window.addEventListener) { 
   window.addEventListener("load",run_asciimath, false); // IE9, Chrome, FireFox
  } 

Le caractère underscore _ dans les expressions : text{ }

Juste un petit mot sur le caractère underscore car les exemples d'équations dans les documentations et tutoriaux abordent très peu ce point. Bien souvent dans les expressions les variables possédent des caractères underscore _ , caractère interprété par AsciiMath pour appliquer des indices. Afin que ce caractère ne soit pas interprété, utiliser l'option text{variable_1}.

<div class="asciimath">`R=D/L=frac (text{DEL_LF_ROWS})(text{LF_ROWS}) >= 0,1`</div>
`R=D/L=frac (text{DEL_LF_ROWS})(text{LF_ROWS}) >= 0,1`

Problèmatique du backtick en délimiteur entre les expressions mathématiques et les syntaxes MySQL et Shell

L'utilisation du caractère backtick ` comme délimiteur soulève une question : que se passe-t-il si l'article utilise ce caractère dans le corps du texte ou dans une syntaxe MySQL ou Shell qui utilise le backtick ?

insert into `matable` values ...

Aucun problème à ce sujet, les backticks ne sont pas interprétés par MathJax lorsque ce caractère est présent dans les balises ci-dessous :

  • script, noscript
  • style
  • textarea, pre, code
  • annotation, annotation-xml

Pour MySQL et les scripts Shell, sauf cas particulier, les balises pre et code sont utilisées afin de bénéficier de la coloration syntaxique avec HighlightJs notamment. Pour les autres cas, utiliser la balise code ou encore annotation pour encapsuler le backtick afin que MathJax n'interprète pas le contenu.

<code>`</code> <annotation>`</annotation>

Si le backtick comme délimiteur d'expressions mathématiques génère trop de conflits avec le contenu dans une page, le délimiteur backtick pour AsciiMath peut être modifié avec le code type ci-dessous avant l'appel de la librairie MathJax :


<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
     asciimath2jax: {
         delimiters: [['~','~']]
     }
  });
</script>
<script type="text/javascript" src="../js/lib.js"></script>

Le backtick ` est remplacé par le caractère tilde ~ comme délimiteur dans cet exemple.

Le menu MathJax

Un menu MathJax bien pratique est alors disponible avec un clic droit sur une expression mathématique :Clic droit - Menu MathJax

À partir du menu "Show Math As", le code MathML ou AsciiMath peut être récupéré pour être copié/collé et adapté.code AsciiMath clic droit

Le menu "Math SettingsMath Renderer" propose quant à lui de réaliser un rendu dans d'autres techniques qu'AsciiMath et disponibles dans MathJax (MathML, SVG...) :Menu MathJax - Math renderer

Mais comme cela a été évoqué en introduction, d'où le choix de la librairie MathJax, le rendu en MathML n'est pas devenu un standard avec HTML 5 et n'est pas forcément disponible dans le navigateur utilisé. Avec Google Chrome, c'est KO.MathJax Chrome - MathML non supporté

Conclusion

MathJax et l'option AsciiMath sont vraiment simples pour écrire en HTML des expressions mathématiques avec un rendu ergonomique. MathML n'est pas devenu un standard avec HTML 5, Chrome ne supporte pas ce standard. Essayer MathJax c'est l'adopter.