Richard
Richard

Reputation: 65530

Struggling with D3 general update pattern and groups

I want to update a legend dynamically using D3, using SVG group and text elements. This is my function that gets called when it is time to update the legend.

The goal is that it will add text elements if they don't already exist. If they do exist, it will update the content of those text elements in line with the new data.

function updateCountryLegend(data) { 
  var countries = rightPanel.selectAll('g.country').data(data);    
  var cEnter = countries.enter()
                      .append('g')
                      .attr('class', 'country');    
  var countryText = cEnter.append('text')
         .attr('x', 0)
         .attr('y', 10);
  countryText.text(function(d) { return d.name; }); 
}

The current code is adding the elements OK, but not updating them. I think this is because the text is only being set on the enter selection. But no matter what I try I can't work out how to set the text on the update selection.

I want to continue to use SVG group elements, so that I can add rectangles to indicate legend colour, etc.

JSFiddle with full code here: http://jsfiddle.net/1qhnbqbw/1/

Upvotes: 0

Views: 745

Answers (2)

Lars Kotthoff
Lars Kotthoff

Reputation: 109232

The difficulty in your case is that the update selection contains the g elements, but you want to change the text elements. To do this, call another .select() on the update selection -- countries.select("text"). This new selection will contain the text elements that you can now update in the usual manner and at the same time inherit the new data from the g to the text elements.

Complete demo here. I've replaced the gs with divs for the HTML, removed a few unnecessary variables, and handled the exit selection as well.

Upvotes: 3

ahmohamed
ahmohamed

Reputation: 2970

You don't need to create additional variables cEnter and countryText. You can just use the original countriesin all operations. The updated fiddle now updates text fine.

function updateCountries(data) { 

    console.log('data', data);

    var countries = rightPanel.selectAll('g.country').data(data);

    countries.enter()
             .append('g')
             .attr('class', 'country');

    countries.append('text')
             .attr('x', 0)
             .attr('y', 10);

    countries.text(function(d) { return d.name; });

}

Upvotes: 0

Related Questions