フルスクリーン 横 通常 横  昨年末に、Web地図用のライブラリLeafletの存在を知って、おーこりゃ便利!!と地図を作ったんだけど、android の chrome は、fullscreen 表示時に viewport の表示倍率を無視して、ブラウザ表示の解像度(CSS Resolution)で表示してしまうのねorz。
フルスクリーン 縦 通常 縦  自分が使っているSO-03J(Xperia XZs)はデバイスの画面自体は1080x1920なんだけど、ブラウザ表示の解像度(CSS Resolution)は424x753なので、こんな表示になってしまう。
 最大化して表示領域を拡大できるはずが、逆に表示領域は小さくなってしまうという罠。
 これは見づらいので、なんとかせねば。


 ベンダープレフィックスが付いてるとはいえ、HTML5 では requestFullScreen が使えるようになったので、html内の要素自体を全画面表示にすることができるようになった(iOSは無理)。
 ところが、android の chromeの野郎、実装が他のブラウザと異なって viewport の scale を無視する仕様(バグ?)になっている。
 それに対応するために、表示縮尺を記入した span(ここではid='scaleOrigin')と、フルスクリーン表示用地図のdiv(ここではid='mapCanvas')を用意する。
<html>
<head>
<meta name='viewport' content='initial-scale=0.65, maximum-scale=0.65, minimum-scale=0.65, user-scalable=no, width=device-width,minimal-ui'>
<style type="text/css">
<!--
html {width:100%; height:100%;} /* for IE11 fullscreen bug */
#mapCanvas {width:100%; height:100%;}
#scaleOrigin {display:none;}
-->
</style>
</head>
<body>
<span id='scaleOrigin'>0.65</span>
<div id='mapCanvas'></div>
</body>
</html>

 ブラウザが android の chrome で、画面の解像度(CSS Resolution)が、1280x720(相当)以下の場合に適用する。
 最大化時(webkitfullscreenchange)に、javascript側でcss の transform scale を使って強制的に縮小してやる。
var forceScaled = false;                                                              // scale flag

$(function(){
  var ua = window.navigator.userAgent.toLowerCase();
  var w = screen.availWidth;                                                          // to get Css resolution
  var h = screen.availHeight;

  if(ua.indexOf("android") !== -1 && ua.indexOf("chrome") !== -1 && w * h < 921600){  // androd chrome and screen < 1280 x 720
    document.addEventListener("webkitfullscreenchange", handleFSevent, false);        // fullscreen change
    screen.orientation.onchange = handleFSevent;                                      // also when orientation change
  }
});

function toggleFullscreen(){                                                          // call this function somewhere
  var doc = window.document;
  var docEl = doc.documentElement;                                                    // documentElement to fullscreen in this case
  var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
  var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen;
  if(!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) {
    requestFullScreen.call(docEl);
  } else {
    cancelFullScreen.call(doc);
  }
}

function handleFSevent() {
  if(document.webkitFullscreenElement && document.webkitFullscreenElement !== null){  // android chrome fullscreen
    setTimeout(function(){                                                            // wait for screen rendering
      forceScaled = true;                                                             // scale flag on
      var w = window.innerWidth ? window.innerWidth: $(window).width();
      var h = window.innerHeight ? window.innerHeight: $(window).height();
      var scale = Number( $("#scaleOrigin").text() );
      w /= scale;
      h /= scale;
      $("#mapCanvas").css("transform","scale(" + scale + ")");
      $("#mapCanvas").width(w);
      $("#mapCanvas").height(h);
      $("#mapCanvas").offset({top: 0, left:0});
    },1000);
  } else {                                                                            // normal screen
    if(forceScaled){                                                                  // if force scale
      setTimeout(function(){                                                          // wait for screen rendering
        forceScaled = false;                                                          // scale flag off
        $("#mapCanvas").css("transform","scale(1)");
        $("#mapCanvas").width("100%");
        $("#mapCanvas").height("100%");
        $("#mapCanvas").offset({top: 0, left:0});
      },1000);
    }
  }
}

フルスクリーン 縦 フルスクリーン 横  そうすると、期待通りの表示になった。

 ただ問題もあって、ブラウザが吐き出すサイズ(getBoundingClientRect()など)や位置(.clientX など)が実際の表示と異なってくるため、使用している javascript内にそういった処理がある場合は、適宜書き直さないといけない。
 Leafletでは、
function getMousePosition(e, container) {
  var scale = 1;
  if(document.getElementById("scaleOrigin") != null){
    scale = Number(document.getElementById("scaleOrigin").innerText);
  }
  if (!container) {
    return new Point(e.clientX / scale, e.clientY / scale);
  }
  var rect = container.getBoundingClientRect();
  return new Point(
    (e.clientX - rect.left - container.clientLeft) / scale,
    (e.clientY - rect.top - container.clientTop) / scale);
}
  getSize: function () {
    if (!this._size || this._sizeChanged) {
      var scale = 1;
      if(document.getElementById("scaleOrigin") != null){
        scale = Number(document.getElementById("scaleOrigin").innerText);
      }
      var w = window.innerWidth ? window.innerWidth: $(window).width();
      var h = window.innerHeight ? window.innerHeight: $(window).height();
      w /= scale;
      h /= scale;
      this._size = new Point(w, h);
      this._sizeChanged = false;
    }
    return this._size.clone();
  },
  _onMove: function (e) {
    if (e._simulated || !this._enabled) { return; }
    if (e.touches && e.touches.length > 1) {
      this._moved = true;
      return;
    }
    var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
        newPoint = new Point(first.clientX, first.clientY),
        offset = newPoint.subtract(this._startPoint);
    if(document.getElementById("scaleOrigin") != null){
      var scale = Number(document.getElementById("scaleOrigin").innerText);
      offset._divideBy(scale);
    }
 このあたりを書き直す必要があった。