web-dev-qa-db-fra.com

Afficher une belle formule mathématique sous Android

Il est triste de voir que la science et les mathématiques ne reçoivent jamais assez d’attention sur la plateforme Android. C’est peut-être un problème facile, mais comme j’ai un mec javascript total, j’ai du mal à comprendre comment résoudre ce problème.

Ce que je veux faire est simple: Il me suffit d’utiliser l’équation mathématique de rendu. Cela peut être MathJax ou JqMath ou tout ce qui est petit et rapide. Si je dois le faire dans une vue Web, comment puis-je afficher du texte brut dans un paragraphe et une équation formatée dans la même vue Web?

(Tout le monde sort avec d'autres méthodes qui fonctionnent évidemment, je considérerai cela aussi comme solution)

CE QUE J'AI FAIT SO LOIN:

J'ai commencé par utiliser MathJax pour insérer une formule dans la visualisation Web (je ne sais pas s'il existe un cas d'utilisation réussie pour jqMath? Quelqu'un souhaite-t-il partager son expérience?} _) Je peux reproduire toutes les fonctionnalités comme celle de la version autonome MathJax App . Dans cette application, un utilisateur entre une chaîne dans le champ EditText et MathJax restituera la formule en latex une fois que l'utilisateur aura appuyé sur un bouton pour confirmer.

Je n'ai pas besoin d'utilisateur pour confirmer. Je pensais que cela devrait être plus facile car il n'y a pas d'interaction utilisateur, mais d'une manière ou d'une autre l'équation ne s'affiche jamais. Je sais que je dois manquer quelque chose car les codes de MathJax autonome sont conçus pour être saisis par l'utilisateur. Quelle partie du code dois-je modifier pour rendre directement une équation à partir d'une chaîne, par exemple,\sqrt {b ^ 2-4ac}? Voici l'en-tête initial pour webview:

WebView w = (WebView) findViewById(R.id.webview);
w.getSettings().setJavaScriptEnabled(true);
w.getSettings().setBuiltInZoomControls(true);
w.loadDataWithBaseURL("http://bar", "<script type='text/x-mathjax-config'>"
                        +"MathJax.Hub.Config({ showMathMenu: false, "
                        +"jax: ['input/TeX','output/HTML-CSS'], "
                        +"extensions: ['tex2jax.js'], " 
                        +"TeX: { extensions: ['AMSmath.js','AMSsymbols.js',"
                        +"'noErrors.js','noUndefined.js'] } "
                        +"});</script>"
                        +"<script type='text/javascript' "
                        +"src='file:///Android_asset/MathJax/MathJax.js'"
                        +"></script><span id='math'></span>","text/html","utf-8","");

Et voici comment la vue Web d'origine se charge lorsque l'utilisateur appuie sur un bouton après avoir saisi edittext:

WebView w = (WebView) findViewById(R.id.webview);
EditText e = (EditText) findViewById(R.id.edit);
w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                  +doubleEscapeTeX(e.getText().toString())
                  +"\\\\]';");
w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");

private static String doubleEscapeTeX(String s) {
    String t="";
    for (int i=0; i < s.length(); i++) {
        if (s.charAt(i) == '\'') t += '\\';
        if (s.charAt(i) != '\n') t += s.charAt(i);
        if (s.charAt(i) == '\\') t += "\\";
    }
    return t;
}

J'ai essayé de remplacer par une chaîne codée en dur

w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                  +doubleEscapeTeX("sample string")
                  +"\\\\]';");

mais cela ne fonctionne pas, le texte "sample string" n'apparaîtra même pas dans la vue Web.

[SOLUTION] voir la réponse de Joe

Pour préciser sa réponse, voici un exemple sur la manière de définir une phrase en texte brut, puis d'afficher une équation mise en forme sous forme d'affichage (le tout dans une seule vue Web):

Remplacez la dernière ligne ci-dessus à

+"></script><span id='math'></span>","text/html","utf-8","");

avec

+"></script><span id='text'>This is plain text.</span> <span id='math'></span>", "text/html", "utf-8", "");

Alors appelez

w.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
    super.onPageFinished(view, url);
        if (!url.startsWith("http://bar"))
            return;
        w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                    +doubleEscapeTeX("\\sqrt{b^2-4ac}") + "\\\\]';");
        w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
    }
});

Ceci définira une chaîne Ceci est du texte brut en police normale et affichera la formule au centre. foo+bar en webview.

EDIT (version Android 4.4)

À partir de Android KitKat, vous devez remplacer toutes les lignes loadUrl(...) par evaluateJavascript(...). Mais ceci n'est disponible que pour KitKat (API 19 ou supérieure), vous devez donc d'abord vérifier la version du SDK. Par exemple:

if (Android.os.Build.VERSION.SDK_INT < 19) {
    w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
} else {
    w.evaluateJavascript("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);",null);
}

UPDATE (À PARTIR DE MATHJAX 2.5)

En raison des modifications apportées aux dossiers, le code précédent ne fonctionnera pas avec la dernière version de MathJax. De plus, la méthode recommandée pour minimiser la taille de MathJax local consiste maintenant à utiliser Grunt . Le modèle pour réduire la taille de MathJax peut être trouvé ici .

En supposant que vous ayez réduit avec succès la taille de MathJax et en supposant que HTML-CSS soit généré, voici une version simple capable de charger MathJax:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final WebView w = (WebView) findViewById(R.id.webview);
    w.getSettings().setJavaScriptEnabled(true);
    w.getSettings().setBuiltInZoomControls(true);

    String Url = "</style>"
                 + "<script type='text/x-mathjax-config'>"
                 + "  MathJax.Hub.Config({" + "    showMathMenu: false,"
                 + "             jax: ['input/TeX','output/HTML-CSS', 'output/CommonHTML'],"
                 + "      extensions: ['tex2jax.js','MathMenu.js','MathZoom.js', 'CHTML-preview.js'],"
                 + "         tex2jax: { inlineMath: [ ['$','$'] ], processEscapes: true },"
                 + "             TeX: {" + "               extensions:['AMSmath.js','AMSsymbols.js',"
                 + "                           'noUndefined.js']" + "             }"
                 + "  });"
                 + "</script>"
                 + "<script type='text/javascript' src='file:///Android_asset/MathJax/MathJax.js'>"
                 + "</script>"
                 + "<p style=\"line-height:1.5; padding: 16 16\" align=\"justify\">"
                 + "<span >";

    // Demo display equation
    url += "This is a display equation: $$P=\frac{F}{A}$$";

    url += "This is also an identical display equation with different format:\\[P=\\frac{F}{A}\\]";

    // equations aligned at equal sign
    url += "You can also put aligned equations just like Latex:";
    String align = "\\begin{aligned}"
                + "F\\; &= P \\times A \\\\ "
                + "&= 4000 \\times 0.2\\\\"
                + "&= 800\\; \\text{N}\\end{aligned}"; 
    url += align;

    url += "This is an inline equation \\sqrt{b^2-4ac}.";

    // Finally, must enclose the brackets
    url += "</span></p>";

    mWebView.loadDataWithBaseURL("http://bar", url, "text/html", "utf-8", "");
    mWebView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (!url.startsWith("http://bar")) return;
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KitKat) {
                view.loadUrl(JAVASCRIPT);
            } else {
                view.evaluateJavascript(JAVASCRIPT, null);
            }
        }
    });
}

Contrairement à la réponse de Joes, il n'est pas nécessaire de séparer les types de texte ou les types de mathématiques, MathJax les formatera simplement en conséquence.

Cependant, il semble y avoir un problème qui fait que la vue Web dans les périphériques KitKat ne peut pas restituer la lettre majuscule "A". Toute personne connaissant un moyen est la bienvenue pour fournir une solution de contournement.

27
Neoh

Si je comprends bien votre problème, il semble que le problème soit dû au fait que la bibliothèque MathJax n'a pas été chargée (à partir de l'appel loadDataWithBaseURL()) lorsque vous appelez le loadUrl()s supplémentaire pour afficher la formule. La solution la plus simple consiste à attendre le rappel onPageFinished() pour passer l'appel.

Par exemple, le code suivant semble bien fonctionner sur le mien:

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final WebView w = (WebView) findViewById(R.id.webview);
    w.getSettings().setJavaScriptEnabled(true);
    w.getSettings().setBuiltInZoomControls(true);
    w.loadDataWithBaseURL("http://bar", "<script type='text/x-mathjax-config'>" 
            + "MathJax.Hub.Config({ "
            + "showMathMenu: false, " 
            + "jax: ['input/TeX','output/HTML-CSS'], " 
            + "extensions: ['tex2jax.js'], "
            + "TeX: { extensions: ['AMSmath.js','AMSsymbols.js'," 
            + "'noErrors.js','noUndefined.js'] } "
            + "});</script>" 
            + "<script type='text/javascript' " 
            + "src='file:///Android_asset/MathJax/MathJax.js'"
            + "></script><span id='math'></span>", "text/html", "utf-8", "");
    w.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (!url.startsWith("http://bar")) return;
            w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                    + doubleEscapeTeX("sample string") + "\\\\]';");
            w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
        }
    });
}

Update : Pour permettre une sortie supplémentaire dans WebView, je suggérerais d'ajouter des éléments HTML à l'appel loadDataWithBaseURL() initial. Donc, pour l'exemple ci-dessus, au lieu de cette ligne à la fin:

            + "></script><span id='math'></span>", "text/html", "utf-8", "");

Nous pouvons faire quelque chose comme ce qui suit:

            + "></script><span id='text'>Formula:</span>"
            + "<span id='math'></span>", "text/html", "utf-8", "");

De plus, si vous devez mettre à jour cette partie de manière interactive par la suite, vous pouvez utiliser le même mécanisme que nous avons utilisé pour la partie "math", à savoir:

            w.loadUrl("javascript:document.getElementById('text').innerHTML='"
                    + newText + "';");

Vous pouvez également utiliser d'autres éléments HTML (au lieu du <span> que nous utilisons ci-dessus) si vous souhaitez avoir un style/formatage spécifique.

21
Joe

Au lieu d'utiliser les bibliothèques javascript et javascript pour restituer le côté client LaTeX, pourquoi ne pas procéder comme suit?

  1. Ecrivez une fonction côté serveur qui prend une chaîne LaTeX et génère un fichier image. Vous pouvez le faire avec l'outil de ligne de commande LaTeX standard "prêt à l'emploi". (On dirait que c'est quelque chose que vous êtes capable de faire, et que le problème est que le rendu se fasse côté client.)

  2. Créez un point de terminaison sur votre site Web/service qui se présente comme suit:
    GET /latex?f={image format}&s={latex string}

  3. Sur vos pages Web, utilisez une simple balise HTML <img/> pour rendre votre LaTeX. Par exemple:
    <img src="/latex?f=jpeg&s=f%40x%41%61x%942"/>
    convertira l'équation f(x)=x^2 en JPEG.

  4. (facultatif) Créez un cache côté serveur simple pour les paires (f,s) de manière à ne restituer qu'une chaîne LaTeX particulière lors de la première demande jamais effectuée pour cette chaîne particulière (par un client quelconque). En tant que premier prototype, vous pourriez simplement avoir un répertoire de serveur dans lequel vous avez des fichiers nommés {hash(s)}.{f}, où hash est juste une fonction de hachage telle que SHA1.

Cela vous évite d'essayer de tout faire fonctionner côté client avec javascript. Et, je dirais (bien que certains puissent être en désaccord), que c'est beaucoup plus propre. Tout ce que vous envoyez au client est:

  1. la balise HTML <img/>
  2. le contenu réel de l'image lorsque le navigateur résout l'attribut src

Très léger et rapide!

5
Timothy Shields

Le problème "capital A" est un problème connu de MathJax sur Android WebView. Vous pouvez remplacer les fichiers de polices par des fichiers de polices modifiés . Le correctif fonctionnera lors de l’utilisation de la sortie HTML-CSS avec les polices TeX. Outre MathJax, vous pouvez essayer KaTeX , qui est moins beau mais plus rapide.

En fait, je les ai toutes les deux intégrées dans une vue personnalisée Android, consultez MathView .

2
kexanie

En retard à la fête, mais je pense avoir une meilleure solution que celle de Joe. La question initiale posée:

comment puis-je afficher du texte brut dans un paragraphe et une équation formatée dans la même vue Web?

Dans l'exemple original, nous avions:

w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                  +doubleEscapeTeX("sample string")
                  +"\\\\]';");

Avez-vous remarqué le \\\\[ et le \\\\]? LaTeX interprète ces quatre barres obliques inverses comme une seule, et \[ et \] dans LaTeX est un raccourci pour\begin{equation}... \end{equation} qui produit un bloc de mathématiques affichées. Si nous voulons un paragraphe de texte avec des équations dans le paragraphe, nous devons nous débarrasser du \\\\[ et utiliser la commande LaTeX \( et \). Le code pour un exemple avec les mathématiques de paragraphe et les mathématiques affichées serait:

w.loadUrl("javascript:document.getElementById('math').innerHTML='"
   +doubleEscapeTeX(
           "This is a second degree equation \\( \\small ax^2+bx+c=0\\) and its "
          +"roots are \\[x=\\frac{-b\\pm \\sqrt{b^2-4ac}}{2a}. \\]"
    )+"';");

La WebView devient: enter image description here Remarques:

  • Nous avons seulement besoin de deux barres obliques inverses au lieu de quatre, car nous sommes à l'intérieur de doubleEscapeTeX() et cette fonction duplique les barres obliques inverses.

  • De plus, le texte en dehors des environnements mathématiques est rendu avec HTML (à l'intérieur de la balise <span id='math'>).

  • La police LaTeX est plus grosse que la police html. Par conséquent, l'ajout d'un \\small dans chaque environnement mathématique leur donnera à peu près la même taille. Ici, j'ai ajouté la commande \\small uniquement à la première équation pour montrer la différence.

1
Roberto Canogar

Vous pouvez facilement utiliser la formule mathématique dans Android en utilisant le code ci-dessous.

public void setView(String data,WebView w){
    WebSettings webSettings = w.getSettings();
    webSettings.setJavaScriptEnabled(true);
    String path="file:///Android_asset/v/";
    String js="<html><head>"
       + "<link rel='stylesheet' href='file:///Android_asset/v/jqmath.css'>"
       + "<script src = 'file:///Android_asset/v/jquery-3.0.0.min.js'></script>"
       + "<script src = 'file:///Android_asset/v/jqmath-etc-0.4.3.min.js'></script>"
       + "<script src = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>"
       + "</head><body>"
       + "<script>var s ='"+data+"';M.parseMath(s);document.write(s);</script> </body>";
    w.loadDataWithBaseURL("", js, "text/html", "UTF-8", "");
}
0
Vasant

jqMath est une bibliothèque JavaScript comme MathJax, mais beaucoup plus petite, plus simple et plus rapide. Si vous n'avez pas besoin de tout LaTeX, vous pourriez l'aimer. Cela devrait fonctionner correctement sur Android.

C'est juste une suggestion, je n'ai aucune idée des erreurs ou des avantages que vous pourriez avoir si vous utilisez MathJax.

MathJax est beaucoup plus gros et compliqué que jqMath, et environ 5 fois plus lent .

JSFIDDLE de travail: http://jsfiddle.net/sinhayash/gWWB5/1/

Pour \sqrt{b^2-4ac} vous pouvez avoir ce code: √(b^2-4ac)

Vous pouvez facilement utiliser la gestion des chaînes en javascript pour convertir des chaînes au format jqMath et les afficher facilement.

0
sinhayash