Masking an SVGPattern - svg

fiIs it possible to Mask an SVGPattern?
I've made the following SVG, but I can't get the mask to work.
Or should I be using clipPath?
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="160px" height="600px" viewBox="0 0 160 600" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="circlePattern" patternUnits="userSpaceOnUse"
x="0" y="0" width="10" height="10"
viewBox="0 0 10 10" fill="blue" >
<circle cx='4' cy='4' r='4'/>
</pattern>
<clipPath id="clipPath" maskUnits="userSpaceOnUse">
<rect x="0" y="0" width="200" height="100" fill="white" />
</clipPath>
</defs>
<!-- Outline the drawing area in blue -->
<g id="box">
<rect fill="url(#circlePattern)" width="160" height="600" clip-path="url(#clipPath)"/>
</g>
</svg>
UPDATE: (I would like to use this complex path)
I can't seem to use this path to create the mask/clipPath
<path style="fill:#FFFFFF;" d="M9.35,37.5c4.1,2.467,8.566,3.7,13.4,3.7
c7.667,0,13.783-2.05,18.35-6.15c5.066-4.566,7.6-11.167,7.6-19.8c0-5.7-2.367-12.133-7.1-19.3c-4.1-6.267-9.7-12.684-16.8-19.25
c-5.133-4.8-10.383-8.983-15.75-12.55c-2.4-1.6-3.883-2.6-4.45-3c-1.733-1.033-3.267-1.8-4.6-2.3h-0.05c-1.3,0.5-2.8,1.267-4.5,2.3
c-0.633,0.434-2.133,1.417-4.5,2.95c-5.467,3.667-10.867,8-16.2,13c-6.967,6.566-12.467,12.917-16.5,19.05
c-4.633,7.1-6.95,13.467-6.95,19.1c0,8.633,2.534,15.233,7.6,19.8c4.567,4.1,10.684,6.15,18.35,6.15c4.833,0,9.3-1.233,13.4-3.7
c4-2.367,7.1-5.6,9.3-9.7C2.25,31.9,5.383,35.133,9.35,37.5z"/>

Your mask rect has no fill specified so it will use the default which is black i.e. i.e. rgba(0, 0, 0, 1). So the luminance of the mask is 0 everywhere and you see nothing.
If you change the fill on the mask <rect> to fill="white" you'll see the mask act as a clip which would seem to be what you're looking for. Other colours like "orange" or "blue" as they have a luminance which is neither 0 nor 1 will give you an intermediate effect.
clipPaths clip a shape to a boundary. Masks generally modify colours, you can use them to clip by having a white mask but if all you want is to clip something then a clipPath is faster.
clipPaths and masks can contain any graphics element including a path.

Related

Responsive full width svg logo

So I have this logo that fits the whole page. Is there anyway that, when the browser is resized I can move these paths? That way the height stays the same?
Example of what I want to achieve
Here's my svg code
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1440 52" style="enable-background:new 0 0 1440 52;" xml:space="preserve">
<path d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1H16.3V3.1H7.8v46.8h8.5V30.7h1384.5v19.1h0h9.4V30.6h7.5
c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</svg>
you can do something like this by using preserveAspectRatio="none" for the svg element together with a fixed height and width:100%. This would give tou what you need but the the stroke would be scaled differently on the vertical and horizontal.
To fix it you need to add vector-effect="non-scaling-stroke" for the path.
svg{height:100px; width:100%}
<svg viewBox="0 0 100 20" preserveAspectRatio="none">
<path stroke="black" stroke-width="5" vector-effect="non-scaling-stroke" d="M 1,5V15M1,10H97"/>
</svg>
Yes it is possible, with a bit of trickery. Below is a modified verion of your SVG that behaves how you want.
This matches your SVG exactly, but has a limitation. The trick we are using relies on extending the middle bar a long way to the left. Then covering up the left end of the bar with your vertical piece. But in your original SVG the vertical piece is not right at the left end of your SVG. So I've had to hide some of the extension with a white rectangle. This assumes your background will also be white. If it isn't you'll need to change that white rectangle to be the same colour as your page background.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="52">
<defs>
<path id="middle-and-right" transform="translate(-1440 0)"
d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1
h -3000 v 8.4 h 3000
v19.1h0h9.4V30.6h7.5 c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</defs>
<use xlink:href="#middle-and-right" x="100%"/>
<rect x="-1" y="3.1" width="10" height="46.8" fill="white"/>
<rect x="7.8" y="3.1" width="8.5" height="46.8"/>
</svg>
If you want to get a better idea how the trick works, have a look at this version. I've modified the SVG to make the trick more apparent.
svg {
background-color: red;
overflow: visible;
}
rect {
opacity: 0.5;
}
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="52">
<defs>
<path id="middle-and-right" transform="translate(-1440 0)"
d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1
h -3000 v 8.4 h 3000
v19.1h0h9.4V30.6h7.5 c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</defs>
<use xlink:href="#middle-and-right" x="100%"/>
<rect x="-1" y="3.1" width="10" height="46.8" fill="white"/>
<rect x="7.8" y="3.1" width="8.5" height="46.8"/>
</svg>
However if you don't mind the vertical piece on the left end being moved so it's hard up against the left side of the SVG, then we can remove that restriction regarding the background. The new version below will work for any page background colour.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="52">
<defs>
<path id="middle-and-right" transform="translate(-1440 0)"
d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1
h -3000 v 8.4 h 3000
v19.1h0h9.4V30.6h7.5 c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</defs>
<use xlink:href="#middle-and-right" x="100%"/>
<rect x="0" y="3.1" width="8.5" height="46.8"/>
</svg>

Dynamic svg width/height after applying a stroke

I made an svg with a masked image and applied a stroke to the mask:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="100%">
<defs>
<g id="path">
<path fill="#ffffff"
d="m380.42 600l -235.11 123.61 44.9 -261.8 -190.21 -185.41 262.87 -38.2 117.56 -238.2 117.56 238.2 262.87 38.2 -190.21 185.41 44.9 261.8 z"/>
</g>
<mask id="image-mask">
<use xlink:href="#path" overflow="visible"/>
</mask>
</defs>
<use xlink:href="#path" overflow="visible" stroke="red" stroke-width="20"/>
<image width="781" height="744" xlink:href="cat3.jpg" mask="url(#image-mask)"/>
</svg>
Unfortunately parts of the stroke get cut off and the result is this:
The top/left part of the border are cut off.
Is there any way to make them visible without modifying the width/height and viewBox by hand?
Like others have said, you could translate the path away from the edge of the SVG. Another option would be to use this technique using clipPath to bring your stroke lines 'inside' the shape rather than outside which is what is causing the lines to be clipped off the edge of the drawing (based on this answer):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="781px" height="744px">
<defs>
<path fill-opacity="0" id="path"
d="m380.42 600l -235.11 123.61 44.9 -261.8 -190.21 -185.41 262.87 -38.2 117.56 -238.2 117.56 238.2 262.87 38.2 -190.21 185.41 44.9 261.8 z"></path>
<clipPath id="clip">
<use xlink:href="#path" />
</clipPath>
</defs>
<image width="781" height="744" xlink:href="cat3.jpg" clip-path="url(#clip)"/>
<use xlink:href="#path" stroke="red" stroke-width="20" clip-path="url(#clip)"/>
</svg>
Also, note that I've brought the image element before use so that the stroke lines are drawn over the image, and applied fill-opacity="0" to the path so the image can be seen through the shape.

Flatten clipped areas in SVG to transparency?

I have this SVG file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
<g id="main">
<clipPath id="clip_mask">
<path d="M20.9262,32C18.5189,30.6,16.9,27.9878,16.9,25c0,-4.4735,3.6265,-8.1,8.1,-8.1c2.9878,0,5.6,1.6189,7,4.0262V0L0,0l0,32H20.9262z" fill-rule="evenodd"/>
</clipPath>
<g id="icon" clip-path="url(#clip_mask)">
<g id="transformed_icon" transform="translate(-1 -1)">
<path d="M26.7,30.5H5.3c-0.4418,0,-0.8,-0.3582,-0.8,-0.8V2.3c0,-0.4418,0.3582,-0.8,0.8,-0.8h21.4c0.4418,0,0.8,0.3582,0.8,0.8v27.4C27.5,30.1418,27.1418,30.5,26.7,30.5z" fill="#FFFFFF" stroke="#6D6E71" stroke-width="1" stroke-miterlimit="1"/>
<path d="M8.5,8.5h15M8.5,11.5h15M8.5,14.5h15M8.5,17.5h15M8.5,20.5h15M8.5,23.5h15" fill="none" stroke="#3E79B4" stroke-width="1" stroke-linecap="round" stroke-miterlimit="1"/>
</g>
</g>
<g id="overlay">
<path d="M25,18c-3.866,0,-7,3.134,-7,7c0,3.866,3.134,7,7,7s7,-3.134,7,-7C32,21.134,28.866,18,25,18zM26,29.8c0,0.1105,-0.0895,0.2,-0.2,0.2h-1.6c-0.1105,0,-0.2,-0.0895,-0.2,-0.2v-6.6c0,-0.1105,0.0895,-0.2,0.2,-0.2h1.6c0.1105,0,0.2,0.0895,0.2,0.2V29.8zM26,21.5c0,0.1105,-0.0895,0.2,-0.2,0.2h-1.6c-0.1105,0,-0.2,-0.0895,-0.2,-0.2v-1.3c0,-0.1105,0.0895,-0.2,0.2,-0.2h1.6c0.1105,0,0.2,0.0895,0.2,0.2V21.5z" fill-rule="evenodd" fill="#3E79B4"/>
<path d="M26,20.2c0,-0.1105,-0.0895,-0.2,-0.2,-0.2h-1.6c-0.1105,0,-0.2,0.0895,-0.2,0.2v1.3c0,0.1105,0.0895,0.2,0.2,0.2h1.6c0.1105,0,0.2,-0.0895,0.2,-0.2V20.2z" fill="#FFFFFF"/>
<path d="M26,23.2c0,-0.1105,-0.0895,-0.2,-0.2,-0.2h-1.6c-0.1105,0,-0.2,0.0895,-0.2,0.2v6.6c0,0.1105,0.0895,0.2,0.2,0.2h1.6c0.1105,0,0.2,-0.0895,0.2,-0.2V23.2z" fill="#FFFFFF"/>
</g>
</g>
</svg>
It is an icon with an overlay in the bottom-right corner. There is a clip-gap between the main icon area and the overlay area. This clip-gap is displayed correctly in Affinity Designer 1.5.3.69:
But unfortunately, many other programs don't recognize the clip-gap, so they don't display it. For example, here is a screenshot from LibreOffice Draw:
So, is it possible to "flatten" the clipped area in the SVG to the same background transparency as the icon background? This would make the SVG clip-gap visible and transparent in such incompatible programs and would allow programs which don't support clipped areas in SVG to render the clipped area as transparency.
I've found a practical but cumbersome and time-consuming solution: Since the SVG is displayed correctly in Affinity Designer, I print the SVG in Affinity Designer to a PDF printer driver. Then I reimport the PDF in Affinity Designer and export it as SVG. Then I can import the SVG in a renderer which doesn't support clipping and it is rendered perfectly. It works.
Yes it is possible to re-use a clip shape to make the clipped area transparent using a filter. However, I very much doubt that a renderer that can't handle clipping properly will be able to handle a filter. But here's how you would do that:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
<defs>
<clipPath id="clip_mask">
<path id="original-clip-shape" d="M20.9262,32C18.5189,30.6,16.9,27.9878,16.9,25c0,-4.4735,3.6265,-8.1,8.1,-8.1c2.9878,0,5.6,1.6189,7,4.0262V0L0,0l0,32H20.9262z" fill-rule="evenodd"/>
</clipPath>
<filter id="transparentize">
<feImage xlink:href="#original-clip-shape" x="0" y="0"/>
<feComposite operator="in" in="SourceGraphic"/>
</filter>
</defs>
<g id="main">
<g id="icon" clip-path="url(#clip_mask)">
<g id="filter-layer" filter="url(#transparentize)">
<g id="transformed_icon" transform="translate(-1 -1)">
<path d="M26.7,30.5H5.3c-0.4418,0,-0.8,-0.3582,-0.8,-0.8V2.3c0,-0.4418,0.3582,-0.8,0.8,-0.8h21.4c0.4418,0,0.8,0.3582,0.8,0.8v27.4C27.5,30.1418,27.1418,30.5,26.7,30.5z" fill="#FFFFFF" stroke="#6D6E71" stroke-width="1" stroke-miterlimit="1"/>
<path d="M8.5,8.5h15M8.5,11.5h15M8.5,14.5h15M8.5,17.5h15M8.5,20.5h15M8.5,23.5h15" fill="none" stroke="#3E79B4" stroke-width="1" stroke-linecap="round" stroke-miterlimit="1"/>
</g>
</g>
</g>
<g id="overlay">
<path d="M25,18c-3.866,0,-7,3.134,-7,7c0,3.866,3.134,7,7,7s7,-3.134,7,-7C32,21.134,28.866,18,25,18zM26,29.8c0,0.1105,-0.0895,0.2,-0.2,0.2h-1.6c-0.1105,0,-0.2,-0.0895,-0.2,-0.2v-6.6c0,-0.1105,0.0895,-0.2,0.2,-0.2h1.6c0.1105,0,0.2,0.0895,0.2,0.2V29.8zM26,21.5c0,0.1105,-0.0895,0.2,-0.2,0.2h-1.6c-0.1105,0,-0.2,-0.0895,-0.2,-0.2v-1.3c0,-0.1105,0.0895,-0.2,0.2,-0.2h1.6c0.1105,0,0.2,0.0895,0.2,0.2V21.5z" fill-rule="evenodd" fill="#3E79B4"/>
<path d="M26,20.2c0,-0.1105,-0.0895,-0.2,-0.2,-0.2h-1.6c-0.1105,0,-0.2,0.0895,-0.2,0.2v1.3c0,0.1105,0.0895,0.2,0.2,0.2h1.6c0.1105,0,0.2,-0.0895,0.2,-0.2V20.2z" fill="#FFFFFF"/>
<path d="M26,23.2c0,-0.1105,-0.0895,-0.2,-0.2,-0.2h-1.6c-0.1105,0,-0.2,0.0895,-0.2,0.2v6.6c0,0.1105,0.0895,0.2,0.2,0.2h1.6c0.1105,0,0.2,-0.0895,0.2,-0.2V23.2z" fill="#FFFFFF"/>
</g>
</g>
</svg>
As far as workarounds go, it's hard to debug renderer specific problems without the renderer. But here are some thoughts:
It might support clipping but just not support using the stroke as a clip. You could work around this by using a solid circle as the clip-shape.
it might support masking not clipping. In this case, define a mask that's the inverse of the clip and apply that.
it might not support clipping or masking at all. In that case, you'll have to just draw the original content as if it was being clipped using markers to shape the ends of your paths. (ugh!)

Why will browsers not display my SVG polygon?

I have created an SVG file to display an icon for an open folder.
It consists of a rectangle for the tab and a rectangle for the backleaf of the folder, with the open leaf represented by a polygon.
Image editors display the intended result, but browsers seem to ignore the polygon.
what am I missing?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg id="folder_icon" xmlns="http://www.w3.org/2000/svg"
width="90" height="60" viewbox="0 0 90 60" preserveAspectRatio="xMidYMid slice"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g width="50%" height="80%">
<g id="g3" fill="#ffee77" stroke="#bb7711" stroke-width="2px" opacity="0.7">
<g id="g2">
<rect x="16%" y="1%" rx="6%" ry="6%" width="30%" height="30%" />
<rect x="1%" y="16%" rx="0%" ry="0%" width="84%" height="82%" />
<polygon points="17% 20%, 90% 20%, 75% 59%, 1% 59%" />
</g>
</g>
</g>
</svg>
The same file converted to a PNG is displayed as intended, but I would prefer to use the scalable graphic.

Mask containing pattern not working in SVG

Based on this example: https://bl.ocks.org/jfsiii/7772281
I am trying to fill an SVG shape with a masked pattern.
I have two boxes. The first takes just the dot pattern. This works, but the color of the dots cannot be changed in css.
I have a second box, which has a fill and is then masked with the same pattern. This ought to result in blue dots.
But it's not masking properly. Or at least, it's doing so inconsistently. The first box will show in Chrome, but the second one will not, at least not until I go to inspect it. Then it decides to turn on. :/. Both show up in Firefox correctly.
Since the example I borrowed from works fine in Chrome, I assume I am doing something wrong.
<style>
.mask-dots {
mask: url(#mask-dots);
}
.pattern-dots {
fill: url(#pattern-dots)
}
.blue {
fill: blue;
</style>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="393px"
height="528px" viewBox="0 0 393 528" enable-background="new 0 0 393 528" xml:space="preserve">
<g id="underskirt-4">
<rect class="pattern-dots" width="100" height="100"/>
<rect x="110" class="blue mask-dots" width="100" height="100"/>
</g>
</svg>
<svg><defs><pattern id="pattern-dots" width="50" height="50"
patternUnits="userSpaceOnUse">
<path fill="white" d="M15.946,12.651c0,1.905-1.544,3.45-3.45,3.45c-0.953,0-1.815-0.386-2.439-1.011
c-0.624-0.624-1.01-1.486-1.01-2.439c0-1.905,1.544-3.45,3.45-3.45S15.946,10.746,15.946,12.651z"/>
</pattern>
<mask id="mask-dots">
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-dots)" />
</mask>
</defs>
</svg>
Jsfiddle, with second box not displaying (at least not in Chrome.)
https://jsfiddle.net/qux8yt9g/

Resources