-
Notifications
You must be signed in to change notification settings - Fork 214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Animated Zoom #51
Comments
It sounds like something that's worth profiling - for example it might be that creating new DOM nodes for svg images is time consuming (in which case we could try an object pool) or it might be that we could spread the transition from one layer to the next over a couple of frames. Do you have a test case with setTimeout animation already that we could use for benchmarking? If you share your code as a gist on github we can run it with Mike Bostock's http://bl.ocks.org - e.g. http://bl.ocks.org/600144 is my demo of smooth zooming that could benefit from some of the work you're proposing. |
My guess is the problem is software interpolation of images. We should push browser vendors to do better hardware acceleration of SVG. :) |
I couldn't get bl.ocks.org to work to display both my maps: http://media.benjaminthomas.org/polymaps-zooming/ That shows the issue. In the first map, which uses just stock polymaps.js, when I zoom in and out by double clicking (hold down shift to zoom out), the animation just isn't completely smooth. It is most apparent when you are zooming to a layer you have already zoomed to before. In the second map, I've added a new function to po.map called loadNewTiles. You pass true to it, and it'll load new tiles, pass false and polymaps will load no new tiles. Here's the gist for how it works: https://gist.github.com/789374 po.layer uses this attribute to decide whether or not to try and load in new tiles. My second map turns off new tile loading before doing the zoom animation. The resulting animation is very smooth and snappy on my computer. On my friends computer I don't notice much of a difference between the two maps, so not everyone needs this performance benefit. However, for those of us that do (and maybe on mobile?) it is a nice feature to have. Though, I don't know what effect this change would have on other parts of polymaps. All it affects right now is the Anyway, there's my test case. |
Thanks for following through with this. It's quite a big difference for me in Safari on a new MacBook Pro so it's not just mobile devices that would benefit... I'm sure we'll see lots more people pick up Polymaps this year so this kind of investigation will be very useful. I'd like to see how this affects mousewheel zooming and zooming out as well at some point. Perhaps we could think about allowing people to tune performance for themselves. I wonder if some sort of quality settings should be exposed, to favor animation over seamlessness for example. |
You can somewhat emulate this behavior by temporarily setting the layer's http://polymaps.org/docs/layer.html#zoom If you lock the layer's zoom level, it won't load any new tiles as you zoom in. Then when the animation completes you can reset the zoom constraint to null. This is a little bit different than preventing new tiles from loading, though it should be practically the same if the tiles are already displayed pre-animation. |
I'll have to try setting the layer's zoom attribute. That makes sense. Though, it'll still be a pain to have to loop through all the layers and do that to all of them. I'll try it out this weekend and see what affect it has on performance. |
I finally got around to checking this out (busy week) and setting the layer's That said, I've updated my comparison page: http://media.benjaminthomas.org/polymaps-zooming/ with this new technique. It works quite well for zooming in, but zooming out is still slowed down a little bit, from loading in the new tiles around the edge. My solution to that new issue would be to make it so you can tell it to load in new tiles around the edge before you do the animation. This would also be useful in the case of panning the map when you know ahead of time you are going to need more tiles. Basically, I think more control over how and when new tiles are loaded would really go a long ways to providing a really smooth, crisp UI. Any advice would be appreciated. I'm happy to work more on this (and will for my own personal project), but would love it if my contributions could be helpful to the greater polymaps community. So, if we could settle on an API, I'll make it happen. |
Alright, I didn't get any API suggestions so I had to be left to my own devices :) I've updated my comparison page (http://media.benjaminthomas.org/polymaps-zooming/) with a 4th option, which I have in my forked version (https://github.com/bentomas/polymaps). It adds to methods, one (1) to a layer to address this animation issue and another (2) to the map to address my issue about being able to run a layer method on all the current layers of the map.
You'll notice that the 4th map on the comparison page (the one with the features I just described) is just as snappy in both directions as my previous attempt, and snappier than the existing Polymaps options. |
Any thoughts on this? |
Hi Benjamin, Thanks for implementing the helpful comparison page so that we can evaluate the different options. I agree that the performance of smooth zooming can be dramatically improved. I'm inspired by your diymaps.com and would love to make this the default behavior for pan and zoom. It is nary impossible to get identical zoom behavior across browsers due to lack of standardization in mousewheel events, so analog zooming is often too slow or too fast. And analog zooming results in fractional zoom levels, reducing performances and introducing anti-aliasing artifacts. It looks like you implemented the scrolling behavior by using an invisible scrolling div overlay. Is this behavior more reliable than listening to mouseevents directly, and using Back on-topic, let's enumerate the (non-exclusive) options for improving performance of smooth zooming:
I expect that the highest performance penalty comes from #1. Fixing the I do like the idea that you can tell the layer to preload tiles that are off-screen, which might be useful for an animated pan & zoom (e.g., van Wijk's). However, preloading would typically be implemented as a hint to the layer, rather than a hard constraint. #3 is tempting; for example, you could set a -webkit-transform-3d on the entire map, and then get hardware acceleration for the zoom in and out. However, it'd be difficult to do that without disabling interaction during the zoom animation, as you'd want to make sure that the map understands that the coordinate space is changing during zoom. Also, I'd guess that setting the transform on the enclosing layer (the highest container) would not improve performance noticeably over simply updating the transforms on the individual tiles as we do now. So that leaves Or perhaps we have a way to pause the queue, so that Polymaps can swap in tiles from the cache, but cannot load new tiles from the server? That might be the simplest option, because it seems like the default behavior is just as fast as the optimized behavior, provided all the tiles are cached. |
Sorry, for taking so long to respond to this. About the panning on diymaps.com, I really like the way it works but it Right now it actually puts the map inside a div with scroll bars (and then Basically, add a 'panning' layer, that goes above the map tiles (or above any layers The one other idea I had was to use dispatchEvent Sorry, if none of that makes much sense, I've been thinking a lot about it, but As for this animation business, 3 thoughts:
In conclusion, |
Coincidentally, I played with using https://bugs.webkit.org/show_bug.cgi?id=29601 What I did what wait until I receive the first "mousewheel" event, then dispatch that to an invisible scroll area. Essentially something like this:
Then, after dispatching the event, look at So, once you have this normalization factor, then the wheelDelta should correspond exactly to the number of pixels that would be scrolled natively, and you can eliminate the extra scrollable containers. It's a pain in the butt, yes, but it appears to work 100% of the time, much more reliable than my speed-detection heuristic in Polymaps. Of course, you still have the handle nonstandard behavior in Opera, Firefox and presumably IE9. But at least those never had WebKit's bug so the interpretation of events is straightforward. |
I'm just posting to say I love this thread and I'm sorry I can't contribute more fully. Ben, I agree with Mike that your scrolling experiment is really informative and interesting and points the way for a more diverse post-Google-Maps world. I'm also glad you're pushing on some of the performance limits of polymaps and I think you're onto something with the tile lock. I'd urge you to profile the visibility calculations before optimizing around them though, I'm not convinced they'll be anywhere near as slow as DOM manipulation or loading/parsing images. (Sorry to be vague, but I did a lot of profiling in modestmaps js which does similar calculations and on modern browsers only 1 or 2ms typically elapse - I'd expect similar in polymaps). Perhaps time for some judicious use of Mike, I'm psyched that you're still trying to solve the mouse wheel normalization issues - and getting somewhere! Sorry I can only offer cheerleading at this time, but I hope it's better than nothing! |
RE: panning with the scroll wheel I have a new version of my scrolling library out: https://github.com/bentomas/smooth-scrolling I looked into the stuff you mentioned you had done with dispatchEvent, and was impressed by how well using dispatchEvent worked in webkit. No extra elements, and as smooth as pie! However, I found using it to normalize the wheelDeltaX didn't produce a reliable normalization factor (though I'm not sure if was doing it in exactly the same way you were). I also didn't like that I was checking for the existence of a bug though, and since just dispatching the event seems to work great left it at that. Firefox can't handle dispatchEvent but its MozMousePixelScroll event does everything we need it to. So, I just use that. But fall back to DOMMouseScroll if that event isn't available. IE and Opera both can't handle horizontal scrolls, so they just scroll vertically. Which is technically a regression over the previous version, where it could scroll any direction you could make it with a scroll wheel. But I figured smooth and simple scrolling in Firefox, Chrome, Safari outweighed that. So, now my map panning is a lot simpler. And doesn't involve embedding the map inside two divs and such. I made a polymaps layer which does all this, called wheelPan. So it can work seamlessly with polymaps and not depend on an external library. I'll send a pull request over right after I comment this. |
Hi – for future googlers, this issue appears to be resolved by the |
I'd really love to be able to do an animated zoom on a polymap. I feel like it produces a less jarring user experience. This isn't hard to do currently with a setTimeout/setInterval and the map.zoom function.
However, I notice a very consisten lag right when the zoom switches from one level to another. Funnily enough, this only happens when the tiles for the new zoom level have already been loaded. So, I think trying to switch the tiles while the zoom is going on just takes too much processing power that it can't keep the animation smooth. If it is still loading the tiles then it doesn't have to do that and the animation looks great.
Is there anyway to get a built in animated zoom or to be able to delay/pause swapping in new tiles? The later would be useful for other kinds of animations, too, where you want to make sure the animation is as smooth as possible.
The text was updated successfully, but these errors were encountered: