How to obtain screen scaling on the client machine? - javascript

I am trying to obtain the screen scaling on the client machine - the value in the image below. As you can see it's set to 150%.
I've tried window.devicePixelRatio, which returns 1.5 - which is what I want, but only if the browser zoom is at 100%. I am unclear how to get zoom level in a modern browser, which precludes me from getting accurate screen scaling.
Am I missing a simple way to obtain screen scaling?
P.S. This question doesn't solve anything because the ratio as the same as zoom, which makes it impossible to find the scaling. See example.

Related

Why doesn't window.devicePixelRatio change on zoom in Safari?

Context: I'm using window.devicePixelRatio to determine the display resolution for a few canvases on a website.
To the best of my knowledge, the DPR value should change when zooming in and out on a website. This is what happens on Chrome. But it doesn't seem to happen in Safari. Querying the value of window.devicePixelRatio or devicePixelRatio from the JS Console always returns the same value, no matter how much I zoom in or out. I've tried this on three separate computers, all of them Macs running either Safari v13.1.2, v14.1.2, or v15.1.
The MDN Web Docs page on Window.devicePixelRatio implies that the DPR should change on zoom, both in its definition at the top and in its example code. The spec linked by MDN says the following (bolded emphasis mine):
The devicePixelRatio attribute must return the result of the following determine the device pixel ratio algorithm: If there is no output device, return 1 and abort these steps. Let CSS pixel size be the size of a CSS pixel at the current page zoom scale factor and at a pinch zoom scale factor of 1.0. Let device pixel size be the vertical size of a device pixel of the output device. Return the result of dividing CSS pixel size by device pixel size.
Should Safari's window.devicePixelRatio be changing on zoom? If the DPR doesn't change with zooming, is there a different way to determine a good canvas display resolution on Safari?
This is my first question on StackOverflow so please let me know if anything can be improved.

Get Height of Surface Pro 3 on web page

I have a monitor with 1920x1080 resolution for my laptop and a Surface Pro 3 with 1920x1280 resolution. I am developing a web page designed for full-screen viewing on 1920x1080 and 1920x1280 displays.
I have confirmed the settings for each display (see below).
Why am I getting 8xx instead of 1280? How can I obtain a value of 1280 to match the resolution height of the Surface Pro 3?
1920x1080 monitor (on Windows 8):
1920x1280 (Surface Pro 3) display (on Windows 10):
Using $(window).height() on my 1920x1080 monitor, I get the following:
That works for me.
However, using suggestions from this question for my 1920x1280 (Surface Pro 3) display...
Using suggestions from the accepted answer.
Using $(window).height():
Using $(document).height():
Using screen.height:
Using the suggestion from this answer:
Using the suggestion from this answer:
Using the suggestion from this answer:
Using the suggestion from this answer and this answer and this answer:
Using this suggestion from this answer:
This suggestion is a self-recommendation of a plugin. I will pass on this for now.
This suggestion uses a Coffee solution. I'll stick to JavaScript and jQuery for now.
Using this suggestion from this answer (which regurgitates a few other answers):
This suggestion requires an external library. I will pass on this for now.
Using the suggestion from this answer:
This suggestion was incorporated into a few other answers above.
It seems that your Surface Pro 3 uses an operating system wide zoom factor of 150%. Due to this the browser returns width 1280 and height 853 (as 1280 * 1.5 = 1920 and 853 * 1.5 = 1280). Switch Windows' zoom factor to 100% in Control Panel and your browser will return width and height as expected.
1) How can I obtain a value of 1280 to match the resolution height of the Surface Pro 3?
Have you tried
window.outerHeight
yet?
All I see in your test cases is the innerHeight.
That's only showing you what the browser will render(pixels will be zoomed, etc.. decreasing the available width you actually have)
2) Why am i getting 8xx instead of 1280?
Basically, browsers will zoom text/images/ etc.. to give a consistent experience across several resolutions.
Even though you are building it for a 1280 screen, you might only have 8xx pixels to your availability.
For more information about the pixeling I advice you read:
http://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html
Here is a solution that worked for me in Firefox, Chrome, IE11, and Edge. I don't have a Mac to test on but this should work there too. You need to factor in the device pixel ratio. Here is an example (JSBin):
var screenHeight = window.devicePixelRatio * screen.height;
This will give you the screen dimensions regardless of DPI of the device.
An important thing to note is that innerHeight (size of window without browser UI) and outerHeight (size of window with browser UI) are relative to the browser window. You should use those instead of screen.height if you want to know the size of the browser window.
In the browser, you deal with the abstraction of CSS pixels, not with physical pixels. The size reported to you is most likely correct (unless there is a weird browser bug at play), so the height of the window is 853 CSS pixels.
My advice would be to work with that size. Adjust your layout with media queries etc. Don't try to second-guess the browser; don't optimize for hardware specifics which browser vendors, and web standards, are actively trying to hide from you.
(I'll try to expand this answer later on, if I have the time. A proper explanation of the concepts is the length of a blog post.)

Is there any way to find screen size in dp (not px) in Ionic/Angular/Cordova stack?

I know how to find dimensions in pixels both inner, outer, browser etc in Javascript using document, window and other objects..
Problem is, the returned width and hight are in px not in dp.
Lets say if screen is small enough that something is too big to fit I wanna hide some elements. And I wanna make it in a way that I remove elements in specific order (some are more useful, other are for additional info) until everything fits screen both horizontally and vertically (no scroll).
So I would get the screen size and ng-if remove objects from window until remaining objects sizes in pixels added together would be less then window.innerSize. Works well on desktop where pixel is pixel.
BUT, here comes the problem. On mobiles there is often a ratio of real screen pixels and displayed pixels. Eg. lets say a block is 300px high in css (height: 300px !important) but its 700 pixel high on actual device (measured using developer mode click on his bottom). I realize some is due to extra pixels on screen outside of app, like staus bar on top, but rest is in dp to px ratio of a screen.
How would you approach this problem, if there is no solution to original question of finding the dp dimensions of window?
Found it, when you are using Cordova you have
window.devicePixelRatio
available for you.
And it comes to play just nicely. Use window.innerHeight to get actual height of everything inside window (ALSO works with keyboard overlaying your app!).
For each element its height on screen is his_css_height * window.devicePixelRatio.
Translates exactly to what i wanted.
Sorry to answering my own question here but I spent almost 3 hours searching for an answer, and I decided to post here and then continue my search. Just became aware of this, hopefully it helps someone else :)
you can try this :
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();
display.getMetrics(outMetrics);
float density = getResources().getDisplayMetrics().density;
float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels / density;

Why do rendered pixels differ from real pixels?

In my HTML i have a <div> (call it the panel) with fixed width that contains some text; that text is set to font-size: 25px; line-height: 25px; in the accompanying CSS. It so happens that the text ends up as 36 lines.
Given that all margins, paddings and borders are zero, you'd expect the height of the panel to be 36 * 25px = 900px, and that is in fact what i find in Firefox, using the DOM's getBoundingClientRect() method.
However, in Google Chrome i get different figures; it would appear the panel is only 892.7999877929688px high while lines are 24.799999660915798px high. Dividing those two numbers still gives 36 though. It looks like there is a scaling ratio between nominal pixels as set in the CSS and real pixels as reported by getBoundingClientRect(); in my case, this is 1.0080645299120465 nominal per real pixels.
One more piece of evidence comes from Chromium running inside an nwjs app where i initially observed the discrepancy. During my tests, it showed consistently a different ratio from the one in Chrome. Now, at some point during my tests, the pixels reported by Chromium suddenly jumped to the integer values as reported in Firefox; i'm not sure what i did to make this happen.
It could be expected that the fractional ratios are in some way linked to page zoom; after all, at very small sizes, Chrome and Chromium reflow the text (and sometimes do it wrong). And indeed, varying the zoom in Chrome leads to different ratios, and making Chrome zoom in to the max will make the ratio flat out at 1. Still, my Chromium app is not zoomed in to the max and still has a fractional ratio. an integer pixels ratio in the test but a fractional value in the real app.
For all i presently know, all i can do to obtain the ratio so i can make sound, consistent box size measuring with JavaScript is to set up a box of known size and measure it.
I'm still wondering what the source of the observed behavior is. Are there any reports of it? Is it an intentional or an emergent behavior of the renderer? Was it ever discussed by the devs? Is there an API to obtain the ratio?
I've put some code on a gist at https://gist.github.com/loveencounterflow/d8c20b9021d2ab3f573a to simplify testing.
Some fonts cant be rendered at the exact size u ask for, and fonts had properties that affect indirectly to the real size reported. If you want same behavior everywere, maybe u have to import your own font to achieve similar rendering cross browsing. I had a similar problem while working on IE and Chrome.

Zooming SVG is blury or pixelated, not sharp

vI know to some extent this is a known issue that has been asked here but never answered, but I'm hoping for some additional insight.
I have a simple SVG image in a div on a web page. I want to be able to zoom the image using pinch gestures and have the SVG render sharply. It doesn't need to be sharp during the zoom, but should be sharp after the gesture is complete.
I'm doing my testing on a Windows 8.1 computer with a touch monitor, on an iPad, and on an old Android Galaxy Tab. On the main computer, I'm using IE11 and Chrome. For handling touch gestures, I'm using Hammer.js. I'm doing the zooming by modifying the transform CSS using the jQuery css() function (I'm setting scale3d and translate3d).
IE11 on my computer works exactly like I would like it to. It keeps the SVG image sharp throughout the pinch zoom and the image is always sharp regardless of when I set the CSS.
Chrome on my computer always renders the SVG blocky when I am zoomed in using pinch zoom. It is blocky during the zoom and does not get sharp afterwards. If I add a call to zoom the image after the page (x13) is loaded, the image is sharp. If I use a setTimeout() call to reset the zoom and then rezoom the image after the pinch zoom ends, the image is sharp.
On the iPad and Android tablet, the SVG never renders sharply, regardless of when I zoom it in code.
Does anyone have any ideas of how to reliably end up with a sharp rendering of SVG after a pinch-zoom is completed? Does anyone have a better solution? Using the SVG viewBox to zoom and pan during the gesture does not provide good enough performance for our more complex SVG images. I'm thinking of attempting to use the hardware accelerated scale3d/translate3d during the gesture and then attempt to convert this to new SVG viewBox settings afterwards, but this is a challenge and I'm not sure panning will work correctly after this is done. Any pointers or ideas are greatly appreciated.
Having just tried to answer your other SVG Question I will have a try at this one.
Michael Mullany is spot on that GPU translations will never give you a sharp image. This is because the GPU just maps one array of pixels to a new one. Because it has no concept of lines or rectangles the resolution is set by the time the GPU gets the image. The CPU will always struggle to re-render in time for a smooth drag.
What happens to allow some browsers to produce a sharp image is they do clever manipulations like rendering more pixels than they need so some zooming can happen without loss of resolution. These however are completely inconsistent and just not possible to rely on.
The as I see it 'correct' solution is to translate and zoom with hardware accelerated transformations during a pinch or zoom and then to refresh the viewbox with no css transformation when the translation has finished.
Challenges to overcome are
The css transformation will use screen coordinates but the viewBox manipulation will use the SVG coordinate system.
There are browser inconsistencies in both screenCTM and device pixel ratio
limits so that people don't drag or zoom too far need to be calculated in both systems
Pinch centerpoints also need to be calculated in both
To improve performance further the css transforms will be wrapped into updating on the requestAnimationFrame loop.
My working solution is hammerhead2. I am concentrating on desktops and android mobiles first and it seams to be working for them. To simplify the problem zoom is always centered to the screen center. I do however thing this is currently one of the only solutions. Here is an example of it working.

Categories

Resources