Why is this SVG ellipse not a gradient? - svg

The following SVG should show an ellipse that has a gradient from blue to green. But it's all green. Why?
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:jfreesvg="http://www.jfree.org/jfreesvg/svg" width="2.0in" height="2.0in" text-rendering="auto" shape-rendering="auto" viewBox="0 0 1828800 1828800">
<defs>
<linearGradient id="783907957477109gp0" x1="0" y1="0" x2="0" y2="152400" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="rgb(0,0,255)"/>
<stop offset="100%" stop-color="rgb(0,255,0)"/>
</linearGradient>
</defs>
<ellipse cx="228600" cy="304800" rx="76200" ry="152400" style="fill: url(#783907957477109gp0); fill-opacity: 1.0" transform="matrix(1,0,0,1,0,0)"/>
</svg>

The gradient runs from 0 to 152400 in the y direction, anything bigger than y=152400 will be drawn in the last stop colour.
The ellipse y centre is 304800 so its lowest point is 304800 - 152400 = 152400 which is the gradient end point.

Related

SVG gradient gradient units vs gradienttransform - not the same gradient

I am trying to figure out conversion from gradienttransform to gradientunits. I am getting different gradient distribution. Why?
<svg width="540" height="540" xmlns="http://www.w3.org/2000/svg" >
<defs>
<linearGradient id="linear1" gradientTransform="rotate(45 0.5 0.5)" spreadMethod="pad">
<stop offset="0%" stop-color="gold"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="linear2" x1="0%" y1="0%" x2="100%" y2="100%" spreadMethod="pad">
<stop offset="0%" stop-color="gold"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<rect fill="url(#linear1)" x="0" y="0" width="270" height="270" />
<rect fill="url(#linear2)" x="0" y="270" width="270" height="270" />
</svg>
These 2 gradients are not the same:
because the distance between the left side and right side of a rectangle does not equal the distance from one corner to the opposite corner when you rotate it 45 degrees.
the left and right sides are 270 units apart (default x2 is 100% the others default to 0%).
the corners 270 * √2 units apart
So the distance between x1,y1 and x2,y2 is different in each case given that the rotation transform is distance invariant.

Is it possible to convert a raidal gradient expressed in objectBoundingBox coordinates to userSpaceOnUse coordinates?

I have this radial gradient expressed in objectBoundingBox coordinates.
<svg width="300" height="300">
<defs>
<radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="100"/>
</svg>
Is it possible to convert it to userSpaceOnUse coordinates?
For this question it is same to assume that each radial gradient only applies to one shape, and that we know x, y, width, and height of said shape.
<svg width="300" height="300">
<defs>
<radialGradient id="MyGradient" gradientUnits="userSpaceOnUse"
cx="?" cy="?" r="?" fx="?" fy="?">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="100"/>
</svg>
First I would show how to do it if the rect you fill with the gradient is a square:
svg{border:solid; width:45vw}
<svg viewBox="0 0 300 300">
<defs>
<radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="200"/>
</svg>
<svg viewBox="0 0 300 300">
<defs>
<radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse"
cx="110" cy="180" r="60" fx="70" fy="140" >
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient1)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="200"/>
</svg>
In the case of `gradientUnits="userSpaceOnUse":
The bounding box of the rect to fill is:
bb:{x:50, y:100, width:200, height:200}
The calculated attributes for gradientUnits="userSpaceOnUse" are:
cx = bb.x + bb.width *.3 = 50 + 200 * .3 = 110
cy = bb.y + bb.height *.4 100 + 200*.4 = 180
r = bb.width*.3 = 200*.3 = 60
fx = bb.x + bb.width *.1 = 50 + 200 * .1 = 70
fy = bb.y + bb.height *.2 = 100 + 200 * .2 = 140
So you can use
<radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse" cx="110" cy="180" r="60" fx="70" fy="140" >
When using objectBoundingBox the values of the attributes of the radialGradient are taking values between 0 and 1 or 0 and 100% of the filled box.
You can also use objectBoundingBox as a value for clipPathUnits. Please take a look at the folowing example.
There is this clipPath where the clipping path is a circle. If the clipped shape is a square the result is a circle. If the clipped shape is a rectangle the result is an ellipse meaning that the clipping path is stretched according to the aspect ratio of the clipped shape.
<svg viewBox="0 0 120 60">
<defs>
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<circle cx=".5" cy=".5" r=".45" />
</clipPath>
</defs>
<rect id="r" x="5" y="5" width="50" height="50" />
<use xlink:href="#r" fill="gold" clip-path="url(#clip)" />
<rect id="r1" x="60" y="15" width="55" height="30" />
<use xlink:href="#r1" fill="gold" clip-path="url(#clip)" />
</svg>
The same is happening with the gradient. If the radial gradient with gradientUnits="objectBoundingBox" is used to fill a rectangle with a different width and height the result would be an elliptical gradient (as in your example). If you want to translate an elliptical gradient to gradientUnits="userSpaceOnUse" you would need a way to create a gradient with a different rx and ry. Unfortunately this is not posible.

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>

How to make a vertical cross browser linear gradient using svg (for modern browsers)?

I am having trouble making SVG vertical linear gradients work in IE 11
, so the question is - given the following svg how to make the gradient identified as Gradient1 work in such a way that it is a vertical gradient?
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 79.4 59.5" xml:space="preserve">
<rect x="2.4" y="29.8" width="74.6" height="27.4"/>
<g>
<defs>
<linearGradient id="Gradient1" gradientUnits="userSpaceOnUse" x1="100%" y1="0%" x2="100%" y2="100%" gradientTransform="rotate(45 50 50)">
<stop offset="0%" style="stop-color:#9AAFCC"/>
<stop offset="20%" style="stop-color:#557096"/>
<stop offset="35%" style="stop-color:#36557D"/>
<stop offset="49%" style="stop-color:#1E3F6B"/>
<stop offset="63%" style="stop-color:#0D305D"/>
<stop offset="87%" style="stop-color:#032756"/>
<stop offset="100%" style="stop-color:#002453"/>
</linearGradient>
</defs>
<rect x="2.4" y="2.4" class="st0" width="74.6" height="27.4" fill="url(#Gradient1)"/>
</g>
</svg>
I have of course tried to use a gradientTransform, what I have that works in Chrome (and presumably other browsers but not in IE) includes the following on the linearGradient element
x1="-383.9706" y1="317.1023" x2="-382.9706" y2="317.1023" gradientTransform="matrix(0 -27.3826 -27.3826 0 8722.7842 -10484.3682)"
however as soon as I try to do this in IE the gradient I have stops working and the rectangle just takes the first full stop color.
I am open to translating the gradient into CSS if it can be made to work in the svg if that is the only cross-browser solution available.
Your example works the same in Chrome and IE for me.
<svg viewBox="0 0 79.4 59.5">
<rect x="2.4" y="29.8" width="74.6" height="27.4"/>
<defs>
<linearGradient id="Gradient1" gradientUnits="userSpaceOnUse" x1="100%" y1="0%" x2="100%" y2="100%" gradientTransform="rotate(45 50 50)">
<stop offset="0%" style="stop-color:#9AAFCC"/>
<stop offset="20%" style="stop-color:#557096"/>
<stop offset="35%" style="stop-color:#36557D"/>
<stop offset="49%" style="stop-color:#1E3F6B"/>
<stop offset="63%" style="stop-color:#0D305D"/>
<stop offset="87%" style="stop-color:#032756"/>
<stop offset="100%" style="stop-color:#002453"/>
</linearGradient>
</defs>
<rect x="2.4" y="2.4" class="st0" width="74.6" height="27.4" fill="url(#Gradient1)"/>
</svg>
It's a linear gradient rotated 45 degrees as your markup requests.
If you want the gradient to be vertical, remove the gradientTransform.
<svg viewBox="0 0 79.4 59.5">
<rect x="2.4" y="29.8" width="74.6" height="27.4"/>
<defs>
<linearGradient id="Gradient1" gradientUnits="userSpaceOnUse" x1="100%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#9AAFCC"/>
<stop offset="20%" style="stop-color:#557096"/>
<stop offset="35%" style="stop-color:#36557D"/>
<stop offset="49%" style="stop-color:#1E3F6B"/>
<stop offset="63%" style="stop-color:#0D305D"/>
<stop offset="87%" style="stop-color:#032756"/>
<stop offset="100%" style="stop-color:#002453"/>
</linearGradient>
</defs>
<rect x="2.4" y="2.4" class="st0" width="74.6" height="27.4" fill="url(#Gradient1)"/>
</svg>

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>

Resources