SVG clipPath on multiple elements use in different places

Until recently, the following SVG code rendered correctly in Firefox (v25) however it was (v33). All other browsers I've tested (Chrome 33, Safari 6, IE 10).

http://jsfiddle.net/9btoveeL/

<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="1000px" width="1000px" y="0px" x="0px" version="1.1">
<defs>
    <clipPath id="clip1">
        <rect height="100" width="10" y="0" x="0"/>
    </clipPath>
    <clipPath id="clip2">
        <rect height="100" width="10" y="0" x="10"/>
    </clipPath>
    <clipPath id="clip3">
        <rect height="100" width="10" y="0" x="20"/>
    </clipPath>
    <symbol id="fill_texture">
        <g>
            <rect height="10" width="10" x="0" y="0" fill="#ff0000"/>
            <rect height="10" width="10" x="3" y="5" fill="#0ff000"/>
            <rect height="10" width="10" x="6" y="10" fill="#0000ff"/>
            <rect height="10" width="10" x="9" y="15" fill="#ffff00"/>
            <rect height="10" width="10" x="12" y="20" fill="#ff00ff"/>
            <rect height="10" width="10" x="15" y="25" fill="#00ffff"/>
        </g> 
    </symbol>
</defs>
<g id="columns">
    <use id="unclipped" xlink:href="#fill_texture" width="100" height="100" x="0" y="0"/>


    <use id="slot1" xlink:href="#fill_texture" clip-path="url(#clip1)" x="50" y="0"/>
    <use id="slot2" xlink:href="#fill_texture" clip-path="url(#clip2)" x="100" y="0"/>
    <use id="slot3" xlink:href="#fill_texture" clip-path="url(#clip3)" x="150" y="0"/>
</g>    
</svg>

      

What I am trying to do is cut the prepared symbol into three parts and then use those three parts where I like. In Firefox 33, it appears to be using the clip at its original location (0.0 or 0.10 in my example), while other browsers and previous versions of Firefox apply the clip starting at the top-left corner of the element use

to apply to it. If each clip path needs to be moved according to location use

instead of relative to it, I don't see how the clip can be reused across multiple elements.

+3


source to share


1 answer


The default clipping path position is calculated in the custom coordinate system of the object it is applied to ( clipPathUnits="userSpaceOnUse"

).

(You can set it to clipPathUnits="objectBoundingBox"

, but then you will have to override all the lengths of the shapes in the clipping paths relative to the height and width of the cropped shape.)

There is a simple solution to always get the desired effect: transform the coordinate system for the elements of use. Instead of positioning them with attributes x

and y

, place them with attribute transform="translate(x,y)"

. So the coordinate system used to position the clipping path will move with them.

Here your violin has been updated to show the change . It is repeated below as a stack fragment and should work as expected in all browsers.

<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" 
     xml:space="preserve" version="1.1"
     height="100px" width="400px" y="0px" x="0px" >
<defs>
	<clipPath id="clip1" >
		<rect height="100" width="10" y="0" x="0"/>
	</clipPath>
	<clipPath id="clip2">
		<rect height="100" width="10" y="0" x="10"/>
	</clipPath>
	<clipPath id="clip3">
		<rect height="100" width="10" y="0" x="20"/>
	</clipPath>
	<symbol id="fill_texture">
		<g>
			<rect height="10" width="10" x="0" y="0" fill="#ff0000"/>
			<rect height="10" width="10" x="3" y="5" fill="#0ff000"/>
			<rect height="10" width="10" x="6" y="10" fill="#0000ff"/>
			<rect height="10" width="10" x="9" y="15" fill="#ffff00"/>
			<rect height="10" width="10" x="12" y="20" fill="#ff00ff"/>
			<rect height="10" width="10" x="15" y="25" fill="#00ffff"/>
		</g> 
	</symbol>
</defs>
<g id="columns">
	<use id="unclipped" xlink:href="#fill_texture"  
         width="100" height="100" x="0" y="0"/>
	
	
	<use id="slot1" xlink:href="#fill_texture" clip-path="url(#clip1)"  
         transform="translate(50,0)"/>
	<use id="slot2" xlink:href="#fill_texture" clip-path="url(#clip2)" 
         transform="translate(100,0)"/>
	<use id="slot3" xlink:href="#fill_texture" clip-path="url(#clip3)"   
         transform="translate(150,0)"/>
</g>	
</svg>

    
      

Run codeHide result



So what should happen if you use x

and y

instead transform

? It's hard to say because there is inconsistency in the specifications.



The Firefox implementation (v33) makes sense in the logical application of clipping path rules. When you <use>

a <symbol>

, you create a new coordinate space for the content inside the symbol, but the using element is still in the original coordinate space. And since it is the use item that is being clipped, it is the coordinate that matters to match the clipping path. A use element with an x โ€‹โ€‹coordinate of 50 or more will always be outside the clipping paths that you don't pass x = 30.

But why, why do other browsers position the clipping path origin at the <use>

(x, y) element instead of the system origin? This is because of the way the spec defines how x

it y

should be implemented
: as an additional transformation added to the grouping element that also has all the other attributes and styles (including clip-path

) that you point to <use>

.

According to the specs, the following code:

<use xlink:href="#content" clip-path="url(#clip)" 
     x="50" y="100" width="50" height="100" />

      

The rendering is supposed to be

(assuming "content" is <symbol>

) just like:

<g clip-path="url(#clip)" transform="translate(50,100)">
    <svg width="50" height="100" <!--viewBox and other attributes from the symbol--> >
       <!-- graphics from symbol#content go here -->
    </svg>
</g>

      

and under that view, the clipping path must be mapped to match the attribute transform

.

However, this is completely different from what would happen if you used <image>

, or <rect>

instead of <use>

, but with the same x

, y

, width

, height

and clip-path

. For these other elements, x

and y

only define positions in the original coordinate system, not coordinate system transformations, so they change the origin of the clipping path. This is why I would call it an unfortunate inconsistency in the specifications.

+5


source







All Articles