SVG Masking issue - svg

I have a simple SVG graphic with a path for a mask. As soon as I assign the #myMask to the object,the mask doesn't work at all. This should be something obvious, but I'm not seeing it.
CodePen: https://codepen.io/ambidustrious/pen/powddJd
Thoughts?
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 527.8 498.1" style="enable-background:new 0 0 527.8 498.1;" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="myMask" x="0" y="0" width="1" height="1" maskUnits="userSpaceOnUse">
<path id="mask" class="st2" d="M 113.297 497.17 L 113.297 300.87 C 113.397 239.27 163.297 205.07 224.997 205.07 L 300.697 205.07 C 330.997 206.07 418.497 106.27 432.997 91.67 L 527.297 0.57" fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="58">
</path>
</mask>
</defs>
<g id="arrow" transform="matrix(1, 0, 0, 1, 1190.697021, 194.369995)" mask="url(#myMask)" >
<linearGradient id="Union_6_00000050629510371142239550000012438780590208862086_" gradientUnits="userSpaceOnUse" x1="-1883.5894" y1="595.0461" x2="-1883.5894" y2="594.0461" gradientTransform="matrix(432.3066 0 0 -496.631 813408.6875 295324.4688)">
<stop offset="0" style="stop-color:#E89657"/>
<stop offset="1" style="stop-color:#D8251F"/>
</linearGradient>
<path id="Union_6" style="fill:url(#Union_6_00000050629510371142239550000012438780590208862086_);" d="m-1095.7 302.8v-196.3c.1-61.6 50-111.6 111.7-111.7h75.7c20.6.1 40.3-8.1 54.8-22.7l148.7-148.7-17.2-17.2 58.6 0 0 58.6-17.2-17.2-148.7 148.6c-10.4 10.4-22.7 18.6-36.2 24.2c-13.5 5.6-28.1 8.5-42.7 8.5h-75.8c-42.8 0-77.5 34.7-77.6 77.6v196.3h-34.1z" />
</g>
</svg>

I think that there was something about the position of the elements. And then your mask more or less covers the entire arrow. I cleaned up a bit and positioned your elements in the viewBox of "0 0 500 500", so that there is no need for using transform/translate.
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="myMask" x="0" y="0" maskUnits="userSpaceOnUse">
<path id="mask" class="st2" d="m 20.307087,495.15767 v -196.3 c 0.1,-61.6 50,-95.8 111.700063,-95.8 h 75.7 c 30.3,1 117.8,-98.79997 132.3,-113.399929 l 94.3,-91.1000322" fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="58" />
</mask>
<linearGradient id="LG01" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#E89657"/>
<stop offset="1" style="stop-color:#D8251F"/>
</linearGradient>
</defs>
<g id="arrow" mask="url(#myMask)">
<path id="Union_6" style="fill:url(#LG01);" d="M 0,496.6 V 300.3 C 0.1,238.7 50,188.7 111.7,188.6 h 75.7 c 20.6,0.1 40.3,-8.1 54.8,-22.7 L 390.9,17.2 373.7,0 h 58.6 V 58.6 L 415.1,41.4 266.4,190 c -10.4,10.4 -22.7,18.6 -36.2,24.2 -13.5,5.6 -28.1,8.5 -42.7,8.5 h -75.8 c -42.8,0 -77.5,34.7 -77.6,77.6 v 196.3 z" />
</g>
</svg>

Related

SVG reduced path with fill pattern

I try to draw a shape with a path that must be reduced like in this solution Find Parallel or Offset SVG path
I use the filter "erode" but with pattern it doesn't work : the pattern is deformed.
Is there a way to do this without the bezier.js solution, with pure SVG/CSS ?
Here is a sample of my problem
I want to have the shape of the right with the pattern of the left.
<!DOCTYPE html>
<html>
<body>
<svg>
<defs>
<pattern id="circ" x="0" y="0" width="30" height="30" patternUnits="userSpaceOnUse">
<rect fill="blue" width="100%" height="100%" />
<circle cx="10" cy="10" r="10" fill="green" />
</pattern>
<filter id="erode">
<feMorphology in="SourceGraphic" operator="erode" radius="10"/>
</filter>
<path id="thing" d="M 0,0 H 50 A 35,35 0 1 0 100,50 V 75 C 50,125 0,85 0,85 Z" />
</defs>
<use href="#thing" fill="url(#circ)" width="400" height="400" filter="#erode"/>
<use x="100" href="#thing" filter="url(#erode)" fill="url(#circ)" width="400" height="400" />
</svg>
</body>
</html>
Yes. You can use a mask.
svg {
width: 300px;
}
.purple {
fill: rebeccapurple;
}
.reduce-me {
mask: url(#reducer);
}
#reduce-amount {
stroke-width: 5px;
}
<svg viewBox="0 0 100 100">
<path class="purple"
d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z"/>
</svg>
<svg viewBox="0 0 100 100">
<defs>
<!-- the shared path that is used by both the purple path and the mask -->
<path id="shared-path"
id="p" d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z" />
<!-- a mask that shrinks the shape by half the stroke-width -->
<mask id="reducer">
<use id="reduce-amount" xlink:href="#shared-path"
fill="white" stroke="black"/>
</mask>
</defs>
<!-- the shape that gets reduced -->
<use class="purple reduce-me" xlink:href="#shared-path"/>
</svg>
How this works
If we just render what the mask looks like (on the right) we can see how this works.
svg {
width: 300px;
}
.purple {
fill: rebeccapurple;
}
.reduce-me {
mask: url(#reducer);
}
#reduce-amount {
stroke-width: 10px;
}
<svg viewBox="0 0 100 100">
<path class="purple"
d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z"/>
</svg>
<svg viewBox="0 0 100 100">
<defs>
<!-- the shared path that is used by both the purple path and the mask -->
<path id="shared-path"
id="p" d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z" />
</defs>
<use id="reduce-amount" xlink:href="#shared-path"
fill="white" stroke="black"/>
</svg>
We are using the same shape as a mask. However the mask has a thick black stroke around it. Black in a mask makes things transparent. The rest of the mask is white, which stays visible.
You can alter the amount of the shape reduction by changing the stroke-width value in the .reduce-amount class.
The disadvantages of this method are:
1. you need a mask for every different path shape
2. you can't set the stroke style of the reduced size shape. However you could simulate a stroke colour by overlaying two paths with different reduction amounts.
You can extend the filter to make this work. There seems to be a bug eroding pattern filled shapes - it's not taking the minimum of the alpha channels in the radius correctly. But if you start with SourceAlpha rather than SourceGraphic and then create your mask using component transfers it seems to work.
<svg>
<defs>
<pattern id="circ" x="0" y="0" width="30" height="30" patternUnits="userSpaceOnUse">
<rect fill="blue" width="100%" height="100%" />
<circle cx="10" cy="10" r="10" fill="green" />
</pattern>
<filter id="erode3">
<feMorphology in="SourceAlpha" result="eroded"
operator="erode" radius="10"/>
<feComponentTransfer>
<feFuncR type="discrete" tableValues="1 0"/>
<feFuncG type="discrete" tableValues="1 0"/>
<feFuncB type="discrete" tableValues="1 0"/>
</feComponentTransfer>
<feComposite operator ="in" in="SourceGraphic"/>
</filter>
<path id="thing" d="M 0,0 H 50 A 35,35 0 1 0 100,50 V 75 C 50,125 0,85 0,85 Z" />
</defs>
<use href="#thing" fill="url(#circ)" width="400" height="400" filter="url(#erode3)"/>
<use x="100" href="#thing" filter="url(#erode)" fill="url(#circ)" width="400" height="400" />
</svg>

Apply filter to path in svg

I have a triangle drawn with path:
I want to apply a filter to it:
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradA0" gradientUnits="userSpaceOnUse" x1="50.000000" y1="50.000000" x2="130.000000" y2="210.000000">
<stop offset="0%" stop-color="#ff0000"/>
<stop offset="100%" stop-color="#000000"/>
</linearGradient>
<path id="pathA0" d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" fill="url(#gradA0)"/>
<filter id="default0">
<feImage xlink:href="#pathA0" result="layerA0" x="0" y="0"/>
</filter>
</defs>
<path d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" filter="url(#default0)"/>
</svg>
And the result:
Why the applied image is clipped? How to fix that?
You haven't sized your SVG element. SVG has no implicit sizing, if you don't provide it, then browsers are free to give you whatever size they want. Firefox is 100px by 100px I think..
Update:
You also haven't sized your feImage (SVG is not very forgiving). This version works:
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000px" height="800px" viewBox="0 0 1000 800">
<defs>
<linearGradient id="gradA0" gradientUnits="userSpaceOnUse" x1="50.000000" y1="50.000000" x2="130.000000" y2="210.000000">
<stop offset="0%" stop-color="#ff0000"/>
<stop offset="100%" stop-color="#000000"/>
</linearGradient>
<path id="pathA0" d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" fill="url(#gradA0)"/>
<filter id="default0">
<feImage xlink:href="#pathA0" result="layerA0" x="0%" y="0%" width="100%" height="100%"/>
</filter>
</defs>
<path d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" filter="url(#default0)"/>
</svg>

is it possible to make SVG circle fill color from bottom to top based on percentage? [duplicate]

This question already has answers here:
Outlining and partially filling an SVG Shape
(3 answers)
Closed 7 years ago.
<svg viewbox="-20 -20 100 100">
<circle r="15.29563" cx="0" stroke="#7dc4c2" fill="#5ea4a2">
</svg>
How to fill the circle as below based on percentage!!
http://i.stack.imgur.com/gVAN5.png
Thanks in advance.
you could use a gradient with stop-opacity to do this.
you would add two "middle" stops with opacity 0 and 1 respectively an set the offset of both to the percentage you need.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="0" stop-color="royalblue"/>
<stop offset="100%" stop-opacity="0" stop-color="royalblue"/>
</linearGradient>
<circle cx="50" cy="50" r="45" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
</svg>
you could even animate it
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="1" stop-color="royalblue">
<animate attributeName="offset" values="0;1;0" repeatCount="indefinite" dur="10s" begin="0s"/>
</stop>
<stop offset="40%" stop-opacity="0" stop-color="royalblue">
<animate attributeName="offset" values="0;1;0" repeatCount="indefinite" dur="10s" begin="0s"/>
</stop>
<stop offset="100%" stop-opacity="0" stop-color="royalblue"/>
</linearGradient>
<circle cx="50" cy="50" r="45" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
</svg>
the advantage is that this works on any shape and size without changing the gradient
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 300" width="400" height="200">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="0" stop-color="royalblue"/>
<stop offset="100%" stop-opacity="0" stop-color="royalblue"/>
</linearGradient>
<circle cx="50" cy="50" r="45" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<circle cx="250" cy="150" r="145" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<rect x="400" y="20" width="100" height="100" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<path d="M50 150L95 290 h-90z" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<path d="M450 205 A45 45 0 0 1 450 295A100 100 0 0 0 450 205z" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
</svg>
The easiest way to do this is to create a mask with a circular hole in it, and then animate a rectangle behind it. For example:
<path fill="#fff" fill-rule="evenodd"
d="M0 0 200 0 200 200 0 200ZM20 100 A80 80 0 0 0 180 100 80 80 0 0 0 20 100Z"/>
The path data here starts with a square box 200 units wide (M0 0 200 0 200 200 0 200Z) and then uses two arcs to draw a circle of diameter 80 units inside it (A80 80 0 0 0 180 100 80 80 0 0 0 20 100Z). The evenodd fill rule ensures that the circle is cut out from the square.
If you want the circle to fill from bottom to top, then you'll have to use a rotate transformation:
<rect transform="rotate(180 100 100)" x="20" y="20" width="160" height="0" fill="#47f" id="fillup"/>
This spins the coordinate system around the middle of the SVG image so that the rect grows upwards when you increase its height. Here, I'm using a CSS transition to change the height of the rect when you hover over it. But you can use Javascript or JQuery to change the height to whatever you want.
Here's a working example:
svg #fillup { height:0px; transition:height 0.5s; }
svg:hover #fillup { height:160px; }
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="10" y="10" width="180" height="180" fill="#eee"/>
<rect transform="rotate(180 100 100)" x="20" y="20"
width="160" height="0" fill="#47f" id="fillup"/>
<path fill="#fff" fill-rule="evenodd"
d="M0 0 200 0 200 200 0 200ZM20 100 A80 80 0 0 0
180 100 80 80 0 0 0 20 100Z"/>
<circle cx="100" cy="100" r="90" fill="none" stroke="#888"
stroke-width="20"/>
<circle cx="100" cy="100" r="99" fill="none" stroke="#333"
stroke-width="1"/>
<circle cx="100" cy="100" r="80" fill="none" stroke="#333"
stroke-width="1"/>
</svg>

SVG Path shadow only on outside of the form

I have a simple closed svg path
<path d="M10 10 H 90 V 90 H 10 L 10 10" fill="none" stroke-width="2px" stroke="black" />
Is it possible to get a shadow effect only on the outside border?
Not like that:
But like that:
The inner part should remain transparent.
As #Robert Longson said using a mask is the solution:
<svg>
<defs>
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 1 0"></feColorMatrix>
<feGaussianBlur stdDeviation="4" result="coloredBlur"></feGaussianBlur>
<feMerge>
<feMergeNode in="coloredBlur"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<defs>
<mask id="myMask">
<rect x="0" y="0" width="100" height="100" fill="white" />
<rect x="11" y="11" width="78" height="78" fill="black" />
</mask>
</defs>
</svg>
<svg width="100px" height="100px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="100" fill="yellow" />
<path d="M10 10 H 90 V 90 H 10 L 10 10" stroke-width="2px" stroke="black" filter="url(#glow)" mask="url(#myMask)" fill="none" />
</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