HSP3Dish.jsでフルスクリーン化(5)

目次

フルスクリーン化

 ここまでで大きく表示されるようになりましたが、アプリの操作中にうっかりスクロールしてしまう危険が残っています。 ゲームに熱中している最中にスクロールはイラッと来てしまうので何とかしたいです。 アドレスバーがあると表示面積が狭くなるし、誤タップの原因にもなります。これもできれば消したいです。 というわけで、これまでの手法を使いつつ、フルスクリーン表示機能を付けてみます。

 PCブラウザではF11キーを押すとフルスクリーン表示にできますが、アドレスバーやウィンドウの枠などが非表示になるだけなのでページ全体をスクロールすることができてしまいます。 今回用いるのは、特定の要素のみをフルスクリーン化する方法です。動画配信サイトなどでも、動画コンテンツだけをフルスクリーン表示するとかでよく見かけますね。 この方法なら単にサイト全体をフルスクリーン化するのとは違い、上下の不要な要素がないのでスクロールしてしまう心配がありません。

 フルスクリーンにするのは、HSP3Dishの描画領域のコンテナがよさそうです。 フルスクリーン化と解除の切替も必要なので、操作のためのボタンの追加もします。

サンプル

サンプルを見ながらの方がいいと思いうので、こちらをどうぞ。
./dish/mobile02_f4.html

フルスクリーンに切り替えるボタン

 フルスクリーンに切り替えるボタンを配置します。出来るだけ邪魔にならないようにしつつ、押しやすいサイズがいいですね。


      div.emscripten_border {
        position: relative;
        height: 100vh;
        width:  100vw;
        background-color: black;
        overflow: hidden;
        /* 中央寄せ */
        display: flex;
        justify-content: center;
        align-items: center;
      }

      /* フルスクリーン ボタン */
      .btn-fscr{
        position: absolute;
        top: 10px;
        right: 10px;
        background-color: rgba(255,255,255,0.5);
        border: 2px solid rgba(0, 0, 0, 0.5);
        border-radius: 10px;
        z-index: 110;
        cursor: pointer;
        height: 40px;
        width:  40px;
        /* 中央寄せ */
        display: flex;
        justify-content: center;
        align-items: center;
      }
      #btn-open {
        display: block;
      }
      #btn-close {
        display: none;
      }

 ボタンはコンテナの右上に表示したいので、div.emscripten_borderposition: relative;を追加しています。

 フルスクリーン ボタン.btn-fscrは、タッチデバイスにおいて指で押しやすい高さとされている40pxに設定。目立ちすぎないように半透明表示にしています。。


    <div class="emscripten_border" id="main_screen">
      <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
      <!-- Google Fonts https://fonts.google.com/ -->
      <button id="btn-open"  class="btn-fscr"><svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#000000"><path d="M120-120v-200h80v120h120v80H120Zm520 0v-80h120v-120h80v200H640ZM120-640v-200h200v80H200v120h-80Zm640 0v-120H640v-80h200v200h-80Z"/></svg></button>
      <button id="btn-close" class="btn-fscr"><svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#000000"><path d="M240-120v-120H120v-80h200v200h-80Zm400 0v-200h200v80H720v120h-80ZM120-640v-80h120v-120h80v200H120Zm520 0v-200h80v120h120v80H640Z"/></svg></button>
    </div>

 フルスクリーン ボタンは、押すたびにフルスクリーン化ボタンとフルスクリーン解除ボタンに切り替えたいので、 切替用のスタイルも用意しました。最大化ボタン#btn-openと、最大化解除ボタン#btn-close。押されるたびにどちらかが非表示になります。

 ボタンのアイコンは、Google Fonts(https://fonts.google.com/)から、ちょうどよさそうなものを見つけて持ってきました。

後の処理の準備


    <div class="emscripten_border" id="main_screen">

 フルスクリーンに出来るのは1要素だけなので、間違えないようにidを割り当てています。このコンテナをフルスクリーン化します。


      // スクリーンの表示方法設定
      //   0 解像度や表示サイズを変更しない
      //   1 ウィンドウサイズに合わせて拡大表示する
      //   2 解像度をウィンドウサイズに合わせる
      HSP_SCREEN_MODE = 0;
      // フルスクリーンボタンを使用する
      HSP_VIEW_USEFULLSCRN = 1; // 0=OFF, 1=ON

      const isMobile = !!navigator.userAgent.match(/iPhone|Android.+Mobile/);

 JavaScriptの最初の方で、動作のオプションを設定する項目を追加しています。 引数を書き換えるだけで、動作内容を変更出来るようにしています。

 閲覧している端末がスマホの場合とスマホ以外の場合で動作を変えたいので、最初に状態を取得しています。 スマホなら、isMobiletrueになります。スマホ以外ならfalseです。

解像度の設定


        ENV.HSP_WX = "430";//スクリプトの動作解像度
        ENV.HSP_WY = "764";
        ENV.HSP_SX = "430";//表示解像度
        ENV.HSP_SY = "764";
        ENV.HSP_AUTOSCALE = "0";//スケーリングモード
        ENV.HSP_FPS = "0";//フレームレート
        ENV.HSP_LIMIT_STEP = "15000";//ブラウザに処理を返すまでの実行ステップ数
        // 解像度をウィンドウサイズに合わせる
        if(HSP_SCREEN_MODE == 2){
          // スクリーンの画面サイズに合わせる
          ENV.HSP_WX = String(screen.width);
          ENV.HSP_WY = String(screen.height);
          ENV.HSP_SX = ENV.HSP_WX;
          ENV.HSP_SY = ENV.HSP_WY;
        }

 通常は指定した解像度で動作します。「解像度をウィンドウサイズに合わせる」を選択した場合のみ、解像度が変更されます。

フルスクリーン化、拡大などの機能

 フルスクリーン化と拡大などの機能をJavaScriptで記述しています。 フルスクリーン化は古いブラウザなどへの対応も考慮すると少し面倒です。 そこでこちらのサイトを参考に機能を組み込んでみました。 (今はブラウザの対応が進んでいるので、無用な配慮になっている可能性があります。)

[HTML5] フルスクリーンの開始と解除
https://blog.katsubemakito.net/html5/fullscreen


      // 参考資料:https://blog.katsubemakito.net/html5/fullscreen
      // フルスクリーン機能
      const btnOpen  = document.querySelector("#btn-open");   // フルスクリーン化ボタン
      const btnClose = document.querySelector("#btn-close");  // フルスクリーンキャンセルボタン

      window.onload = ()=>{
        const album = document.querySelector("#main_screen"); // フルスクリーンにするオブジェクト

        //--------------------------------
        // [event] 開始ボタンをクリック
        //--------------------------------
        btnOpen.addEventListener("click", ()=>{
          if( ! enabledFullScreen() ){
            alert("フルスクリーンに対応していません");
            return(false);
          }
          // フルスクリーンを開始
          goFullScreen(album);
        });

        //--------------------------------
        // [event] 閉じるボタンをクリック
        //--------------------------------
        btnClose.addEventListener("click", ()=>{
          // フルスクリーンを解除
          cancelFullScreen(album);
        });

        //--------------------------------
        // フルスクリーンイベント
        //--------------------------------
        eventFullScreen( ()=>{
            // ボタンを入れ替える
          if( getFullScreenObject() ){
            // console.log("フルスクリーン開始");
            btnOpen.style.display  = "none";    // OpenをOFF
            btnClose.style.display = "block";   // CloseをON
            // フルスクリーン化の準備
            if((HSP_SCREEN_MODE == 2) && (!isMobile)){
              document.querySelector("#canvas").classList.remove("sm-height");
              document.querySelector("#canvas").classList.remove("sm-width");
            }
          }
          else{
            // console.log("フルスクリーン終了");
            btnClose.style.display = "none";    // CloseをOFF
            btnOpen.style.display  = "block";   // OpenをON
            // フルスクリーン解除の準備
            if((HSP_SCREEN_MODE == 2) && (!isMobile)){
              resizeCanvas();
            }
          }
        });
      };

      /**
       * フルスクリーン開始/終了時のイベント設定
       *
       * @param {function} callback
       */
      function eventFullScreen(callback){
        document.addEventListener("fullscreenchange", callback, false);
        document.addEventListener("webkitfullscreenchange", callback, false);
        document.addEventListener("mozfullscreenchange", callback, false);
        document.addEventListener("MSFullscreenChange", callback, false);
      }

      /**
       * フルスクリーンが利用できるか
       *
       * @return {boolean}
       *  true  - 全画面モードに移行できる。
       *  false - 全画面モードが利用できない。
       */
      function enabledFullScreen(){
        return(
          document.fullscreenEnabled ||
           document.mozFullScreenEnabled || document.documentElement.webkitRequestFullScreen || document.msFullscreenEnabled
        );
      }

      /**
       * 指定された要素をフルスクリーンモードにする
       * @param {HTMLElement} [element=null]
       *    - フルスクリーンにするHTML要素。省略可能で、デフォルトはdocument.documentElement。
       *    - フルスクリーンにする要素を指定する場合はその要素を渡す。
       *    - 省略した場合、またはnullを渡した場合はドキュメント全体をフルスクリーンにする。
       */
      function goFullScreen(element=null){
        const doc = window.document;
        const docEl = (element === null)?  doc.documentElement : element;
        let requestFullScreen = 
          docEl.requestFullscreen || 
          docEl.mozRequestFullScreen || 
          docEl.webkitRequestFullScreen || 
          docEl.msRequestFullscreen;
        requestFullScreen.call(docEl);
      }
      
      /**
       * フルスクリーンモードを終了する
       *  特定の要素やドキュメント全体がフルスクリーン状態になっているときに呼び出すと
       *  フルスクリーンモードを終了します。
       */
      function cancelFullScreen(){
        const doc = window.document;
        const cancelFullScreen = 
            doc.exitFullscreen ||
            doc.mozCancelFullScreen ||
            doc.webkitExitFullscreen ||
            doc.msExitFullscreen;
        cancelFullScreen.call(doc);
      }

      /**
       * フルスクリーン中のオブジェクトを返却
       *  フルスクリーン化された状態で実行すると、フルスクリーン状態になっている要素を返します。
       *  フルスクリーンが解除されていればundefinedを返します。
       */
      function getFullScreenObject(){
        const doc = window.document;
        const objFullScreen = 
            doc.fullscreenElement ||
            doc.mozFullScreenElement ||
            doc.webkitFullscreenElement ||
            doc.msFullscreenElement;
        return(objFullScreen);
      }

 フルスクリーン切り替え維持にいくつかの操作が必要なので、「フルスクリーンイベント」にいくつか追記しています。 そのほかは、そのままです。

 縦横比を維持したまま、canvasを拡大する関数もここに書いています。 object-fitが使えればいらないんですが…。


      // 追加機能
      // object-fit の代わりの機能
      function resizeCanvas() {
          const canvas = document.getElementById('canvas');
          const container = canvas.parentElement;
          const canvasAspectRatio = canvas.width / canvas.height;
          const containerAspectRatio = container.clientWidth / container.clientHeight;

          // canvas要素
          // object-fit を使うと座標取得に不具合が起きるためここで対応しています。
          canvas.classList.remove('sm-height', 'sm-width'); // クラスをリセット
          if (containerAspectRatio > canvasAspectRatio) {
              // 親要素の方が横に長い場合
              canvas.classList.add('sm-width');
          } else {
              // 親要素の方が縦に長い場合
              canvas.classList.add('sm-height');
          }
      }

 あとは、設定に応じて有効・無効を切り替えています。


      // 解像度をウィンドウサイズに合わせる
      if((HSP_SCREEN_MODE == 2) && (!isMobile)){
        resizeCanvas();
      }
      
      // ウィンドウサイズに合わせて拡大する
      if(HSP_SCREEN_MODE == 1){
          resizeCanvas();
          window.addEventListener('load', resizeCanvas);
          window.addEventListener('resize', resizeCanvas);
      }
      
      // フルスクリーンボタン
      if(HSP_VIEW_USEFULLSCRN == 0){
          const el = document.getElementsByClassName('btn-fscr');
          for(i=0;i<el.length;i++){
              el[i].style.display   = "none";
          }
      }

ホーム画面に追加できるようにする

 iPhoneの場合、Safariで「ホーム画面に追加」とすると、ホーム画面にブックマークが追加されます。 これをタップするとアドレスバーが表示されないフルスクリーンでサイトが表示されます。 せっかくなのでこの機能も追加しておきます。


    <meta name="apple-mobile-web-app-capable" content="yes"><!-- iOS用 -->
    <meta name="mobile-web-app-capable" content="yes"><!-- Android用 -->

作成例

 以上を踏まえた作成例を見てみます。 mobile02_f4、mobile02_f5は、プログラムは同じでHSP_SCREEN_MODEのみ変えています。

./dish/mobile02_f4.html
HSP_SCREEN_MODE = 0; 解像度や表示サイズを変更しない
拡大しないので画像がぼやけません。配置を固定して開発できます。

./dish/mobile02_f5.html
HSP_SCREEN_MODE = 1; ウィンドウサイズに合わせて拡大表示する
手軽に作ったままの結果を表示できます。

./dish/mobile01_f6.html
HSP_SCREEN_MODE = 2; 解像度をウィンドウサイズに合わせる
拡大しないので画像がぼやけません。実行環境の解像度に合わせたプログラミングが可能です。
※ PCの場合ウィンドウモードで高解像度表示してしまうと、大きすぎて状況が把握しにくいので、ウィンドウモードでは縮小表示されるようにしています。

 HSP3Dish helperが出力する物から選択肢が増やせました。 どれが一番いいという事は無いので、アプリ内容に合わせて適切なものを選択する必要があると思います。 アプリにとって何が重要で、どこが重要ではないのかを考えてみるといいかと思います。 画面の隅々まで使いたいなら、HSP_SCREEN_MODE = 0;では困ります。 ドット絵が奇麗に表示される必要があるなら、HSP_SCREEN_MODE = 1;は選択できません。 画面配置に悩みたく無いのならHSP_SCREEN_MODE = 2;は避けたいところです。

 結局悩みが増えた気がします。みんなスマホアプリってどうやって開発してるの?!

終わりに

 さて長くなりましたが、HSP3Dish.jsでのフルスクリーン化は今回で最終回です。 まだ細かい修正が必要な部分もありますが、大体の問題は片付いたと思います。

 全画面表示で遊べるので、ほぼアプリと変わらない体験をユーザーに提供できますね。 アプリストアに登録するほどでもないアプリを開発する私としては大満足です。

 スマホにインストールしたい?オフラインで遊びたい?アプリストアのハードル高い?更新をプッシュ通知したい? それにはPWA化がいいかもしれません。HSP3DishのPWA化は可能です。 やり方?がんばれ!

関連記事

  1. HSP3Dish.jsでフルスクリーン化(1) はじめに HSP3Dish.jsを始める これからやりたい事の計画 HSP3Dish.jsを使った例...
  2. HSP3Dish.jsでフルスクリーン化(2) はじめに 標準機能で解像度を調整 実行環境によって解像度を変える ビューポートを設定 スマホ判定 環...
  3. HSP3Dish.jsでフルスクリーン化(3) 解像度を固定して拡大表示 サンプル HSP3Dishの描画先要素 コンテナサイズを調整 HSP3Di...
  4. HSP3Dish.jsでフルスクリーン化(4) 解像度を固定したまま表示 作成例 ビューポート解像度を使う 画面解像度のシェア スクリプト html...
  5. HSP3でPWA 言い訳から始める PWAとは HSP3Dish.jsでPWA 作成例 PWAに必要なもの HTMLフ...