Brandon Meredith
Brandon Meredith

Reputation: 135

SVG Gradient Bug: gradients change after zoom

I have a few hundred svg containers on a page. Each container has a thick line, and each line has a different gradient applied to it. (I've done this dynamically with d3.js.)

the good gradients

But when I zoom in on the image, all the gradients change to the gradient on the first svg container.

one gradient repeated over and over

Why is this happening, and more importantly how can I stop this from happening?

Thanks!

Edit: Here's the code:

<style id="css">
.line {                         
    fill: none;                 
    stroke: url(#line-gradient);    
    stroke-width: 10px;          
}
</style>

<script>
var myData = <%= @myData %>


for (i = 0; i < myData.length; i++) { 

var margin = {top: 20, right: 20, bottom: 30, left: 50};
var width = 960 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

//Make an SVG Container
var svgContainer = d3.select("body").append("svg")
                                    .attr("width", 200)
                                    .attr("height", 20);

//Set the gradient
svgContainer.append("linearGradient")                
       .attr("id", "line-gradient")            
       .attr("gradientUnits", "userSpaceOnUse")    
       .attr("x1", 0).attr("y1", 0)         
       .attr("x2", 200).attr("y2", 0)      
   .selectAll("stop")                      
       .data(myData[i])                  
   .enter().append("stop")         
       .attr("offset", function(d) { return d.offset; })   
       .attr("stop-color", function(d) { return d.color; })
       .attr("stop-opacity", function(d) { return d.opacity; });

//Draw the line
var circle = svgContainer.append("line")
                         .attr("class", "line")
                         .attr("x1", 5)
                         .attr("y1", 5)
                         .attr("x2", 200)
                         .attr("y2", 5)
                         .attr("stroke-width", 2)
                         .attr("stroke", "black");
}
</script>

Edit2: Using the Robert's answer, I was able to get the results I wanted. I needed to learn how to create style elements dynamically using javascript, which I found here:

http://www.phpied.com/dynamic-script-and-style-elements-in-ie/

and here

How to create a <style> tag with Javascript

The code I used:

Inside the for-loop:

...
var ss1 = document.createElement('style');
var def = '.line'+i+' {\
    fill: none;\
    stroke: url(#line-gradient'+i+');\
    stroke-width: 10px;\
}';
ss1.setAttribute("id", "css");
var hh1 = document.getElementsByTagName('header')[0];
hh1.appendChild(ss1);
var tt1 = document.createTextNode(def);
ss1.appendChild(tt1);
...
svgContainer.append("linearGradient")                
       .attr("id", "line-gradient" + i)
...
var circle = svgContainer.append("line")
                         .attr("class", "line"+i)
...

Upvotes: 0

Views: 476

Answers (1)

Robert Longson
Robert Longson

Reputation: 124324

All id attributes on a page must be unique. Yours aren't, you have multiple elements with the attribute line-gradient.

Upvotes: 4

Related Questions