SVG pattern repeating from set location - svg

i have an pattern that i repeat in a rectangle. By default it start at the top left of the rectangle and flows across. Instead of starting the first pattern at the top left is it possible to start it from say the middle and work outwards from that point?
Cheers
Luke

You can translate a pattern using a patternTransform e.g.
<svg>
<defs>
<pattern id="pattern1"
x="10" y="10" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
<pattern id="pattern2"
x="10" y="10" width="20" height="20"
patternTransform="translate(2, 5)" patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="10" y="10" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="140" y="10" width="100" height="100"
style="stroke: #000000; fill: url(#pattern2);" />
</svg>

Related

Is it possible to center align <rect>'s inside a <g> for SVG?

Is it possible to vertically center align all the rects inside a tag without having to adjust the y attributes on <rect>? (see snippet for example)
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3/org/1999/xlink" viewBox="0 0 225 38" preserveAspectRatio="none" width="100%" height="100%">
<g fill="black">
<rect x="10" y="1" width="6" height="5" />
<rect x="20" y="1" width="6" height="10" />
<rect x="30" y="1" width="6" height="20" />
<rect x="40" y="1" width="6" height="5" />
<rect x="50" y="1" width="6" height="15" />
</g>
</svg>
<h3>desired result</h3>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3/org/1999/xlink" viewBox="0 0 225 38" preserveAspectRatio="none" width="100%" height="100%">
<g fill="black">
<rect x="10" y="8" width="6" height="5" />
<rect x="20" y="6" width="6" height="10" />
<rect x="30" y="1" width="6" height="20" />
<rect x="40" y="8" width="6" height="5" />
<rect x="50" y="4" width="6" height="15" />
</g>
</svg>
No, it's not possible to center align <rect> elements.
But it is possible to center-align <line> elements and give them a stroke-width (note the viewBox is vertically centered around 0):
<svg viewBox="0 -19 225 38" width="100%" height="100%">
<g stroke="black">
<line x1="10" x2="16" stroke-width="5" />
<line x1="20" x2="26" stroke-width="10" />
<line x1="30" x2="36" stroke-width="20" />
<line x1="40" x2="46" stroke-width="5" />
<line x1="50" x2="56" stroke-width="15" />
</g>
</svg>
You could also achieve vertically centered <rect> elements by setting a transform: translate(0, -50%) css rule.
This approach also requires a transform-box: fill-box; (or content-box) property.
All <rect>elements get a y="50%" attribute to start at the vertical center of the svg viewBox.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3/org/1999/xlink" viewBox="0 0 225 38" width="100%" height="100%" style="border:1px solid #ccc">
<style>
rect {
transform: translate(0, -50%);
transform-origin: center;
transform-box: fill-box;
}
</style>
<g fill="black" >
<rect x="10" y="50%" width="6" height="5" />
<rect x="20" y="50%" width="6" height="10" />
<rect x="30" y="50%" width="6" height="20" />
<rect x="40" y="50%" width="6" height="5" />
<rect x="50" y="50%" width="6" height="15" />
</g>
</svg>
Browser support for transform-box is decent. (See caniuse).
However, if you need legacy browser (e.g. ie11) support, #ccprog's answer is a more robust solution.

How to create an SVG icon consisting of two overlapping shapes, one with a hole?

I have made a progress bar icon from two partially overlapping SVG shapes.
I would like the icon to have the same color as the surrounding text, so I set stroke and fill to currentColor.
The icon is displayed correctly if the color of the surrounding text doesn't have alpha channel e.g. color: black. However, if the color of the surrounding text has alpha channel e.g. color: rgba (0, 0, 0, 0.7), then the icon is darker where the shapes overlap.
How can I get the same color at each point of the icon?
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" fill="currentColor" />
</svg>
Question Prevent overlapping figures with alpha channel from shading each other? is very similar, but the accepted answer doesn't work in this case:
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<defs>
<clipPath id="myClip">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="black" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" />
</clipPath>
</defs>
<rect width="100%" height="100%" fill="currentColor" clip-path="url(#myClip)"/>
</svg>
Update:
I decided to draw the icon without overlapping parts, because it is much easier and it also looks good:
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="4" y="4" width="23" height="7" rx="2" ry="2" fill="currentColor" />
</svg>
One solution is to user a mask. But if you don't change the geometry, you will get the same issue as with #InvisibleGorilla's solution: you will get antialiasing artifacts.
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<defs>
<mask id="cutout">
<rect width="100%" height="100%" fill="white" />
<use xlink:href="#bar" fill="black" />
</mask>
<rect id="bar" x="2" y="2.5" width="24" height="10" />
</defs>
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent"
mask="url(#cutout)" />
<use xlink:href="#bar" fill="currentColor" />
</svg>
To fix the antialiasing artifacts, move your bar so that it is positioned at a whole pixel (y="2") instead of a half pixel (y="2.5"). You still might still see very slight artifacts at some scales. But it should be a lot better.
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<defs>
<mask id="cutout">
<rect width="100%" height="100%" fill="white" />
<use xlink:href="#bar" fill="black" />
</mask>
<rect id="bar" x="2" y="2" width="24" height="10" />
</defs>
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent"
mask="url(#cutout)" />
<use xlink:href="#bar" fill="currentColor" />
</svg>
Before the rect where fill has currentColor, add a rect with the exact same attributes but with a white fill directly before it (so that it gets drawn underneath it in the svg).
See snipped below:
<style>
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
</style>
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" fill="white" />
<rect x="2" y="2.5" width="24" height="10" fill="currentColor" />
</svg>
You could also change the order of your rects and add a matching white rect under the one where the stroke has currentColor.
Here's the updated snippet using background color and underlying both rects. I've tested on Chrome and Firefox on Mac and I don't see any lines from the background color rects.
<style>
body { background-color: #232b32; color: rgba(240, 240, 240, 0.7); }
</style>
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="#232b32" stroke-width="2" fill="transparent" />
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" fill="#232b32" />
<rect x="2" y="2.5" width="24" height="10" fill="currentColor" />
</svg>
<p>Some text</p>
Here's a screenshot of when I run this snippet.

How to apply svg pattern to different rectangles using objectBoundingBox coordinate system and keep aspect ratio?

I.e. in this code the pattern applied with gap between the tiles or overlaping.
<svg width="400" height="400">
<defs>
<pattern id="pattern1"
x="0" y="0" width="0.1" height="0.2"
patternUnits="objectBoundingBox"
>
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="10" y="10" width="170" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="10" y="110" width="235" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
</svg>
How to do that tiles were placed side by side and the last tile which is not fit in rectangle will be sliced?
You can't do what you want with objectBoundingBox units. You need to use patternUnits="userSpaceOnUse".
<svg width="400" height="400">
<defs>
<pattern id="pattern1" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="10" y="10" width="170" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="10" y="110" width="235" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
</svg>
But, as you can see, the default pattern origin is at the origin of the SVG document (the top left). To change that so that the pattern is aligned with the rectangles, you'll need to define the rectangles at the origin and move them into position with a transform.
<svg width="400" height="400">
<defs>
<pattern id="pattern1" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="0" y="0" width="170" height="100" transform="translate(10,10)"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="0" y="0" width="235" height="100" transform="translate(10,110)"
style="stroke: #000000; fill: url(#pattern1);" />
</svg>

How to properly use patternContentUnits="objectBoundingBox" for svg element?

I want to apply a pattern to a few svg elements, the pattern should apply from the (0,0) point for each element.
First I try code like this
<svg width="400" height="400">
<defs>
<pattern id="pattern1"
x="0" y="0" width="25" height="25"
patternUnits="userSpaceOnUse"
>
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="10" y="10" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="110" y="17" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="210" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="0" y="110" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
</svg>
The issue in this example is that the pattern for each element starts from the (0,0) point of the svg document not of each element.
Ok, lets try (setting the patternUnits="objectBoundingBox" attribute to the pattern definition so that the coordinate system for the pattern starts from the (0,0) point of each element)[https://jsfiddle.net/gwrgd1wf/1/]
The Coordinate system start point is changed as I want it, but the pattern has stopped tiling and the width and height attribute of pattern stop working properly. You can see I set height="2", but it does not change the height of the pattern.
So my question is how to properly use the patternUnits="objectBoundingBox" attribute?
In objectBoundingBox units 1 unit is the size of the shape so if you write 2 that means the pattern is 2 times the size of the shape so 1/2 the pattern fills the shape and you get no tiling.
If you want tiling you'll need to make the pattern smaller than the shape e.g. with 0.2 you'll get 5 circles displayed. E.g.
<svg width="400" height="400">
<defs>
<pattern id="pattern1"
x="0" y="0" width="0.2" height="0.2"
patternUnits="objectBoundingBox"
>
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="10" y="10" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="110" y="17" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="210" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="0" y="110" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
</svg>

Imagemagick svg conversion

I have a svg file which I want to be converted into jpg/png. Probem is that conversion is fine if there is no background image. But when I try to put some background image its not being rendered in the converted image and showing plain background color.
content of svg:
<svg height="370" version="1.1" width="350" xmlns="http://www.w3.org/2000/svg" style="overflow: hidden; position: relative; left: -0.5px;">
<defs>
<pattern id="38A07B9C-47E8-4E02-A005-E6E4443FE5D0" x="0" y="0" patternUnits="userSpaceOnUse" height="300" width="300" patternTransform="matrix(1,0,0,1,0,0) translate(0,20)">
<image x="0" y="0" href="/home/mahad/public_html/svg/user-backgrounds/4f41f6a2a75dc_back.png" width="300" height="300"/>
</pattern>
</defs>
<rect x="0" y="0" width="350" height="370" r="0" rx="0" ry="0" fill="#ffffff" stroke="none" style=""/>
<rect x="0" y="20" width="350" height="350" r="0" rx="0" ry="0" fill="url(#38A07B9C-47E8-4E02-A005-E6E4443FE5D0)" stroke="none" style="fill: url("#38A07B9C-47E8-4E02-A005-E6E4443FE5D0") rgb(0, 0, 0); opacity: 0.38;" opacity="0.38"/>
<rect x="0" y="20" width="14" height="14" r="0" rx="0" ry="0" fill="#000000" stroke="none" style=""/>
<text style="text-anchor: middle; font: 12px "Arial"; opacity: 1;" x="100" y="100" text-anchor="middle" font="10px "Arial"" stroke="none" fill="#ff0000" font-size="12px" opacity="1" transform="matrix(1,0,0,1,73,92)">
<tspan dy="4.5">helllloooo...</tspan>
</text>
</svg>
conversion command:
echo exec("/usr/bin/convert /home/public_html/qr.svg /home/public_html/qr.png");
please help
In my case, installing librsvg2-bin fixed the problem:
sudo apt-get install librsvg2-bin

Resources