JavaScriptのMath.tanh():入力に応じた移動量を滑らかに制限する
Math.tanh()で正負の入力を一定範囲の移動量へ変換する方法を解説。引数・戻り値、ブラウザーとNode.jsの実行手順、期待出力、入力検証や丸め誤差の注意点を学べます。
目的:大きな入力でも移動量が増えすぎないようにする
ドラッグ操作やポインターに反応する演出では、入力をそのまま移動量にすると、操作が大きいほど要素が遠くまで動いてしまいます。一方、境界で突然打ち切る方法では、上限付近で反応の変化が急になります。
Math.tanh()は、数値の双曲線正接を返す静的メソッドです。ゼロ付近では入力の変化を比較的よく伝え、絶対値が大きくなるほど出力の変化が小さくなります。この性質を使うと、上限付近で反応を緩やかにできます。
この記事では、正負の入力を最大約40ピクセルの移動量に変換します。上限へ近づく数値変換を扱うもので、時間に沿って動きを補間するアニメーション機能ではありません。
動作環境と互換性
2026年10月24日時点で確認したMDNでは、Math.tanh()は広く利用可能な機能に分類され、2015年7月からブラウザー間で利用可能と説明されています。現在のChrome、Edge、Firefox、Safariで使えます。古い組み込みブラウザーなどでは、利用前に機能の有無を確認してください。MDNのMath.tanh()
ブラウザーとNode.jsの両方で動作します。本記事のNode.js側の対象は22系・24系です。DOMや外部ライブラリーを使わないため、同じ計算コードを両環境で利用できます。Node.js公式の配布情報でも22系・24系がLTSとして掲載されています。Node.js公式のバージョン情報
ここで挙げたNode.jsのバージョンは記事の対象環境であり、APIが初めて導入されたバージョンを意味しません。
引数と戻り値
呼び出し方は次のとおりです。
Math.tanh(x);x:双曲線正接を求める数値です。- 戻り値:計算結果を表す
numberです。 0に対しては0、-0に対しては-0を返します。Infinityに対しては1、-Infinityに対しては-1を返します。NaNに対してはNaNを返します。
Mathのインスタンスを作る必要はありません。常にMath.tanh(x)という形で呼び出します。基本仕様と無限大・ゼロの動作は、MDNの引数・戻り値と使用例で確認できます。
出力範囲の考え方
数学上、有限の入力に対する値は-1より大きく、1より小さくなります。ただし、JavaScriptの浮動小数点演算では、十分に大きな有限値でも丸めによって1や-1になることがあります。「有限値なら端点には絶対に到達しない」という判定には使わないでください。
数値はIEEE 754の倍精度形式で表現されるため、計算には精度の限界があります。MDNのNumber
コピーして実行するコード
次のコード全体で、入力から移動量への変換と、不正入力の処理を確認できます。画面上の要素を操作せず、計算結果だけを出力するため、ブラウザーでもNode.jsでも同じ手順で結果を比較できます。
(() => {
"use strict";
if (typeof Math.tanh !== "function") {
console.log("この環境はMath.tanh()に対応していません");
return;
}
function toOffset(input, scale = 100, limit = 40) {
if (!Number.isFinite(input)) {
throw new TypeError("inputは有限の数値にしてください");
}
if (!Number.isFinite(scale) || scale <= 0) {
throw new RangeError("scaleは正の有限数にしてください");
}
if (!Number.isFinite(limit) || limit <= 0) {
throw new RangeError("limitは正の有限数にしてください");
}
return limit * Math.tanh(input / scale);
}
const inputs = [-300, -100, 0, 100, 300];
for (const input of inputs) {
const offset = toOffset(input);
console.log(`${input} -> ${offset.toFixed(2)}px`);
}
try {
toOffset("100");
} catch (error) {
console.log(`${error.name}: ${error.message}`);
}
try {
toOffset(100, 0);
} catch (error) {
console.log(`${error.name}: ${error.message}`);
}
})();ブラウザーでの実行方法
通常のWebページを開き、開発者ツールのConsoleを選びます。コードブロックの中身全体を貼り付けて実行してください。貼り付け制限が表示される場合は、使用するブラウザーの案内に従います。
コードを即時実行関数で囲んでいるので、繰り返し実行しても、同名のトップレベル変数を再宣言する問題を避けられます。ネットワーク通信や追加パッケージは不要です。
Node.jsでの実行方法
Node.jsの22系または24系を用意し、コード全体をUTF-8のmath-tanh-demo.jsとして保存します。そのファイルがあるディレクトリーで、次のコマンドを実行します。
node --version
node math-tanh-demo.js最初のコマンドで対象バージョンであることを確認します。ファイルを引数に渡す実行方法は、Node.js公式のスクリプト実行手順に沿っています。
期待出力と計算の読み方
対応環境での期待出力は次のとおりです。公式の数値例と計算式から確認したもので、この記事の作成時に実機で実行した結果ではありません。
-300 -> -39.80px
-100 -> -30.46px
0 -> 0.00px
100 -> 30.46px
300 -> 39.80px
TypeError: inputは有限の数値にしてください
RangeError: scaleは正の有限数にしてくださいinputが100なら、input / scaleは1です。Math.tanh(1)は約0.761594なので、40を掛けると約30.46になります。入力が300でも結果は約39.80にとどまります。
この例のscaleは反応の強さを決める値です。小さくすると、小さな入力でも上限へ近づきます。大きくすると、同じ入力に対する移動量が小さくなります。limitは出力の上限の大きさです。
ゼロ付近の感度は、おおよそlimit / scaleで考えられます。この例では約0.4なので、非常に小さな入力では入力の約0.4倍が移動量になります。上限と感度を別々の設定として持つと、調整の意図を説明しやすくなります。
失敗例と制約
暗黙の型変換で不正入力を見逃す
Math.tanh()は数値への変換を行います。例えば、数値文字列は計算され、nullはゼロとして扱われます。入力ミスを検出したい処理では、この動作をそのまま受け入れると問題が隠れる場合があります。
console.log(Math.tanh("0"));
console.log(Math.tanh(null));
console.log(Math.tanh(undefined));期待出力は順に0、0、NaNです。数値への変換では、BigIntやSymbolはTypeErrorになります。MDNの数値への型変換
実用例のtoOffset()は、有限のnumberだけを受け付けます。そのため文字列の"100"も拒否します。フォーム入力を使う場合は、呼び出す前に空欄を確認し、数値へ変換したうえで検証してください。
不正な設定値を境界への到達と取り違える
scaleがゼロだと、ゼロ以外の入力を割った結果は正負の無限大になります。するとMath.tanh()の結果が端点になり、設定ミスなのに正常に制限できたように見えます。コードでは正の有限数かを先に確認しています。
極端に小さな正のscaleでも、除算結果が無限大へあふれる可能性があります。この例では端点への飽和として扱いますが、通常のUI設定では極端な値を許可しない設計が扱いやすいでしょう。
処理はすべて同期的です。awaitは不要で、不正入力による例外は呼び出し元のtry...catchで処理できます。
活用事例と導入時の判断
- ドラッグの端で抵抗感を出すための、入力距離から表示距離への変換。
- ポインターからの距離に応じて、カードの傾きを一定範囲に収める計算。
- ゲームの入力値から、上限のある操作量を求める処理。
この変換は非線形なので、入力が2倍でも出力は2倍になりません。正確な距離や測定値の表示には向かず、操作感を調整する用途に適しています。また、入力値だけから結果が決まるため、時間方向の揺れを取り除く効果はありません。
導入時は、まずlimitで許容する最大移動量を決め、次にscaleを調整してください。元の入力値も保持し、表示に使う値だけを変換すると、操作の記録や後からの再調整が容易になります。
公式参考資料
Googleの優先するニュース提供元にSEの部屋を追加
Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。
候補にSEの部屋が表示されない場合は、まだ追加できません。