1

I'm new to D3 and am trying to build a table like structure out of rectangles. I would like the header to be a different color than the rest of the rectangles. I've written the following code:

table = svgContainer.selectAll('rect')
                    .data([managedObj])
                    .enter()
                    .append('rect')
                    .attr("width", 120)
                    .attr("height", 20)
                    .attr("fill", "blue")
                    .text(function(d) {
                        return d.name;
                    });

                // create table body
                table.selectAll('rect')
                    .data(managedObj.data)
                    .enter()
                    .append('rect')
                    .attr("y", function() {
                        shift += 20;
                        return shift;
                    })
                    .attr("width", 120)
                    .attr("height", 20)
                    .attr("fill", "red")
                    .text(function(d) {
                        return d.name;
                    });

This is producing the following results: enter image description here

This is almost what I intended except it is nesting the second group of rectangles inside the first rectangle. This causes only the first blue rectangle to be visible. I'm assuming this has something to do with calling the data method twice. How can I fix this issue?

  • There is nothing strange here. `svgContainer` is an enter selection for a rectangle. You **cannot** append a rect to another rect. – Gerardo Furtado Feb 07 '17 at 06:16

1 Answers1

2

I think I understand the intended result, so I'll give it a go:

This line :

table.selectAll('rect')

is selecting the rectangle just created here:

table = svgContainer.selectAll('rect')....append('rect')....

You don't want to append rectangles to that rectangle (or any rectangle for that matter) because this won't work, but you do want to append them to the SVG itself.

So instead of table.selectAll you should be using svgContainer.selectAll, but there are two other issues:

  1. if you use svgContainer.selectAll('rect') you will be selecting the rect you have already appended, when you actually want an empty selection. See the answer here.

  2. you cannot place text in a rect (See answer here), instead you could append g elements and then append text and rect elements to those. And, for ease of positioning, you could translate the g elements so that positioning the rectangles and text is more straight forward.

So, your code could look like:

var data = ["test1","test2","test3","test4"];
 
var svgContainer = d3.select('body').append('svg').attr('width',900).attr('height',400);


 
var header = svgContainer.selectAll('g')
 .data([data])
    .enter()
    .append('g')
 .attr('transform','translate(0,0)');
     
header.append('rect')
    .attr("width", 120)
    .attr("height", 20)
    .attr("fill", "blue");
 
header.append('text')
    .attr('y',15)
    .attr('x',5)
    .text(function(d) {
         return "header";
    });

     // create table body
var boxes = svgContainer.selectAll('.box')
    .data(data)
    .enter()
    .append('g')
 .attr('class','box')
 .attr('transform',function(d,i) { return 'translate(0,'+((i+1)*20)+')'; });
     
       
boxes.append('rect').attr("width", 120)
 .attr("height", 20)
 .attr("fill", "red");
      
boxes.append('text')
 .attr('y',15)
 .attr('x',5)
 .text(function(d) {
        return d;
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Graham
  • 7,431
  • 18
  • 59
  • 84
Andrew Reid
  • 37,021
  • 7
  • 64
  • 83