How to apply CSS filter saturate to SVG elements? [duplicate] - css

This question already has an answer here:
Why don't CSS filters work on SVG elements in Chrome?
(1 answer)
Closed 4 years ago.
I have this svg composition:
<svg width="400" height="200">
<circle id="circle-1" cx="50" cy="100" r="40"></circle>
<circle id="circle-2" cx="150" cy="100" r="40"></circle>
</svg>
I would like to apply filter: saturate(0.2) to the second circle but the CSS filter property is not working.

In SVG elements we have to use SVG Color Matrix Transformations.
For the specific case we have to do:
<svg width="400" height="200">
<filter id="saturate" filterUnits="objectBoundingBox">
<feColorMatrix type="saturate" in="SourceGraphic" values="0.2"/>
</filter>
<circle id="circle-1" cx="50" cy="100" r="40" ></circle>
<circle id="circle-2" cx="250" cy="100" r="40" filter="url(#saturate)"></circle>
</svg>
Working example: https://jsfiddle.net/fguillen/dx947a36/19/

Related

Apply :hover to all children of an svg group

How do I get all the elements of an svg group to change their fill color on hover?
The example below does not work at all. If I use .sgroup circle:hover only the circle under the pointer works not both.
.sgroup:hover {
fill: green;
}
<div>
<svg width="200" height="200">
<g class="sgroup">
<circle cx="50" cy="50" fill="pink" r="10" ></circle>
<circle cx="150" cy="150" fill="purple" r="10" ></circle>
</g>
</svg>
</div>
Please see below. I assume this is what you're looking for?
.sgroup:hover circle {
fill: green;
}
<div>
<svg width="200" height="200">
<g class="sgroup">
<circle cx="50" cy="50" fill="pink" r="10" ></circle>
<circle cx="150" cy="150" fill="purple" r="10" ></circle>
</g>
</svg>
</div>

Portions of SVG that were offscreen while zoomed in disappear when zooming back out

I'm using css transitions to animate zooming into an SVG. The only problem is that when zooming out, portions of the SVG are missing until the animation is complete and then it all pops in.
(Only tested in Chrome on a Mac so far)
I'm not changing the SVG at all, just zooming in and then back out by setting the a scale transform on a group in the SVG.
How can I make the browser re-render these offscreen elements so that don't pop in like this?
const root = document.getElementById('root')
setTimeout(function() {
root.setAttribute('transform', 'scale(10,10)')
}, 1)
setTimeout(function() {
root.setAttribute('transform', 'scale(1,1)')
}, 4200)
#root {
transition: 4s transform;
}
circle {
stroke: white;
stroke-width: 3px;
}
<svg viewbox="0 0 300 100">
<g id="root">
<circle cx="50" cy="50" r="50" />
<circle cx="100" cy="50" r="50" />
<circle cx="150" cy="50" r="50" />
<circle cx="200" cy="50" r="50" />
<circle cx="250" cy="50" r="50" />
</g>
</svg>
As said in comments, this is probably because of some optimizations in the CSS renderer.
This is a Chrome bug (one of the many they have with their CSS paintings optimizations...), and you should let them know about it.
For the time being, have you considered using SMIL instead?
Since you used javascript in your code, I will assume you run this in a browser from some place where script execution is allowed (i/e not in <img> tag), and hence where you will be able to use a polyfill like FakeSmile.
So this will actually offer you a better browser support than through CSS transitions (IIRC IE<11 didn't support CSS transform transitions on svg elements), and moreover than the still experimental SVG2 only mix-up CSS transition of SVGTransformAttribute.
Indeed, only Chrome does support it for now (probably because while some attributes were already CSS transitionable in SVG1.1, transform having a different syntax than its CSS equivalent, the algo should be differents).
Here is what your example would look like in SMIL:
// and if you need JS control
document.onclick = e => {
document.getElementById('zoomin').beginElement();
};
circle {
stroke: white;
stroke-width: 3px;
transform: translateZ(1);
}
<svg viewbox="0 0 300 100">
<g id="root">
<animateTransform attributeName="transform" type="scale" id="zoomin"
from="1 1" to="10 10" dur="4s" begin="1s"/>
<animateTransform attributeName="transform" type="scale" id="zoomout"
from="10 10" to="1 1" dur="4s" begin="zoomin.end"/>
<circle cx="50" cy="50" r="50" />
<circle cx="100" cy="50" r="50" />
<circle cx="150" cy="50" r="50" />
<circle cx="200" cy="50" r="50" />
<circle cx="250" cy="50" r="50" />
</g>
<!-- for IE -->
<script xlink:href="https://cdn.rawgit.com/FakeSmile/FakeSmile/master/smil.user.js"></script>
</svg>
How about, transition every circle,
is this ok for you?
I actually dont have an explanation about why it works this way
const circles = document.getElementsByTagName('circle')
setTimeout(function() {
circles[0].setAttribute('transform', 'scale(10,10)');
circles[1].setAttribute('transform', 'scale(10,10)');
circles[2].setAttribute('transform', 'scale(10,10)');
circles[3].setAttribute('transform', 'scale(10,10)');
circles[4].setAttribute('transform', 'scale(10,10)');
}, 1)
setTimeout(function() {
circles[0].setAttribute('transform', 'scale(1,1)');
circles[1].setAttribute('transform', 'scale(1,1)');
circles[2].setAttribute('transform', 'scale(1,1)');
circles[3].setAttribute('transform', 'scale(1,1)');
circles[4].setAttribute('transform', 'scale(1,1)');
}, 4200)
#root {
transition: 4s transform;
}
circle {
stroke: white;
stroke-width: 3px;
transition: 4s transform;
}
<svg viewbox="0 0 300 100">
<g id="root">
<circle cx="50" cy="50" r="50" />
<circle cx="100" cy="50" r="50" />
<circle cx="150" cy="50" r="50" />
<circle cx="200" cy="50" r="50" />
<circle cx="250" cy="50" r="50" />
</g>
</svg>
Why not transition the entire svg element?
const root = document.getElementById('root')
setTimeout(function() {
root.setAttribute('transform', 'scale(10,10)')
}, 1)
setTimeout(function() {
root.setAttribute('transform', 'scale(1,1)')
}, 4200)
#root {
transition: 4s transform;
transform-origin: top left;
}
circle {
stroke: white;
stroke-width: 3px;
}
<svg id="root" viewbox="0 0 300 100">
<g>
<circle cx="50" cy="50" r="50" />
<circle cx="100" cy="50" r="50" />
<circle cx="150" cy="50" r="50" />
<circle cx="200" cy="50" r="50" />
<circle cx="250" cy="50" r="50" />
</g>
</svg>
The setAttribute need the style attribue. Try this script:
setTimeout(function() {
root.setAttribute('style', 'transform: scale(10,10)')
}, 1)
setTimeout(function() {
root.setAttribute('style', 'transform: scale(1,1)')
}, 4200)

svg grouped elements jointly hover

Is it possible for hover on an svg element cause other elements with the same class to hover too without jQuery? Or do I have to next the two into an outer group?
I have inside an inline svg the following groups:
<g class="class1">
<path....>
<path....>
</g>
<g class="class1">
<path....>
<path....>
</g>
I then have in my CSS:
class1 {
...
}
class1:hover {
...
}
I guess you can't do it directly, but you can achieve it by adding an id to the parent element, no classes needed, like that:
#circles:hover circle{
fill: Wheat;
}
<svg id="circles" width="100" height="260" >
<circle cx="50" cy="50" r="40" stroke="Tomato" stroke-width="4" fill="Tomato" />
<circle cx="50" cy="140" r="40" stroke="Tomato" stroke-width="4" fill="Aquamarine"/>
</svg>

How do I add a drop shadow to an SVG path element?

I've been attempting to apply a drop shadow to my SVG Path. I googled across the filter option which when applied to path by applying: -webkit-filter: drop-shadow( -5px -5px 10px #000 ); which didn't seem to get applied.
Here's a fiddle with my SVG path demonstrating the problem
Within your JSFiddle, I deleted your CSS and added a filter definition. It seems to work:
<svg width="100%" height="300px">
<defs>
<filter id="filter1" x="0" y="0">
<feOffset result="offOut" in="SourceAlpha" dx="-5" dy="-5" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="3" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<path stroke-linejoin="round" stroke-linecap="round" stroke="red" stroke-opacity="1" stroke-width="5" fill="none" class="leaflet-clickable" d="M1063 458L1055 428L1034 433L1030 421L1017 423L911 452L895 455L885 441L859 424L809 410L788 394L774 377L744 309L730 313L727 304L669 319L599 341L596 331L491 364L488 357L498 343L490 343L450 352L417 256L371 270L366 253L355 256L351 242L217 282L194 210L191 196L166 113L45 147L44 140L13 150" filter="url(#filter1)"></path>
</svg>
Maybe a few tweaks to the dx, dy, and stdDeviation values will get it just the way you want.

SVG - Css filter to blur some elements

I am trying to apply the CSS filter blur to some elements but somehow this is not working.
Here is an example in a jsfiddle:
http://jsfiddle.net/kuyraypj/
I have applied the following css but my '.blurred' circle is not blurred at all.
HTML:
<svg width="500px" height="500px">
<circle class="blurred" cx="100" cy="100" r="50" fill="red"></circle>
<circle cx="220" cy="100" r="50" fill="red"></circle>
</svg>
CSS:
svg circle.blurred {
fill: green;
-webkit-filter: blur(5px);
-moz-filter: blur(5px);
-o-filter: blur(5px);
-ms-filter: blur(5px);
filter: blur(5px);
}
Is there a way to apply CSS3 filter to some svg elements or is there any other way?
Many thanks
Here is a SVG with the same filter effect as your CSS describes:
<svg width="500px" height="200px">
<defs>
<filter id="blur">
<feGaussianBlur stdDeviation="5" />
</filter>
</defs>
<circle cx="100" cy="100" r="50" fill="green" filter="url(#blur)" ></circle>
<circle cx="220" cy="100" r="50" fill="red"></circle>
</svg>
You can either use the filter attribute like in the above snippet or you can use CSS:
svg circle.blurred {
filter: url(#blur);
}
<svg width="500px" height="200px">
<defs>
<filter id="blur">
<feGaussianBlur stdDeviation="5" />
</filter>
</defs>
<circle class="blurred" cx="100" cy="100" r="50" fill="green"></circle>
<circle cx="220" cy="100" r="50" fill="red"></circle>
</svg>
It would seem that you are trying this!
http://www.w3schools.com/svg/svg_fegaussianblur.asp
However it is not supported by certain browsers.
http://www.w3schools.com/svg/tryit.asp?filename=trysvg_fegaussianblur

Resources