14

I have a canvas that needs to be resized when the browser window is resized, so I have the following:

var resizeCanvas = function () {
    var ratio =  Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = (canvas.offsetWidth || canvas.width) * ratio;
    canvas.height = (canvas.offsetHeight || canvas.height) * ratio;
    canvas.getContext('2d').scale(ratio, ratio);
}

window.addEventListener('resize', resizeCanvas);

This works great, except on mobile devices scrolling triggers the resize event.

This is undesired as resizing the canvas clears its contents, which means as a mobile user scrolls, the canvas is always wiped.

Thanks to this answer I came up with a solution based on caching the width and double checking it, but based on my design, I really only need to resolve the issue for devices which are affected by my viewport metatag:

<meta name="viewport" content="width=device-width, initial-scale=1">

Is there someway I can check if that meta tag is being used by the browser? I'm looking for something like:

if(viewportMetaTagIsUsed){
    //For mobile browsers
    window.addEventListener("orientationchange", resizeCanvas);
} else {
    //For desktop browsers
    window.addEventListener('resize', resizeCanvas);
}
John Slegers
  • 45,213
  • 22
  • 199
  • 169
Mister Epic
  • 16,295
  • 13
  • 76
  • 147
  • Would it be a possibility to also bind to the touchmove event and detect the fact that the event is in fact caused by a scroll? Also one thing i noticed on my android device is that the resize event only appends when i reach the end and begining of the page. On an other note, you could detect the browser with code like the one here : http://stackoverflow.com/q/11381673/643039 – Mathieu de Lorimier Mar 12 '16 at 02:16

8 Answers8

8

AFAIK, it's not possible to detect whether a browser is capable of processing the viewport meta-tag.

Herebelow are some alternatives to consider...


Alternative 1 : browser sniffing

!function(a){var b=/iPhone/i,c=/iPod/i,d=/iPad/i,e=/(?=.*\bAndroid\b)(?=.*\bMobile\b)/i,f=/Android/i,g=/(?=.*\bAndroid\b)(?=.*\bSD4930UR\b)/i,h=/(?=.*\bAndroid\b)(?=.*\b(?:KFOT|KFTT|KFJWI|KFJWA|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|KFARWI|KFASWI|KFSAWI|KFSAWA)\b)/i,i=/IEMobile/i,j=/(?=.*\bWindows\b)(?=.*\bARM\b)/i,k=/BlackBerry/i,l=/BB10/i,m=/Opera Mini/i,n=/(CriOS|Chrome)(?=.*\bMobile\b)/i,o=/(?=.*\bFirefox\b)(?=.*\bMobile\b)/i,p=new RegExp("(?:Nexus 7|BNTV250|Kindle Fire|Silk|GT-P1000)","i"),q=function(a,b){return a.test(b)},r=function(a){var r=a||navigator.userAgent,s=r.split("[FBAN");return"undefined"!=typeof s[1]&&(r=s[0]),s=r.split("Twitter"),"undefined"!=typeof s[1]&&(r=s[0]),this.apple={phone:q(b,r),ipod:q(c,r),tablet:!q(b,r)&&q(d,r),device:q(b,r)||q(c,r)||q(d,r)},this.amazon={phone:q(g,r),tablet:!q(g,r)&&q(h,r),device:q(g,r)||q(h,r)},this.android={phone:q(g,r)||q(e,r),tablet:!q(g,r)&&!q(e,r)&&(q(h,r)||q(f,r)),device:q(g,r)||q(h,r)||q(e,r)||q(f,r)},this.windows={phone:q(i,r),tablet:q(j,r),device:q(i,r)||q(j,r)},this.other={blackberry:q(k,r),blackberry10:q(l,r),opera:q(m,r),firefox:q(o,r),chrome:q(n,r),device:q(k,r)||q(l,r)||q(m,r)||q(o,r)||q(n,r)},this.seven_inch=q(p,r),this.any=this.apple.device||this.android.device||this.windows.device||this.other.device||this.seven_inch,this.phone=this.apple.phone||this.android.phone||this.windows.phone,this.tablet=this.apple.tablet||this.android.tablet||this.windows.tablet,"undefined"==typeof window?this:void 0},s=function(){var a=new r;return a.Class=r,a};"undefined"!=typeof module&&module.exports&&"undefined"==typeof window?module.exports=r:"undefined"!=typeof module&&module.exports&&"undefined"!=typeof window?module.exports=s():"function"==typeof define&&define.amd?define("isMobile",[],a.isMobile=s()):a.isMobile=s()}(this);

alert(isMobile.any ? 'Mobile' : 'Not mobile');

This particular browser sniffing code is that of a library called isMobile.


Alternative 2 : window.orientation

Test is window.orientation is defined :

alert(typeof window.orientation !== 'undefined' ? 'Mobile' : 'Not mobile');
John Slegers
  • 45,213
  • 22
  • 199
  • 169
3

Ideally, you should treat mobile devices and desktops as the same, because the line is so very blurred. Tablet propped up with a keyboard? Laptop with touchscreen? The only difference is where the cpu is located at that point.

Stick with what you were doing: Cache the width and check if it changes. Don't try to determine if the device is a mobile or a desktop device, because you will at some point fail.

Shelvacu
  • 4,245
  • 25
  • 44
2

Have you tried:

var viewportMetaTag = document.querySelector('meta[name="viewport"]');
var viewportMetaTagIsUsed = viewportMetaTag && viewportMetaTag.hasAttribute('content') ? true : false;

Documentation on MDN:

Viktor
  • 3,436
  • 1
  • 33
  • 42
  • 3
    This will only indicate whether the meta tag is present, which it is in both desktop and mobile browsers. It's just mobile browsers will take that as a cue to blow the webpage up to take the full width of the device. Your code will always return true (p.s. you don't need the ternary at the end) – Mister Epic Mar 09 '16 at 16:44
  • Ah yes, now I understand what you're looking for. – Viktor Mar 09 '16 at 16:49
2

you can check if orientationchange event exists or not and based on that assign the function. something like below code

if("onorientationchange" in window) {
  //For mobile browsers
  window.addEventListener("orientationchange", resizeCanvas);
} else{
  //For desktop browsers
  window.addEventListener('resize', resizeCanvas);
}

code snippet to detect event support is taken from below thread

Detecting support for a given JavaScript event?

Community
  • 1
  • 1
S4beR
  • 1,872
  • 1
  • 17
  • 33
2

Try this:

//mobile detection
    var isDevice = false;
    if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
        isDevice = true;
        // your code ...
    }

or:

if ($('meta[name="viewport"]').size() > 0) {
      // your code ...
}

or:

if ($('meta[name="viewport"]').attr('content').indexOf('device-width') - 1) {
      // your code ...
}
Undefitied
  • 747
  • 5
  • 14
1

I would argue that what you want is not necessarily to detect the use of the viewport tag, but really whether you are running inside of a mobile browser.

From this answer we can snag a function to detect most mobile browsers:

window.mobilecheck = function() {
    var check = false;
    (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
    return check;
}

Then you can use it to do what you want:

if(window.mobilecheck()){
    //For mobile browsers
    window.addEventListener("orientationchange", resizeCanvas);
} else {
    //For desktop browsers
    window.addEventListener('resize', resizeCanvas);
}
Community
  • 1
  • 1
Ted A.
  • 2,264
  • 17
  • 22
1

You could change the content of the meta tag via js (for example, set it to width=123). Now, you've got to have such an element in your page which would certainly change its size because of that (div@width:100% maybe?). After that, you restore original value of meta, but already knowing if it means anything for the browser.

If you go this way, the result of the proceduce should be saved to localStorage or cookie, so that you mess with the page only once.

Serge Seredenko
  • 3,541
  • 7
  • 21
  • 38
0

Try this:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=0.1">
<script>
    var width=$(window).width();
    $('meta[name=viewport]').attr('content','width=device-width, initial-scale=1');
    var newWidth=$(window).width();
    var viewportMetaTagIsUsed=width!=newWidth;
    alert(viewportMetaTagIsUsed?'using meta viewport':'not using meta viewport');
</script>

Or more encapsulated:

 function usesViewport() {
  var meta=$('meta[name=viewport]');
  var content=meta.attr('content');
  if (!meta.length) {
   meta=$('<meta name="viewport" content="width=device-width, initial-scale=1" />').appendTo('head');
   console.log(meta.parent());
  }
  $('meta[name=viewport]').attr('content','width=device-width, initial-scale=1');
  var width1=$(window).width();
  $('meta[name=viewport]').attr('content','width=device-width, initial-scale=0.1');
  var width2=$(window).width();
  if (content) {
   $('meta[name=viewport]').attr('content',content);
  } else {
   meta.remove();
  }
  var result=width1!=width2;
  return result;
 }
 $(function() {
  alert(usesViewport()?'Uses viewport':'Doesn\'t use viewport');
 });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

I don't know why it doesn't work here, probably something to do with the sandboxing of the script, but still, I copied and pasted it in the console on Wikipedia and it works, for example.

Siderite Zackwehdex
  • 6,293
  • 3
  • 30
  • 46