Zooming past the maximum level is crappy on iPhone
This is completely our fault, but the android browser has a bug related to css transitions on hardware accelerated elements which prevents it from being manifested there.
Basically, we set the scale() of the element as the user is zooming. When they release their fingers, if the scale is larger than some arbitrary maxScale (currently 4), we make a nice smooth transition back to the max zoom level.
The problem arises when the user releases one finger, then moves the other by a couple pixels. This happens naturally quite a bit while zooming. When this happens, we remove the transition (since normally you don't want any lag between when you move your finger and when the element animates), causing the zoom animation to instantly jump to the final state, even if it had just started.
Fundamentally, this problem is because css gives us a single hardware-accelerated transform property for all of our transforms, and doesn't let us animate them separately (i.e by providing transform-scale and transform-translate properties, as the non-hardware accelerated analogues of zoom and top/left do).
I think you could fix this by emulating simultaneous transitions on multiple transforms (i.e running a scale and translate animation at the same time) using CSSMatrix, but this could get hairy with all the browser quirks. For example, if you wanted, as in this case, a scale animation to run for 300ms, and a translate property to be applied immediately, you would have to do something like:
currentTransform = getComputedStyle()...
currentTransform.translate = newTranslate
element.transform = currentTransform 0s
setTimeout(function () {
element.transform = currentTargetTransform remaining-time
}, 0);
Which is possible, at least in theory, but has lots of little intricacies that could fail. For example, figuring out the time remaining in your animation would require solving the cubic equation which represents the easing function, something which isn't exactly trivial.
Of course, implementing a truly generic solution would be even more complicated and maybe even impossible (i.e if you wanted to support scale() and translate() animations with different durations, or different easing functions). However, that's not really something we have to worry about yet.
Of course, you could implement all of this with relative ease and having to handle relatively few browser quirks by just running the animation in JavaScript using requestAnimationFrame with a setTimeout fallback. However, this would be really jerky and crappy on Android, since their built-in webkit browser STILL doesn't have support.