SVG polyline gradient apply only to stroke - html

I'm new in svg drawing.
Is there any option to colorize an svg <polyline> with gradient? I need to colorize only stroke, but all filters I founded is applied gradient both to stroke and body.
In fact I'm trying to make glow neon effect like this: http://screencloud.net/v/j2hE and it works fine for now with code below when I'm draw a strict line:
<linearGradient id="grad">
<stop offset="0%" stop-color="#ffd95d"/>
<stop offset="100%" stop-color="#ffd95d" stop-opacity="0" />
</linearGradient>
But when I'm drawing a line by circle, it looks like:
http://screencloud.net/v/9M6x (bottom is start and around circle to top where finish). As you can see, gradiend is applied to all polyform, but I need it to be gradiented only line as I draw it.
Is there any option to make neon glow lines like I need it?
For better understanding - I'm trying to get effect similar to default Windows screensaver named "glowing lines".

There is no way to apply a linearGradient along the length of a line's stroke.
The only way you could do it is to draw a sequence of individually coloured line/path segments that slowly fade out.

Related

SVG line with gradient doesn't render [duplicate]

I'm attempting to replicate an <hr> with SVG. Now, making a straight line with SVG works perfectly, but the second I stroke it with a gradient it will no longer display in a straight line.
The following code works, but take note, y1 and y2 must be 1 unit apart. If I set y1 and y2 to 210 for instance, the line will disappear.
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgba(0,0,0,0);stop-opacity:0" />
<stop offset="50%" style="stop-color:rgba(0,0,0,0.75);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(0,0,0,0);stop-opacity:0" />
</linearGradient>
</defs>
<line x1="40" y1="210" x2="460" y2="211" stroke="url(#grad1)" stroke-width="1" />
I'm probably just missing some obvious function of linear gradients, and the line looks alright, but I'd much rather just have it straight. Thanks.
You are getting caught out by the last paragraph in this part of the SVG specification
Keyword objectBoundingBox should not be used when the geometry of the applicable element has no width or no height, such as the case of a horizontal or vertical line, even when the line has actual thickness when viewed due to having a non-zero stroke width since stroke width is ignored for bounding box calculations. When the geometry of the applicable element has no width or height and objectBoundingBox is specified, then the given effect (e.g., a gradient or a filter) will be ignored.
objectBoundingBox is the default for gradientUnits so you need to use gradientUnits="userSpaceOnUse" and then adjust the values to be appropriate for the different coordinate system.
Robert Longson gives an excellent explanation. But sometimes userSpaceOnUse is a pain, because it spreads the interpolation over the entire canvas, instead of just the line.
Instead, you could add a tiny amount to the values, to ensure the bbox size is not zero.
For example,
<line x1="40" y1="210" x2="460" y2="210.001" stroke="url(#grad1)" stroke-width="1" />
will draw a straight line with gradient.
Assuming you do not want any in-accuracy at all, you can change the line to a filled path as below
<path d='M 40 209.5 L 460 209.5 L 460 210.5 L 40 210.5' fill='url(#grad1)' />
or alternatively to a filled rect as below
<rect x=40 y=209.5 width=420 height=1 fill='url(#grad1)' />
It is also interesting to note that this issue only affects vertical and horizontal lines. Slanted line display correctly.

SVG path with equal height positions will not render [duplicate]

I'm attempting to replicate an <hr> with SVG. Now, making a straight line with SVG works perfectly, but the second I stroke it with a gradient it will no longer display in a straight line.
The following code works, but take note, y1 and y2 must be 1 unit apart. If I set y1 and y2 to 210 for instance, the line will disappear.
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgba(0,0,0,0);stop-opacity:0" />
<stop offset="50%" style="stop-color:rgba(0,0,0,0.75);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(0,0,0,0);stop-opacity:0" />
</linearGradient>
</defs>
<line x1="40" y1="210" x2="460" y2="211" stroke="url(#grad1)" stroke-width="1" />
I'm probably just missing some obvious function of linear gradients, and the line looks alright, but I'd much rather just have it straight. Thanks.
You are getting caught out by the last paragraph in this part of the SVG specification
Keyword objectBoundingBox should not be used when the geometry of the applicable element has no width or no height, such as the case of a horizontal or vertical line, even when the line has actual thickness when viewed due to having a non-zero stroke width since stroke width is ignored for bounding box calculations. When the geometry of the applicable element has no width or height and objectBoundingBox is specified, then the given effect (e.g., a gradient or a filter) will be ignored.
objectBoundingBox is the default for gradientUnits so you need to use gradientUnits="userSpaceOnUse" and then adjust the values to be appropriate for the different coordinate system.
Robert Longson gives an excellent explanation. But sometimes userSpaceOnUse is a pain, because it spreads the interpolation over the entire canvas, instead of just the line.
Instead, you could add a tiny amount to the values, to ensure the bbox size is not zero.
For example,
<line x1="40" y1="210" x2="460" y2="210.001" stroke="url(#grad1)" stroke-width="1" />
will draw a straight line with gradient.
Assuming you do not want any in-accuracy at all, you can change the line to a filled path as below
<path d='M 40 209.5 L 460 209.5 L 460 210.5 L 40 210.5' fill='url(#grad1)' />
or alternatively to a filled rect as below
<rect x=40 y=209.5 width=420 height=1 fill='url(#grad1)' />
It is also interesting to note that this issue only affects vertical and horizontal lines. Slanted line display correctly.

Behavior of stop-opacity in radialGradient in SVG

Background
In the SVG2 spec we can read that:
The opacity value used for the gradient calculation is the product of
the value of stop-opacity and the opacity of the value of stop-color.
For stop-color value types of that don't include explicit opacity
information, the opacity of that component must be treated as 1.
Question
Why does setting stop-opacity: 0 on a 100% gradient stop (for example), not make that gradient stop completely transparent?
You can see the green in the code below.
Pointers to text in the spec that explains this behavior, would be appreciated.
Code
<svg height="150" width="200">
<defs>
<radialGradient id="grad1" cx="50%" cy="50%" r="50%">
<stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(0,255,0);stop-opacity:0" />
</radialGradient>
</defs>
<ellipse cx="100" cy="75" rx="100" ry="75" fill="url(#grad1)" />
Sorry, your browser does not support inline SVG.
</svg>
EDIT 1
I was using Chrome for these tests. The opacity does work as expected in Firefox.
EDIT 2
Removed fx fy to demonstrate that problem still remains, even without those.
The SVG 1.1 spec doesn't say much on the subject of interpolating colors between stops. But all the renderers I have seen so far are in concordance with this SVG 2 spec statement:
For linear and radial gradients, the color value between two stops along the gradient vector is the linear interpolation, per channel, of the color for each stop, weighted by the distance from each stop.
It's not explicitely said that opacity is treated as a channel in this context, but again that is what renderers do: If there are two gradient stops with color1 and opacity=1 and color2 and opacity=0, then the color at an intermediate point is a linear interpolation between the color values, and the opacity is partial.
For your example color will change like this:
color stop at 0%: red 255, green 0, blue 0, opacity 1
color interpolation at 25%: red 192, green 64, blue 0, opacity 0.75
color interpolation at 50%: red 128, green 128, blue 0, opacity 0.5
color interpolation at 75%: red 64, green 192, blue 0, opacity 0.25
color stop at 100%: red 0, green 255, blue 0, opacity 0
As the color fades, it goes from red to green:
I can see this with almost all browsers I have access to: Chrome 70/Windows, Chromium 70/Debian, Firefox 60esr/Debian, Firefox 62/Debian, Edge, IE11. The only exeption is Firefox on Windows: v62/63 show a gradient going from opaque red to transparent red:
From my point of view, it is Firefox that is in error here.

How to fill outside of html <polygon> or <path>?

Can I fill outside of html <polygon> or <path> like the below image?
<div style="background:'image.png'>
<svg style="background:rgb(100,100,230)">
<polygon points="x,y x1,y1 ..."
style="fill:???;fill-rule:???"/>
</svg>
</div>
I can definitely fill inside of <polygon> or <path>. But how can I fill outside of them? I know one work-around which uses outer polygon enclosing the outside of the star. Is there a simple way?
I haven't found a way to fill the outside of a polygon. But you can produce the same effect, though it's a bit messy, like this.
Start somewhere outside your canvas. Create a path that goes from there to a point on the near side of the perimeter of your polygon, follow round your polygon - let's say we do this clockwise - all the way back to where you joined it, carry on clockwise to a point outside your canvas, and then go round the outside of your canvas, anticlockwise, in a big rectangle, back to where you first started.
You can't "fill outside" of a shape. But you can put a shape behind it.
In your example, you would have a blue square and then in front of it put a star-shaped clipped image.

Why does this combination of Raphael radiant fill coordinates fail?

Using Raphael, I noticed that if I tried to apply a radial fill on a circle using 0.9 and 0.2 as the radial focus points, it fails to draw the radial fill.
paper.circle(50,300,20).attr({"fill":"r(0.5,0.1)#f00-000"});
paper.circle(100,300,20).attr({"fill":"r(0.9,0.2)#f00-000"}); // <-- fails
paper.circle(150,300,20).attr({"fill":"r(0.9,0.3)#f00-000"});
I've set up a fiddle, here, and did a 10x10 grid, and the (0.9,0.2) is the only one that failed.
I'd like to understand why. http://jsfiddle.net/ENMry/2/
This is not problem of Raphael library but most probably of JS SVG rendering. You can repeat the same problem using just JavaScript and SVG markup without Raphael library. See example at jsBin
I changed your example to have bigger circles with 11x11 grid (from 0.0 to 1.0) and put also one row separately on the top to show how is focus point moving. See example at jsBin.
Using browser console (ctrl+shift+J in Chrome) you can inspect DOM elements. The following markup is set for our white element (the 2nd one in the first row):
<radialGradient id="2r_0.1_0.2__f00-_000" fx="0.1" fy="0.2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">
<stop offset="0%" stop-color="#ff0000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></stop>
<stop offset="100%" stop-color="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></stop>
</radialGradient>
<circle cx="175" cy="50" r="30" fill="url(#2r_0.1_0.2__f00-_000)" stroke="#000" opacity="1" fill-opacity="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); opacity: 1; fill-opacity: 1;">
</circle>
This MDN Gradients tutorial explains how radial gradient works.
If I understand correctly radial gradient is defined with 5 data and stop markup:
where is point of radiation: for example cx="0.25" cy="0.25" r="0.25". They define position and where the gradient ends. If not set cx and cy are in the midle of the element (same as value 0.5 or 50%; cx=0, cy=0 means top-left), r is 1 or 100%. In our case radiation starts in the middle of the circle and ends on its edge.
stop markup defines which colors should be at certain position.
where is focal (focus) point: in our case fx="0.1" fy="0.2". Standard says: fx and fy define the focal point for the radial gradient. The gradient will be drawn such that the 0% gradient stop is mapped to (fx, fy).
If you imagine a rectange around the circle, fx="0.1" fy="0.2" is somewhere to the left upper corner. This tutorial says: If the focal point is moved outside the circle described earlier, its impossible for the gradient to be rendered correctly, so the spot will be assumed to be on the edge of the circle. If the focal point isn't given at all, its assumed to be at the same place as the center point.
The first circle in the top row has fx="0.0" fy="0.2" and is out of radiation circle. So the spot is set on the edge: left, middle.
The "problematic" white circle has fx="0.1" fy="0.2" and this point is exactly on the edge of (radiation) circle. And rendering somehow fails. The same is for fx="0.9" fy="0.2", fx="0.2" fy="0.1" and fx="0.2" fy="0.9".
Following the same logic we should have another 4 white circles:
fx="0.8" fy="0.1"
fx="0.8" fy="0.9"
fx="0.1" fy="0.8"
fx="0.9" fy="0.8"
but they are rendered correctly.
You can easily see all those "problematic" points if you draw a circle and a grid.
So, I do not know if this is some rounding problem or something else. Anyway, it could be a bug. I found one connected with radial rendering but it is not exactly the same.
BTW, FireFox and IE10 render it without problem.
Note: I submit an issue 322487