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:
收官!