Add shadow to an SVG icon - svg

i try to create two svg-icons
one with a shadow
and one with an inset-shadow
I tried many solutions but the shadow from my icon looks the hole time "wrong".
I dont get it. Can somebody help me please.
I create a preview with photoshop, so u can better understand what i need.
FIDDLE HERE
http://jsfiddle.net/7dghx0tr/
svg
<defs>
<radialGradient id="rgrad" cx="50%" cy="50%" r="75%" >
<stop offset="0%" style="stop-color:#87e0fd;stop-opacity:1" />
<stop offset="100%" style="stop-color:#05abe0;stop-opacity:1" />
</radialGradient>
<filter id="drop-shadow">
<feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
<feOffset dx="5" dy="5" result="offsetblur"/>
<feFlood flood-color="#000000"/>
<feComposite in2="offsetblur" operator="in"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<style type="text/css" >
<![CDATA[
* { stroke: #006584;
stroke-width: 0.3;
fill:url(#rgrad);}
path { stroke: #666666;
stroke-width: 0.1;
filter:url(#drop-shadow);}
]]>
</style>
</defs>
<g>
<path d="M33.437,13.872C30.938,9.97,41.322,4.599,34.753,0.46c-1.508-0.944-3.168,1.32-1.572,2.322
c3.627,2.279-5.914,6.629-1.999,12.745C32.181,17.08,34.434,15.431,33.437,13.872z"/>
<path d="M40.748,13.872c-2.507-3.914,7.894-9.268,1.314-13.412c-0.802-0.504-1.909-0.041-2.162,0.841
c-0.652,2.274,3.575,0.756-0.135,5.835c-1.995,2.729-3.094,5.551-1.275,8.392C39.503,17.089,41.732,15.412,40.748,13.872z"/>
<path d="M26.086,13.872C23.578,9.955,33.99,4.608,27.401,0.46c-1.503-0.946-3.17,1.319-1.572,2.322
c3.601,2.263-5.892,6.665-1.999,12.745C24.833,17.08,27.08,15.434,26.086,13.872z"/>
<path d="M31.563,33.913c15.729,0,24.001-4.011,24.001-7.331c0-3.832-10.432-7.489-23.49-7.322
c-13.082-0.168-23.489,3.5-23.489,7.322C8.585,30.123,17.818,33.913,31.563,33.913z M31.87,21.226c0.048,0,0.096,0,0.145,0.002
v0.001c0.02,0,0.04-0.001,0.06-0.001c0.021,0,0.04,0.001,0.06,0.001v-0.001c0.049-0.001,0.097-0.002,0.145-0.002
c9.891,0,19.903,1.744,19.903,5.075c0,4.3-15.53,5.176-20.048,5.074v-0.001c0,0-0.118,0-0.119,0v0.001
c-4.641,0.106-20.046-0.805-20.046-5.074C11.969,22.969,21.979,21.226,31.87,21.226z"/>
<path d="M17.636,28.765l0.08-4.949c-2.973,0.763-4.62,1.697-4.62,2.484C13.096,27.081,14.714,28.006,17.636,28.765z"/>
<path d="M24.491,22.697c-1.673,0.164-3.178,0.376-4.511,0.625l-0.094,5.941c1.332,0.251,2.84,0.468,4.516,0.634L24.491,22.697z"/>
<path d="M31.258,22.361c-1.595,0.012-3.098,0.067-4.51,0.157l-0.094,7.561c1.41,0.092,2.914,0.148,4.509,0.162L31.258,22.361z"/>
<path d="M56.106,28.697c-0.004-0.068-0.022-0.134-0.03-0.202c-3.37,5.298-17.273,6.637-23.942,6.539v-0.002c0,0-0.117,0-0.119,0
v0.002c-8.507,0.125-20.9-1.76-23.941-6.539c-0.009,0.068-0.027,0.134-0.03,0.202c-2.588,0.566-3.726,1.76-3.654,3.796
c0.061,1.724,2.262,3.215,5.128,4.063c1.798,4.475,5.129,8.107,9.418,10.506l-6.173,14.399c-0.369,0.857,0.029,1.854,0.889,2.221
c0.216,0.092,0.442,0.137,0.665,0.137c0.656,0,1.28-0.384,1.555-1.024l6.126-14.29c5.895,2.286,13.754,2.481,20.156,0l6.126,14.29
c0.274,0.641,0.898,1.024,1.555,1.024c0.223,0,0.449-0.045,0.665-0.137c0.86-0.367,1.259-1.363,0.89-2.221l-6.174-14.399
c4.289-2.398,7.619-6.031,9.419-10.506c2.865-0.848,5.065-2.339,5.128-4.063C59.831,30.457,58.694,29.263,56.106,28.697z
M7.219,32.812c-0.049-0.926,0.094-1.466,0.917-1.815c0.115,1.139,0.338,2.233,0.625,3.297C7.835,33.934,7.25,33.442,7.219,32.812z
M55.388,34.294c0.288-1.064,0.511-2.159,0.626-3.297c0.821,0.349,0.965,0.889,0.916,1.815
C56.898,33.442,56.313,33.934,55.388,34.294z"/>
<path d="M51.054,26.3c0-0.787-1.647-1.722-4.62-2.484l0.079,4.949C49.435,28.006,51.054,27.081,51.054,26.3z"/>
<path d="M44.262,29.262l-0.093-5.941c-1.334-0.248-2.839-0.461-4.511-0.625l0.089,7.199C41.423,29.73,42.93,29.514,44.262,29.262z"
/>
<path d="M37.496,30.079l-0.095-7.561c-1.412-0.09-2.915-0.145-4.51-0.157l0.096,7.879C34.582,30.227,36.085,30.171,37.496,30.079z"
/>
</g>
</svg>

Well for a start, you are applying the filter to every path element in the file. You only want to apply it to the parent <g>.
Move the filter from <path> and apply it only to the <g>.
path {
stroke: #666666;
stroke-width: 0.1;
}
g {
filter:url(#drop-shadow);
}
I think you will begin to make progress then.

Related

How to add image to nodes in Cytoscape

I'm using Cytoscape.js and Svelte to display a graph. I currently have my graph displayed but I want to add an svg image to the background-image of each node.
I've tried a few situations but currently this random .jpg works properly for background image. I cannot get my svg to work at all, it just displays the default circle node.
{
selector: '#HQ',
style: {
// 'background-image': '../../static/icons/server.svg'
// 'background-image': 'url(../../static/icons/server.svg)'
'background-image': 'url(https://live.staticflickr.com/7272/7633179468_3e19e45a0c_b.jpg)'
}
}
My question is, am I typing in the file paths incorrectly or could I potentially be something wrong with the SVG itself. I tried my exact SVG in someone elses code and it just doesn't display anything either and they used SVG.
This is the router.svg file:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 76 81" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<style>
<![CDATA[
.RouterB {
stroke: none
}
]]>
</style>
<use xlink:href="#RouterC" x=".5" y=".5" />
<defs>
<linearGradient id="RouterA" x1="100%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" />
<stop offset="100%" stop-color="gray" />
</linearGradient>
<path id="RouterB" d="M37.527 69.604v2.712l.655 1.356 1.53.904.874-.678v-2.486z" />
</defs>
<symbol id="RouterC" overflow="visible">
<g fill="url(#RouterA)" class="RouterB">
<path d="M69.705 20c0-1.23-.1-2.222-1.324-2.222s-1.324.99-1.324 2.222l-.882 31.11h4.412z" />
<path d="M38.823 2.222C38.823.99 38.722 0 37.5 0s-1.324.99-1.324 2.222l-.882 31.11h4.412z" />
</g>
<path d="M31.4 27.12q-1.53-.904-3.06 0L.82 43.4q-1.53.904 0 1.808l42.826 25.31q1.53.904 3.06 0l27.53-16.27q1.53-.904 0-1.808L31.4 27.12" fill="#eceff1" class="RouterB" />
<path d="M45.175 70.96q.765 0 1.53-.452l27.53-16.27q.765-.452.765-.904v9.04q0 .452-.765.904l-27.53 16.27q-.765.452-1.53.452z" fill="#78909c" class="RouterB" />
<path d="M45.175 70.96q-.792.017-1.584-.45L.765 45.198Q0 44.746 0 44.294v9.04q0 .452.765.904l42.826 25.31q.792.468 1.584.45z" fill="#b0bec5" class="RouterB" />
<path d="M3.223 48.814v6.78l3.715 2.26v-6.78z" fill="#464646" class="RouterB" />
<ellipse cx=".665" cy=".448" rx=".665" ry=".448" transform="matrix(.866025 .5 -.5 .866025 4.666385 51.191101)" class="RouterB" />
<g fill="#464646">
<use xlink:href="#RouterB" class="RouterB" />
<path d="M32.94 66.893v2.712l.655 1.356 1.53.904.874-.678V68.7zm-4.6-2.713v2.712l.655 1.356 1.53.904.874-.678V66z" class="RouterB" />
<use xlink:href="#RouterB" x="-13.765" y="-8.134" class="RouterB" />
<use xlink:href="#RouterB" x="-18.354" y="-10.847" class="RouterB" />
</g>
<path d="M43.2 40.17l8.548-.767-1.185 5.03-2.454-1.45-7.363 4.263-2.37-1.364 7.278-4.348zM27.36 45.5l8.548.767-1.185-5.03-2.454 1.45-7.363-4.263-2.37 1.364 7.278 4.348zm4.687 9.944l-8.548.767 1.185-5.03 2.454 1.45 7.363-4.263 2.37 1.364-7.278 4.348zM48.42 49.8l-8.548-.767 1.185 5.03 2.454-1.45 7.363 4.263 2.37-1.364-7.278-4.348z" class="RouterB" fill="#788f9b" />
</symbol>
</svg>
Thanks

Animate SVG on scroll using GSAP

GSAP has this ScrollTrigger plugin that will trigger animations on scroll, that I would like to use.
I already got a working SVG animation (without GSAP):
<svg width="596" height="255">
<linearGradient id="prog-mask" x1=0% x2="100%" y1="0%" y2="100%">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="5%" stop-color="white" stop-opacity="0">
<animate attributeName="offset" values="0; 1" dur="2s" begin="0s" repeatCount="0" fill="freeze" />
<animate attributeName="stop-opacity" values="0; 1" dur="2s" begin="2s" repeatCount="0" fill="freeze" />
</stop>
<stop offset="100%" stop-color="white" stop-opacity="0" />
</linearGradient>
<mask id="prog-render">
<rect x="0" y="0" width="100%" height="100%" fill="url(#prog-mask)"/>
</mask>
<pattern id="pattern-circles" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="6" cy="6" r="3" stroke="red" stroke-width="2" fill="transparent">
<animate attributeName="r" values="0; 5" dur="2s" begin="0s" repeatCount="0" fill="freeze" />
</circle>
</pattern>
<!-- The canvas with our applied pattern -->
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-circles)" mask="url(#prog-render)"/>
</svg>
As mentioned, this SVG animation is not hooked up with GSAP (which I believe is a must if it should work in conjunction with the ScrollTrigger plugin?)
That's why I have tried to create this animation using GSAP:
// 1. offset
gsap.to("#prog-mask stop:nth-child(2)", {
duration: 2,
attr: { offset: 1, fill: "freeze" },
repeat: 1,
delay: 0
});
// 2. stop-opacity
gsap.to("#prog-mask stop:nth-child(2)", {
duration: 5,
attr: { stopOpacity: 1, fill: "freeze" },
repeat: 1,
delay: 2
});
// 3. r = radius
gsap.to("circle", {
duration: 5,
attr: { r: 5, fill: "transparent" },
repeat: 0,
delay: 0
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.0/gsap.min.js"></script>
<section>
<svg width="596" height="255">
<linearGradient id="prog-mask" x1=0% x2="100%" y1="0%" y2="100%">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="5%" stop-color="white" stop-opacity="0">
<!-- <animate attributeName="offset" values="0; 1" dur="2s" begin="0s" repeatCount="0" fill="freeze" />
<animate attributeName="stop-opacity" values="0; 1" dur="2s" begin="2s" repeatCount="0" fill="freeze" />-->
</stop>
<stop offset="100%" stop-color="white" stop-opacity="0" />
</linearGradient>
<mask id="prog-render">
<rect x="0" y="0" width="100%" height="100%" fill="url(#prog-mask)"/>
</mask>
<pattern id="pattern-circles" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="6" cy="6" r="0" stroke="red" stroke-width="1.5" fill="transparent">
<!--<animate attributeName="r" values="0; 5" dur="2s" begin="0s" repeatCount="0" fill="freeze" />-->
</circle>
</pattern>
<!-- The canvas with our applied pattern -->
<rect id="rect" x="0" y="0" width="100%" height="100%" fill="url(#pattern-circles)" mask="url(#prog-render)"/>
</svg>
</section>
As you can tell, I have basically just tried to replace the three <animate> elements with some GSAP code.
At this point the dots are revealed immediately and not revealed in a linear fashion from top left to bottom right.
Also, for some unknown reason, the whole rectangle is gradient (actually, I don't mind this effect, but I don't understand why it is happening?).
Do I have to animate this SVG in GSAP to use ScrollTrigger?
How can I get the original animation result using GSAP?
Why does this color gradient happen in the GSAP code?
Do I have to animate this SVG in GSAP to use ScrollTrigger?
It depends. If you just want to fire off an animation (SMIL animation, CSS animation, GSAP animation, whatever), you could use the ScrollTrigger callbacks to do that.
If you want to scrub through the animation it probably makes sense to make the animation in GSAP because it's easier to update. AFAIK, you can't tell SMIL animations to go to a specific progress point like you can with GSAP.
With that being said, pretty much everyone who animates SVGs regularly recommends using JS for your SVG animations in most cases (more info on that here).
Why does this color gradient happen in the GSAP code?
If you look at the SVG of the GSAP version with your dev tools you can see it's animating a stopOpacity attribute instead of the stop-opacity attribute. Using the regular attribute name (i.e. not camel-case) inside of quotes fixes that.
How can I get the original animation result using GSAP?
I'd make use of GSAP's timeline functionality to set things up like this: Demo.

How to apply a gradient to a marker?

In SVG, how to apply the gradient applied to a line to its marker-end ?
<?xml version='1.0' encoding='UTF-8' standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="820px"
height="500px"
viewBox="0 0 820 500"
version="1.1" >
<style>
.axis3 {
stroke-width: 40px;
marker-end:url(#arrow);
stroke: url('#gradient_3');
fill: url('#gradient_3');
height: 30px;
}
.axis4 {
stroke-width: 40px;
marker-end:url(#arrow);
stroke: url('#gradient_4');
fill: url('#gradient_4'); /* corrected */
height: 30px;
}
</style>
<defs>
<marker
id="arrow"
markerWidth="20"
markerHeight="40"
refX="0"
refY="20"
orient="auto"
markerUnits="userSpaceOnUse"
style="fill:inherit;">
<path style="stroke:none;fill:inherit;overflow:visible;" d="M0 0 L20 20 L0 40 Z" />
</marker>
<linearGradient id="gradient_3" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse" >
<stop offset="0%" stop-color="yellow" />
<stop offset="20%" stop-color="red" />
</linearGradient>
<linearGradient id="gradient_4" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse" >
<stop offset="0%" stop-color="blue" />
<stop offset="20%" stop-color="green" />
</linearGradient>
</defs>
<line class="axis3" x1="50" x2="400" y1="50" y2="50" />
<line class="axis4" x1="50" x2="400" y1="100" y2="100" />
</svg>
With the code above, marker is always black.
As there are several elements line with different gradients, gradient can not be applied directly on the path.
I tried to add style="fill:inherit" - with no success.
This is how I would do it:
Instead of fill:inherit; I'm setting two css variables for the svg element: style="--fill:url(#gradient_3); --stroke:url(#gradient_4)". Both the line and the marker are using those variables for the fill and the stroke.
Alternatively you may choose to use the gradients directly in the code <path style="overflow:visible;fill:url(#gradient_3);"...
To your code I've added a #gradient_3 since you are using it.
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="820px"
height="500px"
viewBox="0 0 820 500"
version="1.1"
style="--fill:url(#gradient_3); --stroke:url(#gradient_4)">
<style>
.axis {
stroke-width: 40px;
marker-end:url(#arrow);
height: 30px;
stroke:var(--stroke);
}
</style>
<defs>
<marker
id="arrow"
markerWidth="20"
markerHeight="40"
refX="0"
refY="20"
orient="auto"
markerUnits="userSpaceOnUse">
<path style="overflow:visible;fill:var(--fill);" d="M0 0 L20 20 L0 40 Z" />
</marker>
<linearGradient id="gradient_3" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse" >
<stop offset="0%" stop-color="green" />
<stop offset="20%" stop-color="blue" />
</linearGradient>
<linearGradient id="gradient_4" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse" >
<stop offset="0%" stop-color="blue" />
<stop offset="20%" stop-color="green" />
</linearGradient>
</defs>
<line class="axis" x1="50" x2="400" y1="50" y2="50" />
</svg>
Answer to "Make marker-end same color as path?" mentions that there is no inheritance of colors from related path.
Situation has not evolve since this answer.

Is it possible to remove the stroke from being displayed from within the filter only?

I am trying to figure out what I need to change in the SVG below to remove the stroke entirely from the filter? I want to keep the element as it is, I just want the stroke removed from the filter, in the most simple way, and I can't seem to figure out if this is even possible?
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="640" height="480" viewBox="0 0 640 480" xml:space="preserve">
<rect x="0" y="0" width="640" height="480" fill="rgba(255,255,255,1)"></rect>
<filter id="SVGID_3" y="-20%" height="140%" x="-82%" width="264%">
<feGaussianBlur in="SourceAlpha" stdDeviation="0"></feGaussianBlur>
<feOffset dx="100" dy="0" result="oBlur"></feOffset>
<feFlood flood-color="rgb(221, 221, 221)"></feFlood>
<feComposite in2="oBlur" operator="in"></feComposite>
<feMerge>
<feMergeNode></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<circle cx="0" cy="0" r="81" style="stroke: rgb(0,0,0); stroke-width: 36; stroke-dasharray: 7 7; stroke-linecap: butt; stroke-linejoin: bevil; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;filter: url(#SVGID_3);" transform="translate(213 86.2) "></circle>
</svg>
Thank you
The basic answer is no. You could make the black parts transparent, but it would leave the red circle with chunks missing where the stroke used to be. I doubt that is what you want.
However if you mean "how do I achieve that effect by altering this SVG", then the answer would be to duplicate the circle and give one the fill and the filter, and the other the stroke.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="640" height="480" viewBox="0 0 640 480" xml:space="preserve">
<rect x="0" y="0" width="640" height="480" fill="rgba(255,255,255,1)"></rect>
<filter id="SVGID_3" y="-20%" height="140%" x="-82%" width="264%">
<feGaussianBlur in="SourceAlpha" stdDeviation="0"></feGaussianBlur>
<feOffset dx="100" dy="0" result="oBlur"></feOffset>
<feFlood flood-color="rgb(221, 221, 221)"></feFlood>
<feComposite in2="oBlur" operator="in"></feComposite>
<feMerge>
<feMergeNode></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<circle cx="0" cy="0" r="81" style="fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;filter: url(#SVGID_3);" transform="translate(213 86.2) "></circle>
<circle cx="0" cy="0" r="81" style="stroke: rgb(0,0,0); stroke-width: 36; stroke-dasharray: 7 7; stroke-linecap: butt; stroke-linejoin: bevel; stroke-miterlimit: 10; fill: none;" transform="translate(213 86.2) "></circle>
</svg>

Blurring svg shapes as they pass through clip path

Example below:
I'd like to maintain a fixed area in the middle that has svg circles being animated through it.
Most examples I've seen involve some sort of merge that ends up showing both the original circle and the blurred version. Led me to something like this:
<clipPath id="top-mask">
<rect id="top-mask-rect" x="0" y="-100" width="100" height="100" />
</clipPath>
<filter id="top-blur" x="-200%" y="-200%" width="500%" height="500%">
<feimage xlinkHref="url(#top-mask)" result="mask" />
<feGaussianBlur stdDeviation="1.5" result="blur" />
<feComposite in2="mask" in="blur" operator="in" result="comp" />
<feMerge result="merge">
<feMergeNode in="SourceGraphic" />
<feMergeNode in="comp" />
</feMerge>
</filter>
This seems to overlay the circles on top of a slightly blurred version. My next naive step was to remove the feComposite and instead apply clipPath to both feMergeNode which didn't work at all.
What is the correct approach to this problem?
Things are not that elementary. You have to stack things a bit on top of one another for this to work. You need a mask to show the un-blurred object outside, and a filter to show it inside the designated area. Both need units defined as userSpaceOnUse.
#moving {
animation: move 5s ease-in-out infinite;
}
#keyframes move {
0% { transform: translate(0px, 0px) }
50% { transform: translate(300px, 0px) }
100% { transform: translate(0px, 0px) }
}
<?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"
height="300" width="500">
<defs>
<mask id="mask"
maskUnits="userSpaceOnUse">
<rect width="100%" height="100%" fill="white" />
<rect id="still" x="150" y="0" width="200" height="300" fill="black" />
</mask>
<filter id="blur" x="150" y="0" width="200" height="300"
filterUnits="userSpaceOnUse">
<feGaussianBlur stdDeviation="10" />
</filter>
</defs>
<g mask="url(#mask)">
<circle id="moving" r="60" cy="150" cx="100" fill="blue" />
</g>
<g filter="url(#blur)">
<use xlink:href="#moving" />
</g>
</svg>
The way the filter works is interesting. It seems the object is clipped before the blur is applied, resulting in a blur near the border of the designated area instead of a hard cut. I am unsure whether to call this a bug or expected behavior. (A quick test showed this both for Firefox and Chrome.)

Resources