◆ mousemove の代わりに pointermove を使うと PointerEvent を受け取れる
◆ PointerEvent の getCoalescedEvents() を使ってイベントを取得すると 高負荷時に mousemove で取れなかった座標のイベントも取得できる
◆ getPredictedEvents() を使うとほんの少し未来の座標を予測できる

知名度が低い?せいで探すのに苦戦した

マウスの移動の履歴を取得する必要がありました
普通にやると mousemove イベントにリスナを設定してイベントが起きたときの座標を取得します
ただ この方法って負荷が高いときには飛び飛びになったりで あまり正確じゃないんですよね
以前それをうまくやる方法を使ったことがあったはず なのですが何というメソッドを使ったかを全然覚えてなくて苦戦しました

ググればすぐに出ると思ったのに それっぽいのが全く出てきません
あまり見ない機能だった記憶はありますが そこまでマイナーな機能だったのでしょうか??

こういうのはだいたいこのブログに書いてるはず と思って探したのに全然見当たりません
検索で引っかかりそうな「マウス」「移動履歴」「重い場合」「mousemove」などそれっぽいワードでも出てきません
組み合わせるとどれかが含まれてないのかもと「マウス」や「mousemove」単体で検索した結果を 1 記事 1 記事見ていったのに見つかりませんでした
このブログの全記事だと 2000 記事近くあるので候補が多すぎてかなり大変なのですよね
たしか 2, 3 年程度前のはずなので その期間を優先的に見たりもしましたが 見つからないです

マウスの移動軌跡なら mousemove イベントでしょうし MouseEvent.prototype のメソッドを全部見ていけばあるはずと思って確認もしました
ですが ここにもそれらしいのは見つからず

そんな感じで記憶力に自信がなくなりつつ探すこと数時間
予想外なことに このブログとは別の場所で書いてました……
このブログ内の検索で引っかかってほしいので このブログにも書いておくことにします

getCoalescedEvents

使うメソッドは getCoalescedEvents でした
名前を見て納得
RDB でも COALESCE 関数の名前が覚えられず毎回 null 関係の関数でググってるくらいです

このメソッドは mousemove イベントではなく pointermove イベントで使います
prototype から探すのなら MouseEvent.prototype ではなく PointerEvent.prototype を見ないといけなかったです

mousemove ならイベントが起きた時点のマウスの位置を clientX/Y や offsetX/Y プロパティから取得します
pointermove では event の getCoalescedEvents メソッドを呼び出すことで複数の PointerEvent オブジェクトを取得できます
このイベントオブジェクトの clientX/Y や offsetX/Y プロパティを使います

window.addEventListener("mousemove", event => {
console.log("mousemove", event.clientX, event.clientY, event.timeStamp)
})

window.addEventListener("pointermove", event => {
for (const eve of event.getCoalescedEvents()) {
console.log("pointermove", eve.clientX, eve.clientY, eve.timeStamp)
}
})

基本的には getCoalescedEvents() の返り値は 1 つだけで 取得できる座標は mousemove と同じです
負荷が高くなって mousemove イベントが処理できないようになると 複数取得できるようになります

試せるページを用意しました

DEMO

一番左の四角いエリアの中でマウスを動かすとその軌跡を 2 種類の方法で取得して残りの四角いエリアに表示します
赤色の線が mousemove イベント 青色の線が getCoalescedEvents で取得した座標を使っています
2 つめ 3 つめの四角は個別に表示していて 4 つめの四角は重ねて差分をわかりやすく表示しています
ずっと残すと古い線が邪魔になってくるので 3 秒過ぎた座標は削除するようにしています

上部の blocking_ms と interval_ms でページ負荷を調整できます
1 回の while ループでメインスレッドをブロックする時間を blocking_ms で設定できます
ブロックする while ループを実行する間隔を interval_ms で設定できます
blocking_ms=100ms, interval_ms=10ms だと 10ms 間隔で 100ms 間メインスレッドをブロックします
ブロックされているうちはタイマーが止まっているので 負荷の参考にできます

メインスレッドがブロックされている間は mousemove イベントは起きないので 描画される線は飛び飛びになっています
その間のマウスの位置は getCoalescedEvents メソッドで取得できるイベントオブジェクトで取得できるので getCoalescedEvents を使った方ではなめらかに表示できています

波線や円を描くように動かすとわかりやすいです
デフォルトの両方 100ms だとわずかに青色のほうがなめらかかなって程度ですが interval_ms を 10ms にしてみると差が目立ちます

getcoalescedevents

getPredictedEvents

探していた getCoalescedEvents を見つけれてこれで終わりの予定だったのですが PointerEvent では getPredictedEvents というメソッドもありました
名前的には今後の移動を予測してくれそうです

試してみると タイムスタンプが未来のものになっていました

window.addEventListener("pointermove", () => {
const round = n => +n.toFixed(3)
const now = round(performance.now())
const coalesced = event.getCoalescedEvents().map(event => round(event.timeStamp))
const predicted = event.getPredictedEvents().map(event => round(event.timeStamp))
console.log({ now, coalesced, predicted })
})

これでマウスを動かすと 表示されるログの一つはこうなっていました

coalesced: [2034.8]
now: 2035.9
predicted: (5) [2039.6, 2044.4, 2049.2, 2054, 2058.8]

coalesced のあとに now があって predicted には now よりあとのタイムスタンプが並んでいます

座標を見てもマウスを移動している方向の先に向かっています

こっちも試せるページを用意しました

DEMO

四角の中でマウスを動かすと 各イベント発生時の予測される移動先を赤色の線で表示しています
マウスカーソルが邪魔で見づらいので マウスカーソルは非表示にして マウスの位置には黒いドットを表示するようにしています

予測といっても 何秒も先は取得できず数ミリ秒から十数ミリ秒先程度です
単純に表示してもほぼわからないものになったので縦横をそれぞれ 10 倍に拡大して表示しています

マウスを動かしていると 動かしてる方向へマウスの座標より少し先に赤い線が出てるのがわかるかと思います
分かりづらい場合はマウス感度を上げて高速で動かすと線が長くなります