Показать симпатичную математическую формулу в Android
Грустно видеть, что науке и математике никогда не уделяется достаточного внимания на платформе Android. Возможно, это легкая проблема, но я полный чувак в javascript, поэтому я изо всех сил пытаюсь понять, как решить эту проблему.
То, что я хочу сделать, просто: Мне просто нужно использовать математическое уравнение рендеринга. Это может быть MathJax или JqMath или что-то маленькое и быстрое. Если мне нужно сделать это в веб-просмотре, как я могу показать простой текст в абзаце и форматированном уравнении в пределах одного веб-представления?
(кто-то выходит с другими методами, которые, очевидно, работают, я также рассмотрю это как решение)
ЧТО Я СДЕЛАЛ СКАЗАТЬ:
Я начал с использования 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","");
И вот как загружается исходный веб-просмотр, когда пользователь нажимает кнопку после ввода в 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;
}
Я попытался заменить жестко запрограммированной строкой
w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
+doubleEscapeTeX("sample string")
+"\\\\]';");
но он не работает, текст "sample string"
даже не появится в веб-просмотре.
[РЕШЕНИЕ] см. "Ответ на вопрос"
Чтобы подробно описать его ответ, это пример того, как установить предложение в виде простого текста, а затем отобразить форматированное уравнение в форме отображения (все в одном веб-просмотре):
Замените последнюю строку выше на
+"></script><span id='math'></span>","text/html","utf-8","");
с
+"></script><span id='text'>This is plain text.</span> <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("\\sqrt{b^2-4ac}") + "\\\\]';");
w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
}
});
Это установит строку. Это обычный текст в обычном шрифте, а в центре - формула
в веб-просмотре.
EDIT (проблема с Android 4.4)
Начиная с Android KitKat, вы должны заменить все строки 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);
}
ОБНОВЛЕНИЕ (КАК 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);
}
}
});
}
В отличие от ответа Джоса, нет необходимости отделять текстовые или математические типы, MathJax просто форматирует их соответственно.
Однако, похоже, что есть ошибка, что веб-просмотр в устройствах KitKat не может отображать заглавную букву "A". Любой, кто знает способ, может предложить обходной путь для этого.
Ответы
Ответ 1
Если я правильно понимаю вашу проблему, кажется, проблема связана с тем, что библиотека MathJax не завершила загрузку (из вызова loadDataWithBaseURL()
), когда вы вызываете дополнительный loadUrl()
для отображения формулы. Самое простое решение - дождаться обратного вызова 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]);");
}
});
}
Обновить. Чтобы разместить дополнительный вывод в WebView, я бы предложил добавить элементы HTML к первоначальному вызову loadDataWithBaseURL()
. Итак, для примера выше, вместо этой строки в конце:
+ "></script><span id='math'></span>", "text/html", "utf-8", "");
Мы можем сделать что-то вроде следующего:
+ "></script><span id='text'>Formula:</span>"
+ "<span id='math'></span>", "text/html", "utf-8", "");
Кроме того, если вам нужно впоследствии обновить эту часть, вы можете использовать тот же механизм, который мы использовали для части "math", например:
w.loadUrl("javascript:document.getElementById('text').innerHTML='"
+ newText + "';");
Вы также можете использовать другие элементы HTML (вместо <span>
, которые мы используем выше), если вы хотите иметь специальный стиль/форматирование.
Ответ 2
Вместо того, чтобы использовать javascript и javascript-библиотеки для визуализации клиентской стороны LaTeX, почему бы не сделать следующее?
-
Напишите серверную функцию, которая принимает некоторую строку LaTeX и создает файл изображения. Вы можете сделать это с помощью стандартного инструмента командной строки LaTeX "из коробки". (Кажется, это то, что вы способны сделать, и что проблема заключается в том, чтобы сделать рендеринг на стороне клиента.)
-
Создайте конечную точку на своем веб-сайте/службе, которая выглядит следующим образом:
GET /latex?f={image format}&s={latex string}
-
На ваших веб-страницах используйте простой тег HTML <img/>
, чтобы отобразить ваш LaTeX. Например:
<img src="/latex?f=jpeg&s=f%40x%41%61x%942"/>
будет отображать уравнение f(x)=x^2
как JPEG.
-
(необязательно) Создайте простой кеш-сервер для пар (f,s)
, чтобы вы отображали только одну строку LaTeX по первому запросу, когда-либо сделанному для этой конкретной строки (любым клиентом). В качестве первого прототипа вы можете просто иметь каталог сервера, в котором у вас есть файлы с именем {hash(s)}.{f}
, где hash
- это просто хеш-функция, например SHA1
.
Это избавляет вас от попыток заставить все работать на стороне клиента с помощью javascript. И, я бы поспорил (хотя некоторые могут не согласиться), что это намного чище. Все, что вы отправляете клиенту:
- тег HTML
<img/>
- фактическое содержимое изображения, когда браузер разрешает атрибут
src
Очень легкий и быстрый!
Ответ 3
Проблема "Capital A" - это ошибка Konwn MathJax в Android WebView. Вы можете заменить файлы шрифтов tweaked font files. Исправление будет работать при использовании вывода HTML-CSS с TeX-шрифтами. Помимо MathJax, вы можете попробовать KaTeX, который менее красив, но быстрее.
Собственно, я упаковал их оба в пользовательское представление Android, посмотрите MathView
.
Ответ 4
Поздно вечеринке, но я думаю, что у меня есть лучшее решение, чем у Джо.
Первоначальный вопрос:
как я могу показать простой текст в параграфе и форматированное уравнение внутри тот же веб-просмотр?
В исходном примере мы имели:
w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
+doubleEscapeTeX("sample string")
+"\\\\]';");
Вы заметили \\\\[
и \\\\]
? Эти четыре обратной косой черты интерпретируются LaTeX как один, а \[
и \]
в LaTeX является сокращением для \begin{equation}... \end{equation}
, которое производит блок отображаемой математики. Если нам нужен абзац текста с некоторыми уравнениями в абзаце, нам нужно избавиться от \\\\[
и использовать команду LaTeX \(
и \)
. Код для примера с математикой абзаца и отображаемой математикой:
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}. \\]"
)+"';");
WebView становится:
Примечания:
-
Нам нужны только две обратные косые черты вместо четырех, это потому, что мы находимся внутри doubleEscapeTeX()
, и эта функция дублирует обратную косую черту.
-
Также текст вне среды математики отображается с помощью HTML (внутри тега <span id='math'>
).
-
Шрифт LaTeX больше, чем шрифт html, поэтому добавление \\small
в каждой математической среде сделает их примерно одного размера. Здесь я добавил команду \\small
только к первому уравнению, чтобы показать разницу.
Ответ 5
jqMath - это библиотека JavaScript, такая как MathJax, но намного меньше, проще и быстрее. Если вам не нужен весь LaTeX, вам может понравиться. Он должен отлично работать на Android.
Это просто предложение, я понятия не имею, какие ошибки или преимущества у вас есть, если вы используете MathJax.
MathJax намного больше и сложнее, чем jqMath, а примерно в 5 раз медленнее.
Работа JSFIDDLE: http://jsfiddle.net/sinhayash/gWWB5/1/
Для \sqrt{b^2-4ac}
вы можете получить этот код: √(b^2-4ac)
Вы можете легко использовать обработку строк в javascript для преобразования строк в формат jqMath и легко отображать его
Ответ 6
Вы можете легко использовать математическую формулу в android, используя приведенный ниже код.
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", "");
}