在Android中显示漂亮的数学公式

Neo*_*eoh 28 javascript math android mathjax jqmath

令人遗憾的是,在Android平台上,科学和数学从未得到足够的重视.也许这是一个简单的问题,但我在javascript中是一个完全的家伙,所以我很难理解如何解决这个问题.

我想做的很简单:我只需要使用渲染数学方程.它可以是MathJax或JqMath或任何小而快的东西.如果我必须在webview中执行此操作,如何在同一webview中的段落和格式化方程式中显示纯文本?

(任何人都提出其他显然有效的方法,我会认为这也是解决方案)

我做了什么:

我开始使用MathJax将公式放入webview(如果有任何成功的jqMath用例,我不知道吗?有人愿意分享他们的经验吗?)我可以重现所有功能,就像独立的MathJax应用程序一样.在该应用程序中,用户将字符串键入EditText字段,一旦用户按下按钮进行确认,MathJax将在Latex中呈现公式.

我不需要用户确认.我认为这应该更容易,因为没有用户交互,但不知何故方程式永远不会显示.我知道我必须遗漏一些东西,因为独立MathJax中的代码用于用户输入.我应该修改哪部分代码直接从字符串中呈现方程,比如说\ sqrt {b ^ 2-4ac}?这是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","");
Run Code Online (Sandbox Code Playgroud)

以下是用户在输入edittext后按下按钮时加载原始webview的方式:

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;
}
Run Code Online (Sandbox Code Playgroud)

我试图用硬编码的字符串替换

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

但它不起作用,文本"sample string"甚至不会出现在webview中.

[解决方案]见乔的答案

为了详细说明他的答案,这是一个关于如何在纯文本中设置句子然后以显示形式显示格式化方程式的示例(所有这些都在一个webview中):

替换上面的最后一行

+"></script><span id='math'></span>","text/html","utf-8","");
Run Code Online (Sandbox Code Playgroud)

+"></script><span id='text'>This is plain text.</span> <span id='math'></span>", "text/html", "utf-8", "");
Run Code Online (Sandbox Code Playgroud)

然后打电话

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]);");
    }
});
Run Code Online (Sandbox Code Playgroud)

这将设置一个字符串这是普通字体的纯文本和中心显示公式FOO +酒吧 在webview中.

编辑(Android 4.4问题)

与Android奇巧开始,您必须更换所有的线loadUrl(...)evaluateJavascript(...).但这仅适用于KitKat(API 19或更高版本),因此您需要先进行SDK版本检查.例如:

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);
}
Run Code Online (Sandbox Code Playgroud)

更新(作为MATHJAX 2.5)

由于存在文件夹更改,因此以前的代码无法在最新版本的MathJax上运行.此外,最小化本地MathJax大小的推荐方法现在使用Grunt.可以在此处找到减小MathJax大小的模板.

假设您已成功缩小MathJax的大小,并假设输出HTML-CSS,这里是一个可以加载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);
            }
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

与Joes的答案不同,不需要分开文本或数学类型,MathJax将相应地格式化它们.

但是,似乎有一个错误,即KitKat设备中的webview无法呈现大写字母"A".任何了解方式的人都欢迎为此提供解决方法.

Joe*_*Joe 21

如果我正确理解你的问题,似乎问题是由于loadDataWithBaseURL()当你调用附加的loadUrl()s来显示公式时,MathJax库还没有完成加载(来自调用).最简单的解决方法是等待onPageFinished()回调拨打电话.

例如,以下代码似乎在我的工作正常:

/** 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]);");
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

更新:为了在WebView中容纳额外的输出,我建议在初始loadDataWithBaseURL()调用中添加HTML元素.因此,对于上面的示例,而不是最后的这一行:

            + "></script><span id='math'></span>", "text/html", "utf-8", "");
Run Code Online (Sandbox Code Playgroud)

我们可以做以下事情:

            + "></script><span id='text'>Formula:</span>"
            + "<span id='math'></span>", "text/html", "utf-8", "");
Run Code Online (Sandbox Code Playgroud)

此外,如果您之后需要以交互方式更新该部件,则可以使用我们用于"数学"部分的相同机制,例如:

            w.loadUrl("javascript:document.getElementById('text').innerHTML='"
                    + newText + "';");
Run Code Online (Sandbox Code Playgroud)

<span>如果您想要具有特定的样式/格式,您还可以使用其他HTML元素(而不是我们上面使用的).


Tim*_*lds 5

而不是使用JavaScript和JavaScript库来呈现LaTeX客户端,为什么不执行以下操作?

  1. 编写一个服务器端函数,它接受一些LaTeX字符串并生成一个图像文件.您可以使用"开箱即用"标准LaTeX命令行工具执行此操作.(看起来这是你能够做到的事情,问题在于让渲染发生在客户端.)

  2. 在您的网站/服务上创建一个如下所示的端点:
    GET /latex?f={image format}&s={latex string}

  3. 在您的网页上,使用简单的HTML <img/>标记来呈现您的LaTeX.例如:
    <img src="/latex?f=jpeg&s=f%40x%41%61x%942"/>
    f(x)=x^2等式渲染为JPEG.

  4. (可选)为(f,s)对创建一个简单的服务器端缓存,这样您只能在对该特定字符串(由任何客户端)进行的第一个请求上呈现特定的LaTeX字符串.作为第一个原型,你可以只有一个服务器目录,你可以在其中命名文件{hash(s)}.{f},其中hash只有一些哈希函数SHA1.

这使您免于尝试使用javascript使一切工作在客户端.而且,我会争辩(虽然有些人可能不同意),这是更清洁.您发送给客户的所有内容是:

  1. HTML <img/>标记
  2. 浏览器解析src属性时的实际图像内容

非常轻巧,快速!