Texture mapping bitmap to SVG path - svg

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>

Related

How to make this SVG pattern seamless?

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>

SVG mask not working with multiple transforms

I have several avatar frames(on chairs around a round table) that I'm generating dynamically in react. I'm trying to add a clip-path to the frames which will clip the image according to the frame's shape.
I have the (generated) code below for one of the frames, which doesn't seem to work even though the clipping region falls exactly on the image(checked using chrome's inspector). I have tried clipping/masking it with a clip-path as well as mask(included in the code below). It'd be great if somebody could explain why this isn't working?
<svg viewBox="0 0 2000 2000">
<g class="avatar_container">
<defs>
<symbol id="avatarFrame" viewBox="-12 -8 135 135">
<path d="M55.5 121.217l8.313-11.856A50.55 50.55 0 00106.049 59.5 50.55 50.55 0 0055.5 8.951 50.55 50.55 0 004.951 59.5a50.55 50.55 0 0042.237 49.861z"></path>
</symbol>
<use id="frame-def" xlink:href="#avatarFrame" x="0" y="0" width="100" height="100"></use>
<mask id="frame-mask" x="0" y="0" width="2200" height="2200">
<rect x="0" y="0" width="2200" height="2200" fill="#000"></rect>
<use x="1067.525" y="100" transform="rotate(315,1117.525,400)" xlink:href="#frame-def" fill="#fff"></use>
</mask>
<clipPath id="frame-clip">
<use x="1067.525" y="100" transform="rotate(315,1117.525,400)" xlink:href="#frame-def"></use>
</clipPath>
</defs>
<g class="avatar" transform="rotate(315,1117.525,400)" mask="url(#frame-mask)">
<image xlink:href="https://via.placeholder.com/100" x="1067.525" y="100" transform="rotate(-315,1117.525,150)" width="100" height="100"></image>
</g>
<use id="frame" class="avatar_frame" xlink:href="#frame-def" transform="rotate(315,1117.525,400)" x="1067.525" y="100" width="100" height="100" fill="none" stroke="#545454" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></use>
</g>

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>

How to size an SVG

I am trying to create an SVG sprite.
I have set the SVG image to be 100px wide, 50px height, then offset the second by 50.
How can I set the size of the actual icon? Currently, the icon is huge and not 50px.
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100px"
height="50px">
<defs>
<g id="arrow">
<path d="M378.135,227.256L206.224,55.354c-12.354-12.359-12.354-32.394,0-44.748c12.354-12.359,32.388-12.359,44.747,0
L445.258,204.89c6.177,6.18,9.262,14.271,9.262,22.366c0,8.098-3.091,16.195-9.262,22.372L250.971,443.91
c-12.359,12.365-32.394,12.365-44.747,0c-12.354-12.354-12.354-32.391,0-44.744L378.135,227.256z M9.265,399.166
c-12.354,12.354-12.354,32.391,0,44.744c12.354,12.365,32.382,12.365,44.748,0l194.287-194.281
c6.177-6.177,9.257-14.274,9.257-22.372c0-8.095-3.086-16.192-9.257-22.366L54.013,10.606c-12.365-12.359-32.394-12.359-44.748,0
c-12.354,12.354-12.354,32.388,0,44.748L181.18,227.256L9.265,399.166z"/>
</g>
</defs>
<use x="0" y="0" style="fill: #333" xlink:href="#arrow" />
<use x="50" y="0" style="fill: #999" xlink:href="#arrow" />
</svg>
This is what I see:
DO NOT USE TRANSFORM FOR SCALING
What you are missing is a defined viewBox.
If you do not define a viewBox the viewBox is the same size as the height and width that you defined.
So when you draw a path and some of its point are above 370 then they will be outside its container. Since your defined size is 100 width by 50 height. Any point with values higher then the size will not be drawn.
when you define a viewBox you can change the size without affecting what is drawn or not.
This is the article i allways use when i forget how to properly scale svgs: https://css-tricks.com/scale-svg/
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100px"
height="50px"
viewBox="0 0 500 500">
<defs>
<g id="arrow">
<path d="M378.135,227.256L206.224,55.354c-12.354-12.359-12.354-32.394,0-44.748c12.354-12.359,32.388-12.359,44.747,0
L445.258,204.89c6.177,6.18,9.262,14.271,9.262,22.366c0,8.098-3.091,16.195-9.262,22.372L250.971,443.91
c-12.359,12.365-32.394,12.365-44.747,0c-12.354-12.354-12.354-32.391,0-44.744L378.135,227.256z M9.265,399.166
c-12.354,12.354-12.354,32.391,0,44.744c12.354,12.365,32.382,12.365,44.748,0l194.287-194.281
c6.177-6.177,9.257-14.274,9.257-22.372c0-8.095-3.086-16.192-9.257-22.366L54.013,10.606c-12.365-12.359-32.394-12.359-44.748,0
c-12.354,12.354-12.354,32.388,0,44.748L181.18,227.256L9.265,399.166z"/>
</g>
</defs>
<use x="0" y="0" style="fill: #333" xlink:href="#arrow" />
<use x="50" y="0" style="fill: #999" xlink:href="#arrow" />
</svg>
Like this? I just added transform="scale(0.1)" attribute to the g tag to make it 10x smaller
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100px"
height="50px">
<defs>
<g id="arrow" transform="scale(0.1)">
<path d="M378.135,227.256L206.224,55.354c-12.354-12.359-12.354-32.394,0-44.748c12.354-12.359,32.388-12.359,44.747,0
L445.258,204.89c6.177,6.18,9.262,14.271,9.262,22.366c0,8.098-3.091,16.195-9.262,22.372L250.971,443.91
c-12.359,12.365-32.394,12.365-44.747,0c-12.354-12.354-12.354-32.391,0-44.744L378.135,227.256z M9.265,399.166
c-12.354,12.354-12.354,32.391,0,44.744c12.354,12.365,32.382,12.365,44.748,0l194.287-194.281
c6.177-6.177,9.257-14.274,9.257-22.372c0-8.095-3.086-16.192-9.257-22.366L54.013,10.606c-12.365-12.359-32.394-12.359-44.748,0
c-12.354,12.354-12.354,32.388,0,44.748L181.18,227.256L9.265,399.166z"/>
</g>
</defs>
<use x="0" y="0" style="fill: #333" xlink:href="#arrow" />
<use x="50" y="0" style="fill: #999" xlink:href="#arrow" />
</svg>

Drawing a grid using SVG markup

I'm seeking to draw a grid onto which i will be adding a number of simple rectangles, again using SVG. The grid should fit on a single page when viewed in a browser. Suspect i'm missing something very simple but do i code the SVG (viewport and grid) for this outcome; namely a grid?
I've read advice to specify a viewbox that defines the internal coordinate system of the document's canvas; also that it's possible to set height and width attributes as percentages (?). Ideally final result (ultimately a map) is to have gridlines.
Use a pattern on a fully wide and high rectangle.
<svg width="800" height="600">
<defs>
<pattern id="tenthGrid" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="silver" stroke-width="0.5"/>
</pattern>
<pattern id="grid" width="100" height="100" patternUnits="userSpaceOnUse">
<rect width="100" height="100" fill="url(#tenthGrid)"/>
<path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)"/>
</svg>

Resources