I am trying to add a fullscreen option for a JavaScript canvas game of mine, and it is functional across some browsers, but issues with Firefox have made me realize that my logic was very broken and it was lucky that it worked for any browser.
I want to have a button on the canvas that lets you toggle fullscreen, but I am running into a few issues. The first problem I found was that if I canvas.getBoundingClientRect() on resize (when I exit/enter fullscreen), then in certain browsers cough Firefox, the function runs too early and it gets the bounds before they have changed, so the game still thinks it should be huge.
You can check out the code and the program here. Let me know if I wasn't very clear on anything, this one has hard to explain.
Welcome to the fullscreen API nightmare.
This API is still in development and the specs have changed a lot since it first came out on the web.
Unfortunately, as of today, none of the major browsers do really support it (e.g actual specs recommend the use of promises) and even worse, none of those do use the same keywords for this API.
So it can be a bit harsh to make them all happy with it.
But first, you should not listen to the resize event, since it may occur multiple times during the activation/desactivation of the fullscreen mode.
What you need is the fullscreenchange event.
Fortunately enough, every UA did write the whole event name without any camelCase in it, but with vendor prefixes. (and for some reason, IE doesn't support attaching it with addEventListener method...)
Once you get the event, in order to know if we actually entered or exited the fullscreen mode, you have to check for a document.[vendor-prefix]full(s||S)creenElement if there is one, then we entered the mode ; else we exited it.
And now, to exit the fullscreen mode, you've got to call
document.[vendor-prefix]((e||E)xit||Cancel)(f||F)ull(s||S)creen method.
So here is a little dirty helper function for it :
// if fullscreen API is supported it will return an array containing
// [vendor-prefix, 'full(s||S)creen', 'Exit||Cancel'];
var fs = function(){
// if it is natively supported without vendor prefix (may it happen some day...)
if('onfullscreenchange' in document){
return ['', 'Fullscreen', 'exit'];
}
if('onmozfullscreenchange' in document){
return ['moz','FullScreen', 'Cancel'];
}
if('onwebkitfullscreenchange' in document){
return ['webkit', 'Fullscreen', 'Exit'];
}
if('onmsfullscreenchange' in document){
return ['ms', 'Fullscreen', 'Exit'];
}
}();
if(fs){
// for some reason, IE doesn't support the addEventListener method...
document['on'+fs[0]+'fullscreenchange'] = function(){
ctx.clearRect(0, 0, c.width, c.height);
// check for 'fullscreenElement' to know weither we entered or exited the fullscreen mode
var status = document[fs[0]+fs[1]+'Element'];
var statusString = status ? 'entered':'exited';
ctx.fillText(statusString+' fullscreen', 250, 50);
// increment our fullscreen change counter
fs_count++;
if(status){
ctx.fillText('click the canvas to exit fullscreen mode', 150 , 100);
// attach the exit/cancel fullscreen call
c.onclick = function(){document[fs[0]+fs[2]+fs[1]]();};
}
// log the counters
ctx.fillText('fullscreen calls : '+fs_count, 0, 140);
ctx.fillText('resize calls : '+resize_count, 0, 150);
};
btn.onclick = function(){
//this one implies a new camelCase if a vendor prefix is needed...
var camel = fs[0] ? 'R':'r';
c[fs[0]+camel+'equest'+fs[1]]();
};
}
var ctx = c.getContext('2d');
ctx.fillStyle = "red";
var resize_count = 0;
var fs_count = 0;
// increment our resize counter
window.onresize= function(){resize_count++};
<canvas id="c" width="500"></canvas>
<button id="btn">enter fullscreen</button>
Since fullscreen requests are blocked in iframes, you can see it in action here and play with the code here
Also, you will notice that every browser will act differently with this request : webkit browsers will make the page fullscreen but keep the element at the same scale, while FF and IE will scale the element to fit to the new page dimentsions.
This means you shouldn't look to the getBoundingClientRect() rect, but rather calculate the new size based on the window.innerWidth and window.innerHeight properties.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With