Reputation: 1511
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
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 rect
s 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