WebController - ユーザーインタラクション

onResize メソッドは、 index.html の Web ページのユーザー操作に使用されるすべてのメソッドが含まれています。すべてのキー入力機能とクリック機能は、このセクションにあります。

onKeyDown

onKeyDown(event)

onKeyDown メソッドが、ウィンドウが選択されたときにどのキーが押されたかに応じて、指定の機能をトリガします。

changeDelayOffset
値を変更して、ビデオ遅延オフセットを変更する。
toggleGenvidOverlay
Genvid オーバーレイの表示、非表示を切り替える。
toggleFullscreen
全画面の ON/OFF を切り替えます。
genvidClient.videoPlayer.isPaused
ビデオが一時停止しているかどうかを示すブール値を返す。
genvidClient.videoPlayer.play
ビデオを再生する。
genvidClient.videoPlayer.pause
ビデオを一時停止する。
genvidClient.videoPlayer.getMuted
ビデオサウンドがミュートされているかどうかを示すブール値を返す。
genvidClient.videoPlayer.setMuted
引数に応じて、サウンドのミュートの有効、無効を切り替える。
genvidClient.videoPlayer.setVolume
送信された引数にビデオボリュームを設定する。
genvidClient.videoPlayer.getVolume
現在のビデオボリュームを取得する。
onHelpActivation
ヘルプオーバーレイの表示、非表示を切り替える。
  onKeyDown(event) {
    // Seems to be the most cross-platform way to determine keys:
    // Ref: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
    let code = event.code || this.getKeyCode(event);
    switch (code) {
      case "Equal":
      case "NumpadAdd":
        this.changeDelayOffset(+1, event);
        break;
      case "Minus":
      case "NumpadSubtract":
        this.changeDelayOffset(-1, event);
        break;
      case "NumpadMultiply":
        this.changeDelayOffset(0, event);
        break;
      case "KeyG":
        this.toggleGenvidOverlay();
        break;
      case "KeyF":
        this.toggleFullScreen();
        break;
      case "Space":
        if (this.genvidClient.videoPlayer.isPaused()) {
          this.genvidClient.videoPlayer.play();
        } else {
          this.genvidClient.videoPlayer.pause();
        }
        event.preventDefault();
        break;
      case "KeyM":
        this.toggleMute();
        break;
      case "KeyZ":
        this.decreaseVolume();
        break;
      case "KeyX":
        this.increaseVolume();
        break;
      case "KeyH":
        this.onHelpActivation();
        break;
    }
  }

getKeyCode

getKeyCode(event)

getKeyCode メソッドは、さまざまなブラウザで適切な keyCode を取得します。

  // Compatibility code for browsers (Safari) not having KeyboardEvent.code.
  getKeyCode(event) {
    if (event.keyCode) {
      if (65 <= event.keyCode && event.keyCode <= 90) {
        return "Key" + String.fromCharCode(event.keyCode);
      } else {
        switch (event.keyCode) {
          case 13:
            return "Enter";
          case 106:
            return "NumpadMultiply";
          case 107:
            return "NumpadAdd";
          case 109:
            return "NumpadSubtract";
          case 110:
            return "NumpadDecimal";
          case 111:
            return "NumpadDivide";
          case 187:
            return "Equal";
          case 188:
            return "Comma";
          case 189:
            return "Minus";
          case 190:
            return "Period";
          case 222:
            return "Backquote";
        }
      }
    }
  }

onResize

onResize()

onResize メソッドは、 index.html の Web ページで使用されているさまざまなオーバーレイのサイズを変更します。この関数の影響を受けるオーバーレイは、次のとおりです。

  • videoOverlay,
  • canvas3d,
  • volumeDisplay (サウンド調整に使用)
  • 各オブジェクト名のアニメーション div。

index.html ページに表示されるビデオストリームのサイズ値を取得し、このサイズを元に他のオーバーレイを調整します。このサンプルでは、オブジェクトが適切に選択できるようにするために、適切なオーバーレイサイズが必要となるため、サイズ変更が不可欠です。また、ビデオ内のオブジェクトの目印にするために、適切な場所に WebGL の円を表示する必要があります。

  // Allows to adjust the various overlays when resizing the windows - needed to see the PromptOverlay and Name moving div
  onResize() {
    const refElement = this.genvidClient.videoElem; // The element to match.
    const refElementSize = refElement
      ? genvidMath.vec2(refElement.clientWidth, refElement.clientHeight)
      : genvidMath.vec2(1280, 720);
    const refElementRatio = refElementSize.x / refElementSize.y;
    const videoRatio = this.genvidClient.videoAspectRatio;
    let pos;
    let size;
    if (videoRatio >= refElementRatio) {
      // Top+Bottom bars, fills width fully, shrinks height.
      const ey = refElementSize.x / videoRatio;
      const dy = refElementSize.y - ey;
      // Centers vertically.
      const y = dy * 0.5;
      pos = genvidMath.vec2(0, Math.round(y));
      size = genvidMath.vec2(refElementSize.x, Math.round(ey));
    } else {
      // Left+Right bars, fills height fully, shrinks width.
      const ex = refElementSize.y * videoRatio;
      const dx = refElementSize.x - ex;
      // Centers horizontally.
      const x = dx * 0.5;
      pos = genvidMath.vec2(Math.round(x), 0);
      size = genvidMath.vec2(Math.round(ex), refElementSize.y);
    }
    const style = this.videoOverlay.style;
    const curPos = genvidMath.vec2(parseInt(style.left), parseInt(style.top));
    const curSize = genvidMath.vec2(
      parseInt(style.width),
      parseInt(style.height)
    );

    if (
      !genvidMath.equal2D(curSize, size, 0.9) ||
      !genvidMath.equal2D(curPos, pos, 0.9)
    ) {
      this.videoOverlay.style.left = pos.x + "px";
      this.videoOverlay.style.width = size.x + "px";
      this.videoOverlay.style.top = pos.y + "px";
      this.videoOverlay.style.height = size.y + "px";
      this.canvas3d.width = size.x;
      this.canvas3d.height = size.y;
      this.genvidWebGL.setViewport(0, 0, size.x, size.y); // Renders in the whole area.
    }
  }

toggleFullScreen

toggleFullScreen()

toggleFullScreen メソッドは、ビデオのフルスクリーンを有効または無効にします。checkFullScreen 関数でフルスクリーンの状態を確認し、適切な状態に調整します。

すでにフルスクリーンである場合は、Web ブラウザ機能に従ってフルスクリーンをキャンセルし、フルスクリーンボタンアイコンも調整します。

フルスクリーンでない場合は、 video_area 要素を取得します。その後、Web ブラウザ機能でフルスクリーンを有効にし、フルスクリーン ボタン アイコンを更新します。

  toggleFullScreen() {
    if (this.checkFullScreen()) {
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
      } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen();
      } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
      }
      this.fullScreenIcon.classList.remove("fa-compress");
      this.fullScreenIcon.classList.add("fa-expand");
    } else {
      let element = document.querySelector("#video_area");
      if (element.requestFullscreen) {
        element.requestFullscreen();
      } else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen();
      } else if (element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen();
      } else if (element.msRequestFullscreen) {
        element.msRequestFullscreen();
      }
      this.fullScreenIcon.classList.remove("fa-expand");
      this.fullScreenIcon.classList.add("fa-compress");
    }
  }

toggleMute

toggleMute()

toggleMute メソッドは、ビデオプレイヤーがミュート/ミュート解除されるたびに呼び出されます。

この関数を呼び出すと、 getMuted() を呼び出してミュート状態を取得し、オーディオ、ボリュームアップなどのアイコンの見やすさ、オーバーレイメッセージの調整をすることができます。

  // Depending on the status, mutes or unmutes the video player audio
  toggleMute() {
    const muteIcon = document.querySelector("#mute-button i");
    if (this.genvidClient.videoPlayer.getMuted()) {
      muteIcon.classList.remove("fa-volume-off");
      muteIcon.classList.add("fa-volume-up");
      this.genvidClient.videoPlayer.setMuted(false);
      this.volumeDisplay.style.visibility = "visible";
      this.volumeDisplay.textContent = "Volume is unmuted";
      this.volumeInfoDisplayCount = 0;
    } else {
      muteIcon.classList.remove("fa-volume-up");
      muteIcon.classList.add("fa-volume-off");
      this.genvidClient.videoPlayer.setMuted(true);
      this.volumeDisplay.style.visibility = "visible";
      this.volumeDisplay.textContent = "Volume is muted";
      this.volumeInfoDisplayCount = 0;
    }
  }

decreaseVolume increaseVolume

decreaseVolume() increaseVolume()

decreaseVolume および increaseVolume メソッドは genvidClient.videoPlayer.setVolume を使用し、それに応じて volumeDisplay オーバーレイを調整します。

  decreaseVolume() {
    const newVolume = this.genvidClient.videoPlayer.getVolume() - 20;
    this.genvidClient.videoPlayer.setVolume(newVolume);
    this.volumeDisplay.style.visibility = "visible";
    this.volumeInfoDisplayCount = 0;
    this.volumeDisplay.textContent = `Volume: ${this.genvidClient.videoPlayer.getVolume()} %`;
  }

  increaseVolume() {
    const newVolume = this.genvidClient.videoPlayer.getVolume() + 20;
    this.genvidClient.videoPlayer.setVolume(newVolume);
    this.volumeDisplay.style.visibility = "visible";
    this.volumeInfoDisplayCount = 0;
    this.volumeDisplay.textContent = `Volume: ${this.genvidClient.videoPlayer.getVolume()} %`;
  }

showOverlay

showOverlay()

showOverlay メソッドは、Genvid オーバーレイを表示します。

  // Changes the style to display the Genvid overlay
  showOverlay() {
    this.genvidOverlay.style.display = "block";
  }

hideOverlay

hideOverlay()

showOverlay メソッドは、Genvid オーバーレイを非表示にします。

  // Changes the style to hide the Genvid overlay
  hideOverlay() {
    this.genvidOverlay.style.display = "none";
  }

clickCube

clickCube(event)

clickCube は、WebGL オーバーレイをクリックしてキューブが選択されたと pickCube メソッドが判断した場合に、 true を戻します。そうでない場合は、false を返します。

  // Method used when clicking on the WebGL overlay
  clickCube(event) {
    return !!this.pickCube(event);
  }

pickCube

pickCube(event)

pickCube メソッドは、WebGL オーバーレイをクリックした時にキューブが選択されているかどうかを確認します。

  1. ゲームデータが有効かどうかを確認し、無効の場合は、他の検証を行いません。

  2. ウィンドウ内でクリックした位置を取得します。

  3. その後、この座標を投影空間に変換します。

        if (this.lastGameData == null) {
          return false;
        }
    
        // [0, 1] coordinates in the window.
        const rect = this.canvas3d.getBoundingClientRect();
        const x = event.pageX - rect.left; // More robust to recompute from pageX/pageY.
        const y = event.pageY - rect.top;
        const p01 = genvidMath.vec2(x / rect.width, y / rect.height); // viewport click coord between 0 and 1
        // [-1, 1] coordinates in projection space.
        const p = genvidMath.mad2D(
          p01,
          genvidMath.vec2(2, -2),
          genvidMath.vec2(-1, 1)
        );
        const mat = this.convertMatrix(this.lastGameData.MatProjView); //generates proj view matrix
        let best = null;
        let bestDist = Infinity;
    
  4. 各オブジェクトの座標を確認するループ処理を開始します。

  5. このループ処理で、オブジェクトの座標を取得し、検索するゾーンの半径を適用します。

  6. 最後に、座標がオブジェクトゾーン内にあるかどうかを検索し、距離に応じて最良の結果として保持します (2 つのオブジェクトが近い場合、ゾーンまでの距離が小さいものが選択されます)。

        for (let cube of this.lastGameData.cubes) {
          let pos3D = genvidMath.vec3(cube.mat[12], cube.mat[13], cube.mat[14]);
          let pos2DRad2D = this.projectWithRadius(mat, pos3D, 1.0);
          let pos2D = pos2DRad2D[0];
          let rad2D = pos2DRad2D[1];
    
          let pos2DToP = genvidMath.sub2D(p, pos2D);
          let d = genvidMath.length2D(pos2DToP);
          if (d < rad2D && d < bestDist) {
            best = cube.name;
            bestDist = d;
          }
        }
    
        this.onSelect(best || "");
        return best;
    

isSelected

isSelected(name)

isSelected メソッドは、オブジェクトが選択されているかどうかを判別します。

  // Verifies if the cube is selected
  isSelected(name) {
    return this.selectedCubeName === name;
  }

changeDelayOffset

changeDelayOffset(direction, event)

changeDelayOffset メソッドはビデオの遅延オフセットを追加、縮小、またはリセットします。引数の方向が 0 の場合、ビデオの遅延オフセットはリセットされ、それ以外の場合は送信された値に応じて変更されます。

  // Function that changes the delay offset depending of the key pressed
  changeDelayOffset(direction, event) {
    if (direction !== 0) {
      let delayDelta = 100 * direction;
      if (event.altKey) delayDelta *= 10;
      if (event.shiftKey) delayDelta /= 3;
      this.genvidClient.delayOffset += delayDelta;
    } else {
      this.genvidClient.delayOffset = 0;
    }
  }

toggleGenvidOverlay

toggleGenvidOverlay()

toggleGenvidOverlay メソッドは、Genvid オーバーレイの表示、非表示を切り替えます。Genvid オーバーレイは、ストリームに関するさまざまなデータを表示します。

Local
Web ページを表示するマシンのローカルタイム。
Est. Video
ビデオを受信した時の推定時間。
Stream received
Compose service からレポートされた直前のデータの時間。
Stream played
一般化されたストリームの現在時刻。
Latency
ゲームと視聴者の間の予測遅延時間。
DelayOffset
同期を調整するための遅延オフセット (オプション)
  // Displays or removes the Genvid Overlay
  toggleGenvidOverlay() {
    if (this.genvidOverlay.getAttribute("data-isHidden")) {
      this.genvidOverlay.setAttribute("data-isHidden", "");
      this.genvidOverlay.style.visibility = "visible";
      this.genvidOverlayButton.classList.remove("disabled");
    } else {
      this.genvidOverlay.setAttribute("data-isHidden", "true");
      this.genvidOverlay.style.visibility = "hidden";
      this.genvidOverlayButton.classList.add("disabled");
    }
  }

onHelpActivation

onHelpActivation()

onHelpActivation メソッドは、ヘルプオーバーレイの表示、非表示を切り替えます。

  // Displays or removes the help overlay
  onHelpActivation() {
    if (this.helpOverlay.style.visibility === "visible") {
      this.helpOverlay.style.visibility = "hidden";
    } else {
      this.helpOverlay.style.visibility = "visible";
    }
  }

onCheer

onCheer(cubeName)

onCheer メソッドは、プレイヤーを応援するボタンをクリックしたときに、クライアントにイベントを送信します。イベントにはオブジェクト名が含まれます。

  // Upon cheering a player
  onCheer(cubeName) {
    this.genvidClient.sendEventObject({
      cheer: cubeName,
    });
  }

onReset

onReset(cubeName)

onReset メソッドは、プレイヤーをリセットするボタンをクリックしたときに、イベントを送信します。イベントにはオブジェクト名が含まれます。

  // Resets the position of the cube
  onReset(cubeName) {
    this.genvidClient.sendEventObject({
      reset: cubeName,
    });
  }

onColorChange

onColorChange(cube, color)

onColorChange メソッドは、プレイヤーの色を変更するボタンをクリックしたときにイベントを送信します。イベントには、オブジェクト名と色が含まれます。

  // Method used when clicking on a color to change the color of a cube
  onColorChange(cube, color) {
    let evt = {
      key: ["changeColor", cube],
      value: color,
    };
    this.genvidClient.sendEvent([evt]);
  }

onSelect

onSelect(cubeName, selectionInterface)

onSelect メソッドを使うと、ビデオストリームの下に表示されるプレイヤーテーブルをクリックした時に UI を変更することができます。各テーブルの色をリセットし、選択したテーブルにのみ色を適用し、その後、WebGL の円を選択します。

  // Selects the cube from the interface
  onSelect(cubeName) {
    for (let nameSelect of this.cubePanelDiv) {
      nameSelect.style.backgroundColor = "#181818";
    }

    if (cubeName) {
      let cubeDiv = document.querySelector(`#${cubeName} .cube`);
      if (cubeDiv) {
        cubeDiv.style.backgroundColor = "#32324e";
      }
    }

    this.selectedCubeName = cubeName;
  }