Is it possible to achieve this gradient without having to define it first under <defs>?
I'm working on a network map showing network load on links between devices (switches, routers ..). I draw this using SVG, but I don't want to define all gradients as the start (uplink) and end (downlink) color is already given to me from the back end system and accessible through template variables in our application.
I wish to use inline-styles as it is much easier to do code wise as I don't have to keep track of thousands of link references and make sure I specify the right gradient for every link, as every gradient will '99.9%' of the time be unique for every line (link-load) I draw in my network map
Put in simple words, can I do something along the line: <line stroke=<linearGradient... ? without having to define one and reference back to it? Like style in CSS: <span style='color: blue'> .. </span>
<svg width="1024" height="800">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#000066;stop-opacity:1" />
<stop offset="50%" style="stop-color:#000066;stop-opacity:1" />
<stop offset="51%" style="stop-color:#00ffff;stop-opacity:1" />
<stop offset="100%" style="stop-color:#00ffff;stop-opacity:1" />
</linearGradient>
</defs>
<text x="50" y="50" fill="red">foo bar</text>a
<line stroke="url(#grad1)" x1="130.8757632890282"
y1="163.6818288670081" x2="651.9483366457684" y2="415.704113030817" />
</svg>
( http://jsfiddle.net/GgJnB/ )
You could use a data URI i.e. fill="url(data:image/svg+xml;base64,...encoded full svg...#mygradient)"
Here's an example: http://xn--dahlstrm-t4a.net/svg/paint/datauri-gradient.svg
First of all, I probably should have thought of this before asking the question at all, but my excuse is that I'm still learning svg. And my suggested answer is probably not the fully correct either. See code example at bottom with SVG Params which probably is the best solution and not having to keep track of a changing link reference to a gradient.
I however solved my issue with wrapping the following code inside a <g> for every link/line I draw as shown below:
<linearGradient id="gradientForLoopi" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#000066;stop-opacity:1" />
<stop offset="50%" style="stop-color:#000066;stop-opacity:1" />
<stop offset="51%" style="stop-color:#00ffff;stop-opacity:1" />
<stop offset="100%" style="stop-color:#00ffff;stop-opacity:1" />
</linearGradient>
<line stroke="url(#gradientForLoopi)" x1="130.8757632890282"
y1="163.6818288670081" x2="651.9483366457684" y2="415.704113030817" />
(I probably didn't even need to do that either, but I did for the semantic purposes so I could work with d3js more easily).
Doing some more research on the field, a better solution would be to use SVG Params (draft as pr. writing) when it is commonly available in browsers with HTML5 doctype (only partly working with SVG context headers(?), and not inline <svg> inside a HTML5 document) See demo with HTML5 doctype not working, and the same <svg>-content with svg content-type/.svg working as it should here.
You can probably already now use the SVG Params draft using a prototyping script, which I didn't get to work and probably doesn't work in 'all common browsers'-yet.
With SVG Params you would simply do something along the lines (I assume):
<defs>
<linearGradient id="linkload" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:param(uplink_color);stop-opacity:1" />
<stop offset="50%" style="stop-color:param(uplink_color);stop-opacity:1" />
<stop offset="51%" style="stop-color:param(downlink_color);stop-opacity:1" />
<stop offset="100%" style="stop-color:param(downlink_color);stop-opacity:1" />
</linearGradient>
<line stroke="url(#linkload)" x1="param(x1)"
y1="param(y1)" x2="param(x2)" y2="param(y2)" />
</defs>
<use id="linkid" xlink:href="#linkload" x1="300" x2="0" y1="0" y2="300">
<param name="downlink_color" value="#00ffff" />
<param name="uplink_color" value="#006666" />
</use>
<use id="linkid" .. for every link..
Related
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.
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>
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...)
I've been reading the SVG specification and trying to find out whether you can have a combined fill and opacity gradient, but with the fill and opacity at different angles?
See the following example:
<linearGradient id="MyFill" gradientUnits="objectBoundingBox">
<stop offset="0%" stop-color="#FF0000" />
<stop offset="100%" stop-color="#0000FF" />
</linearGradient>
<linearGradient id="MyTransparency" gradientUnits="objectBoundingBox">
<stop offset="0%" stop-opacity="0%" x1="50%" x2="50%" />
<stop offset="100%" stop-opacity="100%" x1="50%" x2="50%" />
</linearGradient>
The opacity is defined at a different angle to the fill, how can I combine these into one fill? Or if I can't, how can I apply this to a single object?
It's not supported in SVG 1.1, but you can probably do a workaround with e.g filter markup to combine the gradients (an example), or <use> to apply different gradients to the same element that way, or write a script to do the color interpolation yourself.
(source: elv1s.ru)
What a proper way to do a gradient like this? I tried this SVG:
<linearGradient id="hue" x1="0" y1="1" x2="0" y2="0">
<stop offset="0%" stop-color="#ff0000"/>
<stop offset="17%" stop-color="#ffff00"/>
<stop offset="34%" stop-color="#00ff00"/>
<stop offset="50%" stop-color="#00ffff"/>
<stop offset="66%" stop-color="#0000ff"/>
<stop offset="82%" stop-color="#ff00ff"/>
<stop offset="100%" stop-color="#ff0000"/>
</linearGradient>
It works, but still not good enough:
(source: elv1s.ru)
I can see the difference between those two gradients. Is there a better way of doing it?
Have you tried using better precision in your %? As Josh is showing, you can have sub-percent precision and space your stops better.
If it's acceptable to generate the SVG with Javascript you might want to look at: How to interpolate hue values in HSV colour space?
or perhaps:
http://www.carto.net/papers/svg/gui/colourPicker/
Edit: Actually there is one here. would that be correct?
http://upload.wikimedia.org/wikipedia/commons/5/5d/HSV-RGB-comparison.svg
<linearGradient
id="linearGradient3706">
<stop
style="stop-color:#ff1c1c;stop-opacity:1;"
offset="0"
id="stop3708" />
<stop
id="stop3728"
offset="0.16105497"
style="stop-color:#fd00ca;stop-opacity:1;" />
<stop
id="stop3724"
offset="0.35173747"
style="stop-color:#0202ff;stop-opacity:1;" />
<stop
id="stop3720"
offset="0.48789391"
style="stop-color:#02fff9;stop-opacity:1;" />
<stop
id="stop3718"
offset="0.70091939"
style="stop-color:#60ff18;stop-opacity:1;" />
<stop
id="stop3714"
offset="0.83720928"
style="stop-color:#ffef15;stop-opacity:1;" />
<stop
style="stop-color:#ff0000;stop-opacity:1;"
offset="1"
id="stop3710" />
</linearGradient>
works for me (made with inskape)