トップ «前の日記(2022-04-24) 最新 次の日記(2022-05-04)» 編集

日々の破片

著作一覧

2022-04-29

_ 2つのiFrameをマウスホイールで同時にスクロールする

同時に良く似たページを比較して眺めたいので、方法をいろいろ考えた。 それぞれをスクロール可能なDIVに組み込めば、同じWindow内の要素同士なので、ほぼ何も考えなくても、片側のDIVのスクロール量をもう一方に与えれば良いので簡単だ。 が、それぞれが独自にJavaScriptを読み込んだりするので、htmlタグ全体を読み込みたい。

となると、iFrameを2つ並べてそれを使うしか、ちょっと方法を考えつかなかった。 で、MDNを読むとwheelイベントというWeb標準があるので、それを利用して、片方のiFrameで受信したwheelイベントのdeltaYを親Windowに与えて、親Windowはもう片方のiFrameのwindowをスクロールすれば良い。簡単じゃん。

と、Firefoxで実装したわけだ。おお、ちゃんと同期する。し、(比較したいわけなので)片方を余分にスクロールしたければスクロールサムをドラッグすればそのiFrameだけ動くので具合も良い。

が、残念。

EdgeでもChromeでもwheelイベントのdeltaYは正しいスクロール量ではない。

なんじゃこれ? と、MDNを良く読むと、ブラウザーの実装ではwheelイベントのdelta*を反映する必要はないと書いてある。だから、scrollイベントを使え。

とはいえ、単純にscrollイベントを使うと、移動量を変えたい場合に処理ができない。ということは、スクロールバーを使ったスクロール時は無視する必要がある。

結局、ホイール操作からスクロールバー操作に人間の動作が移る最短時間を500ミリ秒と適当に判断して、以下のような実装となった(Coffeeで記述している)。

 <iframe data-opposite-id="B" src=... ></iframe> <!-- こちらのHTMLは自身をAと認識 -->
 <iframe data-opposite-id="A" src=... ></iframe> <!-- こちらのHTMLは自身をBと認識 -->
# 親Window側
window.addEventListener('message', (e) ->
  try
    msg = JSON.parse(e.data)
  catch e then return
  if msg.command == 'scroll'
    document.querySelector('iframe[data-opposite-id="' + msg.sender + '"]').contentWindow.scrollBy(0, Math.ceil(msg.deltaY)) # Math.ceilは不要だとは思うし、おそらく余分にスクロールする
)  
# フレーム側
wheelTimer = null
currentTop = null
window.addEventListener('wheel', (e) ->
  if wheelTimer
    clearTimeout(wheelTimer)
  if currentTop == null
    currentTop = window.scrollY
  wheelTimer = setTimeout(() ->
    wheelTimer = null
    currentTop = null
    , 500)
  )
)
window.addEventListener('scroll', (e) ->
  if wheelTimer
    id = document.querySelector('body').dataset['myId'] # A or B
    data = {command: 'scroll', sender: id, deltaY: window.scrollY - currentTop}
    origin = /^[^:]+:\/\/[^/]+/.exec(document.location.href)
    window.parent.postMessage(JSON.stringify(data), origin[0])
    currentTop = window.scrollY
  )
)

もちろん、もっとスマートな方法があればそれを知りたいところ。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|

ジェズイットを見習え