Reputation: 1150
I have an quite complex, dynamically created svg image, that has been created using jQuery SVG. I'd like to create a "popup" area that shows on top of all svg elements in the canvas. To create a modern translucent iOS7 like look I'd like to apply a blur filter to everything below the popup area. I want to be able to dynamically set the x,y and also width and height attributes of this popup area.
Have a look at this example:
<svg width="500" height="500">
<rect x="10" y="10" height="235" width="235" fill="red" />
<rect x="255" y="10" height="235" width="235" fill="green" />
<rect x="10" y="255" height="235" width="235" fill="blue" />
<rect x="255" y="255" height="235" width="235" fill="yellow" />
<rect x="50" y="50" height="400" width="400" fill="rgba(255,255,255,0.8)" />
</svg>
In this case, everything that is covered by the white area should be blurred. It should then look like this:
I have found this, but here a static background image is used, which I don't have. Is there any why to accomplish this effect using svg, css and jQuery?
Upvotes: 12
Views: 5959
Reputation: 31715
This is only directly possible with inline SVG in a single browser - Internet Explorer 10 - you use the "enable-background" attribute and use the built-in "BackgroundImage" source. This is the method shown in the text of the tutorial you linked to.
There is a workaround if your background is exclusively images. You write a filter that uses the feImage filter to pull in the same images that are in the background, blurs them, and composite the blur under whatever content you want to show on top. This is the method used in the actual code of the tutorial you linked to.
If your background is other SVG content (text, paths etc.), then there is no cross-browser way to achieve your effect since Firefox does not support SVG objects as inputs to the feImage filter primitive. If you don't care about Firefox then you can use the same workaround as that tutorial uses for images.
Here is an example of the latter - it's pretty close to what you want, but I've only tested it in Chrome/Windows (I know it doesn't work in Firefox)
<svg x="0px" y="0px" width="500px" height="500px" viewbox="0 0 500 500">
<defs>
<filter id="blurry" x="-20%" y="-20%" height="140%" width="140%" primitiveUnits="userSpaceOnUse">
<feImage x="0" y="0" width="500" height="500" xlink:href="#squares" result="mySquares"/>
<feGaussianBlur stdDeviation="40" in="mySquares" result="blurSquares"/>
<feComponentTransfer in="blurSquares" result="morealpha">
<feFuncA type="linear" intercept=".8"/>
</feComponentTransfer>
<feComposite operator="in" in="morealpha" in2="SourceGraphic" result="clipBlur"/>
<feFlood x="10%" y="10%" width="80%" height="80%" flood-color="white" flood-opacity="0.6" result="whitesquare"/>
<feBlend mode="screen" in="clipBlur" in2="whitesquare"/>
</filter>
</defs>
<g id="squares">
<rect x="10" y="10" height="235" width="235" fill="red" />
<rect x="255" y="10" height="235" width="235" fill="green" />
<rect x="10" y="255" height="235" width="235" fill="blue" />
<rect x="255" y="255" height="235" width="235" fill="yellow" />
</g>
<rect filter="url(#blurry)" x="50" y="50" height="400" width="400" fill="rgb(255,255,255)" />
</svg>
(Update: recent discovery - you can use javascript to encode any content you want to feed to feImage into a svg+xml encoded data URI - then that works cross browser. Super ugly.)
Upvotes: 3
Reputation: 101820
How about this approach? It's a bit harder to use, but it seems to work on all browsers.
<svg x="0px" y="0px" width="500px" height="500px" viewbox="0 0 500 500">
<defs>
<filter id="blurry" x="0%" y="0%" height="100%" width="100%" primitiveUnits="userSpaceOnUse">
<feGaussianBlur x="50" y="50" width="400" height="400" stdDeviation="40" in="SourceGraphic" result="blurSquares"/>
<feComponentTransfer in="blurSquares" result="opaqueBlur">
<feFuncA type="linear" intercept="1"/>
</feComponentTransfer>
<feBlend mode="normal" in="opaqueBlur" in2="SourceGraphic"/>
</filter>
</defs>
<g id="squares" filter="url(#blurry)">
<rect x="10" y="10" height="235" width="235" fill="red" />
<rect x="255" y="10" height="235" width="235" fill="green" />
<rect x="10" y="255" height="235" width="235" fill="blue" />
<rect x="255" y="255" height="235" width="235" fill="yellow" />
</g>
<rect x="50" y="50" height="400" width="400" fill="rgb(255,255,255)" fill-opacity="0.8" />
</svg>
It is trickier because the filter is applied to the background rather than the <rect>
. For it to work, you have to copy the x
,y
,width
and height
from the <rect>
to the feGaussianBlur
primitive.
Upvotes: 13