简体   繁体   中英

d3(behind the scene)-area.style.append works while area.style + area.append doesn't work. why?

Hi I have a question about nature of d3, which I think very deep details about d3.

As far as I understood,

variable declaration in d3 like,

 var svg = d3.select('boby').append('svg')

means,

"I'm going to select 'body' and append 'svg'. and store this as a variable called 'svg'."

Instead of

"variable svg is 'to select body and append svg"

The reason why I think this way is
If the second one is the right intepretation,

everytime I type svg, it would append svg everytime.

So I think my first intepretation is right.



However,

If this is the case, the code below should work.

var area = svg.append('g')

area.append('path')

area.attr('d').data(somedata)

Because, I appened 'g'
and then stored it as variable called 'area'
and then appeneded 'path' there
and then added attribute there
and then tied some data for that.

But, it didn't work out.

What I tried was then,

decalring another variable and added additional conditions after that new variable, like

var uarea = area.append('path')

uarea.attr('d').data(somedata)

And it worked out perfectly.

Why did my first approach not work out while the last one works. I think this question is more about what happened behind the scene in d3. I wish someone could give me some enlightment strike in d3.

I'm not certain I understand your question correctly. But I'll try to provide an answer here.

The short answer is: No, the assumption you are testing is incorrect because it assumes that .append() modifies an existing selection. area remains a selection of a g regardless of what you append to area .


I'm going to start right at the beginning because of your first assumption about appending the SVG .

D3 selection methods are often chainable because they are frequently used to return a selection. By returning a selection, another selection method can be used on the returned value, allowing chaining.

But a selection returned by a selection method isn't always a selection of the same elements - that is to say it could be a different selection.

If using a .style() , .attr() , .each() , .call() , .on() , .raise() , .html() , .text() etc method to set an attribute, style, etc, the returned value is the original selection itself. The methods that generally can be used to return the current selection are those that modify something about the selection. If not setting a value, many of these methods can be used to return a value instead of the selection .

If using a method such as .append() , .enter() , .exit() , .merge() , .filter() , .select() , .selectAll() , etc then the returned value is a different selection.

When using a chain to define a variable, the assigned value is the return value of the last item in the chain.

Lastly, D3 selections cannot be changed:

Selections are immutable. All selection methods that affect which elements are selected (or their order) return a new selection rather than modifying the current selection. ( source )

Once we define a selection as consisting of certain elements, we cannot change it. We can only redefine a variable with a different selection.

D3v3 was slightly different in this regard, but not for the purposes of your question


Now, looking at your initial assessment on this line:

var svg = d3.select('body').append('svg')

And your explanation:

I'm going to select [the] 'body' and append [a] 'svg'. and store this as a variable called svg .

Your explanation is correct, let's break the chaining and use two variables to achieve the same thing to see the two selections you are using:

var body = d3.select("body") // returns a selection of the body
var svg = body.append("svg") // returns a selection of a newly created svg

body remains a selection of the body - appending things to body doesn't change that body is a selection of the body. Then we use svg to store the new selection: the selection of a newly appended SVG. Appending any item to svg later will not change svg from being a selection of the svg .


Applying all of the above we can see that an approach such as:

var area = svg.append('g') // returns a selection of a new g element, stored as `area`

area.append('path')        // returns a selection of a new created path element, but you don't store this reference, nothing is done with it.

area.attr('d', somePathData) // attempting to modify a g element instead of a path.

This won't work as you expect, area remains a selection of a g element: you defined it as such and have not redefined area to be some different selection. .append() creates a new selection - one you don't use other than to create the path.

As you noted, if we store the path selection in a new variable, the code will work as expected:

var area = svg.append('g') // returns a selection of a new g element

var path = area.append('path') // returns a selection of a new path element

path.attr('d', somePathData) // modifies a path element

Lastly, if we never need to modify the path again, we wouldn't need to use a variable to store it, we could do:

var area = svg.append('g') // returns a selection of a new g element

area.append('path') // returns a selection of a new path element
    .attr('d', somePathData) // modifies the selection of the path element

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM