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

匿名 (未验证) 提交于 2019-12-03 01:45:01

问题:

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"} ]

回答1:

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!