【JSXGraph】textにLaTeXを使う, 特定の領域を塗りつぶす【MathJax】

# 前書き
小ネタになります。最近は計算プリント作成に解説も追加していますが、その過程でグラフを使う必要に迫られました。結果として採用したのがJSXGraphです。[Github](https://github.com/jsxgraph/jsxgraph)には以下のように紹介されています。

> JSXGraph is a cross-browser library for interactive geometry, function plotting, charting, and data visualization in a web browser. It is implemented completely in JavaScript, does not rely on any other library, and uses SVG, canvas, or even the venerable VML. JSXGraph is easy to embed and has a small footprint: approx. 160 KByte if embedded in a web page. No plug-ins are required! Special care has been taken to optimize the performance.

> JSXGraphはブラウザ上でインタラクティブな幾何学的配置や関数プロット、チャートの作成やデータの可視化を行えるクロスブラウザなライブラリです。完全にJavaScriptのみで実装されており、他のライブラリに依存せず、SVGやcanvas、さらには由緒正しいVMLなども利用していません。JSXGraphは容易に埋め込み可能で、仮にウェブページに埋め込んでも高々160kBを専有するだけです。プラグインは不要です。パフォーマンスを最適化することに特別な注意を払っています。

以前どこかで書いたかもしれませんが、私はWebサイトをPythonAnywhereの無料プランで展開しており、あまり重いものを突っ込む余裕がないのです。このライブラリはそんな状況にドンピシャリで、非常にお世話になっております。CDNで手軽に利用できるのも至れり尽くせりでした。

# 手こずったアレコレ
で、本題なのですが、扱っていくなかで手こずる点が何点かあったので、それらをピックアップして書いていくことになります。非常に便利な神ライブラリなのですが、今ひとつ日本語の情報が出てこないのが唯一のネックとなっています。どなたかの参考になれば幸いです。

なお、JSXGraphの導入を含むトータルの解説については、[こちらのサイト様](https://zenn.dev/sdkfz181tiger/articles/5e738594713db2)が非常にわかりやすかったので、導入を検討されている方は参考にしてみてください。

とはいっても、導入自体はかなり楽で、単に下の諸々を追加するだけです。

```javascript:
// mathjaxの設定
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
// jsxgraphの設定
<link href="//cdnjs.cloudflare.com/ajax/libs/jsxgraph/1.4.5/jsxgraph.min.css" rel="stylesheet">
<script src="//cdnjs.cloudflare.com/ajax/libs/jsxgraph/1.4.5/jsxgraphcore.js"></script>
// mathjaxのルール設定
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        extensions: ["tex2jax.js"],
        jax: ["input/TeX","output/HTML-CSS"],
        tex2jax: {
            inlineMath: [["$","$"],["\\(","\\)"]],
            displayMath: [["$$","$$"],["\\[","\\]"]]
        }
        });
</script>
```

以下はMathJax、JSXGraphは利用できる状態だと仮定して話を進めます。

## 1.) textにLaTeX形式を表示する
グラフを表示するのであれば、その式も当然ながらセットで表示したいところです。JSXGraphはそのあたり気が利いていて、普通の式であれば特に何もせずとも数式として表示してくれます。

まずはjxgboxをhtml上に配置します。ざっくりcanvas要素のような使い方をすると捉えてくれればokです。

```html:
<div id="jxgbox0" class="jxgbox" style="width: 500px; height: 500px;"></div>
```

次に、描画部分を作ります。ここではページにアクセスしてロードする時に動くようにしましょう。

```javascript:
window.addEventListener("load", (event)=>{
    // jxgbox0に(-2, 3)が左上隅、(5, -1)が右下隅となる平面を作成。軸も表示
	let jsx0 = JXG.JSXGraph.initBoard("jxgbox0", {axis: true, boundingbox: [-2, 3, 5, -1]}); 
    // y = x^2 - 5x + 6を表示
    jsx0.create('functiongraph', [x => x ** 2 - 5 * x + 6]);
    // (0.5, 0.25)に式を表示
    jsx0.create('text', [0.5, 0.25, 'y=x^2-5x+6']);
});
```

できあがるグラフはこんな感じです。

![y=x^2-5x+6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/ce9b6b5a-c7dc-1eae-96df-6220b276bd87.png)

簡単な表示で行ける割には、非常にきれいなグラフがかけます。非常に良いですね。

それでは次に頂点を表示してみましょう。

```javascript:
// 頂点(5/2, -1/4)に赤点を配置
jsx0.create('point', [5/2, -1/4], {strokeColor: 'red', name: '(5/2, -1/4)'});
```

![y=x^2-5x+6(頂点つき).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/036a47f7-e3af-db9e-0d2a-dca0c83b1210.png)

見れないことはないのですが、分数の表示がちょっと微妙ですし、位置も少しずらしたいところです。

こんなときはまずはnameを空の文字列にします。そもそもnameを指定しないと、A,B...自動で命名される仕様だからです。多分表示オプションとかあると思うんですど、見つけられなかったんでこのような対応をしています。

```javascript:
// nameを空っぽに
jsx0.create('point', [5/2, -1/4], {strokeColor: 'red', name: ''});
```

それとは別にtext要素を微調整しながら配置します。useMathJax: trueを設定しているのがポイントとなります。

```javascript:
// (5/2-0.25, -1/4-0.25)にLaTeX形式で座標を表示
jsx0.create('text', [5/2-0.25, -1/4-0.25, '$$\\left( \\dfrac{5}{2}, -\\dfrac{1}{4} \\right)$$'], {useMathJax: true});
```

![y=x^2-5x+6(LaTeXによる頂点つき).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/9fc19b34-0072-ecb0-6c28-b2f9b64dcf9e.png)

ついでに式の方の表示も修正して、もう一つついでにx,y軸にもそれぞれ名前を表示しておきましょう。フォントサイズなど、諸々をまとめたコードは以下のようになります。

```javascript:
window.addEventListener("load", (event)=>{
    // (-2, 3)が左上隅、(5, -1)が右下隅となる平面を作成。軸も表示
	let jsx0 = JXG.JSXGraph.initBoard("jxgbox0", {axis: true, boundingbox: [-2, 3, 5, -1]}); 
    // x,y軸の名前を表示
    jsx0.create('text', [4.8, 0.2, '$$x$$'], {useMathJax: true});
    jsx0.create('text', [0.2, 2.8, '$$y$$'], {useMathJax: true});
    // y = x^2 - 5x + 6を表示
    jsx0.create('functiongraph', [x => x ** 2 - 5 * x + 6]);
    // (0.2, 0.25)にLaTeX形式のy=x^2 - 5x + 6を表示
    jsx0.create('text', [0.2, 0.25, '$$y=x^2-5x+6$$'], {fontSize: 13, useMathJax: true});
    // 頂点(5/2, -1/4)に赤点を配置
    jsx0.create('point', [5/2, -1/4], {strokeColor: 'red', name: ''});
    // (5/2-0.25, -1/4-0.25)にLaTeX形式で座標を表示
    jsx0.create('text', [5/2-0.25, -1/4-0.25, '$$\\left( \\dfrac{5}{2}, -\\dfrac{1}{4} \\right)$$'], {useMathJax: true});
});
```

ここから出てくるのが以下のグラフです。最初より少しは見やすくなりましたね。

![y=x^2-5x+6(最終成果).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/c47418e5-3138-9127-e7df-43cfa7653954.png)

以上、textにLaTeX形式を用いる方法でした。

## 2.) 特定の領域を塗りつぶす
時にはグラフを表示するだけではなく、そのグラフで囲まれた領域を示してあげたい場合もあります。今回は例として、2次関数y=x^2と直線y=xの間にできる領域を塗りつぶしていきましょう

jxgboxを配置して、さらにそこにグラフを描きます。また、ロード時に表示する設定もそのままです。ちなみに、boundingboxの設定はxの幅とyの幅が同じになるようにしないと、マス目が歪みます。

```javascript:
let jsx0 = JXG.JSXGraph.initBoard("jxgbox0", {axis: true, boundingbox: [-0.5, 1.8, 1.5, -0.2]});
// y=x^2を-10≦x≦10で表示
let function0_1 = jsx0.create('functiongraph', [x => x ** 2, -10, 10]);
// 同じ範囲でy=xを表示
let function0_2 = jsx0.create('functiongraph', [x => x, -10, 10]);
```

![y=x^2, y=x.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/d7ef7259-8d5c-6292-4225-bad82c22d7f1.png)

createしたときの返り値を受け取っているという点で、先程までとは異なっています。作るだけなら不要なのですが、その後利用するときは予め格納しておく必要があります。

次にそれぞれの関数を基準として、inequalityを指定して領域を取ります。inverseがtrueだと下、falseだと上を取ります。
で、最後にcurveintersectionを取ると共通範囲を塗ってくれます。fillColorはそのまま塗るときの色で、fillOpacityはその透明度になります。

```javascript:
// y=x^2より下の領域を示す
let ineq0_1 = jsx0.create('inequality', [function0_1], {inverse: true, fillColor: 'white'});
// y=xより上の領域を示す
let ineq0_2 = jsx0.create('inequality', [function0_2], {inverse: false, fillColor: 'white'});
// ２つの領域の共通範囲を塗る
jsx0.create('curveintersection', [ineq0_1, ineq0_2], {fillColor: 'yellow', fillOpacity: 0.5});
```

![y=x^2, y=x(領域つき).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/235eb182-511e-6899-3dc9-2b71a3225325.png)

以上になります。ちなみにineq0_1とineq0_2ではfillColorにwhiteを指定していますが、これをやらないと共通範囲以外の場所も塗られてしまいます。

```javascript:
// y=x^2より下の領域を示す
// let ineq0_1 = jsx0.create('inequality', [function0_1], {inverse: true, fillColor: 'white'});
let ineq0_1 = jsx0.create('inequality', [function0_1], {inverse: true});
// y=xより上の領域を示す
// let ineq0_2 = jsx0.create('inequality', [function0_2], {inverse: false, fillColor: 'white'});
let ineq0_2 = jsx0.create('inequality', [function0_2], {inverse: false});
```

![y=x^2, y=x(white指定なしの領域つき).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/b1c4963e-29e1-2195-5e62-be0665a011ee.png)

ただ、自動的に色を重ねてくれるので、これはこれでcurveintersectionなしに「範囲が重なった場所はここだよ」と示すのには良いかもしれませんね。

![y=x^2, y=x(curveintersectionなし).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/ce7fbc28-5b5a-b65a-1747-9d976c572293.png)


# 後書き
短いですが、今回は以上となります。いずれもそれなりに詰まったので、どなたかの参考になれば幸いです。分かりづらい部分、誤っている部分があれば、コメント欄で指摘していただければ幸いです。

（忘れなかったら）今後も随時追加していく予定です。

# その他参考サイト様
[JSXGraph 1.5.0 Reference: Element CurveIntersection](https://jsxgraph.uni-bayreuth.de/docs/symbols/CurveIntersection.html)