title: How to place rectangles behind text in d3.js
body: <p>I am having difficulty trying to place rectangles behind text as background in d3.js. I read that in order to do that you have to append to the same g element but in my case it does not work like that. 
  my code: <a href="https://plnkr.co/edit/4V1xff?p=preview" rel="nofollow noreferrer">plunker</a></p>
  
  <pre><code>var urls = [{
    "wor": "Nordmerika",
    "number": "10.9",
    "lon": "-100.33",
    "lat": "47.61"
  }, {
    "wor": "Latinamerika",
    "number": "14.2",
    "lon": "-56.62",
    "lat": "-8.53"
  }, {
    "wor": "Afrika",
    "number": "51.8",
    "lon": "24.5085",
    "lat": "8.7832"
  }, {
    "wor": "Asien",
    "number": "27.5",
    "lon": "104.238281",
    "lat": "34.51561"
  }, {
    "wor": "GUS | Russland",
    "number": "3.4",
    "lon": "62.753906",
    "lat": "47.923705"
  }, {
    "wor": "Europa | MSOE",
    "number": "10.9",
    "lon": "15.2551",
    "lat": "54.526"
  }]
  
  //starting map
  var margin = {
      top: 10,
      left: 10,
      bottom: 10,
      right: 10
    },
    width = parseInt(d3.select('#map').style('width')),
    width = width - margin.left - margin.right,
    mapRatio = .5,
    height = width * mapRatio;
  
  //Map projection
  var projection = d3.geo.equirectangular()
    .scale(width / 5.8)
    .translate([width / 2, height / 2]) //translate to center the map in view
  
  //Generate paths based on projection
  var path = d3.geo.path()
    .projection(projection);
  
  //Create an SVG
  var svg = d3.select("#map")
    .append("svg")
    .attr("viewBox", "0 0 " + width + " " + height)
    .attr("preserveAspectRatio", "xMinYMin");
  
  //Group for the map features
  var features = svg.append("g")
    .attr("class", "features");
  
  var labelWidths = [];
  
  d3.json("countries.topojson", function(error, geodata) {
    if (error) return console.log(error); //unknown error, check the console
  
    var layerOne = svg.append("g");
    var layerTwo = svg.append("g");
    var layerThree = svg.append("g");
  
    //Create a path for each map feature in the data
    features.selectAll("path")
      .data(topojson.feature(geodata, geodata.objects.subunits).features) //generate features from TopoJSON
      .enter()
      .append("path")
      .attr("d", path)
      .on("click", clicked)
      .style('fill', '#cdd5db')
      .style('stroke', '#ffffff')
      .style('stroke-width', '0.5px')
      .on('mouseover', function(d, i) {
        d3.select(this).style('stroke-width', '2px');
      })
      .on('mouseout', function(d, i) {
        d3.select(this).style('stroke-width', '0.5px');
      });
  
  
    var bubbles = layerOne.attr("class", "bubble")
      .selectAll("circle")
      .data(urls)
      .enter()
      .append("circle")
      .attr("cx", function(d, i) {
        return projection([d.lon, d.lat])[0];
      })
      .attr("cy", function(d, i) {
        return projection([d.lon, d.lat])[1];
      })
      .attr("r", function(d) {
        if (width &gt;= 1000) {
          return (d.number)
        } else {
          return d.number
        }
  
      })
      .style('fill', function(d) {
        if (d.wor == 'Afrika') {
          return '#dc0f6e'
        } else {
          return '#3e3e3e'
        }
      });
  
  
  
    var text = layerTwo
      .attr('class', 'text')
      .selectAll('text')
      .data(urls)
      .enter()
      .append('text')
      .attr('x', function(d, i) {
        if (d.number &lt; 10) {
          return projection([d.lon, d.lat])[0] + 60;
        } else {
          return projection([d.lon, d.lat])[0]
        }
  
      })
      .attr('y', function(d, i) {
        return projection([d.lon, d.lat])[1];
      })
      .text(function(d) {
        return d.number;
      })
      .attr("dy", function(d) {
        if (this.getBBox().width &gt; d.number * 3) {
          return '-2em'
        } else {
          return "0.3em"
        }
      })
      .attr("text-anchor", "middle")
      .style('fill', '#fff')
      .style('font-weight', 'bold')
      .style('font-size', '1em');
  
  
    var labels = layerThree
      .attr('class', 'labels')
      .selectAll('text')
      .data(urls)
      .enter()
      .append('text')
      .attr('x', function(d, i) {
        return projection([d.lon, d.lat])[0] + 60;
  
      })[plunker][1]
      .attr('y', function(d, i) {
        return projection([d.lon, d.lat])[1];
      })
  
    .attr("text-anchor", "middle")
      .text(function(d) {
        return d.wor;
      })
      .attr('dy', function(d) {
        labelWidths.push(this.getBBox().width)
        var radius = d.number * 2
        if (radius &gt; 10) {
          return d.number * 4;
        } else {
          return '-0.5em'
        }
      })
      .style('font-size', '1em')
      .style('font-weight', 'bold');
  
    var rect = layerThree
      .attr('class', 'rectlabels')
      .selectAll('rect')
      .data(urls)
      .enter()
      .append('rect')
      .attr('x', function(d, i) {
        return projection([d.lon, d.lat])[0] + 60;
      })
      .attr('y', function(d, i) {
        return projection([d.lon, d.lat])[1];
      })
      .attr('dy', function(d) {
        return '1em'
      })
  
    .style('fill', '#ffffff')
      .attr('width', function(d, i) {
        return labelWidths[i] / 10 + 'em'
      })
      .attr('height', '1em');
  
    function clicked(d, i) {
  
    }
  
  });
  </code></pre>