Scaling SVG rect on hover using CSS transform - css

It seems that applying the same CSS transform on hover to an HTML or SVG element does not create the same effect. As you can see in the following fiddle, the p and rect do not behave the same way while scaling, and that is precisely my problem.
http://jsfiddle.net/rKD7T/2/
How could I make the rect behave exactly as the p and scale properly?
I tried scaling the rect with a matrix - taking into account the origin point - but it did not seem to work either, or I did it wrong.
I'd like to stick to CSS solutions here but JS ones might also be an option.
Thanks for your help.

This seems about right.
<div>
<p></p>
<p></p>
<p></p>
<p></p>
</div>
<svg>
<g transform="translate(20, 40)">
<rect x="-20" y="-40" width="50" height="100"/>
<g transform="translate(55, 0)" >
<rect x="-20" y="-40" width="50" height="100"/>
</g>
<g transform="translate(110, 0)" >
<rect x="-20" y="-40" width="50" height="100"/>
</g>
<g transform="translate(165, 0)" >
<rect x="-20" y="-40" width="50" height="100"/>
</g>
</g>
</svg>
It works in Firefox trunk but doesn't seem to work with Firefox 16. I haven't tested Firefox Beta or Aurora to see in exactly when it's fixed.

Related

Rotate svg text around central text position using css

I want to apply a single css rotation transformation to a set of elements in an SVG, such that each element is rotated independently, without having to calculate the centre of each element in the css. For example, I have an SVG that looks like the picture on the left, and want to apply css to achieve the effect on the right
I'm writing the svg myself, and am creating something like this
<svg baseProfile="full" height="200" version="1.1" width="200" xmlns="http://www.w3.org/2000/svg">
<text transform="translate(50 100)" text-anchor="middle">Text 1</text>
<text transform="translate(100 100)" text-anchor="middle">Text 2</text>
</svg>
When I apply a css rotation, e.g. by inserting <style>text {transform: rotate(10deg)}</style>, it seems to overwrite the first transformation, and the rotated text is placed in the top left corner:
I can modify the svg to use `x="X" y="Y" instead of a transform attribute, but that results in the transformation being applied around a different centre instead:
<svg baseProfile="full" height="200" version="1.1" width="200" xmlns="http://www.w3.org/2000/svg">
<style>text {transform: rotate(10deg)}</style>
<text x="50" y="100" text-anchor="middle">Text 1</text>
<text x="100" y="100" text-anchor="middle">Text 2</text>
</svg>
How can I structure the svg so that I can apply a rotation which works independently on each element without overwriting the initial transform?
This is a possible solution:
-The text has x="0" y="0" and is rotated with CSS.
-You put the text in the <defs>.
-You use the text and the <use> element has the x and y values you need.
text{transform:rotate(90deg)}
<svg baseProfile="full" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<text id="a" text-anchor="middle" >Text 1</text>
<text id="b" text-anchor="middle" >Text 2</text>
</defs>
<use xlink:href="#a" x="50" y="50" />
<use xlink:href="#b" x="100" y="50" />
</svg>
Yet another solution (inspired by the comment of Robert Longson) would wrapping the rotated text in a g element and translate the g
text{transform:rotate(90deg)}
<svg baseProfile="full" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(50,50)"><text text-anchor="middle" >Text 1</text></g>
<g transform="translate(100,50)"><text text-anchor="middle" >Text 2</text></g>
</svg>

svg - keep fill texture original size when resizing a path

I define a svg <pattern> like this:
<svg height="10" width="10" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<pattern id="circles-1_4" patternUnits="userSpaceOnUse" width="10" height="10">
<image xlink:href="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxMHB4IiBoZWlnaHQ9IjEwcHgiIHZpZXdCb3g9IjAgMCAxMCAxMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTAgMTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxjaXJjbGUgY3g9IjEuMjUiIGN5PSIxLjI1IiByPSIxLjI1Ii8+PHJlY3QgZmlsbD0ibm9uZSIgd2lkdGg9IjEwIiBoZWlnaHQ9IjEwIi8+PC9zdmc+"
x="0" y="0" width="10" height="10">
</image>
</pattern>
</defs>
</svg>
visually, this is the equivalent of this:
So then I call my css for svg as a fill like this:
svg #VISUEL-3 * {fill: url(#circles-1);}
I get a pretty good result:
But when I display my graphic smaller (1/4 in this i.e), the fill adapt like this
It's difficult to see on the screenshots because the scale is broken due to the width 100% of stackoverflow but the vector-effect:non-scaling-stroke works perfectly so the strokes have the same size between the first and the second screenshot and the number "1,2,3,4,5,6" as well.
So as you can see the fill has adapted...
Is it possible to keep the same pattern size (same size of dots) like in css? That look messy visually when I have two graphics that are not of the same size and are next to each other.
Is my method right to obtain that? (I'm ready to change my method..)
The pattern elements are applied to the referencing element before transformations on the element or one of its parents are applied - so the pattern size gets transformed as well. The only way to counteract this is to write a seperate pattern element for each scale you us it at, including a patternTransform with the inverse scale. Fortunately, there is a mechanism for cloning patterns with a xlink:href attribute.
.simple {
fill: url(#dots);
}
.quarter {
fill: url(#quadrupleDots);
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="150">
<defs>
<pattern id="dots" patternUnits="userSpaceOnUse" width="10" height="10">
<circle r="1.25" cx="1.25" cy="1.25" />
</pattern>
<pattern id="quadrupleDots" xlink:href="#dots" patternTransform="scale(4)" />
</defs>
<rect id="shape" class="simple" x="20" y="20" width="100" height="100" />
<rect class="quarter" x="800" y="80" width="100" height="100" transform="scale(0.25)" />
</svg>

Image clip to text

How can I clip an image to text? I would prefer a method that is available in any browser. I tried background-clip but it not available in all modern browsers.
Add a clip-path to an image and you'll see a clipped image.
I've made it look more like your example by adding an additional copy of the image with low opacity behind the clipped image.
<svg width="100%" height="100%">
<defs>
<clipPath id="sample" clipPathUnits="userSpaceOnUse">
<text x="85" y="330" font-family="sans-serif" font-size="380" font-weight="bold">I CAM</text>
</clipPath>
</defs>
<image transform="scale(0.4)" xlink:href="http://netghost.narod.ru/gff/sample/images/png/marble24.png" x="20" y="20" width="1419" height="1001" opacity="0.3" />
<image transform="scale(0.4)" xlink:href="http://netghost.narod.ru/gff/sample/images/png/marble24.png" x="20" y="20" width="1419" height="1001" clip-path="url(#sample)" />
</svg>

How do I use svg patterns in a cross browser consistent way?

I want a SVG image (prerendered, but inserted with js in an svg tag, to allow for some further manipulation) to be able to use a predefined pattern, using the "pattern" tag. Sounds simple enough, doesn't it? Well, turns out Chrome (Webkit?) behaves a bit different from any other browsers, and now I'm not sure what the best way would actually be to achieve this.
My svg looks like this:
<svg>
<defs>
<pattern id="specialPattern">...</pattern>
</defs>
<path class="special"></path>
</svg>
and I want paths with the class special to have "pattern" as fill.
Attempt one: Works in Chrome, not in FF or Opera
My first attempt was to simply put this in my css:
.special { fill:url("#specialPattern");}
This actually works in Chrome, though when you think about it, it probably shouldn't. The other browsers I tried interpret this url as relative to the file it's in (the css file), which makes more sense.
Attempt two: Works in FF and Opera, not in Chrome
Next attempt: Provide an absolute url to the pattern.
.special { fill:url("//example.com/styles/svgWithStyleDeclaration.svg#specialPattern");}
While this works as expected in FF and Opera, Chrome now resets the fill instead (I have no idea where it is actually looking for that style)
Attempt three: Works, kind of
Inlining the style in the SVG works everywhere it seems: style="fill:url('#specialPattern')"
And though I guess this is a case where the lines between content and presentation is blurred, in my case at least it would be much better to keep style decclarations elsewhere (not least because this would make my SVG need to be much bigger)
Attempt four: Works (?) but dirty
I haven't tested a lot of browsers, so I'm not sure about how water proof it is, but it seems to me like using a css hack to detect webkit browsers would work:
#media screen and (-webkit-min-device-pixel-ratio:0) {
.special {fill: url("#specialPattern");}
}
.special { fill:url("//example.com/styles/svgWithStyleDeclaration.svg#specialPattern");}
Now, there MUST be a more elegant way to solve this. How should it be done?
Edit: Turns out that IE behaves like Chrome here, so you would also need to make sure IE<=9 has 'fill: url(#specialPattern)'
Here's a Fiddle that I did for manipulating patterns and masks. It's a ratings display in svg xml, in which I wanted to be able to use a percentage for the rating bar.
Fiddle: http://jsfiddle.net/cnLHE/296/
By changing the last line to "width="50", and pressing Run, you can see the rating bar resizes.
<svg width="100%" height="100%" viewBox="0 0 100 20" version="1.1">
<defs>
<pattern id="pattern1" x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="5" style="fill:white" />
</pattern>
<pattern id="pattern2" x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="9" style="fill:white" />
<circle cx="10" cy="10" r="7" style="fill:black" />
</pattern>
<mask id="mask1" x="0" y="0" width="100" height="20" >
<rect x="0" y="0" width="100" height="20"
style="stroke:none; fill: url(#pattern2)"/>
</mask>
<mask id="mask5" x="0" y="0" width="100" height="20" >
<rect x="0" y="0" width="100" height="20"
style="stroke:none; fill: url(#pattern1)"/>
</mask>
</defs>1<rect x="0" y="0" width="500" height="20" fill="url(#pattern2)" style="fill:#2498c7; mask: url(#mask1)"/>
<rect x="0" y="0" width="50" height="20" style="fill:#2498c7; mask: url(#mask5)"/>
</svg>
I didn't have any cross browser issues, BUT, I did have issues with the SVG disappearing intermittently in grid layouts. In webkit with multiple instances in page, they weren't always showing.
Further info available at css-tricks: http://css-tricks.com/using-svg/

Is it possible to use a background image on the stroke of an SVG element?

Just as the question asks - I'm trying to figure out whether or not it's possible to use some kind of pattern or repeated background image for the stroke of an SVG path.
Is this doable? Or are you limited to colors only?
TIA!
You can use a <pattern> as a stroke e.g.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="p1" patternUnits="userSpaceOnUse" width="32" height="32">
<image xlink:href="http://phrogz.net/tmp/alphaball-small.png" width="32" height="32" />
</pattern>
</defs>
<rect stroke-width="32" stroke="url(#p1)" width="200" height="200" fill="none"/>
</svg>
The pattern can contain <svg> drawing elements or (as here) an image, or both.
You can use the property stroke-dasharray for "patterns" in the stroke:
<line stroke-dasharray="5, 5" x1="10" y1="10" x2="190" y2="10" />
With this you can specify the length of strokes and gaps between. For some examples have a look at the MDN example page.

Resources