user2587132
user2587132

Reputation:

SVG border appears trimmed


I think I am missing an apparent offset issue in my very first svg here, The top and left borders are tirmmed (pointed by red arrow), Also if something like nested <g> or <symbol> is possible pleas let me know, Thanks. (screenshot in FF27)

.

enter image description here

The simplified code and a fiddle

<svg>
    <defs>
        <symbol id="ringCenters" style="fill:black;">
            <circle cx="50" cy="50" r="2" />
            /*...more circles*/
        </symbol>
        <symbol id="ring1" class="rings">
            <path d="M99.9746,51.5943 
                     A50 50 0 1 0 
                     62.5254,98.4057" 
                     stroke="green" />
            <path d="M99.9746,51.5943 
                     A50 50 0 0 1 
                     62.5254,98.4057" 
                     stroke="red" />
        </symbol>
        /*...more rings*/
    </defs>
    <use xlink:href="#ringCenters" x="10" y="10" />
    /*...more rings*/
</svg>


.rings{fill:none;}

svg {
    width:600px;
    height:300px;
}

Upvotes: 4

Views: 992

Answers (2)

AmeliaBR
AmeliaBR

Reputation: 27544

The stroke around a shape is always centered on the exact geometric border of the shape, and so extends beyond the shape by half the stroke width.

If for any reason you don't want to use overflow:visible, another option is therefore to just adjust the positions of your shape so that you have a bit of padding on the edges, equal to half the stroke width. (Of course, that assumes that the stroke-width will be the same every time you use the symbol.)

Note that you have to adjust the position of the <path> within the <symbol>, not just the position of the <symbol> within your SVG. That's because each reference to a symbol element is drawn as if it was a nested <svg> element within it's own viewport, with a fixed height, width, and "viewBox" coordinate system. You're not setting those attributes on the symbol, so they end up as the defaults for nested SVGs: width and height equal to 100% of the parent, and a default coordinate system with (0,0) at the top left corner of the viewport.

That "nested SVG" then gets positioned so that it's top left corner is at the (x,y) position specified in the <use> element, but as far as the drawing content within the symbol is concerned, the rectangular edges of that viewport are the edges of the drawing surface. Unless, of course, you specifically allow overflow, as @helderdarocha suggested.

(By the way, the symbols-are-drawn-as-nested-SVGs idea is probably why you needed to specify svg{ overflow:visible;} for Firefox, although it really should work by setting the property on the symbols directly; I'd call that a Firefox bug.)

On your other question: <g> elements can be nested multiple times without problem. For <symbol> elements, it's not so clear. The specs say that symbols are much like <g> elements except (a) they have viewports and (b) the symbol is not drawn directly, it is only available for reference by a <use> element.

Now, that suggests that <symbol>s can be nested like <g> elements. And on Chrome it works. On Firefox, not so much. I assume what is happening is that when Firefox copies the internal content of the outer <symbol>, it treats the internal <symbol> elements as if they were just symbol definitions, not as if they were renderings of those symbols.

I.e. code like this

<svg>
  <defs>
    <symbol id="complicated">
       <symbol id="firstPart">
            <path d="...."/>
       </symbol>
       <symbol id="secondPart">
            <path d="...."/>
       </symbol>
    </symbol>
  </defs>
  <use xlink:href="#complicated"/>
</svg>

Gets rendered as if it was

<svg>
  <defs>
    <symbol id="complicated">
       <symbol id="firstPart">
            <path d="...."/>
       </symbol>
       <symbol id="secondPart">
            <path d="...."/>
       </symbol>
    </symbol>
  </defs>
  <g> <!-- The <use> element is drawn as if it was a <g> element -->
     <svg> <!-- The <symbol> element is drawn as if it was a nested <svg> -->
       <symbol id="firstPart"> <!-- the internal symbol is copied as-is -->
            <path d="...."/>
       </symbol>
       <symbol id="secondPart"> <!-- but symbols aren't drawn directly! -->
            <path d="...."/>
       </symbol>
    <svg>
  </g>
</svg>

...and that shouldn't really be rendered as anything at all. This, I wouldn't call a Firefox "bug", just a literal interpretation of the specs, which don't give any special treatment to nested symbol elements.

There is a way to get symbols to nest, however, and that's to use <use> elements within the symbol definition:

<svg>
  <defs>
    <symbol id="firstPart">
        <path d="...."/>
    </symbol>
    <symbol id="secondPart">
        <path d="...."/>
    </symbol>
    <symbol id="complicated">
        <use xlink:href="#firstPart"/>
        <use xlink:href="#secondPart"/>
    </symbol>
  </defs>
  <use xlink:href="#complicated"/>
</svg>

Here's your fiddle updated with that structure: http://jsfiddle.net/vGNMu/6/

Upvotes: 4

helderdarocha
helderdarocha

Reputation: 23637

Half of your stroke is outside the viewBox. You can avoid clipping by using:

svg, symbol {
    overflow: visible;
}

Or adding an overflow="visible" attribute to each symbol.

Your updated JSFiddle

Upvotes: 3

Related Questions