score:5

Accepted answer

Notice that the var svg is being assigned to a <g> nested inside the <svg>

svg = d3.select("body").append("svg")
        .attr("width",  width  + margin.left + margin.right)
        .attr("height", height + margin.top  + margin.bottom)
        .append("g") // <-- This is what svg is currently being assigned to
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

And so, when you later execute var legend = svg.append("g"), you're actually appending the legend as a child of the aforementioned <g>. And that's what you described seeing in the dev tools.

One implication is that the translate() transform you applied to the outer <g> affects the inner <g> (i.e. the translation of the innter <g> of legend is added to that of the outer <g>).

Likely, you want split things up like so:

var svg = d3.select("body").append("svg")
            .attr("width",  width  + margin.left + margin.right)
            .attr("height", height + margin.top  + margin.bottom);

var inner = svg.append("g")
              .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

Then change your code to draw the existing chart into inner rather than svg.

As a result, var legend = svg.append("g") will append legend as a sibling of inner, and any translation you apply to legend would be relative to the svg's top left (as opposed to inner's top left, which is translated by margin)

And likely you want to translate legend like so:

var legend = svg.append("g")
               .attr("transform", "translate(" + width - margin.right + "," + margin.top + ")");

That moves the legend to the right end of the chart, MINUS margin.right. That way, you can tweak margin.right to create enough room for legend.

Finally, note that calling

legend
  .attr("height", 300)
  .attr("width", 200)

doesn't do anything, because for svg <g>, there isn't a way to explicitly set the width and height. Those wouldn't mean much anyway, because svg doesn't have a the "flow" behavior of html layouts. The width and height shown in dev tools are the implicit bounds resulting from the bounds of the children of the <g>. (If needed, there's a way to get those computed bounds in javascript, using the getBBox() function).

score:-1

by looking at the code you provided, you are actually attaching the legend var to your group "g", instead of "svg",
var legend = svg.append("g")

in this line you are telling d3 to get your legend variable to "g" which is append to svg, if i understand correctly you should try something like this:

var legend = svg.selectAll(".legend")
.enter().append("g")

to create another group "g" for your legends. i apologize for my bad english.


Related Query

More Query from same tag