How to make this SVG pattern seamless? - svg

I'm trying to make a SVG pattern seamless but with no luck
https://codepen.io/unlocomqx/pen/LYzbbNp
Code
<svg viewBox="0 0 100 100" width="300" height="300">
<defs>
<pattern id="grid2" width="10pt" height="10pt" patternUnits="userSpaceOnUse">
<path d="M 0 0 L 0 10 10 10 10 0 0 0" fill="#f7f6f4" stroke="#DDD" stroke-width="0.5"/>
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#grid2)"></rect>
</svg>
When I change the size to 5pt instead of 10pt, it works well
<svg viewBox="0 0 100 100" width="300" height="300">
<defs>
<pattern id="grid1" width="5pt" height="5pt" patternUnits="userSpaceOnUse">
<path d="M 0 0 L 0 10 10 10 10 0 0 0" fill="#f7f6f4" stroke="#DDD" stroke-width="0.5"/>
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#grid1)"></rect>
</svg>
How to fix it for the 10pt case?

You're running into the problem here that you can still only use SVG's built-in userSpaceOnUse or objectBoundingBox units for paths, so you'll have to use a rect, which does support more unit types (like pts).
Not seamless
<svg viewBox="0 0 100 100" width="300" height="300">
<defs>
<pattern id="grid2" width="10pt" height="10pt" patternUnits="userSpaceOnUse">
<rect x="0pt" y="0pt" width="10pt" height="10pt" fill="#f7f6f4" stroke="#DDD" stroke-width="0.5"/>
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#grid2)"></rect>
</svg>
Seamless
<svg viewBox="0 0 100 100" width="300" height="300">
<defs>
<pattern id="grid1" width="5pt" height="5pt" patternUnits="userSpaceOnUse">
<path d="M 0 0 L 0 10 10 10 10 0 0 0" fill="#f7f6f4" stroke="#DDD" stroke-width="0.5"/>
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#grid1)"></rect>
</svg>

Related

How do I stop svg GaussianBlur from being clipped? [duplicate]

Why does the grid in this SVG not fill the entire 256x256 space? No matter what size I change it to, about 15% of the grid is cut off, which appears to me to be arbitrary in the context of my code.
<svg width="256" height="256" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="grid" width="18.75" height="18.75" patternUnits="userSpaceOnUse">
<path d="M 18.75 0 L 0 0 0 18.75" fill="none" stroke="black" stroke-width="1"/>
</pattern>
<rect id="gridRect" width="100%" height="100%" fill="url(#grid)" />
<filter id="gridify" width="100%" height="100%" filterUnits = "userSpaceOnUse">
<feImage result="sourceTwo" xlink:href="#gridRect" />
<feComposite in="SourceGraphic" in2="sourceTwo" operator="in"/>
</filter>
</defs>
<g filter="url(#gridify)" >
<rect width="100%" height="100%" fill="url(#linGradient)" />
</g>
<rect width="100%" height="100%" fill="none" stroke="black" stroke-width="1"/>
</svg>
The SVG specification defaults filters to being 10% larger than the filtered object by default.
If ‘x’ or ‘y’ is not specified, the effect is as if a value of -10% were specified.
If ‘width’ or ‘height’ is not specified, the effect is as if a value of 120% were specified.
I imagine that's to stop lots of questions along the lines of "why is my Gaussian blur based drop-shadow filter cut off?"
So, looks like all I needed to do to fix it was add an x="0" and a y="0" to the filter. I don't understand why it is necessary though, as it does not make sense that it would default to "-15%".
<svg width="256" height="256" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="grid" width="18.75" height="18.75" patternUnits="userSpaceOnUse">
<path d="M 18.75 0 L 0 0 0 18.75" fill="none" stroke="black" stroke-width="1"/>
</pattern>
<rect id="gridRect" width="100%" height="100%" fill="url(#grid)" />
<filter id="gridify" x="0" y="0" width="100%" height="100%" filterUnits = "userSpaceOnUse">
<feImage result="sourceTwo" xlink:href="#gridRect" />
<feComposite in="SourceGraphic" in2="sourceTwo" operator="in"/>
</filter>
</defs>
<g filter="url(#gridify)" >
<rect width="100%" height="100%" fill="url(#linGradient)" />
</g>
<rect width="100%" height="100%" fill="none" stroke="black" stroke-width="1"/>
</svg>

SVG GRID Transformation - Flip Horizontally

I need to flip this SVG Grid horizontally, because I'd like to drawing the grid from the top left corner, not the bottom left. If run the code, you'll see what's my problem. I need the full squares from the bottom left corner.
Here it is the code:
<svg width="80mm" height="50mm" viewBox="0 0 80 50" xmlns="http://www.w3.org/2000/svg">
<defs><pattern id="grid" width="3" height="3" patternUnits="userSpaceOnUse"><path d="M 3 0 L 0 0 0 3" fill="none" stroke="black" stroke-width="0.3"/></pattern></defs>
<rect x="0" y="0" width="80" height="50" style="fill:gray; stroke-width:0; stroke:black"/><rect x="0" y="0" width="80" height="50" fill="url(#grid)"/>
</svg>
You could simply rotate the whole thing by 180 degrees.
<svg width="80mm" height="50mm" viewBox="0 0 80 50" xmlns="http://www.w3.org/2000/svg">
<g transform="rotate(180 40 25)">
<defs><pattern id="grid" width="3" height="3" patternUnits="userSpaceOnUse"><path d="M 3 0 L 0 0 0 3" fill="none" stroke="black" stroke-width="0.3"/></pattern></defs>
<rect x="0" y="0" width="80" height="50" style="fill:gray; stroke-width:0; stroke:black"/><rect x="0" y="0" width="80" height="50" fill="url(#grid)"/>
</g>g>
</svg>

In nested SVG, inner icon is getting truncated

My challenge is to take two random svg icons and splice them together such that the inner one is located on the lower left quadrant of the overall image. Thanks to a previous answer I have a framework for doing this but the inner icon is getting truncated unless I make manual changes. I need to do this programmatically, so the question becomes, how do I know how large to make my B viewport, algorithmically speaking?
If this is Icon A:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0 0 100 100">
<rect width="100%" height="100%" style="fill:rgb(255,0,0);stroke-width:3; stroke:rgb(0,0,0)"
</svg>
This is a minimal but fairly accurate example of an Icon B:
<svg height="512pt" viewBox="-51 0 512 512.00253" width="512pt" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" style="fill:rgb(0,0,255);stroke-width:30; stroke:rgb(0,0,0)" />
</svg>
This is the framework for putting them together:
<svg viewBox="0 0 100 100">
<defs>
<symbol id="A" viewBox="0 0 100 100"> <!-- making viewbox of symbol A
match viewbox on contained
svg element, which works -->
%ENTIRE CONTENTS OF SVG A%
</symbol>
<symbol id="B" viewBox="51 0 512 512"> <!-- making viewbox of symbol B
match viewbox on contained
svg element, which truncates -->
%ENTIRE CONTENTS OF SVG B%
</symbol>
</defs>
<use xlink:href="#A" x="0" y="0" width="100" height="100" />
<use xlink:href="#B" x="0" y="50" width="50%" height="50%" />
</svg>
This is the current svg:
<svg viewBox="0 0 100 100">
<defs>
<symbol id="A" viewBox="0 0 100 100">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0 0 100 100">
<rect width="100%" height="100%" style="fill:rgb(255,0,0);stroke-width:3; stroke:rgb(0,0,0)"
</svg>
</symbol>
<symbol id="B" viewBox="51 0 512 512">
<svg height="512pt" viewBox="-51 0 512 512.00253" width="512pt" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" style="fill:rgb(0,0,255);stroke-width:30; stroke:rgb(0,0,0)" />
</svg>
</symbol>
</defs>
<use xlink:href="#A" x="0" y="0" width="100" height="100" />
<use xlink:href="#B" x="0" y="50" width="50%" height="50%" />
</svg>
Here's what that looks like. Note the truncation; that inner icon is getting chomped on the right and bottom.
I can manually tweak it like this, with the results below. But I can't do manual tweaking on these.
<svg viewBox="0 0 100 100">
<defs>
<symbol id="A" viewBox="0 0 100 100">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0 0 100 100">
<rect width="100%" height="100%" style="fill:rgb(255,0,0);stroke-width:3; stroke:rgb(0,0,0)"
</svg>
</symbol>
<!-- Note this pair of 680 values, and the 0 x-pos on the line below -->
<symbol id="B" viewBox="0 0 680 680">
<svg height="512pt" viewBox="0 0 512 512.00253" width="512pt" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" style="fill:rgb(0,0,255);stroke-width:30; stroke:rgb(0,0,0)" />
</svg>
</symbol>
</defs>
<use xlink:href="#A" x="0" y="0" width="100" height="100" />
<use xlink:href="#B" x="0" y="50" width="50%" height="50%" />
</svg>
Note the tweaked "680" h/w on the symbol B viewbox. (And also tweaking the viewbox on the inner svg to shift the X position to 0, which I'm really unhappy doing). That "680" number was determined experimentally, which would be fine only if this was a one-time deal and not something I need to make systematic. How do I know how big to make that viewbox programmatically?
Remove the width and the height attributes from the inner SVG
svg{width:90vh}
<svg viewBox="0 0 100 100">
<defs>
<symbol id="A" viewBox="0 0 100 100">
<svg viewBox="0 0 100 100">
<rect width="100%" height="100%" style="fill:rgb(255,0,0);stroke-width:3; stroke:rgb(0,0,0)" />
</svg>
</symbol>
<symbol id="B" viewBox="0 0 512 512">
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" style="fill:rgb(0,0,255);stroke-width:30; stroke:rgb(0,0,0)" />
</svg>
</symbol>
</defs>
<use xlink:href="#A" x="0" y="0" width="100" height="100" />
<use xlink:href="#B" x="0" y="50" width="50" height="50" />
</svg>
UPDATE
The OP comments that they can't remove the width and the height attributes from the inner SVG. In this case I need to add a few lines of JavaScript. First I need to get the size of the second SVG canvas in px.
const pt = 96/72;
let size = 512 * pt;
Also I need to know the stroke width
let strokeWidth = 30 * pt;
Next I need to reset the value for the viewBox attribute for the `#B``
const pt = 96/72;
let size = 512 * pt;
let strokeWidth = 30 * pt;
B.setAttributeNS(null,"viewBox", `-${strokeWidth/2} -${strokeWidth/2} ${size+strokeWidth} ${size+strokeWidth}`)
<svg viewBox="0 0 100 100">
<defs>
<symbol id="A" viewBox="0 0 100 100">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0 0 100 100">
<rect width="100%" height="100%" style="fill:rgb(255,0,0);stroke-width:3; stroke:rgb(0,0,0)" />
</svg>
</symbol>
<symbol id="B" viewBox="0 0 512 512">
<svg height="512pt" viewBox="0 0 512 512" width="512pt" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" style="fill:rgb(0,0,255);stroke-width:30; stroke:rgb(0,0,0)" />
</svg>
</symbol>
</defs>
<use xlink:href="#A" x="0" y="0" width="100" height="100" />
<use xlink:href="#B" x="0" y="50" width="50%" height="50%" />
</svg>

Texture mapping bitmap to SVG path

I have an ordinary rectangular bitmap which I would like to be able to use to fill a four-pointed SVG path - basically a mapped texture so that the four corners of the bitmap are mapped to the four points of the path and the rest of the image is 'warped' accordingly.
I have been able to fill an SVG rect with the same image and then transform the rect such that the bitmap is transformed with it:
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1">
<image x="0" y="0" width="100" height="100" href="mybmp.bmp"/>
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#bmp)" stroke="black" transform="skewX(10)"/>
When I try to use the bitmap to fill a path though it gets mapped to the bounding box of the path shape and not the four points of the path itself:
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1">
<image x="0" y="0" width="100" height="100" href="mybmp.bmp"/>
</pattern>
</defs>
<path d="M 0 0 L 100 0 L 120 80 L 50 120 Z" fill="url(#bmp)" stroke="black" />
Is it possible to get the same effect as the first example (texture properly mapped to the all corners of the rectangle) in an arbitrary path shape?
One solution is to give your pattern a viewBox so that its content image gets scaled to fit the pattern bounds.
<svg>
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1"
viewBox="0 0 100 100">
<image x="0" y="0" width="100" height="100" xlink:href="http://www.placekitten.com/100/100"/>
</pattern>
</defs>
<path d="M 0 0 L 100 0 L 120 80 L 50 120 Z" fill="url(#bmp)" stroke="black" />
</svg>
Depending on the shape of your path, you may also need to set preserveAspectRatio="xMidYMid slice". This will ensure that the pattern gets scaled to a size large enough to cover the whole path with no gaps.
<svg>
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1"
viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice">
<image x="0" y="0" width="100" height="100" xlink:href="http://www.placekitten.com/100/100"/>
</pattern>
</defs>
<path d="M 0 0 L 100 0 L 120 80 L 50 120 Z" fill="url(#bmp)" stroke="black" />
</svg>

How to start svg pattern from begin for two elements separately and how to setup right coordinate system?

I have two thick lines and I want to apply pattern for this lines. Lines should have the same pattern, but start of drawing pattern should start from (0, 0) for each line separately. In my experiment http://jsfiddle.net/69t09wey/ patterns apply like mask. I.e pattern apply for whole svg canvas as invisible layer and where line is visible, pattern also visible.
<svg viewBox="0 0 1000 1000"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<pattern id="pattern-1" width="20" height="20" x="0" y="0" patternUnits = "userSpaceOnUse" >
<path d="M 0 0 L 20 20" fill="none" stroke="#0000ff" stroke-width="1"></path>
</pattern>
<g transform="scale(5)">
<rect x="1" y="1" width="1000" height="1000"
fill="none" stroke="blue" />
<path d="M 1 9 L 200 9"
fill="red" stroke="url(#pattern-1)" stroke-width="20" />
<path d="M 1 53 L 200 53"
fill="red" stroke="url(#pattern-1)" stroke-width="20" />
</g>
</svg>
If you make your lines the same. Then move the second one by applying a transform. That will shift the coordinate space of the pattern.
<svg viewBox="0 0 1000 1000"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<pattern id="pattern-1" width="20" height="20" x="0" y="0" patternUnits = "userSpaceOnUse" >
<path d="M 0 0 L 20 20" fill="none" stroke="#0000ff" stroke-width="1"></path>
</pattern>
<g transform="scale(5)">
<rect x="1" y="1" width="1000" height="1000"
fill="none" stroke="none" />
<path d="M 1 9 L 200 9"
fill="red" stroke="url(#pattern-1)" stroke-width="20" />
<path d="M 1 9 L 200 9" transform="translate(0,44)"
fill="red" stroke="url(#pattern-1)" stroke-width="20" />
</g>
</svg>

Resources