Element Widths not behaving when browser is zoomed out? - javascript

I am experiencing frustrating behavior with zooming out my browser. As you can see in this image:
The editor is supposed to be up next to the scheduler. I transition the editor from a width of 0px to 433px, and transition the scheduler from a width of the viewport, to scheduler-width - 453px, giving a 20px buffer, yet this is still colliding at 75%.... I don't get how? Reducing the scheduler width by 453 and increasing the editor from 0 to 433 should always ensure a 20px buffer between them, but this is not happening when zoomed out... Event if pixel size/count is a bit screwed up due to the zooming, it should still behave correctly as I am telling the scheduler to move over 453px (however they are now defined) to let the scheduler take up 433 of those free pixels.
Is this just odd behavior with zooming in/out of the browser?

You could try to use other units, like percents and em, instead of pixels. It should not only solve your issue, but also make your code run better on different-sized displays. Sorry if this is a bit irrelevent.

Related

Ag-charts canvas zoom bug

I would like to comment on my problem in case someone has an idea of what it is due to or proposes an alternative solution.
Currently I have a large ag-charts graph that does not fit and it is always necessary to scroll to be able to see it in its entirety but when scrolling the axes are not maintained, so I resorted to the alternative of cloning the graph canvas twice to generate 2 new canvas clipped with "position:fixed" so that they always stay at the ends.
So far there is no problem except that if the browser zoom and/or the windows scale differs from 100%, it affects the cropping of said canvas in an inconsistent way. I was not able to get a rule of 3 to apply the correct zoom multiplier ( with ctx.drawImage() ) due to its inconsistency.
The error stops happening when you test it with a normal canvas that has not been generated by ag-charts
Here I have a very simple Live Demo to test it.
(To reproduce the bug you need to have the zoom applied before the generation of the graph).
I also tried to get the zoom level using:
(Math.round(window.devicePixelRatio*100)/100, -1);
and applying the correspondent ratio using:
.drawImage(canvas,0, 0, canvas.width*ratio, canvas.height*ratio);
but it only works in specific percentages of zoom

What's the width of a screen? 100vw vs innerWidth vs visualViewport.width vs screen.width (React)

As you could imagine, I'm trying to make my webpage responsive and mobile friendly.
I have an outer container on which I set the width dynamically using this hook (window.innerWidth). So to test if the page is responsive I open up Chrome-devtools and start making the devtools wider:
Sure it's a little jumpy but it scales correctly, as expected. The problem starts when I open up to do the same in the responsive tools:
Suddenly the whole page scales down? Also, it's hard to see but I'm logging window.innerWidth and it's not changing as I'm changing the width.
So I try it out on my cell-phone and the the behaviour is really unexpected:
On load it looks ok
Flip the phone, still as expected, but when I flip it back???
This crazy effect happens, I mean now it looks like window.innerHeight is having some trouble as well? Because the container with the gray background color has it's min-height set to window.innerHeight. And if i try going to some other page of the app and then back I get this:
It's a zoomed in version of the last image. I can pinche-zoom out from it.
So I google around and it looks like I find someone with the same problem there's a detailed answer suggesting I should use window.visualViewport.width instead. So I try it out:
Main differences, the resizing seem's a little jumpier. I'm also logging window.visualViewport.width and it is changing, but only slightly and it's not corresponding to the responsive-width that's shown above the screen.
But most importantly, it's unfortunately not fixing the problem of weirdly resizing the entire screen, and the unexpected behaviour on mobile remains. (should be mentioned that this one too, works as expected if I'm not in "responsive mode" and just resize the window.
So I spot another answer further down suggesting to use window.screen.width instead, so I try it out:
Which introduced a whole new type of wonkyness? It seems to scale correctly, but down at around a few pixels above 300 it starts to just cut-off a piece of the header while making the container (which should be the width of the screen) smaller at a faster rate than the screen?
This seem to be related to the fact that the header has the css:
grid-template-columns: 130px auto 130px;. If I lower the 130px-value, the point at which the header gets cut off lowers as well. I suppose making the screen go below the headers min-width causes some (in my opinion) really unexpected behaviour.
Though the console log (now logging window.screen.width, now correctly prints the width reported by chromes responsive tool. The bug can be seen in my phone as well
I guess my phone must be a few pixels below 300 in width. Interesting fact is that using 100vw displays exactly the same behaviour as using screen.width.
It's also interesting to look at the difference between screen.width, innerWidth and visualViewport.width. If I set the size of the responsive window to 500px and reload the window. All of them evaluates to 500px. If I set the screen to any value below the threshold where screen.width starts to cut off a piece of the screen.
screen.width evaluates to the width of the responsive window.
innerWidth and visualViewport.width will both evaluate to 309px (which I assume is the minimum functional width of the header.
If we look at how innerWidth and visualViewport.width looks on my phone:
On both visualViewport.width and innerWidth we can see a much smaller but similar line to the one on screen.width (here it can be seen on a zoomed in screenshot).
First solution
So the first and most straight forward solution would be to use window.screen.width (or 100vw) and simply make sure that no element ever push themselves outside the width of the screen.
But wait, another solution has appeared!
By looking at a comment to an answer of the previous question I see that someone solved it by changing the the viewport meta-tag from
<meta name="viewport" content="width=device-width, initial-scale=1" />
to
<meta name="viewport" content="width=device-width, minimum-scale=1" />
All alternatives, screen.width, innerWidth and visualViewport.width all now behave identically to each other and as desired:
They all log the correct width of the responsive window, the page on my mobile also works. If you look closely you can see that the header does get cut off a little when the screen goes below the 309-threshold. But with this solution it seems like the page breaks a lot more gracefully than in first solution.
So if you've already solved the problem, why are you posting this question?
Well, as you might have understood by now, I love this problem more than I love the solution. That is, I would really like to know WHY this solution works? So even though my "practical" problem is solved I'm really curious as to a few remaining mysteries:
Why does resizing the window (first video) behave differently from resizing the "responsive box" in chrome dev tools?
Why does the bug appear on my mobile when I tilt my phone, and then tilt it back again? (third picture)
Why, when I (on the phone) go into some page and back again, is the screen super zoomed in? (fourth picture)
Why does innerWidth and visualViewport.width continue to print the same value when resizing the responsive window.
Why do they weirdly scale down the whole screen instead of changing the size of the screen in the expected way (are they for some reason zooming out when making the responsive window smaller? Is that why setting minimum-scale=1 solves the issue?)
Why does screen.width behave differently from innerWidth and visualViewport.width? And why does it cause such a weird white-space effect when going below the minimum width of the header?
Are there any reason one wouldn't want to set minimum-scale=1?

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.

smooth animation only in firefox 4

It seems that the following setup on jsfiddle only runs smooth in firefox 4.
http://jsfiddle.net/ynytc/39/
Im wondering why?
I thought maybe because of the hardware acceleration in firefox 4,
but without it still runs smooth.
So maybe someone knows why?
edit: compared to chrome,safari,ie8
You're animating over a 10 second period a change in size of only 20 pixels. That means that there's going to be only one integral dimension change every 1/2 second, which is exactly what I see in Chrome. The size of the image can't be set to fractions of a pixel (in all browsers). Firefox 4 seems to allow that, however; that's the only thing I can imagine anyway.
If you change your fiddle like this you'll see that Chrome is running the animation as fast as you could want it to, but the image only shifts when there's a whole integer change in the property value (width and height).
This is an interesting side effect that I hadn't encountered before.
It seems that other browsers can't apply subpixel scaling, so you only have 20 pixels to spread in 10 seconds, coming to a glorius 2 frames per second. The workaround for this would be to apply CSS transitions (if you don't need to support IE).
See example with CSS transitions here:
http://jsfiddle.net/nKfdB/

Categories

Resources