kittykatattack / hexi

Make games the fun way!
MIT License
551 stars 83 forks source link

Fullscreen feature #14

Open kittykatattack opened 7 years ago

kittykatattack commented 7 years ago

I had previously implemented a feature to launch games in full screen mode at the click of a button. However, the FullScreen API is quirky, not well supported, and the polyfill I was using was buggy and making Firefox really unhappy. Plus, even when it was working, I was never satisfied with the behaviour.

Would anyone out there reading this like to implement a fullscreen feature?

If so, I suggest you base it on screenful.js:

https://github.com/sindresorhus/screenfull.js/

Currently this seem to be the best (and only reliable) way to implement the FullScreen API.

Also, I suggest that it be done using an HTML button, using this technique:

https://github.com/kittykatattack/hexi#htmlIntegration

When Hexi's canvas element is launched in full screen mode, you will need to figure out the new scale, which, in general, you can do like this:

//Scale the element to the correct size.
//Figure out the scale amount on each axis.
scaleX = screen.width / this.element.width;
scaleY = screen.height / this.element.height;

//Set the scale based on whichever value is less: `scaleX` or `scaleY`.
let fullscreenScale = Math.min(scaleX, scaleY);

... then you'll need to apply fullscreenScale to Hexi's pointer.scale.

And, you might have to center the full screen element. That's tricky! In previous experiments I needed to do it like this:

//To center the element we need to inject some CSS
//and into the HTML document's `<style>` tag. Some
//browsers require an existing `<style>` tag to do this, so
//if no `<style>` tag already exists, let's create one and
//append it to the `<body>:
let styleSheets = document.styleSheets;
if (styleSheets.length === 0) {
  let divNode = document.createElement("div");
  divNode.innerHTML = "<style></style>";
  document.body.appendChild(divNode);
}

//Unfortunately we also need to do some browser detection
//to inject the full screen CSS with the correct vendor 
//prefix. So, let's find out what the `userAgent` is.
//`ua` will be an array containing lower-case browser names.
let ua = navigator.userAgent.toLowerCase();

//Now Decide whether to center the canvas vertically or horizontally.
//Wide canvases should be centered vertically, and 
//square or tall canvases should be centered horizontally.

if (this.element.width > this.element.height) {

  //Center vertically.
  //Add CSS to the stylesheet to center the canvas vertically.
  //You need a version for each browser vendor, plus a generic
  //version
  //(Unfortunately the CSS string cannot include line breaks, so
  //it all has to be on one long line.)
  if (ua.indexOf("safari") !== -1 || ua.indexOf("chrome") !== -1) {
    document.styleSheets[0].insertRule("canvas:-webkit-full-screen {position: fixed; width: 100%; height: auto; top: 0; right: 0; bottom: 0; left: 0; margin: auto; object-fit: contain}", 0);
  } else if (ua.indexOf("firefox") !== -1) {
    document.styleSheets[0].insertRule("canvas:-moz-full-screen {position: fixed; width: 100%; height: auto; top: 0; right: 0; bottom: 0; left: 0; margin: auto; object-fit: contain;}", 0);
  } else if (ua.indexOf("opera") !== -1) {
    document.styleSheets[0].insertRule("canvas:-o-full-screen {position: fixed; width: 100%; height: auto; top: 0; right: 0; bottom: 0; left: 0; margin: auto; object-fit: contain;}", 0);
  } else if (ua.indexOf("explorer") !== -1) {
    document.styleSheets[0].insertRule("canvas:-ms-full-screen {position: fixed; width: 100%; height: auto; top: 0; right: 0; bottom: 0; left: 0; margin: auto; object-fit: contain;}", 0);
  } else {
    document.styleSheets[0].insertRule("canvas:fullscreen {position: fixed; width: 100%; height: auto; top: 0; right: 0; bottom: 0; left: 0; margin: auto; object-fit: contain;}", 0);
  }
} else {

  //Center horizontally.
  if (ua.indexOf("safari") !== -1 || ua.indexOf("chrome") !== -1) {
    document.styleSheets[0].insertRule("canvas:-webkit-full-screen {height: 100%; margin: 0 auto; object-fit: contain;}", 0);
  } else if (ua.indexOf("firefox") !== -1) {
    document.styleSheets[0].insertRule("canvas:-moz-full-screen {height: 100%; margin: 0 auto; object-fit: contain;}", 0);
  } else if (ua.indexOf("opera") !== -1) {
    document.styleSheets[0].insertRule("canvas:-o-full-screen {height: 100%; margin: 0 auto; object-fit: contain;}", 0);
  } else if (ua.indexOf("msie") !== -1) {
    document.styleSheets[0].insertRule("canvas:-ms-full-screen {height: 100%; margin: 0 auto; object-fit: contain;}", 0);
  } else {
    document.styleSheets[0].insertRule("canvas:fullscreen {height: 100%; margin: 0 auto; object-fit: contain;}", 0);
  }
}

... but you may not need to do this!

You can have a look at my previous, abandoned, experiment to implement a fullscreen module here:

https://github.com/kittykatattack/fullScreen

Any contributors welcome!! If you have any more questions about this, or my previous implementation, just post a comment below 😄

.kk