Elliptical gradient in SVG - web

Is there a way to make an elliptical gradient in SVG?
I tried the suggested code below, but it just displays a red ellipse, not a gradient:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
<svg width="100%" height="100%"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events" >
<defs>
<radialGradient id="gradientDefinition"
gradientUnits="userSpaceOnUse">
<stop stop-color="yellow" offset="0%" />
<stop stop-color="red" offset="100%" />
</radialGradient>
</defs>
<ellipse cx="250" cy="150" rx="200" ry="100" stroke="white"
stroke-width="1" stroke-dasharray="1 1 1 1"
style="fill:url(#gradientDefinition)" />
</svg>
I want an elliptical gradient, not a circular gradient inside an ellipse.

To summarize the findings from earlier, it appears that removing the gradientUnits="userSpaceOnUse" attribute and value pair from the <radialGradient> tag allows for the radial gradient to become (or at least appear to become) elliptical in shape. Also, adding stop-opacity attributes and values to each <stop> tag allows for the elliptical gradient effect to be more easily seen (at least for demonstration purposes.)
Here is the code with the above changes made:
<defs>
<radialGradient id="gradientDefinition" >
<stop stop-color="yellow" offset="0%" stop-opacity="0" />
<stop stop-color="red" offset="100%" stop-opacity="1" />
</radialGradient>
</defs>
To show that this code appears to work:
see: elliptical radialGradient vs circular radialGradient
There is also a tutorial online that appears to provide similar behavior for a similar elliptical gradient approach and the results from that tutorial can be found in this jsFiddle.
Note: If this approach does not work for your purposes, there may be some other, better approach (possibly having to do with gradient transformations, or something similar...)

Related

White linear gradient defined in svg def , does't display white gradient. why ?

I was just going though the MDN documention HERE for clipping and masking in SVG and came across the following SVG::-
<svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="Gradient">
<stop offset="0" stop-color="white" stop-opacity="0" />
<stop offset="1" stop-color="white" stop-opacity="1" />
</linearGradient>
<mask id="Mask">
<rect x="0" y="0" width="200" height="200" fill="url(#Gradient)" />
</mask>
</defs>
<rect x="0" y="0" width="200" height="200" fill="green" />
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(#Mask)" />
</svg>
I see the following two stop colors defined::-
<stop offset="0" stop-color="white" stop-opacity="0" />
<stop offset="1" stop-color="white" stop-opacity="1" />
But when the SVG displays i see no white color, why is this ? looking at the above linear gradient, i would expect a white gradient instead of a red one, i am not quite understanding why there is no white gradient.
NOTE ::- this is a why question, not a how-to-do-this-question
The gradient is not used to color the rectangle, but to define a mask. The <mask> is an offscreen image that is never shown, but only used to compute the element it is applied to.
In this case, the mask consists of a black (transparent) background, onto which a white gradient is added, so that it runs from black transparent to white opaque. When this mask is applied to the red rectangle, black is transformed into opacity="0", and white is transformed into opacity="1". So on the left, the lower green rectangle shines through, but on the right it doesn't and you see the red.

I need help minimizing instances of SVG gradients

I have a logo I created in Illustrator that I'm manually crafting into an SVG file piece by piece. It's a highly detailed illustration with lots of layering and blending so I have a lot of repeated gradients that only differ in the values of the gradientTransform property.
Here's an example
<radialGradient id="sil_bor_clr_layer_01" cx="145.8111" cy="91.9766" r="5.5753" gradientTransform="matrix(1.665142e-02 -0.9999 1.0812 1.800584e-02 43.939 236.1114)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.6007" style="stop-color:#DBE2E8"/>
<stop offset="1" style="stop-color:#C0CDD8"/>
</radialGradient>
<radialGradient id="sil_bor_clr_layer_02" cx="121.087" cy="94.1915" r="6.7356" gradientTransform="matrix(-0.1704 -0.9854 0.917 -0.1586 55.3406 228.4433)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.6007" style="stop-color:#DBE2E8"/>
<stop offset="1" style="stop-color:#C0CDD8"/>
</radialGradient>
<radialGradient id="sil_bor_clr_layer_03" cx="98.1764" cy="102.6783" r="7.6206" gradientTransform="matrix(-0.5989 -0.8008 0.6381 -0.4771 91.458 230.294)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.6007" style="stop-color:#DBE2E8"/>
<stop offset="1" style="stop-color:#C0CDD8"/>
</radialGradient>
I have another 21 elements that use this same gradient which means I'll have to define it 21 more times just for the sake of defining the gradientTransform property.
Is there a way for me to define the gradientTransform on the SVG elements using the gradient so I can just define them once? These particular elements have a color layer, shadow layer and highlight layer which will be about 60+ instances of the same thing which is pretty ridiculous. I'm currently doing this in Angular so I know I could make components and export a few const to take care of this, but I'd prefer to keep it svg and css if possible.
You can use the href property to reference a template gradient.
If you want to support Safari you'll need to use xlink:href as Safari doesn't yet support bare href.
head, body, svg {
width: 100%;
height: 100%;
}
<svg viewBox="0 0 400 400">
<defs>
<radialGradient id="template">
<stop offset="10%" stop-color="gold"/>
<stop offset="95%" stop-color="green"/>
</radialGradient>
<radialGradient id="gradient1" gradientTransform="translate(0.25, 0.25) scale(0.5)" href="#template"/>
</defs>
<circle fill="url(#template)" cx="60" cy="60" r="50"/>
<circle fill="url(#gradient1)" cx="160" cy="60" r="50"/>
</svg>
If your gradient is supposed to look the same on each shape though, you'd be better off having one gradient and using objectBoundingBox units instead of userSpaceOnUse units.

Calculating SVG Gradient Coordinates for Angled Repeating Lines

I'm trying to generate a parallelogram in SVG with repeating lines that are along the same angle as the left and right sides of the polygon. Something like this:
I got the repeating gradient to work, but I can't get the angle of the lines right. They're skewed from the angle of the bounding parallelogram:
I know I can manipulate the angle based on the (x1, y1) / (x2, y2) attributes of the gradient, but just playing with the numbers isn't doing it for me. How can I calculate which values to use for these attributes given a known angle?
Here's the SVG code I have right now:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1680 550" preserveAspectRatio="xMidYMin">
<defs>
<linearGradient id="StripedGradient" spreadMethod="repeat" x1="0%" x2="1%" y1="0%" y2="1%">
<stop stop-color="yellow" offset="0%" />
<stop stop-color="yellow" offset="15%" />
<stop stop-color="transparent" offset="15%" />
<stop stop-color="transparent" offset="100%" />
</linearGradient>
</defs>
<polygon fill="url(#StripedGradient)" points="0 550, 415 145, 610 145, 195 550" />
</svg>
This angle currently works out to be just under 45deg (44.301...), but the value could change at the discretion of the designer, so...
(I'm really new to SVG, as in I knew it existed, but I had never written inline SVG by hand until today.)
One fairly simple approach would be to define your gradient as a horizontal stripe. Then if you also use gradientUnits="userSpaceOnUse", you can use a gradientTransform to set your angle.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 750 550" preserveAspectRatio="xMidYMin">
<defs>
<linearGradient id="StripedGradient" spreadMethod="repeat"
gradientUnits="userSpaceOnUse"
x1="0" y1="0" x2="0" y2="20"
gradientTransform="rotate(-44.301)">
<stop stop-color="red" offset="0%" />
<stop stop-color="red" offset="15%" />
<stop stop-color="transparent" offset="15%" />
<stop stop-color="transparent" offset="100%" />
</linearGradient>
</defs>
<polygon fill="url(#StripedGradient)" points="0 550, 415 145, 610 145, 195 550" />
</svg>

Creating a vignette with SVG filters?

I would like to create vignette on an image using SVG filters. What is the best way to approach this? I already tried creating a feFlood with a gradient as flood-color but that doesn't work. Right now I am using a png generated in illustrator but I would like to keep it all in svg.
To illustrate what I am aiming for, this is the original:
And this is what is should be:
UPDATE:
I am using svg.js with the svg.filter.js plugin to generate the code dynamically. This is what I tried:
// create svg canvas
var draw = SVG('canvas').size(400,400)
// define gradient
var gradient = draw.gradient('radial', function(stop) {
stop.at({ offset: 0, opacity: 0 })
stop.at({ offset: 1 })
})
gradient.radius('80%')
// create image
var image = draw.image('http://distilleryimage11.ak.instagram.com/89ac2e90d9b111e297bf22000a1f9263_7.jpg').size(400,400)
// add filter
image.filter(function(add) {
add.blend(add.source, add.flood(gradient), 'multiply')
})
This is the generated code:
<svg id="SvgjsSvg1000" xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="400" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:relative;overflow:hidden;left:0px;top:0px;">
<image id="SvgjsImage1005" xlink:href="http://distilleryimage11.ak.instagram.com/89ac2e90d9b111e297bf22000a1f9263_7.jpg" width="400" height="400" filter="url( #SvgjsFilter1006)"></image>
<defs id="SvgjsDefs1001">
<radialGradient id="SvgjsRadialGradient1002" r="80%">
<stop id="SvgjsStop1003" stop-opacity="0" offset="0"></stop>
<stop id="SvgjsStop1004" offset="1"></stop>
</radialGradient>
<filter id="SvgjsFilter1006">
<feFlood id="SvgjsFeFlood1007" in="SourceGraphic" result="SvgjsFeFlood1007Out" flood-color="url(#SvgjsRadialGradient1002)"></feFlood>
<feBlend id="SvgjsFeBlend1008" in="SourceGraphic" result="SvgjsFeBlend1008Out" in2="SvgjsFeFlood1007Out" mode="multiply"></feBlend>
</filter>
</defs>
</svg>
The result is a completely black image. It seems that the feFlood element does not accept gradients as fill because it works with a color.
Here is a fiddle with the example code: http://jsfiddle.net/wout/VmUu6/
This worked for me without spotlighting, I user a radial gradient with multiple stop points you can adjust the color, stop points and opacity level to get the effect you want. play with the r(radius to widen/shorten the effect and the fx,fy to position. Gradients tend to be more efficient then using some of the filters that require heavy maths processing
<radialGradient id="grad"
fx="50%" fy="50%" r="55%"
spreadMethod="pad">
<stop offset="30%" stop-color="#222222" stop-opacity="0"/>
<stop offset="40%" stop-color="#222222" stop-opacity="0.2"/>
<stop offset="50%" stop-color="#222222" stop-opacity="0.4"/>
<stop offset="70%" stop-color="#222222" stop-opacity="0.6" />
<stop offset="100%" stop-color="#222222" stop-opacity="1" />
</radialGradient>
Apply to the rectangle positioned above an image
<image id="background" x="0" y="0" width="800px" height="530px" preserveAspectRatio="true"
xlink:href="http://i1-qa.adis.ws/i/Client_23/ss_collection_reddress?w=800"/>
<rect filter="url(#blur)" style="fill:url(#grad)" x="0" y="0" width="800px" height="530px"/>
vignette example
I have some vignetteing and selecting compositing methods in my slide share preso on filters. Page 50 onwards for techniques. Here is the most relevant piece of filter code. It's not a real vignette - that requires a much longer filter and selective image combination, but it's easier to understand.
<filter>
<feFlood id="flood-5" result="blackfield-6" x="0%" y="0%" width="100%" height="100%" result="blackfield-6" flood-color="#000000" flood-opacity="1"/>
<feSpecularLighting id="specular-5" result="Spotlight-6" lighting-color="#FFFFFF" surfaceScale="1" specularConstant="1" specularExponent="120">
<fePointLight id="pointlight-5" x="100" y="100" z="854"/>
</feSpecularLighting>
<feBlend id="svg-7" result="A-6" in="blackfield-6" in2="Spotlight-6" mode="lighten"/>
<feBlend id="blend-5" result="B-6" in="A-6" in2="SourceGraphic" mode="multiply"/>
</filter>

Can I define a linear gradient in SVG with a normal/bell-shaped blend?

Consider the following svg snippet:
<linearGradient id="redgradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#ffffff"/>
<stop offset="100%" stop-color="#ff0000"/>
</linearGradient>
<rect x="0" y="0" width="400" height="400" fill="url(#redgradient)"/>
Is there a way of specifying that the colours should be blended together using a bell shaped curve?
(Similar to the GDI+ LinearGradientBrush::SetBlendBellShape method)
The two rectangles below show the difference - left is without bell blend, right is with bell blend:
Or is it left to the SVG renderer to decide how the colors should be blended together?
gradientTransform cannot do this kind of transformation. You will need a
filter to apply a bell shaped transform to a red/white gradient.
.
Original on the left, transformed on the right. The curve isn't very fine grained (only 15 values), so you would probably want to use more terms for a large gradient.
<svg width="500px" height="500px" viewbox="0 0 800 800">
<defs>
<filter id="bellTransform" color-interpolation-filters="sRGB">
<feComponentTransfer>
<feFuncG type="table" tableValues=
"0.0000 0.0059 0.0166 0.0346 0.0628 0.1038 0.1586 0.2259 0.3011 0.3761 0.4406 0.4844 0.5000 0.5156 0.5594 0.6239 0.6989 0.7741 0.8414 0.8962 0.9372 0.9654 0.9834 0.9941 1.0000"/>
<feFuncB type="table" tableValues=
"0.0000 0.0059 0.0166 0.0346 0.0628 0.1038 0.1586 0.2259 0.3011 0.3761 0.4406 0.4844 0.5000 0.5156 0.5594 0.6239 0.6989 0.7741 0.8414 0.8962 0.9372 0.9654 0.9834 0.9941 1.0000"/>
</feComponentTransfer>
</filter>
</defs>
<linearGradient id="redgradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#ffffff"/>
<stop offset="100%" stop-color="#ff0000"/>
</linearGradient>
<rect filter="url(#bellTransform)" x="410" y="0" width="400" height="400" fill="url(#redgradient)"/>
<rect x="0" y="0" width="400" height="400" fill="url(#redgradient)"/>
</svg>
You can apply a gradientTransform to a linear gradient. I'm not sure how the available transforms map to your required effect.
If that doesn't work you can use the gradient as the input to a filter and perhaps end up with a similar effect. Here's an article which covers combining filters.

Resources