Apply filter to path in svg - svg

I have a triangle drawn with path:
I want to apply a filter to it:
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradA0" gradientUnits="userSpaceOnUse" x1="50.000000" y1="50.000000" x2="130.000000" y2="210.000000">
<stop offset="0%" stop-color="#ff0000"/>
<stop offset="100%" stop-color="#000000"/>
</linearGradient>
<path id="pathA0" d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" fill="url(#gradA0)"/>
<filter id="default0">
<feImage xlink:href="#pathA0" result="layerA0" x="0" y="0"/>
</filter>
</defs>
<path d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" filter="url(#default0)"/>
</svg>
And the result:
Why the applied image is clipped? How to fix that?

You haven't sized your SVG element. SVG has no implicit sizing, if you don't provide it, then browsers are free to give you whatever size they want. Firefox is 100px by 100px I think..
Update:
You also haven't sized your feImage (SVG is not very forgiving). This version works:
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000px" height="800px" viewBox="0 0 1000 800">
<defs>
<linearGradient id="gradA0" gradientUnits="userSpaceOnUse" x1="50.000000" y1="50.000000" x2="130.000000" y2="210.000000">
<stop offset="0%" stop-color="#ff0000"/>
<stop offset="100%" stop-color="#000000"/>
</linearGradient>
<path id="pathA0" d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" fill="url(#gradA0)"/>
<filter id="default0">
<feImage xlink:href="#pathA0" result="layerA0" x="0%" y="0%" width="100%" height="100%"/>
</filter>
</defs>
<path d="M 50.000000,50.000000 L 250.000000,150.000000 50.000000,250.000000 Z" filter="url(#default0)"/>
</svg>

Related

SVG styling <use> (fill x% of the content with linearGradient)

I have an icon that I want to use many times on my page.
I want the icon to be filled dynamically (how much of it will be filled) from server data.
what I got so far is this:
<svg version="1.1" id="myWarningId" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 27.8 24" style="enable-background:new 0 0 27.8 24;" xml:space="preserve">
<defs>
<symbol viewBox="0 0 27.8 24" y="0px" x="0px" id="warning" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
#myWarningId .st1{fill:#FFFFFF;}
#myWarningId polygon{fill: inherit;}
</style>
<linearGradient id="half" x2="0%" y2="100%">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="blue" />
</linearGradient>
<g>
<polygon points="13.9,0 0,24 27.8,24"></polygon>
<g>
<path d="m13.9,16.1l0,0c-1.1,0 -2.1,-0.9 -2.1,-2.1l0,-4.9c0,-1.1 0.9,-2.1 2.1,-2.1l0,0c1.1,0 2.1,0.9 2.1,2.1l0,4.9c-0.1,1.2 -1,2.1 -2.1,2.1z" class="st1"></path>
<circle r="1.7" cy="19.5" cx="13.9" class="st1"></circle>
</g>
</g>
</symbol>
</defs>
<g class="layer">
<!-- this use will be generated multiple times -->
<use x="0" y="0" fill="url(#half)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_2"></use>
</g>
Now, if I want to change where the line is I need to do it in the <def> tag. but this is changing all my <use> elements.
how can I change the % of the fill for each <use> dynamically and individually?
I don't think that making 100 <linearGradient> definitions for each precent and changing the fillUrl would be a good practice...
You should not put the gradient into the symbol if you want to change the percentage of the stop. If you are fine with steps (10%, 20%, 30%), you can implement one gradient for each step. It looks like this:
<svg version="1.1" id="myWarningId" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 27.8 24" style="enable-background:new 0 0 27.8 24;" xml:space="preserve">
<defs>
<linearGradient id="_10" x2="0%" y2="100%">
<stop offset="10%" stop-color="red" />
<stop offset="10%" stop-color="blue" />
</linearGradient>
<linearGradient id="_20" x2="0%" y2="100%">
<stop offset="20%" stop-color="red" />
<stop offset="20%" stop-color="blue" />
</linearGradient>
<linearGradient id="_30" x2="0%" y2="100%">
<stop offset="30%" stop-color="red" />
<stop offset="30%" stop-color="blue" />
</linearGradient>
<symbol viewBox="0 0 27.8 24" y="0px" x="0px" id="warning" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
#myWarningId .st1{fill:#FFFFFF;}
#myWarningId polygon{fill: inherit;}
</style>
<g>
<polygon points="13.9,0 0,24 27.8,24"></polygon>
<g>
<path d="m13.9,16.1l0,0c-1.1,0 -2.1,-0.9 -2.1,-2.1l0,-4.9c0,-1.1 0.9,-2.1 2.1,-2.1l0,0c1.1,0 2.1,0.9 2.1,2.1l0,4.9c-0.1,1.2 -1,2.1 -2.1,2.1z" class="st1"></path>
<circle r="1.7" cy="19.5" cx="13.9" class="st1"></circle>
</g>
</g>
</symbol>
</defs>
<g class="layer">
<!-- this use will be generated multiple times -->
<use x="0" y="0" fill="url(#_10)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_1"></use>
<use x="0" y="32" fill="url(#_20)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_2"></use>
<use x="0" y="64" fill="url(#_30)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_3"></use>
</g>
</svg>

SVG Rectangular and Path Gradient

I use radialGradient as below to give a tube bulb glow effect :
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%"
viewBox="0 0 100 100">
<radialGradient id="radial" cx="50" cy="50" r="50"
gradientUnits="userSpaceOnUse">
<stop offset="0.8" style="stop-color:#00FFFF"/>
<stop offset="1" style="stop-color:#004444"/>
</radialGradient>
<circle cx="50" cy="50" r="50"
fill="url(#radial)"/>
</svg>
But how do I do same for Rectangular and Path Gradient or any Custom Shape Gradient for different shapes like rect or star ?
We have this option in MS PowerPoint which is called as Rectangular gradient and Path Gradient.
It shud start at center and first stop point 0.8 and second stop at 1 for each edge line just like above effect.
Are these gradients available in Illustrator?
You can fake it by splitting the shape into multiple sub-shapes.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%"
viewBox="0 0 100 100">
<linearGradient id="horiz" x1="0.5" spreadMethod="reflect">
<stop offset="0.8" style="stop-color:#00FFFF"/>
<stop offset="1" style="stop-color:#004444"/>
</linearGradient>
<linearGradient id="vert" y1="0.5" x2="0" y2="1" spreadMethod="reflect">
<stop offset="0.8" style="stop-color:#00FFFF"/>
<stop offset="1" style="stop-color:#004444"/>
</linearGradient>
<polygon points="0,0, 100,100, 100,0, 0,100" fill="url(#horiz)"/>
<polygon points="0,0, 100,0, 0,100, 100,100" fill="url(#vert)"/>
</svg>
The way this works is that we have two hourglass-shaped polygons, and we apply linear gradients to each.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%"
viewBox="0 0 100 100">
<polygon points="0,0, 100,100, 100,0, 0,100" fill="gold"/>
<polygon points="0,0, 100,0, 0,100, 100,100" fill="green"/>
</svg>

Starting svg animation on the end of another animation doesn't trigger

I have two svg animations and I want to start #anim-join-gradient animation on the end of #anim-vert-gradient, but #anim-join-gradient animation doesn't start.
#anim-join-gradient element has attribute begin="anim-vert-gradient.end"
.box1{width:25px}
<div class="box box1">
<svg viewbox="0 0 100 100">
<path id="button" class="arrow" d="M 50,0 L 60,10 L 20,50 L 60,90 L 50,100 L 0,50 Z" />
</svg>
</div>
<svg id="play-vert-line" width="110" height="110">
<defs>
<linearGradient id="vert-gradient" gradientUnits="userSpaceOnUse" y1="0%" y2="100%" x1="0" x2="0">
<stop stop-color="#1689fb"></stop>
<stop stop-color="#7e7e7e"></stop>
<animate xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#vert-gradient" id="anim-vert-gradient" attributeName="y1" dur="800ms" to="99%" begin="button.click" fill="freeze"></animate>
</linearGradient>
</defs>
<line id="vert-line-1" x1="55.3" y1="0" x2="55.3" y2="105" stroke="url(#vert-gradient)" stroke-width="2"></line>
</svg>
<svg id="line-join" width="110" height="110">
<defs>
<linearGradient id="vert-join-gradient" gradientUnits="userSpaceOnUse" y1="0%" y2="100%" x1="0" x2="0">
<stop stop-color="#1689fb"></stop>
<stop stop-color="#7e7e7e"></stop>
<animate xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#vert-join-gradient" id="anim-join-gradient" attributeName="y1" dur="400ms" from="0%" to="99%" begin="anim-vert-gradient.end" fill="freeze"></animate>
</linearGradient>
</defs>
<line id="vert-line-2" x1="105" y1="0" x2="105" y2="105" stroke="url(#vert-join-gradient)" stroke-width="2"></line>
</svg>
minus signs are treated specially in begin attributes. Unescaped minus signs are treated as the subtraction operator. Per the spec you need to escape them if you don't want that e.g.
begin="anim\-vert\-gradient.end"
That would work on Firefox. Chrome has a bug and doesn't support escaping so if you want it to work there you'd have to remove the - signs.

feImage with internal source

Goal
I'm trying to write a SVG filter to render a wave lighting atop a given shape. So inside that shape I want the waves to apply, but I want no visible effect outside that shape. As far as I understand, I cannot use the same image source both for the hight map used for the waves and as the target domain for an atop composition. So I thought a <feImage> element might be used to obtain the height map from a separate gradient-filled object. But so far I haven't succeeded in getting that object visible inside the filter effect area.
First attempt
Code I have so far:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="512" height="512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<rect id="waveImg" x="-210" y="-105" width="420" height="210"
stroke="none" fill="url(#waveFill)"/>
<filter id="waveFilter">
<feImage xlink:href="#waveImg" result="waves"/>
<!-- feSpecularLighting and so on will be added later on -->
<feComposite operator="atop" in="waves" in2="SourceImage"/>
</filter>
</defs>
<g transform="translate(256 256)">
<!-- use xlink:href="#waveImg"/ works -->
<ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
style="filter:url(#waveFilter)"/>
</g>
</svg>
Relevant documentation
The documentation for <feImage> states:
If the ‘xlink:href’ references a stand-alone image resource such as a JPEG, PNG or SVG file, then the image resource is rendered according to the behavior of the ‘image’ element; otherwise, the referenced resource is rendered according to the behavior of the ‘use’ element. In either case, the current user coordinate system depends on the value of attribute ‘primitiveUnits’ on the ‘filter’ element.
Second attempt
use instead of image looks all right to me, but I'm unsure how the rectangular region is defined in this case. The documentation for use seems to indicate that in such a case (the referenced element is neither a symbol nor a svg element), the width and height properties are irrelevant, but how does that describe a rectangular region? I also thought that perhaps a change of primitive units would help. Or boxing the image inside a symbol. So my second attempt was the following one:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="512" height="512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<symbol viewBox="0 0 100 100" id="waveImg" preserveAspectRatio="none">
<rect width="100" height="100" stroke="none" fill="url(#waveFill)"/>
</symbol>
<filter id="waveFilter" primitiveUnits="objectBoundingBox">
<feImage xlink:href="#waveImg" x="0" y="0" width="100%" height="100%"
preserveAspectRatio="none" result="waves"/>
<!-- feSpecularLighting and so on will be added later on -->
<feComposite operator="atop" in="waves" in2="SourceImage"/>
</filter>
</defs>
<g transform="translate(256 256)">
<!-- use xlink:href="#waveImg"/ works -->
<ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
style="filter:url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>
</g>
</svg>
Still no image visible. What am I doing wrong?
Core question
How can I use a fragment of my SVG file as a bump map for lighting, without also using it as the SourceGraphic of my filter?
Rasterizer
This image isn't intended for web deployment, but will be rasterized locally. So browser compatibility isn't much of an issue; if the thing renders correctly under either Inkscape or rsvg-convert, that's enough for me.
There are a lot of reasons why this might not work.
You may need to specify units for your svg width and height (px, pt, em, % whatever). IE doesn't like unspecified SVG element dimensions.
You're using the wrong term for your feComposite input: "SourceImage" should be "SourceGraphic".
Filters are better applied directly via the filter property not via a style property.
I do not think you can reference a symbol directly in an feImage, you have to <use it first, and then reference the id on the use element. (In any case, why not just use the rect directly?)
Here is a version that works in Chrome (and probably Safari) using your methodology.
<svg version="1.1" width="512px" height="512px" viewbox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> <defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<rect id="waveImg" width="100%" height="100%" stroke="none" fill="url(#waveFill)"/>
<filter id="waveFilter" primitiveUnits="objectBoundingBox">
<feImage xlink:href="#waveImg" x="0%" y="0%" width="100%" height="100%" result="waves"/>
<!-- feSpecularLighting and so on will be added later on -->
<feComposite operator="atop" in="waves" in2="SourceGraphic"/>
</filter>
</defs>
<g transform="translate(256 256)">
<ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
filter="url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/> </g> </svg>
However, this won't work in Firefox because object inputs to feImage are not supported, and from my testing, feImage units are pretty buggy in IE.
There is no reason why you can't re-use your Source Graphic for lighting effects - here is a shorter version of what you're trying to do that works cross browser and avoids feImage.
<svg version="1.1" x="0px" y="0px" width="512px" height="512px" viewbox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> <defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<filter id="waveFilter" x="0%" y="0%" width="100%" height="100%">
<feFlood flood-color="#0000ff" result="blue"/>
<feComposite operator="in" in2="SourceGraphic" in="blue"/>
</filter>
</defs>
<g transform="translate(256 256)">
<!-- use xlink:href="#waveImg"/ works -->
<ellipse rx="200" ry="100" fill="url(#waveFill)" filter="url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/> </g> </svg>
And (because why not) here's an example with specular lighting added in:
<svg version="1.1" x="0px" y="0px" width="512px" height="512px" viewbox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<filter id="waveFilter" x="0%" y="0%" width="100%" height="100%">
<feFlood flood-color="#0000ff" result="blue"/>
<feComposite operator="in" in2="SourceGraphic" in="blue"
result="sourcewithblue"/>
<feSpecularLighting in="SourceAlpha" result="specOut"
specularConstant="2" specularExponent="20" lighting-color="white"
surfaceScale="2">
<fePointLight x="-200" y="-200" z="200"/>
</feSpecularLighting>
<feComposite operator="arithmetic" in="specOut" in2="sourcewithblue" k1="0" k2="1" k3="1" result="unclippedoutput"/>
<feComposite operator="in" in="unclippedoutput" in2="SourceGraphic"/>
</filter>
</defs>
<g transform="translate(256 256)">
<ellipse rx="200" ry="100" fill="url(#waveFill)" filter="url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>
</g>
</svg>

Is it possible to apply a transform matrix to a SVG filter effect

I'm trying to recreate an iphone maps like push pin in SVG and I have the pin part down but I'm wondering how to tackle the shadow. I've seen a bunch of drop shadow examples but they're all just offsetting the original by a few pixels. Is it possible to apply a transform matrix to a filter so it's skewed?
Here's the pin SVG so far:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<radialGradient id="SVGID_1_" cx="29.3623" cy="31.1719" r="11.6241" gradientTransform="matrix(1.1875 0 0 1.1875 -30.8438 -30.2812)" gradientUnits="userSpaceOnUse">
<stop offset="0.2637" style="stop-color:#FF0000"/>
<stop offset="1" style="stop-color:#6D0000"/>
</radialGradient>
</defs>
<rect x="9.251" y="13.844" fill="#CCCCCC" stroke="#7C7C7C" width="2" height="24.83"/>
<circle fill="url(#SVGID_1_)" stroke="#660000" cx="10.5" cy="11.5" r="9.5"/>
<ellipse transform="matrix(0.8843 0.4669 -0.4669 0.8843 4.475 -1.6621)" fill="#FFCCCC" cx="6.591" cy="8.199" rx="1.538" ry="1.891"/>
</svg>
thanks!
Here is a simple transform and filter to rotate it. If you want to do the skewing too you will need to replace the rotate line with some matrix stuff.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<radialGradient id="SVGID_1_" cx="29.3623" cy="31.1719" r="11.6241" gradientTransform="matrix(1.1875 0 0 1.1875 -30.8438 -30.2812)" gradientUnits="userSpaceOnUse">
<stop offset="0.2637" style="stop-color:#FF0000"/>
<stop offset="1" style="stop-color:#6D0000"/>
</radialGradient>
<filter id="drop-shadow">
<feGaussianBlur in="SourceAlpha" result="blur-out" stdDeviation="1" />
</filter>
</defs>
<g id="pin">
<rect x="9.251" y="13.844" fill="#CCCCCC" stroke="#7C7C7C" width="2" height="24.83"/>
<circle fill="url(#SVGID_1_)" stroke="#660000" cx="10.5" cy="11.5" r="9.5"/>
<ellipse transform="matrix(0.8843 0.4669 -0.4669 0.8843 4.475 -1.6621)" fill="#FFCCCC" cx="6.591" cy="8.199" rx="1.538" ry="1.891"/>
</g>
<use xlink:href="#pin" transform="rotate(60 10.251 38.674)" filter="url(#drop-shadow)"/>
</svg>

Resources