LaTeXの数式をちょこちょこっと編集してリアルタイムに出力結果を見たいという際にはDaum Equation Editorが非常に高機能で便利です。ただ、自分の職場はChrome Web AppもMacアプリも(LaTeXも!)インストールできないPC環境なので、極めて単純な数式リアルタイム編集機能だけではありますが、AngularJSとMathJaxで実装してみました。
実装手順
(1) JavaScriptライブラリ(AngularJSとMathJax)をページに読み込む。MathJaxは通常ページ読み込み完了時に自動的にTeXコマンドをレンダリングするが、ここではそれを止める必要があるため&delayStartupUntil=configured
をMathJaxのURLクエリパラメータ最後に追記。
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.27/angular.min.js"></script>
<script type="text/javascript"
src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML&delayStartupUntil=configured">
</script>
(2) MathJaxのページ読み込み時自動レンダリングを無効化するための設定(skipStartupTypeset: true
)を追加。
<script>
MathJax.Hub.Config({
skipStartupTypeset: true,
messageStyle: "none",
"HTML-CSS": {
showMathMenu: false
}
});
MathJax.Hub.Configured();
</script>
(3) bodyタグのng-app属性にモジュール名を追加、LaTeX入力用のtextareaにng-modelとしてexpression
を追加、数式出力用のp要素にはmathjax-bind属性を追加。
<!-- LaTeXコマンド入力用 -->
<textarea ng-model="expression"></textarea>
<!-- MathJaxレンダリング出力用 -->
<p mathjax-bind="expression"></p>
(4) AngularJSのディレクティブmathjax-bindを作成してtextareaを監視させ、expression
モデルに入っているLaTeXコマンドに変更がある都度、そのコマンドを出力用p要素に挿入するようにする。p要素内のLaTeXコマンドが更新されたら、MathJax.Hub.Queue(["Reprocess", MathJax.Hub, $element[0]]);
で即座にMathJaxに再レンダリングさせる。
angular.module("myApp", [])
.directive("mathjaxBind", function () {
return {
restrict: "A",
controller: ["$scope", "$element", "$attrs", function ($scope, $element, $attrs) {
$scope.$watch($attrs.mathjaxBind, function (value) {
var $script = angular.element("<script type='math/tex'>")
.html(value == undefined ? "" : value);
$element.html("");
$element.append($script);
MathJax.Hub.Queue(["Reprocess", MathJax.Hub, $element[0]]);
});
}]
};
})
(5) アクセス時にLaTeX数式コマンドが全く入力されていないとなんとなく寂しいので、デフォルトの数式コマンドをいくつか挿入(JavaScript内ではLaTeXコマンドのバックスラッシュをエスケープするためにダブルバックスラッシュに置き換え)。
.controller("MyCtrl", ["$scope", "$element", function($scope, $element) {
$scope.expression = "\\frac{5}{4} \\div \\frac{1}{6} \\\\ \n\n";
$scope.expression += "d\\!f_n(t,T) = \\alpha_n(t,T) dt + \\tau_n(t,T) dW_n^P\\!(t) \\\\ \n\n";
$scope.expression += "\\zeta(s) = \\sum_{n=1}^\\infty\\frac{1}{n^s} \\\\ \n\n";
$scope.expression += "% You can define custom macro with 'newcommand': \n";
$scope.expression += "\\newcommand\\C{{\\mathbb C}} \n\\newcommand\\np[2]{{#1}#2{#1}} \n\\C[y_1,\\ldots,y_n]\\to {\\mathcal A}, \\quad a\\mapsto\\np{:}{a}";
}]);
(6) おまけとしてBootstrapとjQueryで見た目をごまかす調整。
おしまい
参考
http://www.mathjax.org/demos/
https://github.com/mathjax/MathJax-docs/wiki/More-live-preview-examples
http://stackoverflow.com/questions/7925622/display-mathjax-output-in-realtime
http://genkuroki.web.fc2.com/MathJax/LivePreviewMathJax-jquery.html