2

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.

4
  • Magical suggestion: kick the GPU to re-render the SVG at the new scale, by adding a CSS class that has a non-GPU renderable style to your SVG and then flipping the class on and off post zoom might do it for you. Commented Mar 12, 2014 at 1:13
  • I discovered something interesting. It looks like the problem I'm having won't be solved with GPU rendering, it is caused by it. In my simple test, if I switch all of the transform parameters from the 3D versions to the 2D versions, things stay sharp. Then I was able to use 3D while zooming, then switch to 2D when the transform ended. This worked consistently for me on all platforms. Now I need to see if I can use this to come up with a real solution. If so and if I don't get other responses, I will use this to answer my own question. Thanks Michael for your comment.
    – JSwartzen
    Commented Mar 12, 2014 at 14:40
  • yes it's definitely caused by GPU rendering. The GPU simply scales the texture that it's rendered rather than re-rendering it. So you have to kick the GPU to re-render - or do something that keeps the rendering on the CPU (slower, but non-pixelated) Commented Mar 12, 2014 at 16:13
  • I was unable to figure out a way to kick the GPU that worked on iOS or Android tablets. I could do it on Chrome under windows, but adding or removing TranslateZ or RotateZ transform attributes didn't make a difference for me on the tablets. I finally decided to just turn off GPU transforms in the iScroll library and this is working reasonably well for me.
    – JSwartzen
    Commented Apr 7, 2014 at 13:45

1 Answer 1

1

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.