简体   繁体   中英

How to update/overwrite map and legend content using d3

I've put together a choropleth map using d3, helped by examples written by Mike Bostock. I'm new to d3 (and HTML, JavaScript, CSS to be honest).

I've got as far as creating the map and the legend, and being able to switch between different data sets. The map and source code can be viewed here on bl.ocks.org

Glasgow Index of Deprivation 2012

The problem I'm having now is working out how to replace the map and legend content when switching between the different datasets. As you can see at the moment, when a different dataset is selected, the content is simply added on top of the existing content.

I've tried following the advice given by Stephen Spann in this answer , and the code he provided in a working fiddle. But to no avail.

As I understand, I should add the g append to the svg variable in the beginning like so...

var svg = d3.select("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g");

Then select it when updating like so...

var appending = svg.selectAll("g")
    .attr("class", "S12000046_geo")
    .data(topojson.feature(glasgowdep, glasgowdep.objects.S12000046_geo).features);

     // add new elements
     appending.enter().append("path");

     // update existing elements
     appending.style("fill",
     function (d) {
         return color(choro[d.id]);
     })
     .style("stroke", "#cfcfcf")
     .attr("d", path)

     // rollover functionality to display tool tips
     .on("mouseover", function (d) {
         tip.show(d)
         d3.select(this)
             .transition().duration(200)
             .style("fill", "red");
     })
     .on("mouseout", function () {
         tip.hide()
         d3.select(this)
             .transition().duration(200)
             .style("fill",
             function (d) {
                 return color(choro[d.id]);
             });
     })

     // build the map legend
     var legend = d3.select('#legend')
         .append('ul')
         .attr('class', 'list-inline');

     var keys = legend.selectAll('li.key')
         .data(color.range());

     var legend_items = ["Low", "", "", "", "", "", "", "", "High"];

     keys.enter().append('li')
         .attr('class', 'key')
         .style('border-top-color', String)
         .text(function (d, i) {
             return legend_items[i];
         });

     // remove old elements
     appending.exit().remove();

A solution could be the following: at your code in http://bl.ocks.org/niallmackenzie/8a763afd14e195154e63 try adding the following line just before you build the map legend (line 220 in index.html):

d3.select('#legend').selectAll('ul').remove();

Every time you update your data, you empty first the #legend.

Thanks to the advice from Lars and the solution proposed by nipro, the following works. By adding the following code just above the section that builds the legend, the legend is emptied first before it gets updated:

d3.select('#legend')
   .selectAll('ul')
   .remove();

// build the map legend
var legend = d3.select('#legend')
...

And by doing the same for the main map, we can first empty the map before updating it:

d3.select("g")
  .selectAll("path")
  .remove();

// build the choropleth map
var appending = svg.selectAll("g")
...

The full working updated code can been seen on bl.ocks.org here .

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