最近接手高校的一个高数教学组习题库的项目,经过与团队和老师多次探讨后,初步总结出几个项目实现上的几个难点,具体如下:

  • 大量习题的如何存储最佳?
  • 数学公式如何完美处理?
  • 移动端如何与 PC 端完美接洽?
  • ……

缘由

撇开存储方式的问题,本文主要讨论前端完美展现数学公式的方案。

因为做的是大学数学习题库,各种极限、积分,微分等符号数不胜数,因此数学公式的合理且完美展现成了非常重要的讨论点。

合理是指不要给出题者(即高数组老师)造成太大的负担,因为习题量非常之大,如果处理起来非常麻烦,在项目后期的使用中将会变得无比的痛苦。

完美的含义即首先需要把数学完整的展现出来,其次最好能简易的控制样式,这样能使习题页面显得美观一点。毕竟题目本身难度就不小,还给个黑白、乱码、错位满天飞的页面谁都不会喜欢的。

探讨

好了,到这里我来简述一下我们的思考历程以及最后的选择

1. 图片显示

最开始团队成员提出的方案是静态图片,即把所有公式用 MathType 输出后再处理成图片,然后通过文件存储方式把所有的题目存储在服务器。 这种图片方案有一定的缺点:

  • 网站公式比较多,服务器需要维护大量公式图片;
  • 图片体积一般都比较大,会影响网页加载效率,占用较多的带宽,移动端也会影响程序性能;
  • 公式不能重用,如果公式发生变化,需要重新编辑图片;
  • 图片放大后会变得比较模糊;
  • ……

再者,又有人提出:将题目整个做成一张图片,即“一题一图”。此方案虽然能一定程度上减少图片数量,然而图片的大小控制问题又来了,Web显示不错的,可是到了移动端,屏幕小图片大,需要放大才能看清,势必体验非常之差。到这时,基本已经需要否定静态图片这一方案了,因为图片处理起来并不那么简单,而且样式可控性并不高。

最后,如果真的想使用图片方式的话,还有一种方法就是动态生成图片。首先需要将数学公式转换为表示公式的 TeX 语言,用程序将 TeX 语言生成与公式对应的图片,这种方法解决了直接使用静态图片不能重用的问题,但是这种方法比较复杂,需要后台代码来实现,也可以使用网上开放的 API,如 Google Charts,如果使用 SVG 格式图片,公式在放大后也不会影响清晰度。但是考虑到开放的 API 的不稳定因素,我们并未选择使用此方案。

2. MathML(数学标记语言)

数学置标语言,是一种基于 XML 的标准,用来在互联网上书写数学符号和公式的置标语言。它是由万维网联盟的数学工作组提出的。

MathML 是受 XML 的启发在万维网联盟数学工作组的具体组织下产生的,作为 XML 定义的一种应用,它用标记的形式来表示数学表达式。用 MathML 形式 来描述数学表达式,不仅可以明确地表达数学内容,而且可以在 Web 的其它应用程序中实现再利用和转换。MathML 标记的递归性和树状结构使得它在计算机程序的实现上更方便、简单。MathML 使用文本的形式来描述数学表达式的树形结构,克服了传统的 Web 中使用图片表达数学公式的缺点。

以下为二次函数求根公式的 MathML 代码 demo

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN"
 "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<math xmlns="http://www.w3.org/1998/Math/MathML">
    <mi>x</mi>
    <mo>=</mo>
    <mfrac>
        <mrow>
            <mrow>
                <mo>-</mo>
                <mi>b</mi>
            </mrow>
            <mo>±</mo>
            <msqrt>
                <msup>
                    <mi>b</mi>
                    <mn>2</mn>
                </msup>
                <mo>-</mo>
                <mrow>
                    <mn>4</mn>
                    <mo>⁢</mo>
                    <mi>a</mi>
                    <mo>⁢</mo>
                    <mi>c</mi>
                </mrow>
            </msqrt>
        </mrow>
        <mrow>
            <mn>2</mn>
            <mo>⁢</mo>
            <mi>a</mi>
        </mrow>
    </mfrac>
</math>

可以看出,代码复杂度很高,一个简单的公式需要极多的冗余标记表达。

由于数学符号和公式的结构复杂且符号与符号之间存在多种逻辑关系,MathML 的格式十分繁琐。因此,大多数人都不会去手写MathML,而是利用其它的工具来编写,其中包括 Tex 到 MathML 的转换器。在现在几个主要的网页浏览器中,最新版的 Mozilla、Mozilla Firefox 和 Netscape Navigator 都已经对 MathML 提供直接的支持,但 Chrome 却又停止支持,原因是 Google 出于安全性的考虑,但是 Chrome 和其它一些不支持 MathML 的浏览器,仍可以通过适当的 HTML+CSS 代码将 MathML 显示出来。微软的 IE 在安装了 MathPlayer 插件后也可以识别 MathML。此外,MathML 还得到了一些办公软件的支持,如 openoffice.org 和 Microsoft Office。

总的来说,使用 MathML 语言基本可以达到我们的要求,且在移动端也有相应解决的方案,然而顾及老师对于 MathML 不熟悉,需要使用转化器来实现,我们还是在思索着更好的方案。

3. MathJax 渲染

不断探索中,我们找到了一款基于 Javascript 的数学公式渲染引擎–MathJax

MathJax 是一款运行在浏览器中的开源的数学符号渲染引擎,使用 MathJax 可以方便的在浏览器中显示数学公式,不需要使用图片。目前,MathJax 可以解析 Latex、MathML 和 ASCIIMathML 的标记语言。 MathJax 项目于 2009 年开始,发起人有 American Mathematical Society, Design Science 等,还有众多的支持者,个人感觉 MathJax 会成为今后数学符号渲染引擎中的主流,也许现在已经是了。

可以说,对于大部分的数学公式,目前 MathJax 的功能和显示效果已经完全可以媲美于 LaTex,而 HTML/CSS 对位置和格式的控制能力要比 LaTex 更强大。经过我们的多次测试,MathJax 的兼容性还是非常棒的,这基本已经贴近我们心中所想了。

对于此项目来说,数学习题可以用 LaTex 语言来书写,这对于老师来说是极大的福音,因为 Tex 语言他们再熟悉不过了。反过来对于我们来说也是极大的福音,在 MathJax 将 Tex 语言渲染后,我们可以随心所欲的控制其样式,这样我们就可以将习题界面展现的更加优雅,更加美观。

到此我们基本已经决定使用 MathJax 来展现我们的数学公式,然而在使用下来发现以下几个客观不足性:

  • 直接使用 MathJax 官方提供的 CND 共开库,国内访问速度并不是很理想,有时会出现 Math Processing Error 的错误,解决方案是将其 JS 渲染库放在本地加载。
  • MathJax 官方文档很详细但是不提供中文版,需要大家英语水平不错才行。由于 MathJax 真心不错,我可能会考虑发起翻译计划,将其最新的开发文档翻译成中文,便于国人的使用。
  • MathJax 转化速度一般,需要做进一步优化。

结束

好啦,到这里,我们决定了使用的数学公式展现方案-MathJax,数学的公式展现方案探讨基本结束。如果有其他方案,我会继续补上。

如果有翻译计划,我会找一些队友一起,如果你有兴趣,欢迎联系我。