33441


ニコニコ動画html5版で、画面をクリックしながらホイールすることで音量調節をできるようなスクリプトをgreasemonkeyにて書こうと思っています。  
javascriptには疎く、何を学べばよいか分かりません。  
自分で調べたところ、  
`.VideoAdVolumeBarContainer > div:nth-child(1) > div:nth-child(1)`  
の.XSliderに紐付いている以下のスクリプトが音量調節に関わっていることがわかりました。

[code]

     t.prototype._getRatioFromEvent = function (e) {
       return (e.clientX - this._dom.getBoundingClientRect().left) / this._dom.offsetWidth
                                              },
     t.prototype._onMouseDown = function (e) {
       this.ratio = this._getRatioFromEvent(e),
       this.props.onDragStart(e),
       this._addMouseEventToDocument()
                                              },
     t.prototype._onMouseMove = function (e) {
       this.ratio = this._getRatioFromEvent(e),
       this.isDragging || (this.isDragging = !0),
       this.props.onDragging(e)
                                              },
     t.prototype._onMouseUp = function (e) {
       this._removeMouseEventFromDocument(),
       this.ratio = this._getRatioFromEvent(e),
       this.isDragging = !1,
       this.props.onDragEnd(e)
                                              }
    
[/code]

関数名から処理の内容は何となく分かるのですが、ここに先程述べたようなスクリプトを追記するにはDOM、jsについての知識が必要なのでしょうが、どこで調べていくのが良いのでしょうか?


CC BY-SA 3.0
2017-03-21T05:37:33.903
33435
2017-07-02T06:37:43.053
20533
question
javascript html5
jsやDOMについての調べ方


適切な回答か分かりませんが、JavaScriptに関する知識が掲載されているウェブサイトを紹介します

MDN JavaScript ガイド  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide>

分からないことがあったとき、必要に応じて読むリファレンスです  
先頭から順に読んでいくものではありません  
Mozillaが提供している情報なので、非常に信頼度が高いです

* * *

JavaScript Garden  
<http://bonsaiden.github.io/JavaScript-Garden/ja/>

内容が基本的、かつ、非常に実践的なので、JavaScript(ECMAScript)の基本を理解するのに最適です

* * *

JavaScript初級者から中級者になろう  
<http://uhyohyo.net/javascript/>

HTMLの操作や、ブラウザ機能の利用など、実用的な例がまとまっています

* * *

ブラウザのdeveloper toolのrepl(F12 or Ctrl-Shift-i)

JS fiddle  
<http://jsfiddle.net/>

実際に動作させることが一番理解を進めます  
とりあえず動かしましょう

* * *

今回の例だと

イベントリスナ  
<http://uhyohyo.net/javascript/3_2.html>

ドラッグ＆ドロップ  
<https://developer.mozilla.org/ja/docs/DragDrop/Drag_and_Drop>

あたりを読んでみるといいと思います

JavaScriptは「プログラミング言語」+「ブラウザの機能」の2つの側面を両方理解しなければならないので、覚えなければならないことが多いです  
座学と実践を繰り返して、少しずつ身につけていってください


CC BY-SA 3.0
2017-03-21T07:48:06.233
33440
2017-03-21T07:48:06.233
9796
33435
answer


当該サービスは動画プレイヤーの実体として`<video>`要素を使用していますので、この要素に対応するDOMを何らかの形で取得できれば、[volumeプロパティ](https://developer.mozilla.org/en-
US/docs/Web/API/HTMLMediaElement/volume)から音量の取得/設定が可能です。ただし、この方法ではアプリの音量バーに値が反映されないため、コード後半では疑似的に音量バーのイベントを発火させることで再描画させています。デバッガを使って処理を追うとわかりますが、ここから呼ばれる処理で実際に音量をセットしているようなので、安全性を考慮してコードでは直接volumeプロパティはいじっていません。  
マウスのホイールに関しては[wheelイベント](https://developer.mozilla.org/en-
US/docs/Web/Events/wheel)のイベントオブジェクトの[deltaYプロパティ](https://developer.mozilla.org/en-
US/docs/Web/API/WheelEvent/deltaY)あたりから移動方向が取得できますので、この値から判定して動作を分岐してみました。  
結論としてはつぎのようなコードです。

[code]

    // ==UserScript==
    // @name        nicovideo.jp; mouse wheel volume
    // @namespace   http://ja.stackoverflow.com/questions/33435/
    // @include     http://www.nicovideo.jp/watch/*
    // @version     2
    // @grant       none
    // ==/UserScript==
    
    const volumeStep = 0.05;
    
    window.addEventListener('wheel', e => {
        // if delta is not zero and some mouse button is pressed
        if (e.deltaY == 0 || !e.buttons) {
            return;
        }
    
        // get elements
        const $XSlider = document.querySelector('.VolumeBar > .XSlider');
        const $container = document.querySelector('.PlayerContainer');
        const $video = document.querySelector('#MainVideoPlayer > video');
    
        // prevet scroll
        e.preventDefault();
    
        let volume;
        // scroll down; volume down
        if (e.deltaY > 0) {
            volume = Math.max(0, $video.volume - volumeStep);
        }
        // scroll up; volume up
        else {
            volume = Math.min(1, $video.volume + volumeStep);
        }
    
        // refresh volume bar
        const clientX = volume * $XSlider.offsetWidth + $XSlider.getBoundingClientRect().left;
        $XSlider.dispatchEvent(new MouseEvent('mousedown', { clientX: clientX, bubbles: true }));
        $XSlider.dispatchEvent(new MouseEvent('mousemove', { clientX: clientX, bubbles: true }));
        document.dispatchEvent(new MouseEvent('mouseup', { clientX: clientX, bubbles: true }));
    });
    
[/code]

動作はfirefox 52.0.1で確認しました。ただしアプリの実装が変更されれば動かなくなりますので、日ごろから確認する必要があります。

* * *

volumeプロパティに値をセットすることで音量調節自体は完了ですから、私ならばここでやめてしまいます（手抜き）。ですがしっかり実装するとなると、実際にユーザーが行う音量調節動作（マウスによる音量バーの操作）をエミュレートするのがもっとも簡単なアプローチとなります。なぜかというと、jsアプリケーションの多くは実際の参照構造をクロージャにして外部に出していない（グローバル変数からたどってアクセスできないスコープに格納している）ため、質問にあるような部分のコードを直接呼び出すすることはまずできないからです。

さてそのコードですが、こまかい部分を読み飛ばせば[旧来実装されてきたドラッグ＆ドロップを任意の要素で実装するテクニック](https://q-az.net/elements-
drag-and-drop/)です（[ネイティブ実装されたAPI](https://developer.mozilla.org/en-
US/docs/Web/API/HTML_Drag_and_Drop_API)を使っていないのは互換性のためでしょう）。この実装の中身は、

  1. 動かす対象要素の _mousedown_ イベントを受けてドラッグ開始フラグを設定
  2. (フラグが設定されているとき、)グローバルな _mousemove_ イベントを受けて対象要素の位置を更新
  3. （フラグが設定されているとき、）グローバルな _mouseup_ イベントを受けてドロップ；対象要素の位置を確定、フラグ解除

という流れです。1,3のイベントを疑似的に発生させれば、当該部分の処理を「呼び出す」ことができるわけです。javascriptでは任意のEventTargetに対して任意のEvent基底のオブジェクトを渡してイベントを発火させる[EventTarget.dispatchEvent](https://developer.mozilla.org/en-
US/docs/Web/API/EventTarget/dispatchEvent)というAPIがありますので、これを使います。  
音量の計算はそれぞれのイベントハンドラに渡されたカーソル位置を用いて __getRatioFromEvent_ でやっていると **推測される**
ので、この計算を逆算してイベントオブジェクトの値を設定しています。

ここに至るまでに必要な知識としては、基本的にクロージャにあるようなアプリケーションの内部コードは呼び出せないこと、そのため実装されているイベントの動作の理解、イベントをエミュレーションするための方法、残りはどういうプロパティがあるのかといった知識（これはドキュメントを見ればすぐわかりますが）、などになると思います。  
ここまで参考になれば幸いです。どうしてそうなるのかわからない、という点があればコメントでお知らせください。


CC BY-SA 3.0
2017-03-21T08:07:30.237
33441
2017-07-02T06:37:43.053
2017-07-02T06:37:43.053
33435
answer