ブラウザ上で関数グラフをプロットするJavaScriptライブラリJSXGraphと、数式をタイプセッティングしてくれるJavaScriptライブラリMathJaxの使い方のメモです。今回作ったサンプルの画面はこれです。
DEMO: https://codepen.io/kaz_hashimoto/pen/vYKvyVr
このDEMOでは、メニューで曲線の種類を選ぶとグラフと関数の数式を表示します。うち1つのグラフは、関数のパラメータをスライダーで調整できます。グラフが更新されると、下のカラーチャートにも反映されます。10個のセルの背景色は、ベースの色rgb(128,255,0)
に対して、それぞれアルファチャネルにy = f(x) (x = n/10, n = 1〜10)の値を指定して得られた色です。
動作環境 (記事執筆時点)
- JSXGraph v1.1.0
- MathJax 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
<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
<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を2つ用意します。JSXGraphのAPIはグラフの描画領域を作成するのにHTML要素のidを必要とするため、グラフの出力先のdivにはid="plot"
を付けました。
<div class="graph-wrap">
<!-- グラフの出力先(JSXGraph用) -->
<div id="plot" class="graph"></div>
<!-- 数式の出力先(MathJax用) -->
<div class="math"></div>
</div>
グラフの出力先のdiv.plot
要素については、CSSであらかじめ領域を確保しておきます。このサンプルでは幅・高さ共に260pxに設定しました。
.graph-wrap {
width: 260px;
}
.graph {
width: 100%;
height: 260px;
}
##JSXGraphの使い方
###Boardの作成
まず、プロット領域となるバウンディングボックスをJXG.JSXGraph
のメソッドinitBoardを呼び出して作成します。第1引数は、プロット領域となるHTML要素のidです。領域のサイズは、左上、右下頂点の座標の成分を配列にしてboundingbox
に指定します。
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メソッドを呼び出し、ジオメトリック要素text
としてboard
に文字列を配置しました。
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()
の第2引数に配列で [ x座標, y座標, 文字列 ] の形式で指定します。テキストのスタイルは第3引数に指定するのですが、fontSize
以外のスタイルはcssStyle項目の値として、CSSのルールセットを渡します。
参考)Wiki: Texts and Transformations
###関数グラフのプロット
関数のグラフを描くには、Board
のcreate
メソッドの第1引数にfunctiongraph
を指定して呼び出します。下記のコードは、関数bezier(t)
(0 ≤ t ≤ 1)の曲線のグラフを描画します。
function bezier(t) {
return t * t * (3 - 2 * t);
}
let graph = board.create('functiongraph', [bezier, 0, 1]);
###スライダーの作成
グラフにスライダーを設置することができます。スライダーを作成するには、Board
のcreate
メソッドを第1引数にslider
を指定して呼び出します。下記のコードは、ラベルp
を持つスライダーを目盛の開始位置の座標(0.2, 0.4) 、終了位置(0.8, 0.4)に配置し、値のレンジを1〜4、初期値を2に設定します。
let slider = board.create('slider', [[0.2, 0.4], [0.8, 0.4], [1, 2, 4] ], {name: 'p'});
スライダーの現在の値はValue
メソッドで読み出します。drag
イベントのハンドラを登録することにより、ハンドルを動かしている時のスライダーの値を取得できます。
slider.on('drag', function(e) {
console.log('p=' + this.Value());
});
###パラメータを含む関数のグラフ
次に、パラメータpを含む関数f(t, p)の曲線を描く方法です。pの値をスライダーで動かしながら曲線の形状の変化をグラフに反映させることができます。下記のコードは、パラメータpを含む関数parameterized(t)
(0 ≤ t ≤ 1)の曲線1について、pの現在値をスライダーから読み取ってグラフを描画します。
function parameterized(t) {
const p = slider.Value();
const tp = t**p;
return tp / (tp + (1 - t)**p);
}
graph = board.create('functiongraph', [parameterized, 0, 1]);
###グラフの要素の消去
メニューでグラフを切り替えた時やスライダーでパラメータpの値を動かした時、グラフの内容を更新する前に、現在表示されている曲線などを消去する必要があります。でないと、前の曲線が画面に残ったままの状態で新たな曲線が追記されてしまいます。グラフの要素を消すには、Board
のremoveObjectメソッドを呼び出します。
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()
関数を呼んでいます。
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
LaTexタイプセッティングの表示確認には、こちらのLive Demoが便利です。
https://www.mathjax.org/#demo
注)上記コード例で、「\\frac」のようにLaTexコマンドの前のバックスラッシュをエスケープしていますが、Live Demoのテキストエリアにはバックスラッシュを1個にして入力します。
-
この関数の数式は、stackexchange記事 Ease-in-out function より引用 ↩