krishna_v
krishna_v

Reputation: 1511

d3.js - adding rectangles reading from json file in a svg

I am adding legends(through rectangles) on a svg. The data is read from different json files for each group of legend. I would like to draw the rectangles in the same svg. However only one set of legend is being added. Only the first json data is drawn as rectangles. The second is ignored.

My code is :

  svgcheckins= d3.select("#legend").append("svg").attr("id","svgcheckins")
.attr("width", 250)
.attr("height", 200)
 .append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.json("checkins.json", function(data) 

    {
        CreateLegend('#legend',svgcheckins,"checkins",data,'A - Checkins','');
    });




  d3.json("builds.json", function(data) 

{
    CreateLegend('#legend',svgcheckins,"Builds",data,'B - Builds','');
});

function CreateLegend(div,svg,svgid,data,header,trail)
{

  var traillength=0;
  var svgelem;


jsondata = data;

console.log(data);

rectangle= svg.selectAll("rect").data(data).enter().append("rect");
  var RectangleAttrb = rectangle

                    .attr("id", function (d,i) { return svgid + "id" + i ; })
                    .attr("x", function (d) { return d.x_axis; })
                   .attr("y", function (d) { return d.y_axis; })
                   .attr("width",function(d) { return d.width; } )
                   .attr("height",function(d) { return d.height; })
                   .style("stroke", function (d) { return d.border;})
                   .style("fill", function(d) { return d.color; });





        var textparam = svg.selectAll("text").data(data).enter().append("text");

        var yearheader = d3.select("#header");

    if(yearheader.empty()) 
    {

        var textheader = svg.append("text").attr("dx",20).attr("dy",5).text(header).attr("id",header).attr("style","margin-bottom:21px;border-bottom: solid 2px #ffd97f; font-size:12px;")
    }

        if (trail.length == 0)
    {

          d3.select(header).attr("style","font-size:15.1px;text-decoration:underline");

    }


    var text = textparam .attr("x", function (d) { traillength = d.x_axis + d.width +10; return d.x_axis + d.width +10; })
                   .attr("y", function (d) { return d.y_axis + d.height-5; })
                   .attr("width",30 )
                   .attr("height",20)
                   .attr("style", "text-decoration:none")
                   .text(function(d) { return d.text; });


var yearheader = d3.select("#trail");


if (trail.length > 0 && yearheader.empty() )
  {

    svg.append("text").attr("id","trail").attr("dx",traillength-10).attr("dy",5).text(trail).attr("style","margin-bottom:21px;border-bottom: solid 2px #ffd97f; font-size:12px;" )
  }

}

The json data are :

checkins.json

[
   { "x_axis":10, "y_axis": 10,"width":20,"height":15,"color" : "#FE2E2E","border":"#000000"},
   { "x_axis":30, "y_axis": 10,"width":20,"height":15,"color" : "#FE9A2E","border":"#000000"},
   { "x_axis":50, "y_axis": 10,"width":20,"height":15,"color" : "#FFFF00","border":"#000000"},
   { "x_axis":70, "y_axis":10,"width":20,"height":15,"color" : "#D0FA58","border":"#000000"},
   { "x_axis":90, "y_axis":10,"width":20,"height":15,"color" : "#01DF01","border":"#000000"}


]

builds.json

[
   { "x_axis":10, "y_axis":60,"width":20,"height":15,"color" : "#424242","border":"#000000"},
   { "x_axis":30, "y_axis":60,"width":20,"height":15,"color" : "#D8D8D8","border":"#000000"},
   { "x_axis":50, "y_axis":60,"width":20,"height":15,"color" : "#FFFF00","border":"#000000"},
   { "x_axis":70, "y_axis":60,"width":20,"height":15,"color" : "#FAFAFA","border":"#000000"},
   { "x_axis":90, "y_axis":60,"width":20,"height":15,"color" : "#81DAF5","border":"#000000"}
]

Upvotes: 0

Views: 1494

Answers (1)

Lars Kotthoff
Lars Kotthoff

Reputation: 109292

This is because of how D3's data matching work. In particular, I'm referring to the following line:

rectangle= svg.selectAll("rect").data(data).enter().append("rect");

This selects all rect elements and matches data to them. For the first legend, no rects are there, so nothing is matched and it works as you expect. However, if there's a rect already, it is matched to data and your enter selection is empty. This is because D3 matches based on array index by default.

There are basically two ways around this. You could either use the optional second argument to .data() to tell D3 how to match, or assign a distinguishing class to the created legend to be used in the .selectAll(). Your data doesn't seem to have any distinguishing attributes in it, but you can use svgid for this purpose:

rectangle= svg.selectAll("rect." + svgid).data(data).enter().append("rect");
rectangle.attr("class", svgid);
// rest of code

Upvotes: 1

Related Questions