Fede9390
Fede9390

Reputation: 349

d3.js Change attributes of external svg injected through d3.xml

I am working on this pie-chart. This is what I would like to happen as the user clicks on a wedge of the pie:

1) An external svg is loaded and inserted in the div on the right (DONE)

1.1) The svg has the following structure

<svg id="Ebene_1">
  <circle></circle>
  <path></path>
<svg>

2) Change circle's fill according to a color() function which assign a color depending on the wedge's index

2) Change path's fill to white

This is the relevant code I have so far:

descrImg = d3.select("#descrImg");       //select the target div
descrImg.select("svg").remove();         //removes previous image
descrImgURI = d.data.descrImg;           //extract svg's URI from data
d3.xml(descrImgURI, "image/svg+xml", function(error, xml) {
       if (error) throw error;
       var svg= xml.documentElement;
       descrImg.node().appendChild(svg); //append svg
          var a = document.getElementById("Ebene_1");  //select svg
          var b = a.getElementsByTagName("cicle");     //select circle
          var c = a.getElementsByTagName("path");      //select path
          d3.select(c).attr("fill", "white");         //change path's fill attribute
       });

When I click on a wedge, the svg is loaded correctly but the path's fill is not changed. I get the following error (same happens if I use style instead of attr):

TypeError: this.setAttribute is not a function

Other options:

//Option 1
var c = d3.select(document.getElementById("#Ebene_1").contentDocument).selectAll("path");
d3.select(c).attr("fill", "yellow");

//Option 2
var c = d3.select(document.getElementById("Ebene_1").contentDocument).selectAll("path");
d3.select(c).attr("fill", "yellow");

//Both return the error
TypeError: document.getElementById(...) is null


//while Option 3
var c = document.getElementById("Ebene_1").contentDocument.getElementsByTagName("path");
d3.select(c).attr("fill", "yellow");
//Returns
TypeError: document.getElementById(...).contentDocument is undefined

I do not know if this matters, but when I inspect circle or fill I see their attributes are "locked" (a bit hard to see but there is a lock next to attributes)

enter image description here

Any ideas?

Upvotes: 0

Views: 1041

Answers (1)

Fede9390
Fede9390

Reputation: 349

I have managed to solve the problem. This is the code that works:

d3.xml(descrImgURI, "image/svg+xml", function(error, xml) {
           if (error) throw error;
            var svg= xml.documentElement;
            descrImg.node().appendChild(svg);
            var a = document.getElementById("Ebene_1");
            var b = a.getElementsByTagName("circle")[0];
            var c = a.getElementsByTagName("path");
            // d3.select(b).attr("fill", function (d, i) {
            //       var scale = colorMap[d.data.categoria];
            //       if (scale) return scale(d.data.catIndex);
            //     })
            d3.select(b).attr("fill", fillColor);
            d3.selectAll(c).attr("fill", "white");
          });

getElementsByTagName returns a collection of items, regardless of how many items will be in the collection. Therefore, in the case of b (i.e. the circle) I had to select the first element of the connection (through index [0]). The path(s) in c, on the other hand, can be collectively modified by using d3.selectAll. If I use the same method as with b, then only the first set of paths would be modified and, at least in my case, this would leave some drawings partly uncolored.

Hope this helps!

Upvotes: 2

Related Questions