Wednesday, May 28, 2014

SVG Viewports: Who Knew?


Today could be a very important day for me. It could be the last time that I ever blog about SVG and clipping. It's either that or today is the day that I start a new chain supporting a book entitled “SVG Clipping and You.” I'm really hoping for the former.

Two days ago I blogged what I hoped at the time would be my last ever SVG clipping post. In it, I essentially gave up trying to get clipping working and instead implemented a workaround in which I used the view port that SVG gave me instead of hoping for more. And then Emanuele Sabetta added a comment to that post potentially identifying what I was doing wrong.

The problem remains that I cannot translate the SVG toppings in my <x-pizza> pizza building Polymer element. Well, I can translate them, but they are mysteriously clipped if I stray too far:



I tried overflow and clip properties on those SVG elements, but to no avail. The SVG images were always clipped when moved too far. The “pepperoni” images are sized initially to 32×32 in the asset:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   version="1.1"
   width="32"
   height="32">
  <path
      d="M 22,12 A 10,10 0 1 1 2,12 10,10 0 1 1 22,12 z"
      style="fill:#d40000;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</svg>
From what I glean from Emanuele's comments, I may not even be getting 32×32 for the viewport. Rather, I may only be getting 22×22 from the drawing area (plus a little from the stroke and filter). Anyhow, to test the viewport, I start the SVG 16 pixels to the right, which should be outside the default viewport regardless if it is 32×32 or slightly smaller:
    var path = svg.query('path')
      ..setAttribute('transform', 'translate(16,0)');
And indeed, it is clipped by the viewport:



Now, I apply a viewport. I am going to define the viewport such that it is definitely larger than 32×32 initial size so that it ought to fit my translated image. 48×48 ought to do:
    svg.query('svg')
      ..setAttribute('viewBox', '0 0 48 48');
And indeed it does the trick. The pepperoni images are no longer clipped:



It is no longer clipped, but the images are now scaled smaller. The reason that they are smaller is that I am squishing a 48×48 viewport into a 32×32 sized image. If I change the width and height attributes on the SVG image to match the viewport:
    svg.query('svg')
      ..setAttribute('viewBox', '0 0 48 48')
      ..setAttribute('width', '48')
      ..setAttribute('height', '48');
Then I have my pepperonis translated 16 pixels, still in the viewport, and not scaled:



So the mystery of the clipping seems to be solved (thanks yet again to Emanuele!).

Before calling it a night, I note that this viewport stuff is really non-obvious in browsers. Even with the viewport set to 48×48 and the SVG image set to 48×48, the browser reports the size of the drawing to be just the drawing:



The group element that holds the translated SVG asset does have appropriately large dimensions:



But the dimensions are exactly as they were prior to fiddling with the viewport:



In other words, there is no indication whatsoever that the viewport is at play here, which is what led me down the ill-fated clip and overflow path.

Thankfully, I can rely on the kindness of others to educate me when I go wrong. Thanks again, Emanuele.

Up tomorrow: I get back to a little pure Polymer code as I prep for the actual Patterns in Polymer screencasts.


Day #77

No comments:

Post a Comment