15

I'm using svg to draw line charts, and require a gradient to be applied to it. For each line, I use a path element and set the stroke to one of my lineargradient elements.

This works great for everything but purely horizontal lines - in this case, I get no colours on my line at all.

I've made a fiddle showing the problem: http://jsfiddle.net/b6EQT/

<svg>
    <defs>
        <linearGradient id="grad" x1="0%" x2="100%" y1="0%" y2="0%">
            <stop class="" offset="0%" style="stop-color: red;"></stop>
            <stop class="" offset="33%" style="stop-color: yellow;"></stop>
            <stop class="" offset="66%" style="stop-color: pink;"></stop>
            <stop class="" offset="100%" style="stop-color: blue"></stop>
        </linearGradient>
    </defs>
<-- Gradient not applied -->
<path stroke="url(#grad)" d="M20,20L400,20" style="stroke-width: 10px;"></path>

<-- Gradient applied since height of 1px -->
<path stroke="url(#grad)" d="M20,40L400,41" style="stroke-width: 10px;"></path>

<-- Gradient applied because of fake initial "move to" -->
<path stroke="url(#grad)" d="M-1,-1,M20,60L400,60" style="stroke-width: 10px;"></path>
</svg>​

The pure horizontal line (first path) doesn't appear, and the second one (slight change in y) does.

I tried a little hack to get it going - putting a fake M-1,-1 at the start, which seems to work around the issue in IE and Chrome, but not firefox. This makes me think I'm missing something in my understanding of SVG gradients and paths. Is there a way to get this to work?

XwipeoutX
  • 4,765
  • 4
  • 29
  • 41

2 Answers2

18

The default for gradientUnits is objectBoundingBox. The key issue you have is described in the last paragraph of the specification text...

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.

Why not use a rect with a fill rather than a path with a stroke if you've got a horizontal line? Or alternatively use userSpaceOnUse units.

Robert Longson
  • 118,664
  • 26
  • 252
  • 242
  • 2
    The charts are generated automatically, so whether it's a perfect horizontal or not depends on the data. The userSpaceOnUse units work perfectly though, thanks! – XwipeoutX Nov 04 '12 at 23:06
  • @XwipeoutX if your paths are dynamically generated from you data then an option might be to jitter the paths a little bit so that they are not perfectly horizontal. That way you can keep objectBoundingBox, which might suit you better because the percentages of the stops belong to the path itself – Gabriel Furstenheim Jun 20 '17 at 07:36
12

gradientUnits="userSpaceOnUse" can fix it.

Demo

<linearGradient 
    id="grad" x1="0%" x2="100%" y1="0%" y2="0%" 
    gradientUnits="userSpaceOnUse">
    <stop class="" offset="0%" style="stop-color: red;"></stop>
    <stop class="" offset="33%" style="stop-color: yellow;"></stop>
    <stop class="" offset="66%" style="stop-color: pink;"></stop>
    <stop class="" offset="100%" style="stop-color: blue"></stop>
</linearGradient>

More detail answer

WebBrother
  • 1,447
  • 20
  • 31