JavaScript

JavaScriptのMath.hypot():座標間の距離を計算する

この記事でわかること

Math.hypot()で座標間の距離やベクトルの長さを求める方法を解説。ブラウザーとNode.jsの実行手順、引数・戻り値、入力検証、数値計算の制約をコードで学べます。

Math.hypot()で何ができるか

画面上の二点がどれだけ離れているか調べたいとき、横方向と縦方向の移動量を足すだけでは直線距離になりません。横に3、縦に4離れた二点の直線距離は5です。

Math.hypot()は、引数をそれぞれ二乗して合計した値の平方根を返します。二点の座標差を渡せば距離になり、ベクトルの各成分を渡せば長さになります。ドラッグ操作の移動量、円形の範囲判定、簡単なゲームの接近判定などに使えます。

本記事では、Math.hypot()を中心に、入力を検証する距離計算の例を作ります。DOMや外部ライブラリーに依存しないため、同じコードをブラウザーとNode.jsで実行できます。

動作環境と対応バージョン

確認日は2026年10月9日です。MDNではMath.hypot()を広く利用可能な機能とし、2015年7月以降、主要ブラウザーで利用できると説明しています。現行のChrome、Edge、Firefox、Safariを利用する場合、通常は追加ライブラリーが不要です。MDNのMath.hypot()

この記事のNode.js側の実行対象は22系以降です。これは記事で採用する環境条件であり、APIが22系で初めて導入されたという意味ではありません。ブラウザー専用APIを使わないので、Node.jsでも同じ計算処理を利用できます。

古いブラウザーや組み込み環境では、呼び出す前にtypeof Math.hypot === "function"で存在を確認してください。後述のサンプルにもこの確認を入れています。存在しない環境では処理を停止し、対応環境へ変更します。

ブラウザーで実行する

対応ブラウザーで空のタブを開き、開発者ツールのConsoleを選びます。後述のJavaScriptコードを、外側のコードフェンスを除いてまとめて貼り付け、実行してください。HTMLファイルの用意やサーバーの起動は不要です。

Consoleにはログの後にundefinedが表示される場合があります。これはコード全体を評価した結果であり、距離計算の失敗ではありません。

Node.jsで実行する

Node.jsをインストールした環境で、コードをUTF-8のdistance-demo.jsとして保存します。ターミナルでそのファイルのあるディレクトリーへ移動し、次のコマンドを実行します。

Shell
node --version
node distance-demo.js

最初のコマンドで22系以降か確認します。nodeが見つからない場合は、Node.jsのインストールとコマンドの検索パスを確認してください。ファイルを引数に渡す実行方法はNode.js公式の実行ガイドに記載されています。

引数と戻り値を理解する

基本の呼び出し方はMath.hypot(dx, dy)です。dxは横方向、dyは縦方向の差を表す変数名ですが、API自体に座標の概念はありません。どの値を渡すかは呼び出し側で決めます。

  • 引数は可変個数で、二次元なら2個、三次元なら3個の成分を渡せます。
  • 戻り値はnumberです。通常の有限数を渡した場合、結果は0以上になります。
  • 引数がない場合は0を返します。
  • 有限数を1個だけ渡すと、その絶対値になります。
  • 数値へ変換された値がNaNなら、無限大の引数がない限り結果もNaNです。
  • 数値への変換で例外が起きない場合、正負いずれかの無限大が含まれるとInfinityになります。

これは同期処理です。戻り値はPromiseではなく、awaitやコールバックは必要ありません。また、Mathから直接呼び出す静的メソッドなので、new Math()でインスタンスを作る必要はありません。

二点の距離を計算するときは、座標そのものではなく差を渡します。点Aが(10, 20)、点Bが(13, 24)なら、差は(3, 4)です。Math.hypot(13, 24)と書くと、原点から点Bまでの距離を求める別の計算になります。

コピーして試せる距離計算

次のコードは入力検証、距離計算、範囲判定、失敗時の処理まで含む自己完結した例です。ブラウザーとNode.jsの両方で、そのまま実行する想定です。

JavaScript
(() => {
  "use strict";

  if (typeof Math.hypot !== "function") {
    console.log("この環境はMath.hypot()に対応していません");
    return;
  }

  function distance2D(ax, ay, bx, by) {
    const coordinates = [ax, ay, bx, by];

    if (!coordinates.every((value) => Number.isFinite(value))) {
      throw new TypeError("座標には有限のnumberを指定してください");
    }

    const dx = bx - ax;
    const dy = by - ay;
    const distance = Math.hypot(dx, dy);

    if (!Number.isFinite(distance)) {
      throw new RangeError("距離が有限数の範囲を超えています");
    }

    return distance;
  }

  const distance = distance2D(10, 20, 13, 24);
  const radius = 6;

  console.log(`距離: ${distance}`);
  console.log(`半径${radius}以内: ${distance <= radius}`);
  console.log(`同じ点の距離: ${distance2D(10, 20, 10, 20)}`);
  console.log(`三次元の長さ: ${Math.hypot(2, 3, 6)}`);

  try {
    distance2D(0, 0, "3", 4);
  } catch (error) {
    console.log(`${error.name}: ${error.message}`);
  }
})();

期待出力は次のとおりです。コードは本記事の作成時には実行しておらず、仕様と計算から導いた出力です。

CODE
距離: 5
半径6以内: true
同じ点の距離: 0
三次元の長さ: 7
TypeError: 座標には有限のnumberを指定してください

コードの読み方

独自関数distance2D()は、始点のax、ayと終点のbx、byを受け取ります。座標差をMath.hypot()に渡し、計算した距離を返します。

入力チェックに使うNumber.isFinite()は、文字列を数値へ変換しません。そのため、文字列の"3"、null、NaN、Infinityを座標として拒否できます。この性質はMDNのNumber.isFinite()で確認できます。

最初の距離は、差の3と4から5になります。半径6以内の判定は5 <= 6なのでtrueです。三次元の例は、二乗の合計が4 + 9 + 36 = 49となるため7です。

最後の呼び出しでは意図的に文字列を渡します。独自関数が投げた例外をtry...catchで受け取り、処理を終了させずにエラー内容を表示します。

失敗例と数値計算の制約

暗黙の変換を入力検証に使わない

Math.hypot()自体は文字列などを数値へ変換します。そのため、入力が間違っていても必ず例外になるわけではありません。

JavaScript
console.log(Math.hypot("3", 4));
console.log(Math.hypot("invalid", 4));
console.log(Math.hypot(NaN, Infinity));

期待出力は順に5、NaN、Infinityです。特に最後の例は、NaNが含まれるから必ずNaNになる、と考えると見落とします。これらの挙動はMDNの戻り値と使用例に示されています。

フォーム入力を扱う場合は、空欄を許すか、数値文字列を受け付けるかを先に決めてから変換してください。サンプルのdistance2D()は、変換済みの有限なnumberだけを受け付ける設計です。

大きい値でも無制限に計算できるわけではない

単純に成分を二乗すると、最終的な長さは表現できる場合でも途中計算がInfinityになることがあります。Math.hypot()は、そうした途中のオーバーフローや、小さな値の二乗が0になるアンダーフローを避ける計算に適しています。

例えば1e200を二乗するとnumberの範囲を超えますが、Math.hypot(1e200, 1e200)の結果はおよそ1.4142e200です。MDNの数値計算に関する説明

ただし、座標差を求める減算が先にオーバーフローすれば、Math.hypot()では復元できません。サンプルは結果の有限性も確認し、必要な場合はRangeErrorを投げます。また、浮動小数点の丸め誤差は残るため、境界付近の判定には用途に応じた許容差が必要です。

活用事例と次の改善

円形の操作範囲では、中心から対象までの距離と半径を比較できます。サンプルのdistance <= radiusなら、円周上の点も範囲内です。円周を除外したい場合は<へ変更します。

ドラッグ操作では、開始位置から現在位置までの距離を調べ、一定の距離を超えた時点でドラッグ開始と判断できます。ブラウザーで使う際は、両方の座標を同じ座標系にそろえてください。画面基準とページ基準の座標を混ぜると、計算できても意味の違う距離になります。

三次元データでは、各軸の差を3個渡すことで空間内の距離を求められます。ただし、緯度と経度をそのまま渡して地球上の距離をメートルで求める用途には適しません。座標系と単位に合った計算法を選ぶ必要があります。

実務へ進めるなら、まず入力の単位と許容範囲を決めることを勧めます。画面上のピクセル、ゲーム内の座標、計測値を同じ関数に渡す場合も、呼び出し側で単位をそろえれば、短い距離計算関数を安全に再利用できます。

公式参考資料

PREFERRED SOURCES

Googleの優先するニュース提供元にSEの部屋を追加

Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。

Googleの設定画面で確認する 新しいタブで開きます

候補にSEの部屋が表示されない場合は、まだ追加できません。

y.
WRITTEN BY

y_ymo10

SEの部屋で、HTML・CSSからJavaScript・React・Next.jsまで、Web制作の開発ノートを公開しています。

ほかの開発ノートを読む →