JSXGraph/MathJaxの使い方：関数グラフのプロットと数式のタイプセッティングを行うJavaScriptライブラリ

ブラウザ上で関数グラフをプロットするJavaScriptライブラリ**JSXGraph**と、数式をタイプセッティングしてくれるJavaScriptライブラリ**MathJax**の使い方のメモです。今回作ったサンプルの画面はこれです。
![JSXGraph-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/f62ae41f-6f03-bcb4-a98e-f4956488b940.gif)
DEMO: [https://codepen.io/kaz_hashimoto/pen/vYKvyVr](https://codepen.io/kaz_hashimoto/pen/vYKvyVr)

このDEMOでは、メニューで曲線の種類を選ぶとグラフと関数の数式を表示します。うち１つのグラフは、関数のパラメータをスライダーで調整できます。グラフが更新されると、下のカラーチャートにも反映されます。10個のセルの背景色は、ベースの色`rgb(128,255,0)`に対して、それぞれアルファチャネルにy = f(x) (x = n/10, n = 1〜10)の値を指定して得られた色です。

**動作環境** （記事執筆時点）

* [JSXGraph](https://jsxgraph.uni-bayreuth.de/wp/) v1.1.0
* [MathJax](https://www.mathjax.org/) v3.1.2
* jQuery 3.5.1
* 動作確認ブラウザ: デスクトップ版 Chrome 86, Firefox 82, Safari 14, Opera 72
* macOS 10.14 Mojave

# JSXGraphとMathJaxの使い方
##設定
JSXGraphとMathJaxライブラリはCDNから利用できます。HTMLファイルに追加する行は以下のとおり。

**JSXGraph**

```html:html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsxgraph/1.1.0/jsxgraph.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsxgraph/1.1.0/jsxgraphcore.min.js"></script>
```

**MathJax**

```html:html
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
```

###埋め込み先のdivを設置
グラフと数式を埋め込むために空のdivを２つ用意します。JSXGraphのAPIはグラフの描画領域を作成するのにHTML要素のidを必要とするため、グラフの出力先のdivには`id="plot"`を付けました。

```html:html
<div class="graph-wrap">
  <!-- グラフの出力先(JSXGraph用) -->
  <div id="plot" class="graph"></div>
  <!-- 数式の出力先(MathJax用) -->
  <div class="math"></div>
</div>
```

グラフの出力先の`div.plot`要素については、CSSであらかじめ領域を確保しておきます。このサンプルでは幅・高さ共に260pxに設定しました。

```css:css
.graph-wrap {
  width: 260px;
}
.graph {
  width: 100%;
  height: 260px;
}
```
##JSXGraphの使い方
###Boardの作成
まず、プロット領域となるバウンディングボックスを`JXG.JSXGraph`のメソッド[initBoard](https://jsxgraph.uni-bayreuth.de/docs/symbols/JXG.JSXGraph.html#.initBoard)を呼び出して作成します。第１引数は、プロット領域となるHTML要素のidです。領域のサイズは、左上、右下頂点の座標の成分を配列にして`boundingbox`に指定します。

```javascript:javascript
let board = JXG.JSXGraph.initBoard('plot', {
  boundingbox: [ -0.1, 1.1, 1.1, -0.1],  // 領域の座標[左、上、右、下]
  axis: true,  // 軸を表示する
  showNavigation: false,  // ナビゲーションボタンを表示しない
  showCopyright: false    // コピーライト文字列を表示しない
});
```

###軸タイトルの追加
軸を表すタイトルを付けましょう。JSXGraph APIには軸タイトルを指定する機能が用意されてないようなので、`Board`の[create](https://jsxgraph.uni-bayreuth.de/docs/symbols/JXG.Board.html#create)メソッドを呼び出し、ジオメトリック要素`text`として`board`に文字列を配置しました。

```javascript:javascript
const text_css = 'font-family: "Times New Roman", Times, "serif"; font-style: italic';
board.create('text', [1.05, 0.08, 't'],
       { fontSize: 16, cssStyle: text_css });
board.create('text', [0.05, 1.05, 'y'],
       { fontSize: 16, cssStyle: text_css });
```

テキストの位置と内容は、`create()`の第２引数に配列で [ _x座標, y座標, 文字列_ ] の形式で指定します。テキストのスタイルは第３引数に指定するのですが、`fontSize`以外のスタイルは[cssStyle](https://jsxgraph.uni-bayreuth.de/docs/symbols/Text.html#cssStyle)項目の値として、CSSのルールセットを渡します。
参考）Wiki: [Texts and Transformations](https://jsxgraph.uni-bayreuth.de/wiki/index.php/Texts_and_Transformations)

###関数グラフのプロット
関数のグラフを描くには、`Board`の`create`メソッドの第１引数に`functiongraph`を指定して呼び出します。下記のコードは、関数`bezier(t)`（0 &le; t &le; 1）の曲線のグラフを描画します。

```javascript:javascript
function bezier(t) {
  return t * t * (3 - 2 * t);
}

let graph = board.create('functiongraph', [bezier, 0, 1]);
```

###スライダーの作成
グラフに[スライダー](https://jsxgraph.uni-bayreuth.de/docs/symbols/Slider.html)を設置することができます。スライダーを作成するには、`Board`の`create`メソッドを第１引数に`slider`を指定して呼び出します。下記のコードは、ラベル`p`を持つスライダーを目盛の開始位置の座標(0.2, 0.4) 、終了位置(0.8, 0.4)に配置し、値のレンジを1〜4、初期値を2に設定します。

```javascript:javascript
let slider = board.create('slider', [[0.2, 0.4], [0.8, 0.4], [1, 2, 4] ], {name: 'p'});
```

スライダーの現在の値は`Value`メソッドで読み出します。`drag`[イベント](https://jsxgraph.uni-bayreuth.de/wiki/index.php/Adding_events_2)のハンドラを登録することにより、ハンドルを動かしている時のスライダーの値を取得できます。

```javascript:javascript
slider.on('drag', function(e) {
  console.log('p=' + this.Value());
});
```

###パラメータを含む関数のグラフ
次に、パラメータpを含む関数f(t, p)の曲線を描く方法です。pの値をスライダーで動かしながら曲線の形状の変化をグラフに反映させることができます。下記のコードは、パラメータpを含む関数`parameterized(t)`（0 &le; t &le; 1）の曲線[^1]について、pの現在値をスライダーから読み取ってグラフを描画します。

```javascript:javascript
function parameterized(t) {
  const p = slider.Value();
  const tp = t**p;
  return tp / (tp + (1 - t)**p);
}

graph = board.create('functiongraph', [parameterized, 0, 1]);
```

[^1]: この関数の数式は、stackexchange記事 [Ease-in-out function](https://math.stackexchange.com/questions/121720/ease-in-out-function/121755#121755) より引用

###グラフの要素の消去
メニューでグラフを切り替えた時やスライダーでパラメータpの値を動かした時、グラフの内容を更新する前に、現在表示されている曲線などを消去する必要があります。でないと、前の曲線が画面に残ったままの状態で新たな曲線が追記されてしまいます。グラフの要素を消すには、`Board`の[removeObject](https://jsxgraph.uni-bayreuth.de/docs/symbols/JXG.Board.html#removeObject)メソッドを呼び出します。

```javascript:javascript
function clearGraph() {
  if (graph) { // 今表示されている曲線があれば消す
    board.removeObject(graph);
    graph = null;
  }
  if (slider) { // スライダーが表示されていれば消す
    board.removeObject(slider);
    slider = null;
  }
}
```

これでグラフが描けました！ 次は数式を表示してみましょう。

##MathJaxの使い方
MathJaxを使って数式を描画するには、出力先divの`innerHTML`に、LaTeXコマンドで記述した数式の文字列をセットし、`MathJax.typeset()`関数を呼び出します。下記のコードは、変数`math`に設定したディスプレイ数式モードのLaTex形式文字列(\$\$...\$\$)を`div.math`要素のコンテントに書き込んだ後、`MathJax.typeset()`関数を使って数式を描画させます。タイプセットの更新前に現在の状態をクリアするため、最初に`div.math`要素に対して`MathJax.typesetClear()`関数を呼んでいます。

```javascript:javascript
MathJax.typesetClear([$('.math').get(0)]);
const math = '$$f_{p}(t)=\\frac{t^p}{t^p+(1-t)^p}$$';
$('.math').html(math);
MathJax.typeset();
```

参考） [Typesetting and Converting Mathematics](https://qiita.com/drafts/b27a039b22d405dfa146/edit)

LaTexタイプセッティングの表示確認には、こちらのLive Demoが便利です。
[https://www.mathjax.org/#demo](https://www.mathjax.org/#demo)

注）上記コード例で、「\\\frac」のようにLaTexコマンドの前のバックスラッシュをエスケープしていますが、Live Demoのテキストエリアにはバックスラッシュを１個にして入力します。