Safari iPhone - How to detect zoom level and offset? - iphone

I looking for options on how to track user zooming and panning on a page when viewed in Safari on an iPhone. Safari exposes move and gesture events, so theoretically I can keep a running tally of pan and zoom operations, but that seems like overkill since the browser must track that internally.
Is this information exposed through the Document Object Model?

When you zoom in, window.innerWidth is adjusted, but document.documentElement.clientWidth is not, therefore:
var zoom = document.documentElement.clientWidth / window.innerWidth;
(I've tested iOS4, without viewport <meta>).
However, I wouldn't rely on it for anything important. DOM viewport sizes/pixel sizes in mobile browsers are a complete mess.

On Mobile Safari and Android, here is an accurate way to measure how much the page has been zoomed.
Try it here: http://jsbin.com/cobucu/3 - change zoom then click measure.
Technique is to add a top level div:
<body>
<div id=measurer style="position:absolute;width:100%"></div>
and use the calculation:
function getZoom(){
return document.getElementById('measurer').offsetWidth / window.innerWidth;
}
The only problem is finding a tidy way to detect that the user has changed zoom (pinch, double tap, etc). Options:
webkitRequestAnimationFrame: very reliable, but likely to cause jankiness if using animations (due to performance hit)
setInterval: reliable but very ugly
touch events: look for two fingers or
double tap: ugly and maybe difficult to make 100% reliable
window.onresize + window.onorientationchange + window.onscroll: simple but totally unreliable (Edit: and onscroll can cause performance problems in WKWebView or Mobile Safari 8 or greater).
PS: Windows Phone needs a different solution (pinch-zoom doesn't change the viewport - pinch-zoom on Windows has its own separate viewport that is not visible to javascript).
Edit: Android Visual Viewport resize and scroll events may help? See https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport#Events

According to the Safari Web Content Guide, zoom events (double tap) are not exposed, so I'm not sure how you can track this.
I do not believe this information is exposed through the DOM.

I actually think things might have moved on a little since Steve's answer, as having a look at the content guide link he provided I can see a section on Handling Multi-Touch Events and also Handling Gesture Events.
Haven't tried them yet but they look pretty promising. I'll provide an update once I've checked them out and have a demo link available...

I measure zoom this way (works on iOS only):
screenOrientedWidth = screen.width;
if (window.orientation == 90) {
screenOrientedWidth = screen.height;
}
return screenOrientedWidth / window.innerWidth;
It doesn't depend of how wide content is.
However, in iOS Safari window.innerWidth isn't correct inside a gestureend handler. You should defer such calculation for later execution. In GWT, I use scheduleDeferred, but I can't say how to implement this in pure JavaScript.

If you are using any elements with location:fixed this can get complicated, as the location:fixed coordinates are relative to the unzoomed window, where window coordinates are relative to the zoomed viewport. More info: How to position a fixed-location element on IOS browser when zoomed?

Related

Firebreath NPAPI plugin rendering video to top level browser window (HWND)

I am working on a audio/video rendering plugin that is using FireBreath and we have a need to get HTML elements to overlay on top of the video. I am aware that to do this I need to use the windowless mode in FireBreath. However since I am using DirectX to render the video I cannot initialize DirectX with the HDC handle (it requires a HWND) that I get when I am instructed to render in windowless mode.
Also for other software security reasons I cannot render the video to an off-screen surface then Blt the bits to the HDC.
The alternative I was trying to accomplish is to use the Hardware Overlay feature in DirectX and use the browser's TOP level HWND to initialize DirectX, then use the HDC and coordinates to tell directX where in the TOP browser window to render the video frame. And render it directly to the top parent browser window.
I have tired a proof of concept, but I am seeing my video frames getting erased quite often after I draw them and thus the video appears to be flickering. I am trying to understand why that might be and I am wondering if this is not a viable solution given my parameters.
Also I am wide open to suggestions on how to accomplish this given my constraints.
Any help would be greatly appreciated!
In the FireBreath-dev group, John Tan wrote:
As what I know, you practically have no control precisely when the screen is going to draw. What can only be done is:
1) Inform the browser to repaint by issuing the windowless invalidatewindow
2) browser draw event arrives with the hdc. Draw on the hdc
John is completely correct. In addition, the HDC could potentially (perhaps likely will) be different each time your draw is called. I don't know of anyone who has successfully gotten directx drawing using windowless mode, and you have absolutely no guarantee that what you are doing will ever work as even if you got it working the browser may change the way or order that it draws in in a way that would break it.
You might want to look at the async surface API; I don't know which browsers this works on but I suspect likely only Firefox and IE. It was implemented in this commit.
I haven't used this at all, so I can't tell you how it works, but it was intended to solve exactly the problem you're describing. Your main issue will be browser support. What documentation there is is here.
Hope this helps

Fallback for CSS background image transition

I'm using CSS transitions for the background-image property, though from what I can gather they are only supported by Chrome and Webkit (it doesn't seem to work in Safari 5.1.7). I really don't want to use jQuery for the transition since its only solution is to fade out the element (and with it the content) and fade back with a new background. Normally I would do it the standard way and have multiple divs or images inside a wrapper to rotate between, but the way this site is set up that simply wouldn't work (well technically it could, but it just seems ridiculously and needlessly over-complicated).
Visit the site here and you'll see what I mean: http://bos.rggwebdesigns.com/
Is there some way to safely fall back for other browsers that don't yet support background image transitions, either by disabling it completely or some other method? If the browser can't handle it, I don't want the user to just see the background change abruptly.
You can use Modernizr for feature detection, and then change your CSS on the fly accordingly.
Modernizr

How can I turn off hardware acceleration for certain HTML elements via CSS?

I created a very complex web app using HTML5, CSS3 and jQueryMobile.
It seems like jQueryMobile turns on hardware acceleration here and there via translate3D and/or translateZ.
Now I want to turn this off for certain HTML elements.
This gives me two questions:
Is there a css property/attribute or something that I can use to tell the browser to turn off hardware acceleration for certain elements?
If not: I will have to find the places where either translate3D or translateZ is used and simply remove them, right? How can I do that? The whole markup is very complex with many HTML elements. I can't go through each element in the inspector and search for it.
Update: The reason why I want to fix this
In my web app there are some elements which need to be swipeable (e.g. an image gallery). In this case I need hardware acceleration. Same for div containers that require iScroll and every other element which should be animated (e.g. slide- and fade-animations).
However, there are many parts of the app which are static (not animated). Using a special startup option in Safari, I was able to make the parts which get hardware-accelerated visible. This way I noticed that THE WHOLE app gets hardware-accelerated, not only the necessary parts.
IMHO this is not a good thing because:
Accelerating the whole thing will cause heavy load to the GPU which makes the whole app stutter while scrolling.
AFAIK it's best practice to let the CPU do the static stuff while the GPU only handles all the fancy animated stuff.
When animations have ended, hardware acceleration should be deactived because it's not necessary anymore and would shorten battery lifetime.
After going through thousands of thousands of lines of CSS code, I found this:
.ui-page{-webkit-backface-visibility: hidden !important}
This was active for all pages and caused the problem. Removing that line fixed it for me.

Zooming only an image in mobile Safari

I'm looking to see if anyone has experience with this. I'm a developer first and a designer second, so this is really not my strongest suit.
I have a project I'm working on where the goal is to get image and text side-by-side in landscape mode on the iPhone. I'd like to be able to zoom in on the image using a pinch like normal, but not zoom in on the text as well while that is happening. I don't know if this is even possible or what kind of hacks it would take to get it working.
If someone thinks this is bad in general from a UI perspective, I am open to suggestions.
I have considered keeping two copies of the image (low and high res) and then swapping them out inside of div with an overflow: scroll; so users can get a zoomed version and then scroll around. It doesn't give you the full effect of zooming, but it might accomplish a similar goal. I don't know if this would work either.
If anyone has suggestions or experience on the subject, please chime in. Thank you!
To do this in mobile safari you would probably have to use javascript. Theres a jQuery plugin here: http://plugins.jquery.com/project/pinch
Might be of some help
If you want to use Mobile Safari, then you will need a touch framework like jTouch to simplify things.
Natively, you should put your image and text inside a UIScrollView, and return the image view in the the viewForZoomingInScrollView: (in the scroll view's delegates) to the image view.
Is that what you want?

Blurred text in Iphone 4 browser when loading content dynamically

I am using the Jquery/Jqtouch libraries for an iphone compatible site. I am now stuck with a problem just in iPhone 4 (not in 2g, 3g or 3gs) where the text becomes blurry on one specific scenario. Below is how it happens
The site has one common div container.
<div id="container"></div>
The container is filled with content dynamically based on the user action. Below is the function that does that.
function loadPage(url, section, callback) {
$('#container').empty();
$('#container').load(url + ' ' + section, loadComplete(section));
}
One sample call to the above function
loadPage("Data.htm", "#Friends", null);
Basicaly eveything works fine except on one scenario where the amount the data on the container is huge (ie the #container height increases to 1500px+ not predictable). Now if i replace it with smaller data for different tabs on the same container then the text becomes blurry. Attached is the image
http://i.stack.imgur.com/XE9q4.png
Did anyone come across this scenario. Thanks in advance.
Try closing all your running apps besides safari. It sounds crazy but we have the same problem on the ipad and it just seems to be running out of memory at some point. Closing all the apps stops it. Other thing that seems to make a difference is -webkit-overflow-scrolling:touch, if it doesnt have this property then it doesnt seem to have the problem described.
i was able to fix this by applying the same settings to reduce flicker on the element in webkit browsers:
-webkit-perspective: 1000;
-webkit-transform-style: preserve-3d;
-webkit-backface-visibility: hidden;
Graphics elements must be "aligned" with the pixels on the screen; coordinates must always expressed as integral values and not floating values. If not, the subpixel rendering engine of the GPU would make it blurry, which is not a problem with animation but definitely one with static images.
In the native SDK, we have to make sure everything is aligned (such as using CGRectMakeIntegral()).
Since you're using a web framework, it's more difficult to tell how to exactly how fix the problem, but I would try to adjust the sizes of your to a precise size and not let the framework figure it out.
What content do you load? Images? Text? There's an internal limit on image sizes for the iPhone (about 4 Megapixels or so). It looks like the phone is trying to reduce the memory load of your website and reduces the resolution to non-retina values.
I can't say more without you posting code.
This is a shot in the dark, but have you aset your sizes using pt values for your block elements, and em for your text?
The iphone4 resizes your content to fit its higher-res Retina display (compared to the older iphone), and with that scaling i have sometimes noticed blur when using pixel values for block height, width, font size, etc.
Very hard to diagnose without seeing the actual code, but could be the issue.
In my case it was CSS
-webkit-transform: translateZ(0);
applied to one of the elements in body. So as Ariejan said, it's removing transition property that fixes it.
body{ text-rendering: optimizeLegibility}
could solve this issue, worth a shot if you haven't included it already
Sometimes, Text blurry may be cause of the iScroll Plugin. Did you use this?
Try to comment
trnOpen = 'translate' + (has3d ? '3d(' : '('),
trnClose = has3d ? ',0)' : ')',