13

I am creating a web app using jQuery Mobile and PhoneGap. There is a graph and if the user is using a large screen, I would like to display more points on this graph, because points are tappable and the shouldn't be too close (physically).

For example: if someone has an iPhone, I want to display N points on the line graph. If he has an iPad, i want to display 2xN points (cause iPad has physically larger screen), but if he has some newer Android phone that is physically small like an iPhone but has a screen with many pixels (like an iPad), I want to display N points, because the points are physically small (and closer together).

So is there a way to get this data? An alternative is determining whether the device is a tablet.

duality_
  • 17,738
  • 23
  • 77
  • 95

4 Answers4

12

This issue is a complex one.

You can find out the screen resolution of your device in JavaScript by using screen.width and screen.height, just like you would on a Desktop.

However, on a mobile device 1 CSS pixel will not necessarily have a 1 : 1 proportion with a physical screen pixel. Let's say your screen.width returns a value of 640 pixels. If you add a banner that is exactly 640 pixels wide, it will most likely go over the available screen width of your phone.

The reason for that is that mobile manufacturers set the device's default viewport for a different scale factor than your device's screen. That is so the contents of webpages that were not designed specifically for mobile devices would still appear legible without the need for pinch zooming.

If you use the meta viewport tag, you can set the scale factor of your viewport to a 1 : 1 ratio, by setting its width value to the device's width value, like so:

<meta name="viewport" width="device-width" content="target-densitydpi=device-dpi" />

Now that 640 pixels banner would fit exactly on your 640 pixels screen.

Unfortunately as of this moment, as far as I'm aware, there is no real way to tell the actual physical screen size (as in inches or mm) of the device displaying your web content. At least not in JavaScript. Although the browser can access some useful information such as device.name or device.platform, you cannot tell how many inches or mm those 640 pixels represent, unless you know in advance the measurements of a given device's screen.

To me it's pretty obvious why someone would want a version of an app for small phone screens, and another larger tablet screens. Small buttons, for instance. Sometimes they are so close together that your finger would cover two at once. At the same time you wouldn't want those fat buttons designed for mobile screens showing on a nice 10'' tablet.

You could of course with the help of screen.width and window.devicePixelRatio find out if you are running, say, on an iPhone retina or an iPad 2, but when you start considering the myriad of screen resolutions and pixel densities on Android devices, the task becomes nearly impossible.

The solution is going Native.

On Android, you can use the code at the following thread to figure out if your app is running on a large screen:

Tablet or Phone - Android

You can then use the code on this other thread to query your wrapper app from JavaScript, using PhoneGap:

Communication between Android Java and Phonegap Javascript?

With Apple, it's even more straight forward:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    //running on an iPad
}
else {
    //iPhone or iPod
}

And if you use the same naming convention for your Android and Apple objects, your code will still be universal, which is the whole point of PhoneGap. For instance, in my case I used the same names for both my Java and my Objective-C objects and methods. In JavaScript I just need to call:

window.shellApp.isTabletDevice();

And my code runs and looks nice on every size of screen.

Community
  • 1
  • 1
aeldron
  • 1,575
  • 1
  • 13
  • 16
  • that's why i went native but i dont know how to get it in phonegap ;D – Muhammad Umer Aug 16 '13 at 15:14
  • Yep. -1 for HTML, +1 for native. screen.width and screen.height in a web invironment are not necessarily in the actual pixels of the screen. In native you can get the actual pixel density of a screen, and make your app use real-world inches, points, etc. You might get lucky if PhoneGap has exposed the Android API that actually lets you get the device pixel density. I haven't looked at that, but that doesn't solve the problem for normal browsers. – trusktr Jul 20 '14 at 21:06
8

What you want is to check the device's pixel density - measured in DPI - as @Smamatti already mentioned you control this with CSS media queries.

Here's an article on how to cope with varying DPIs and screen sizes, using those CSS media queries.

UPDATE: here's the javascript function (from the above link) that uses a trick to figure out the current device DPI:

function getPPI(){
 // create an empty element
 var div = document.createElement("div");
 // give it an absolute size of one inch
 div.style.width="1in";
 // append it to the body
 var body = document.getElementsByTagName("body")[0];
 body.appendChild(div);
 // read the computed width
 var ppi = document.defaultView.getComputedStyle(div, null).getPropertyValue('width');
 // remove it again
 body.removeChild(div);
 // and return the value
 return parseFloat(ppi);
}

Hope this helps!

Leon
  • 4,532
  • 1
  • 19
  • 24
  • Please add a snippet of code to your answer (like getPPI or some CSS) from that article and I'll mark this answer as accepted. – duality_ Dec 13 '11 at 16:29
  • 19
    I wish it was that simple. I've tested this function on two different Android phones and 1 Android tablet running PhoneGap, and the value is always the same: 96 PPI. As far as I know "1in" is a CSS inch and there is no real correlation to an actual physical inch. The value is set by the browser, not by the device where it's running. – aeldron Aug 09 '12 at 09:41
  • 2
    I think the article has been updated, you may wish to update your answer accordingly, they seem to recommend this: `var dpr = 1; if(window.devicePixelRatio !== undefined) dpr = window.devicePixelRatio;` – Harry Jun 25 '13 at 00:03
  • 2
    dpr is different than dpi, dpi is how many pixels per inch, dpr is how many pixels per pixel of screen. it's usally always 1. Like for retina display it'd be higher than 1. All this doesn't solve problem. Article sucks, 96px=1in as far as browsers are concerned. Actual value depends on real dpi. Using media resolution doesn't work anywhere. – Muhammad Umer Aug 16 '13 at 15:13
  • 1
    so there are css inches and pixels? which not necessarily correspond to actual pixel or inches. In css 1in is always 96 pixel. https://developer.mozilla.org/en-US/docs/Web/CSS/resolution – Muhammad Umer Jul 14 '14 at 03:47
  • 1
    This is truly sad. Developing in a native environment gives you the pleasure of being able to know a device's true pixel density, and therefore the ability to create elements that are real-world dimensions (e.g. a real inch, real point, real centimeter, etc). One pixel should ***always*** be 1 pixel! It's absurd that in web 1 pixel may not always be one pixel, and physical sizes (pt, in, cm, etc) might not actually be true physical sizes. That's sad! I am hurt inside. – trusktr Jul 20 '14 at 20:00
  • 2
    I've come back to this only to realize I'd previously commented. The sad truth: as of this writing, web browser creators don't want you to know the device's true pixel density. You might be able to do it with PhoneGap/Cordova, etc, but not in a pure web browser. – trusktr Nov 24 '14 at 01:47
  • @trusktr i am crushed. honestly, it's %$#@! like this that makes me question whether i even want to try to excel and produce things and make the world a better place, when what i try to do is made impossible by the environment i must architect my code to run it. why do i bother? why do i allow myself to suffer at the hands of others like this. there is simply no valid excuse for things like this, yet they happen again and again and there is nothing the little guy can do about it. – Michael Feb 08 '18 at 02:33
  • https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio – Robin Payot Apr 04 '21 at 08:53
3

look into window.devicePixelRatio

Otto Nascarella
  • 2,445
  • 2
  • 17
  • 8
  • 8
    Then after looking into it realize that HTML offers no way to get a screen's actual pixel density. :( – trusktr Jul 20 '14 at 21:04
3

I searched all over and found a lot of half solutions. This works on android, iphone, and the web. In your CSS use rem values to scale proportionately.

var dpi = window.devicePixelRatio || 1;
var width = $(window).width();
var ratio = 52; //Ratio of target font size to screen width screenWidth/idealFontSize
var font = Math.ceil((width / dpi / ratio)+dpi*3);
if(font < 15)
    font = 15;// any less is not useable.

$("html").css({"fontSize": font});

Update: I Now use something closer to this. It works in more cases. Ratio changes depending on the project, and the orientation. And I employ a class on the body tag that will change the CSS.

<body class="landscape">
<body class="portrait">

var landscapeUnitsWideThatIWantToBuildThisProjectTo = 50;
var unitsWideThatIWantToBuildThisProjectTo = 30;

var landscape = isLandscape();
var ratio = landscape ? landscapeUnitsWideThatIWantToBuildThisProjectTo : unitsWideThatIWantToBuildThisProjectTo; 
var font = Math.round(width / ratio);
Mardok
  • 1,360
  • 10
  • 14
  • 1
    This is nice, except that you can't tell if 52% is good on a device but not on another if they have the same physical dimensions but different resolutions, because the percentage will be taken from two different width values. HTML is limited in this way, while in native development you can have access to the real-world screen density of a device's display. – trusktr Jul 20 '14 at 21:03
  • If you have the luxury of developing native, it is the better way to go. But if you are developing a web app that you want to be accessible on desktop, and mobile platforms you need to think more in ratios than pixel size. The app needs to be able to adapt to a huge variance of screen sizes and densities, and Windows, Android, and ios all handle it differently. The only solid thing you have is how many units across and down do you have. I build the layout from there. – Mardok Sep 08 '15 at 15:37
  • 1
    The problem with that is that you can't accurately determine how wide something should be in real-world units (like you can with modern devices when programming natively). For example, I want a button that is **exactly** 1 inch wide, no matter what. I can do that in Native (for the most part) but not in the web whatsoever. – trusktr Oct 13 '15 at 19:15