I'd like to add a border to a number of elements which are grouped by <g>. As an example:
<g id="group">
<circle cx="125" cy="125" r="65" fill="orange" />
<line x1="50" y1="50" x2="200" y2="200" stroke="blue" stroke-width="4" />
</g>
Best case, the border should look like in the following picture. The distance between the elements and the border is not required (but nice to have). The main goal should be a single border (stroke) around the group elements.
I found the picture in a tutorial, but there it was just to demonstrate what a group of elements may look like. So this doesn't help.
I already tried different solutions, but none of them worked as expected, e.g.
A SVG filter using feColorMatrix and feMorphology (see this post). But in this case, the color of the elements changes when applying the filter.
Styling the <g> with stroke and stroke-width results in a rectangular border around the group, which is also not the thing I want.
Any ideas, how to get a border around the group as shown in the picture?
It would be difficult to get the dashed stroke shown in the image you provided. But a solid outline should be possible. Here's an example:
<svg width="250" height="250" viewBox="0 0 250 250">
<defs>
<filter id="groupborder" filterUnits="userSpaceOnUse"
x="0" y="0" width="250" height="250">
<feMorphology operator="dilate" in="SourceAlpha"
radius="8" result="e1" />
<feMorphology operator="dilate" in="SourceAlpha"
radius="10" result="e2" />
<feComposite in="e1" in2="e2" operator="xor"
result="outline"/>
<feColorMatrix type="matrix" in="outline"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 .3 0" result="outline2"/>
<feComposite in="outline2" in2="SourceGraphic"
operator="over" result="output"/>
</filter>
</defs>
<g id="group" filter="url(#groupborder)">
<circle cx="125" cy="125" r="65" fill="orange" />
<line x1="50" y1="50" x2="200" y2="200" stroke="blue" stroke-width="4" />
</g>
</svg>
Here's how it works:
<feMorphology operator="dilate" in="SourceAlpha" radius="8" result="e1" />
Uses a dilate operation to fatten up the graphic elements. By using the source alpha as the input image, this results in black regions corresponding to the graphic elements in the image, and white everywhere else.
<feMorphology operator="dilate" in="SourceAlpha" radius="10" result="e2" />
The same filter again, but with a larger amount of dilation, resulting in a slightly fatter image
<feComposite in="e1" in2="e2" operator="xor" result="outline"/>
These dilated results are combined using an XOR operation that leaves behind a black outline.
<feColorMatrix type="matrix" in="outline"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 .3 0" result="outline2"/>
This filter multiplies the alpha component of the outline by 0.3 so it appears grey instead of solid black.
<feComposite in="outline2" in2="SourceGraphic" operator="over" result="output"/>
Finally, add this outline to the original image.
Related
I need to make a box with an inset drop shadow, in the same way that CSS3 has inset box-shadows. What I've found so far is a filter with feGaussianBlur, but the problem with that is that it also adds a drop shadow outside the box, which I don't want. Here's the code I've got so far:
<svg>
<defs>
<filter id="drop-shadow">
<feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="5" />
<feGaussianBlur in="SourceAlpha" result="blur2" stdDeviation="10" />
<feGaussianBlur in="SourceAlpha" result="blur3" stdDeviation="15" />
<feMerge>
<feMergeNode in="blur" mode="normal"/>
<feMergeNode in="blur2" mode="normal"/>
<feMergeNode in="blur3" mode="normal"/>
<feMergeNode in="SourceGraphic" mode="normal"/>
</feMerge>
</filter>
</defs>
<rect x="10" y="10" width="100" height="100"
stroke="black" stroke-width="4" fill="transparent" filter="url(#drop-shadow)"/>
</svg>
I've made a demo that also compares this code with the desired CSS-made result. The filter should not just work on rectangles, but also on trapezoids and more complicated polygons.
I've already tried using radialGradient, but since that makes the gradient circular, that's not good either.
If you had a solid fill, you could just add
<feComposite operator="in" in2="SourceGraphic"/>
to the end of your filter and it would clip the blur to the shape of the SourceGraphic. Since your shape is transparent, you'll have to do a little more work. What I'd suggest is using a semi-transparent fill on the original graphic in order to get the right selection for compositing and using an feFuncA to zero out the fill for the final operation. This turns out to be surprisingly complicated. But here is a solution that will work for any solid-stroke shape
<filter id="inset-shadow" >
<!-- dial up the opacity on the shape fill to "1" to select the full shape-->
<feComponentTransfer in="SourceAlpha" result="inset-selection">
<feFuncA type="discrete" tableValues="0 1 1 1 1 1"/>
</feComponentTransfer>
<!-- dial down the opacity on the shape fill to "0" to get rid of it -->
<feComponentTransfer in="SourceGraphic" result="original-no-fill">
<feFuncA type="discrete" tableValues="0 0 1"/>
</feComponentTransfer>
<!-- since you can't use the built in SourceAlpha generate your own -->
<feColorMatrix type="matrix" in="original-no-fill" result="new-source-alpha" values="0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0"
/>
<feGaussianBlur in="new-source-alpha" result="blur" stdDeviation="5" />
<feGaussianBlur in="new-source-alpha" result="blur2" stdDeviation="10" />
<feGaussianBlur in="new-source-alpha" result="blur3" stdDeviation="15" />
<feMerge result="blur">
<feMergeNode in="blur" mode="normal"/>
<feMergeNode in="blur2" mode="normal"/>
<feMergeNode in="blur3" mode="normal"/>
</feMerge>
<!-- select the portion of the blur that overlaps with your shape -->
<feComposite operator="in" in="inset-selection" in2="blur" result="inset-blur"/>
<!-- composite the blur on top of the original with the fill removed -->
<feComposite operator="over" in="original-no-fill" in2="inset-blur"/>
</filter>
here is my fork of your fiddle: http://jsfiddle.net/kkPM4/
largely based on an experiment that I found, here's what I've come up with:
<defs><filter id="inset-shadow">
<feOffset dx="10" dy="10"/> <!-- Shadow Offset -->
<feGaussianBlur stdDeviation="10" result="offset-blur"/> <!-- Shadow Blur -->
<feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"/> <!-- Invert the drop shadow to create an inner shadow -->
<feFlood flood-color="black" flood-opacity="1" result="color"/> <!-- Color & Opacity -->
<feComposite operator="in" in="color" in2="inverse" result="shadow"/> <!-- Clip color inside shadow -->
<feComponentTransfer in="shadow" result="shadow"> <!-- Shadow Opacity -->
<feFuncA type="linear" slope=".75"/>
</feComponentTransfer>
<!--<feComposite operator="over" in="shadow" in2="SourceGraphic"/>--> <!-- Put shadow over original object -->
</filter></defs>
<rect width="100" height="100" fill="yellow" filter="url(#inset-shadow)"/>
If you want the fill to be seen, uncomment the last <feComposite>. Unfortunately, fill="transparent" will not give the filter an alpha to work with and will produce no shadow.
Hello
I am developing a react app and I want to set a SVG for my header background.
But when I export it from adobe XD it's size will change.
This is the SVG code :
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1970.909" height="211.264" viewBox="0 0 1970.909 211.264">
<defs>
<filter id="Path_7" x="0" y="0" width="1970.909" height="211.264" filterUnits="userSpaceOnUse">
<feOffset dy="6" input="SourceAlpha"/>
<feGaussianBlur stdDeviation="8.5" result="blur"/>
<feFlood flood-color="#396eb0" flood-opacity="0.278"/>
<feComposite operator="in" in2="blur"/>
<feComposite in="SourceGraphic"/>
</filter>
</defs>
<g transform="matrix(1, 0, 0, 1, 0, 0)" filter="url(#Path_7)">
<path id="Path_7-2" data-name="Path 7" d="M0,0,1919.909.341V159.89s-164.931-36.264-428.15-36.264-349.451,32.555-624.725,36.264-259.615-21.429-476.374-21.429S0,159.89,0,159.89Z" transform="translate(25.5 19.5)" fill="#f05454"/>
</g>
</svg>
This is a link to image
Edit: I can resize my SVG in adobe illustrator and every thing is fine , but I want to export and use directly from adobe XD
Edit 2: If I remove width a and height from svg it will not fit the screen again it's like it has margin.
I feel that this SVG could be optimized a bit. The path itself is fairly simple. So, in this example I scaled down the path. Now the numbers in the path are easier to overview. Then the viewBox can be simple as well. And now the filter is also more controllable.
PS: in your code you have two elements with the same id. That should be avoided.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 5">
<defs>
<filter id="Path_7" filterUnits="userSpaceOnUse">
<feOffset dy=".5" input="SourceAlpha"/>
<feGaussianBlur stdDeviation=".2" result="blur"/>
<feFlood flood-color="#396eb0" flood-opacity=".6"/>
<feComposite operator="in" in2="blur"/>
<feComposite in="SourceGraphic"/>
</filter>
</defs>
<path filter="url(#Path_7)" data-name="Path 7" d="M 0 0 L 36 0 V 3 s -3 -0.5 -7 -0.5 s -7 0.5 -11 0.5 s -7 -0.5 -11 -0.5 S 0 3 0 3 Z" fill="#f05454"/>
</svg>
If you remove the width and height attributes from both the svg element and the filter element, then it will scale normally:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1970.909 211.264">
<defs>
<filter id="Path_7" x="0" y="0" filterUnits="userSpaceOnUse">
<feOffset dy="6" input="SourceAlpha"/>
<feGaussianBlur stdDeviation="8.5" result="blur"/>
<feFlood flood-color="#396eb0" flood-opacity="0.278"/>
<feComposite operator="in" in2="blur"/>
<feComposite in="SourceGraphic"/>
</filter>
</defs>
<g transform="matrix(1, 0, 0, 1, 0, 0)" filter="url(#Path_7)">
<path id="Path_7-2" data-name="Path 7" d="M0,0,1919.909.341V159.89s-164.931-36.264-428.15-36.264-349.451,32.555-624.725,36.264-259.615-21.429-476.374-21.429S0,159.89,0,159.89Z" transform="translate(25.5 19.5)" fill="#f05454"/>
</g>
</svg>
I'm having some problems when I imported my svg image as a background in css, it seems like one of the mountains in my background have this small transparent lines. But for some reason it only appears in Chrome but not FireFox.
Thanks.
here's the fiddleJS
.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1440" height="328.656" viewBox="0 0 1440 328.656" style="shape-rendering: geometricPrecision">
<defs>
<style>
.cls-1 {
filter: url(#filter);
}
.cls-2 {
filter: url(#filter-2);
}
.cls-3 {
fill: #47c9af;
fill-rule: evenodd;
}
</style>
<filter id="filter" filterUnits="userSpaceOnUse">
<feOffset result="offset" dx="81.915" dy="57.358" in="SourceAlpha"/>
<feGaussianBlur result="blur"/>
<feFlood result="flood" flood-color="#34495e"/>
<feComposite result="composite" operator="in" in2="blur"/>
<feBlend result="blend" in="SourceGraphic"/>
</filter>
<filter id="filter-2" filterUnits="userSpaceOnUse">
<feOffset result="offset" dx="42.596" dy="29.826" in="SourceAlpha"/>
<feGaussianBlur result="blur"/>
<feFlood result="flood" flood-color="#16a085"/>
<feComposite result="composite" operator="in" in2="blur"/>
<feBlend result="blend" in="SourceGraphic"/>
</filter>
</defs>
<g id="mountain.svg" class="cls-1">
<g id="_" data-name=">" class="cls-2">
<path id="Polygon_1" data-name="Polygon 1" class="cls-3" d="M-1.8,845.344L135.187,1083h-273.97Z" transform="translate(0 -812.344)"/>
<path id="Polygon_1_copy" data-name="Polygon 1 copy" class="cls-3" d="M272.186,903.344L409.171,1141H135.2Z" transform="translate(0 -812.344)"/>
<path id="Polygon_1_copy_2" data-name="Polygon 1 copy 2" class="cls-3" d="M546.171,845.344L683.156,1083H409.186Z" transform="translate(0 -812.344)"/>
<path id="Polygon_1_copy_3" data-name="Polygon 1 copy 3" class="cls-3" d="M820.155,903.344L957.14,1141H683.17Z" transform="translate(0 -812.344)"/>
<path id="Polygon_1_copy_4" data-name="Polygon 1 copy 4" class="cls-3" d="M1094.14,845.344L1231.12,1083H957.155Z" transform="translate(0 -812.344)"/>
<path id="Polygon_1_copy_5" data-name="Polygon 1 copy 5" class="cls-3" d="M1308.12,812.344L1445.11,1050H1171.14Z" transform="translate(0 -812.344)"/>
</g>
</g>
</svg>
This is a drawing bug in webkit/Chrome that seems to be triggered by the repeated use of feOffset to layer content more than 3 layers deep. If you resize the iframe in the jsfiddle, you'll see that the thin lines stay fixed relative to the parent window, not the content - so it seems to be a low level bug. Based on my experiments, any shape that is 4 or more layers deep gets the drawing artifact.
Easiest way to fix is to define your shape once in defs and utilize multiple use elements to place and color them.
I've filed bug#660745 with Chrome.
(That said - your filters have badly specified primitives (no stdDeviation for the (unused) GaussianBlur, no filter dimensions, no mode for the feBlend) that you should fix. These are better specified versions of your filters.)
<filter id="filter" >
<feOffset result="offset" dx="81.915" dy="57.358" in="SourceAlpha"/>
<feFlood result="flood" flood-color="#34495e"/>
<feComposite result="composite" operator="in" in2="offset"/>
<feBlend mode="normal" result="blend" in="SourceGraphic"/>
</filter>
<filter id="filter-2">
<feOffset result="offset" dx="42.596" dy="29.826" in="SourceAlpha"/>
<feFlood result="flood" flood-color="#16a085"/>
<feComposite result="composite" operator="in" in2="offset"/>
<feBlend mode="normal" result="blend" in="SourceGraphic"/>
</filter>
The feTurbulence filter is used to create clouds. By animating frequency value, generated clouds are zoomed in or out. I want them to slide from right to left.
I've made so far:
<svg height="0" width="0" style=";position:absolute;margin-left: -100%;">
<defs>
<filter id="imagenconturbulencias" x="0" y="0" width="100%" height="100%">
<feTurbulence result="cloud" baseFrequency=".2" seed="22" stitchTiles="nostitch" type="fractalNoise" numOctaves="3">
<animate
attributeName="baseFrequency"
calcMode="spline"
dur="5s"
values=".2;.1;"
repeatCount="indefinite"
/>
</feTurbulence>
<feComposite operator="in" in="cloud" in2="SourceGraphic"/>
</filter>
</defs>
<g stroke="none" stroke-width="4" id="rlog" fill="#eee"><path d="M34.2,13.9v19.5h-7.3V13.9H34.2z M30.5,5.2c1,0,1.8,0.3,2.6,1s1.1,1.5,1.1,2.5c0,1-0.3,1.8-1,2.5s-1.6,1-2.6,1c-1.1,0-1.9-0.3-2.6-1s-1-1.5-1-2.5c0-1,0.4-1.8,1.1-2.5S29.5,5.2,30.5,5.2z"/></g>
</svg>
<div id="a">
<svg viewBox="0 0 230 280">
<use filter="url(#imagenconturbulencias)" xlink:href="#rlog"></use>
</svg>
</div>
If you look closely, after 5 seconds animation repeats itself, as should! but it does not look so pretty.
I know this filter is used to create realistic, cloud-like structures. How do we go about moving these clouds continuously ?
feTurbulence filter takes in parameters like randomSeed numberOfOctaves and baseFrequency.
In given example I've animated value of base frequency. Since there is no more attributes to animate.
How to make this animation to appear continuous? Do we use perlin noise generator combined with matrix and displacement maps on this turbulence generated thing and animate all together somehow? (just brainstorming..)
Any help, Ideas, approaches, snippets, sincerely appreciated.
this could be black&white for simplicity, but cloud animation still is not continious. Bonus snippet
Do not animate the base frequency. For a smooth effect use a 360 hueRotate and a colorMatrix (since hueRotate cycles back to the original value).
<svg x="0px" y="0px" width="800px" height="500px" viewbox="0 0 800 500">
<script type="text/ecmascript" xlink:href="http://www.codedread.com/lib/smil.user.js"/>
<defs>
<filter id="heavycloud" color-interpolation-filters="sRGB" x="0%" y="0%" height="100%" width="100%">
<feTurbulence type="fractalNoise" result="cloudbase" baseFrequency=".0025" numOctaves="5" seed="24"/>
<feColorMatrix in="cloudbase" type="hueRotate" values="0" result="cloud">
<animate attributeName="values" from="0" to="360" dur="20s" repeatCount="indefinite"/>
</feColorMatrix>
<feColorMatrix in="cloud" result="wispy" type="matrix"
values="4 0 0 0 -1
4 0 0 0 -1
4 0 0 0 -1
1 0 0 0 0
"/>
<feFlood flood-color="#113388" result="blue"/>
<feBlend mode="screen" in2="blue" in="wispy"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite operator="in" in2="SourceGraphic"/>
</filter>
</defs>
<text x="30" y="380" filter="url(#heavycloud)" font-size="400" font-family="arial" stroke-color="blue" font-weight="bold" kerning="-75" font-stretch="condensed">SVG!</text>
</svg>
I'm using this answer to apply a drop shadow on a SVG element like a circle. I have a fill attribute on my element to apply a background color on it, and now I'd like to combine all that with a background image on the circle.
I've tried using a <pattern>but I can only have the background-image, or adding <feImage> to my filter drop shadow but the filter doesn't work anymore.
Basically, what should I add to this code knowing my image can be found in /public/images/... :
<filter id="dropshadow" width="130%" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer>
<feFuncA type="linear" slope="0.1"/>
</feComponentTransfer>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<circle cx="50%" cy="50%" r="49%" filter="url(#dropshadow)" fill="#f8f8f8" stroke="#e7e7e7" stroke-width="1px"/>
Well I don't know how hard you tried on the feImage,. but this code works perfectly. You want to pull in the feImage, then clip it to the source with a feComposite "in". Then you can composite the dropshadow under that result.
<svg>
<defs>
<filter id="dropshadow" width="130%" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer in="offsetblur" result="dropshadow">
<feFuncA type="linear" slope="0.1"/>
</feComponentTransfer>
<feImage result="bgpic" xlink:href="http://www.sencha.com/img/sencha-large.png" />
<feComposite operator="atop" in="bgpic" in2="SourceGraphic" result="coikelwimg"/>
<feMerge>
<feMergeNode in="coikelwimg"/>
<feMergeNode in="dropshadow"/>
</feMerge>
</filter>
</defs>
<circle cx="50%" cy="50%" r="49%" filter="url(#dropshadow)" fill="#f8f8f8" stroke="#e7e7e7" stroke-width="1px"/>
</svg>