SVG mask not working with multiple transforms - svg

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>

Related

How to mask a portion of a stroked path in SVG?

I'm looking to mask a portion of a straight line in SVG and can really only figure out how to do it one way, but would rather do another because the line lengths will be dynamically generated and the mask portion won't.
Let me explain.
Assume I have a line that is <path d="M0,0 L0,100" stroke="blue" stroke-width="20"/>, I would like to mask with transparency the first 10 pixels, meaning just the d="M0,0 L0,10" portion.
I can do this, which produces the results I'd like:
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<rect x="0" y="0" width="20" height="10" stroke="none"/>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="90" x="0" y="10" fill="white"/>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>
But the issue is that I can't seem to do the opposite with the rect in the mask, wherein I simply define the it as <rect width="20" height="10" x="0" y="0" fill="white"/> (notice only height and y are different).
Am I missing something on how do define a 10x20 rectangle and have it's mask simply hide a portion of a stroked path, or is this impossible?
If I understood the question correctly, then you need to have a mask in the form of a rectangle of fixed size 10Х20, which will be applied to the line with variable length.
In this case, you can try on a combined mask, one part of which will be opaque fill = "black" and the second part will be transparent fill = "white" and show the rest of the line.
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="100" x="0" y="0" fill="white"/>
<rect width="20" height="10" x="0" y="0" fill="black"/>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>
An example of animating the line masking process with a rectangle 10 x 20px
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<rect x="0" y="0" width="20" height="10" stroke="none"/>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="100" x="0" y="0" fill="white"/>
<rect width="20" height="10" x="0" y="0" fill="black">
<animate attributeName="y" dur="2s" values="-10;0" fill="freeze" />
</rect>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>
Works for me ... am I misunderstanding what you're trying to do?
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<rect x="0" y="0" width="20" height="10" stroke="none"/>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="10" x="0" y="0" fill="white"/>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>

Png as background inside svg shape

I'm trying to create an header using a svg to generate a curved shape, like so
I copied the SVG code generate from Sketch, deleted some extra tags and fixed the image path
<svg viewBox="0 0 1440 638" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<path d="M-4.54747351e-13,163 L1440,163 L1440,700.10075 C1259.32216,751.363088 1140.10686,781.914324 1082.35411,791.754457 C776.214966,843.915606 628.837414,646.620792 362.433874,644.205808 C184.831514,642.595818 64.0202229,656.876199 6.73310296e-11,687.046952 L-4.54747351e-13,163 Z" id="path-1"></path>
</defs>
<g id="Header-Copy" transform="translate(0, -163.000000)">
<mask id="mask" fill="white"><use xlink:href="#path-1"></use></mask>
<use id="Rectangle-Copy-2" fill="#0BE17D" transform="translate(720.000000, 481.765165) scale(-1, 1) translate(-720.000000, -481.765165) " xlink:href="#path-1"></use>
<image style="mix-blend-mode: darken;" mask="url(#mask)" x="0" y="0" width="1462.5" height="975" xlink:href="~assets/header_bg.jpg"></image>
</g>
</svg>
But I end up with this
How can I make this work?
Remove the transform attribute from element <use id="Rectangle-Copy-2">.
<svg viewBox="0 0 1440 638" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M-4.54747351e-13,163 L1440,163 L1440,700.10075 C1259.32216,751.363088 1140.10686,781.914324 1082.35411,791.754457 C776.214966,843.915606 628.837414,646.620792 362.433874,644.205808 C184.831514,642.595818 64.0202229,656.876199 6.73310296e-11,687.046952 L-4.54747351e-13,163 Z" id="path-1"></path>
</defs>
<g id="Header-Copy" transform="translate(0, -163.000000)">
<mask id="mask" fill="white"><use xlink:href="#path-1"></use></mask>
<use id="Rectangle-Copy-2" fill="#0BE17D" xlink:href="#path-1"></use>
<image style="mix-blend-mode: darken;" mask="url(#mask)" x="0" y="0" width="1462.5" height="975" xlink:href="~assets/header_bg.jpg"></image>
</g>
</svg>

svg changes when converted to symbol

I have this dummy svg showing a cirle with some grey figure inside
<svg viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<circle id="path-1" cx="43" cy="43" r="43"></circle>
</defs>
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-585.000000, -391.000000)">
<g transform="translate(585.000000, 391.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Oval" fill="currentcolor" xlink:href="#path-1"></use>
<g id="Group" mask="url(#mask-2)" fill="#b8b8b8">
<g transform="translate(21.500000, 27.823529)" id="Page-1">
<path d="M0.5,0.176470588 L0.5,58.1764706 L15.5,58.1764706 L15.5,49.1764706 L29.5,49.1764706 L29.5,31.1764706 L7.5,31.1764706 L7.5,37.1764706 Z"></path>
</g>
</g>
</g>
</g>
</g>
when I convert it to a sprite using gulp-svg-sprite with mode symbol I get this result
<?xml version="1.0" encoding="UTF-8" ?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 86 86" id="company"><defs><circle id="aa" cx="43" cy="43" r="43"/></defs><g fill="none" fill-rule="evenodd"><mask id="ab" fill="#fff"><use xlink:href="#aa"/></mask><use fill="currentcolor" xlink:href="#aa"/><g mask="url(#ab)" fill="#b8b8b8"><path d="M22 28v58h15v-9h14V59H29v6z"/></g></g></symbol></svg>
Now the grey figure breaks out of the circle and this even happens if I copy root defs- and g-tags from my original svg directly into the symbol-tag. I have also tried inserting a clipPath in the symbol version but with no luck.
What am I missing here?
UPDATED: Simplifying your svg may work ... try with the examples below, one using symbols, one without (in case the gulp sprite code cannot have nested symbols) ... it may be an issue with the defs area.
svg {
width: 100px;
}
<svg viewBox="0 0 86 86" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="c">
<circle cx="43" cy="43" r="43" fill="currentColor" />
</symbol>
<mask id="mask" color="#fff">
<use xlink:href="#c" />
</mask>
</defs>
<use xlink:href="#c" color="#666" />
<path fill="#999" mask="url(#mask)" d="M10 0v60h30v-10h20v-20h-30v9z" />
</svg>
<svg viewBox="0 0 86 86" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="mask2" color="#fff">
<circle cx="43" cy="43" r="43" fill="#FFF" />
</mask>
</defs>
<circle cx="43" cy="43" r="43" fill="currentColor" />
<path fill="#999" mask="url(#mask2)" d="M10 0v60h30v-10h20v-20h-30v9z" />
</svg>
It is probably not a complete answer but I managed to get it work;
First I extended my defs with a clipPath using my circle
<defs>
<circle id="circle" cx="43" cy="43" r="43"></circle>
<clipPath id="clippath"><use overflow="visible" xlink:href="#circle" /></clipPath>
</defs>
Then, using the clipPath on my first group and switching from gulp-svg-sprite to gulp-svgstore (which moves the defs to the top, above the symbols) gives me what I expect both as single svg and as an svg symbol sprite.

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 Exclude Area inside of clippath in Svg

I want to hide anything that outside a rectangle. (this i have achieved with clipping successfully). but another condition is that, 'also hide anything that comes inside the black big circle'. Now how i can achieve that?
in below example, 'yellow circle' must be eliminated'.
see below images for detail
Original:-
Desired:-
Below is my Svg code:-
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
</clipPath>
</svg>
Erik Dahlström is right, your clip can include the entire rectangle and the cutout for the circle. This way, anything you associate with #clip1 as the clip-path will not be visible inside your circle area. Here is what it looks like for your example:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<path d="M 50,50 l200 0 l0 200 l-200 0z M150,150 a30,30 1 0,0 60,0z M210,150 a30,30 1 0,0 -60,0z"/>
</clipPath>

Resources