karlitos
karlitos

Reputation: 1656

Appending an DOM/SVG element with the d3 javascript library changes variable reference/scope, why?

I noticed then I get mixed results when I append an DOM/SVG elements to an existing object inline and in the separate step when using the D3 javascript library. If I look at the variable referencing the original SVG object it changes, when another object is appended during the creation of the original object. Here is an example:

var body = d3.select("body");

var svg = body.append("svg")
    .attr("width", '100%')
    .attr("height", '100%')

var html1 = svg.append("foreignObject")
    .attr("x", 50)
    .attr("y", 25)
    .attr("width", 200)
    .attr("height", 100)
    .attr('id', 'fo1')
    .append("xhtml:div")
    .html("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam.");

var html2 = svg.append("foreignObject")
    .attr("x", 250)
    .attr("y", 25)
    .attr("width", 200)
    .attr("height", 100)
    .attr('id', 'fo2');

html2.append("xhtml:div")
    .html("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam.");

console.log('first fo:', html1[0]);
console.log('first fo id:', d3.select('#fo1')[0]);
console.log('second fo:', html2[0]);

The output looks like :

first fo: 
   Array[1]
        0: div
        length: 1
        parentNode: html
        __proto__: Array[0]

first fo id: 
  Array[1]
       0: foreignobject#fo1.[object SVGAnimatedString]
       length: 1
       parentNode: html
       __proto__: Array[0]


second fo: 
  Array[1]
     0: foreignobject#fo2.[object SVGAnimatedString]
     length: 1
     parentNode: html
     __proto__: Array[0]

After appending the DIV element to the foreignObject element inline during the creation the variable changes from foreignObject to div. Doing this in extra step does not chenges the reference. Here is the corresponding jsfiddle Could someone explain this to me and tell me how to avoid it ?

Upvotes: 0

Views: 1071

Answers (1)

Lars Kotthoff
Lars Kotthoff

Reputation: 109262

The result of an append() operation in D3 is the element that you have just appended. This is so that you can chain the methods to set attributes, content, etc. If this wasn't the case, then you couldn't use the .html() function to set the content of your newly-appended div as the current object would still be the parent foreignObject.

This behavior is intentional and you cannot prevent it unless you modify the D3 source. If you need to save the references to all the elements, simply append in separate calls. That is

var html1 = svg.append("foreignObject")
    ...
    .attr('id', 'fo1')
    .append("xhtml:div")
    .html(...);

would become

var html1 = svg.append("foreignObject")
    ...
    .attr('id', 'fo1');

var nested = html1.append("xhtml:div")
    .html(...);

Upvotes: 2

Related Questions