Latex 公式在线可视化编辑器

寻觅

最近的一个demo需要用到Latex公式在线编辑器,从搜索引擎一般会得到类似http://latex.codecogs.com/eqneditor/editor.php的结果,这个编辑器的问题在于使用成本高,并且界面不美观。

继续探寻,发现了wiris Editor

支持mathml和latex:

那么就它了!

选型

首先,我们不会直接使用这个编辑器,只是在编辑公式的时候才使用,所以要选择合适的版本。

以前用过CKEditor,所以就这它了!选用java版本 我们的数据已经是latex的,在wiris 编辑器显示需要注意latex需要用两个$$包括起来 例如:

The history of $$\sqrt(2)$$.

但是CK版本的wiris对latex的支持是非可视化支持,在编辑器里输入latex还是显示为latex:

将焦点移动到$$内部,再点击按钮出现wiris的公式编辑器:

这种设计适合对latex熟悉的人员,可以裸写latex,同时对不熟悉的人来说,可以使用公式编辑器。但是,这样不直观啊!你让不会latex的看到的就一堆符号!

适配

简单试用可以发现,如果直接使用公式编辑器插入公式,是直观显示的:

可以看到保存的时候,mathml是:

<math class="wrs_chemistry" xmlns="http://www.w3.org/1998/Math/MathML">
    <msqrt>
        <mn>2</mn>
    </msqrt>
</math>

那么在latex输入情况下呢:

<math xmlns="http://www.w3.org/1998/Math/MathML">
    <semantics>
        <mrow>
            <msqrt><mo>(</mo></msqrt><mn>2</mn><mo>)</mo>
        </mrow>
        <annotation encoding="LaTeX">\sqrt(2)</annotation>
    </semantics>
</math>

原来问题在这里,正是mathML的区别导致处理的区别。也就是说一开始就生成不带LaTeX的mathML,然后再放入编辑器。简单查看代码,可以知道先调用wrs_endParse,再wrs_initParse就可以了。

CKEDITOR.on("instanceReady", function(event)
    {
        CKEDITOR.instances.example.focus();
        var mathxml = wrs_endParse("已知向量$$\\vec{a}=(\\sqrt{3},2)$$,$$\\vec{b}=(0,-2)$$,向量$$\\vec{c}=(k,\\sqrt{2})$$.$$\\vec{a}-1\\vec{b}$$与$$\\vec{d}$$共线,$$k=$$__.");
        CKEDITOR.instances.example.setData(wrs_initParse(mathxml));
        // 等待完成
        window.setTimeout(updateFunction,0);
    });

直观显示没问题了,但是mathml如何再转换成Latex呢?core.js里的wrs_parseMathmlToLatex函数是直接从mathml里将。。。里的内容提取出来:

function wrs_parseMathmlToLatex(content, characters){
    ....
    var openTarget = characters.tagOpener + 'annotation encoding=' + characters.doubleQuote + 'LaTeX' + characters.doubleQuote + characters.tagCloser;
 
        mathml = content.substring(start, end);

        startAnnotation = mathml.indexOf(openTarget);
        // 包含 encoding=latex,保留latex
        if (startAnnotation != -1){
            startAnnotation += openTarget.length;
            closeAnnotation = mathml.indexOf(closeTarget);
            var latex = mathml.substring(startAnnotation, closeAnnotation);
            if (characters == _wrs_safeXmlCharacters) {
                latex = wrs_mathmlDecode(latex);
            }
            output += '$$' + latex + '$$';
            // Populate latex into cache.
            wrs_populateLatexCache(latex, mathml);
        }else{
            output += mathml;
        }
   ......
}

但是现在的mathml不包含这个信息,如何处理?查看官方文档,发现有一个mathml2latex的服务,查看官方给的java demo里servlet并不包含这个服务,但是jar包里存在代码,于是自己封装一个servlet即可:

public class ServiceServlet extends com.wiris.plugin.dispatchers.MainServlet {

    @Override
    public void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
            throws ServletException, IOException {
        PluginBuilder pb = newPluginBuilder(request);
        String origin = request.getHeader("origin");
        HttpResponse res = new HttpResponse(response);
        pb.addCorsHeaders(res, origin);
        String pathInfo = request.getServletPath();
        if (pathInfo.equals("/mathml2latex")) {
            response.setContentType("text/plain; charset=utf-8");
            ParamsProvider provider = pb.getCustomParamsProvider();
            String mml = provider.getParameter("mml", (String)null);
            String r = pb.newTextService().mathml2latex(mml);
            PrintWriter out = response.getWriter();
            out.print(r);
            out.close();
        }

js里,调用这个服务:

var _wrs_mathmlCache = {};
function wrs_getLatexFromMathML(mml) {
    if (_wrs_mathmlCache.hasOwnProperty(mml)) {
        return _wrs_mathmlCache[mml];
    }
    var data = {
        'service': 'mathml2latex',
        'mml': mml
    };

    var latex = wrs_getContent(_wrs_conf_servicePath, data);
    // Populate LatexCache.
    if (!_wrs_mathmlCache.hasOwnProperty(mml)) {
        _wrs_mathmlCache[mml] = latex;
    }
    return latex.split("\r").join('').split("\n").join(' ');
}

wrs_getLatexFromMathML只能将一个mathml转换为latex,对于编辑器里的内容来说,需要将mathML抽取出来逐一转换:

function wrs_parseRawMathmlToLatex(content, characters){
    var output = '';
    var mathTagBegin = characters.tagOpener + 'math';
    var mathTagEnd = characters.tagOpener + '/math' + characters.tagCloser;
    var start = content.indexOf(mathTagBegin);
    var end = 0;
    var mathml, startAnnotation, closeAnnotation;

    while (start != -1) {
        output += content.substring(end, start);
        end = content.indexOf(mathTagEnd, start);

        if (end == -1) {
            end = content.length - 1;
        }
        else {
            end += mathTagEnd.length;
        }

        mathml = content.substring(start, end);

        output += wrs_getLatexFromMathML(mathml);

        start = content.indexOf(mathTagBegin, end);
    }

    output += content.substring(end, content.length);
    return output;
}
function wrs_getLatex(code) {
    return wrs_parseRawMathmlToLatex(code, _wrs_xmlCharacters);
}

末了,为了方便获取,可以将latex放到_current_latex变量里:

    // 获取数据
    editor.on('getData', function (e) {
        e.data.dataValue = wrs_endParse(e.data.dataValue || "");
        _current_latex = wrs_getLatex(e.data.dataValue || "");
    });

再简单修改下网页,显示latex:

收官!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据挖掘DT机器学习

利用Python绘制MySQL数据图实现数据可视化

第1步:确保MySQL已安装且在运行 安装教程: 亲测:MySQL安装与python下的MySQLdb使用(附软件与模块包) 第2步:使用Python连接...

8476
来自专栏Golang语言社区

【golang】调优工具 pprof

Golang 提供了 pprof 包(runtime/pprof)用于输出运行时的 profiling 数据,这些数据可以被 pprof 工具(或者 go to...

1593
来自专栏游戏杂谈

TexturePacker压缩png的命令

压缩png效果最好的当然是TinyPNG这种神器了,不过一般情况下TexturePacker压缩出来的也基本上能达到效果。

2742
来自专栏逍遥剑客的游戏开发

MPQ 文件系统完成

1914
来自专栏有趣的django

Django+Bootstrap+Mysql 搭建个人博客(一)

1.7K0
来自专栏Java成神之路

GEF入门实例_总结_06_为编辑器添加内容

GEF的MVC模式中的模型、控制器、视图分别对应于 Model 、EditPart、EditPartViewer。

823
来自专栏技术碎碎念

处理机进程调度模拟

一、进程调度 无论是在批处理还是分时系统中,用户进程数一般都多于处理机数、这将导致它们互相争夺处理机。另外,系统进程也同样需要使用处理机。这就要求进程调度程序按...

43011
来自专栏linux驱动个人学习

高通 display 驱动【转】

1.8K4
来自专栏程序员互动联盟

小菜学Chromium之OpenGL学习之二

在这个教程里,我们一起来玩第一个OpenGL程序.它将显示一个空的OpenGL窗口,可以在窗口和全屏模式下切换,按ESC退出.它是我们以后应用程序的框架. 在C...

3056
来自专栏人人都是极客

环形缓冲区的实现

队列 (Queue):是一种先进先出(First In First Out ,简称 FIFO)的线性表,只允许在一端插入(入队),在另一端进行删除(出队)。

3294

扫码关注云+社区

领取腾讯云代金券