Is there a way to remove <defs> elements from <svg> with plain javascript or jquery?
I found solutions with d3 library, but I would like to avoid adding the whole library just for this.
Remove elements using ChildNode.remove() and passing the desired selector to querySelector
document.querySelector("defs").remove();
<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Some graphical objects to use -->
<defs>
<circle id="myCircle" cx="0" cy="0" r="5" />
<linearGradient id="myGradient" gradientTransform="rotate(90)">
<stop offset="20%" stop-color="gold" />
<stop offset="90%" stop-color="red" />
</linearGradient>
</defs>
<!-- using my graphical objects -->
<use x="5" y="5" xlink:href="#myCircle" fill="url('#myGradient')" />
</svg>
For multiple elements use querySelectorAll and NodeList.forEach:
document.querySelectorAll("defs").forEach(EL => EL.remove());
Related
I have a circular, image mask set up in HTML to cover an image.
Here is that code for reference:
<div id="group-focus">
<svg height="800" viewbox="0 0 1000 800">
<defs>
<mask id="text-mask" maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse">
<circle cx="600" cy="400" r="400" fill="white">
</mask>
</defs>
<!-- this is the image that I masked -->
<g mask="url(#text-mask)">
<image id="text-focus" width="2560" height="1440"
y="0" x="0" xlink:href="img/Asset13x.png" />
</g>
</svg>
</div>
Because I have the mask size set in HTML to the size I want, I am unsure of how to go about expanding the mask to a different size. Can you animate a mask in Javascript? This is for a motion graphic project I am working on currently.
Thanks!
How could I create a rect with blurred stroke in svg using d3.js?
Or at least an ordinary svg markup.
I was not able to find such an example or a solution to the problem. If you will tell me that it is a duplicate and provide a similar question I will gladly delete this one. But I am pretty sure that it is not a duplicate.
You might want to look at this article "Adding a subtle touch of glow to your d3.js visualizations"
If you want to do it manually, you can use the feGaussianBlur filter, more infos here : feGaussianBlur
From Mozilla Developer :
<svg width="230" height="120"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="blurMe">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
</filter>
<circle cx="60" cy="60" r="50" fill="green" />
<circle cx="170" cy="60" r="50" fill="green"
filter="url(#blurMe)" />
</svg>
Here's a storyboard of the CSS/JS/SVG animation I'm trying to accomplish. Two triangle masks enter from either side, then intersect resulting in a negative mask:
The point where the triangles intersect is where it gets tricky. When I export the mask for panel 4 to SVG, it looks like this:
<svg width="416px" height="289px" viewBox="0 0 416 289" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M211.503681,65.6626347 L507.009604,-138.787586 L507.009604,425.787586 L211.507182,221.339788 L-84,425.792431 L-84,-138.787586 L211.503681,65.6626347 Z M211.503681,65.6626347 L99,143.5 L211.507182,221.339788 L324.01001,143.502422 L211.503681,65.6626347 Z" id="path-1"></path>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Rectangle-1-Copy-3" fill="#F6A623" x="0" y="0" width="416" height="289"></rect>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Combined-Shape" fill="#000000" xlink:href="#path-1"></use>
<rect id="Rectangle-1-Copy-2" fill="#4990E2" mask="url(#mask-2)" x="0" y="0" width="416" height="289"></rect>
</g>
</svg>
It looks like it's basically drawing two shapes, the negative-space diamond mask in the center and the remainder of the outer triangles.
So the static mask itself appears to be possible with SVG, but I don't know how to animate it. Is there a library that can simplify this kind of SVG transition/tweening, or a fancy math equation that can calculate the paths dynamically?
Or am I looking at this the wrong way entirely and there's a much easier way to do it altogether?
So the solution was to make it both more simple AND more complicated.
Instead of two layers on top of each other with one mask, I needed three layers. One on the bottom to show behind the first mask, the second to be masked by the incoming triangles, and a third layer above that, duplicate to the first, where a diamond-shaped mask is applied.
<svg width="500" height="300" viewbox="0 0 500 300">
<defs>
<clipPath id="triangles">
<path id="left" d="M-250,-150 L250,150 L-250,450 Z" fill="black" />
<path id="right" d="M250,150 L750,-150 L750,450 Z" fill="black" />
</clipPath>
<clipPath id="diamond">
<path id="diamond-path" d="M250,0 L500,150 L250,300 L0,150 Z" fill="black" />
</clipPath>
</defs>
<!-- bottom -->
<g id="bottom">
<rect fill="darkorange" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
<!-- middle/triangles -->
<g id="middle" clip-path="url(#triangles)">
<rect fill="dodgerblue" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
<!-- top/diamond -->
<g id="top" clip-path="url(#diamond)">
<rect fill="darkorange" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
</svg>
The top layer with the diamond path starts out scaled to 0, making it invisible. The two triangle clip paths are animated in towards each other, showing the bottom layer underneath. When the two triangle points meet, the diamond clip path on the top layer is scaled up, revealing the top layer which is a duplicate of the bottom.
I also switched to clip paths instead of masks because they're a) better supported and b) allow for multiple paths.
Here's a Codepen using CSS for the animations (only works in WebKit for the moment).
UPDATE: Here's a Codepen using GSAP that works in all browsers: http://s.codepen.io/kgrote/debug/mPxzZY
I have created an SVG egg and animated a path and added a gradient fine. I've added a linear gradient and it goes top to bottom, however i'd like 0% to be the dark colour and 100% be the light colour - so essentially the gradient is following the already existing path and getting lighter as the number increases.
Here is a link to my jsFiddle. It's probably better for me to link you guys there than put code in here (as for some reason the text doesn't render on SO's snippet thing)
http://jsfiddle.net/andyjh07/Lrywj95t/
Here is the SVG code if you need it:
<div id="stage">
<div class="egg-holder">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 104.7 144.3" enable-background="new 0 0 104.7 144.3" xml:space="preserve">
<defs>
<linearGradient id="orangeGradient"
x1="0%" y1="0%"
x2="0%" y2="100%"
spreadMethod="pad">
<stop offset="0%" stop-color="#ff9800" stop-opacity="1"/>
<stop offset="100%" stop-color="#e65100" stop-opacity="1"/>
</linearGradient>
</defs>
<g id="egg-grey">
<path fill="#FFFFFF" stroke="#212121" stroke-width="10" stroke-miterlimit="10" d="M99.3,92.2c0,25.7-20.8,46.5-46.5,46.5 S6.3,117.8,6.3,92.2S27.2,5.7,52.8,5.7S99.3,66.5,99.3,92.2z"/>
</g>
<g id="egg-orange">
<path fill="none" stroke="url(#orangeGradient)" stroke-width="10" stroke-miterlimit="10" d="M99.3,92.2c0,25.7-20.8,46.5-46.5,46.5 S6.3,117.8,6.3,92.2S27.2,5.7,52.8,5.7S99.3,66.5,99.3,92.2z"/>
</g>
</svg>
<div class="timer">
<p></p>
</div>
</div>
</div>
If I understand your question correctly you want to have a gradient along an SVG path.
It looks like from this question, it's not possible to do this without segmenting the path.
I did however find this reference, it's a pretty complex chunk of code, but based on the result he's able to accomplish what you're after.
Good luck!
Is it possible to create a variable gradient with SVG objects? Here is what I am trying to do:
I have a a horizontal bar chart and I want to apply shading to it. So the top most bar would have the most shading, and the bar after that less shading and so on. However, the number of bars is variable.
I don't want to create a gradient for every bar (plus with a variable number of bars thats hard), what I would like to do is use one gradient for each bar. In the selectall statement, can I edit the gradient that is in the def section? Something like:
.attr("stop-color", function(d,i) "rgb("+50*i+","+50*i+","+50*i+")")"?
I think I need to reference the name of the gradient somewhere. Is this even possible?
If you mean you want to have a gradient that applies across a group of objects, then yes. That is possible. You just have to define the gradient with absolute coordinates. To do that, use gradientUnits="userSpaceOnUse".
Below I am defining a gradient that starts at (0,0) and goes to (0,400). All objects that fall betwee y=0 and y=400 will be drawn using an appropriate part of that gradient.
<svg width="400px" height="400px">
<defs>
<linearGradient id="mygradient" gradientUnits="userSpaceOnUse"
x1="0" y1="0" x2="0" y2="400">
<stop offset="0" stop-color="red"/>
<stop offset="1" stop-color="blue"/>
</linearGradient>
</defs>
<g fill="url(#mygradient)" stroke="black" stroke-width="4">
<rect x="5" y="5" width="390" height="90"/>
<rect x="5" y="105" width="390" height="90"/>
<rect x="5" y="205" width="390" height="90"/>
<rect x="5" y="305" width="390" height="90"/>
</g>
</svg>