0

I have a d3 map with a number of circles and squares appended. The shapes represent data from different years, and I have a selector to allow users to choose the year, which makes that year's shapes more prominent via a function that (among other things) gives them the class '.currentYear'. There's a live version here.

I need to re-append the circles and rects with class '.currentYear' after the others so that they appear on top. My (rather verbose) function for updating when the selector changes is:

    d3.select("#yearSelector").on('change', yearTrans);

    function yearTrans() { 
     selected = this.value;

    rec.selectAll('.grant')
       .filter('.currentYear')
       .classed('currentYear', false)
       .on('mouseover', tip.hide)
       .transition().duration(1000)
       .attr("r", rad/2)
       .style("opacity", 0.8);

    rec.selectAll('.grant')
       .filter('.' + selected)
       .classed('currentYear', true)
       .transition().duration(1000)
       .attr("r", rad)
       .style("opacity", 1);

    rec.selectAll('.award')
       .filter('.currentYear')
       .classed('currentYear', false)
       .on('mouseover', tip.hide)
       .transition().duration(1000)
       .attr("x", function(d) { return proj([d.custom_fields.longitude - 40, d.custom_fields.latitude])[0] - (rad/2); })
       .attr("y", function(d) { return proj([d.custom_fields.longitude, d.custom_fields.latitude])[1] - (rad/2); })
       .attr("width", rad)
       .attr("height", rad)
       .style("opacity", 0.8);

    rec.selectAll('.award')
       .filter('.' + selected)
       .classed('currentYear', true)
       .transition().duration(1000)
       .attr("x", function(d) { return proj([d.custom_fields.longitude - 40, d.custom_fields.latitude])[0] - (rad); })
       .attr("y", function(d) { return proj([d.custom_fields.longitude, d.custom_fields.latitude])[1] - (rad); })
       .attr("width", rad * 2)
       .attr("height", rad * 2)
       .style("opacity", 1);


    rec.selectAll(".grant, .award")
        .sort(function(a, b) {
          if(a.memberOfClass(".currentYear") &&     !b.memberOfClass(".currentYear")) {
            return -1;
          } else if(b.memberOfClass(".currentYear")) {
            return 1;
          } else {
            return 0;
          }
        });



    rec.selectAll(".currentYear")
       .on('mouseover', tip.show)
       .on('mouseout', tip.hide);
        };

One way is to select their parentNode and re-append them. I've come across a number of solutions with this approach such as this one, but they are always on mouseover and I can't seem to make it work in the function.

Another approach is to sort them. I've come across what seems to be the solution here, but I don't understand where to include my class in the sort – I've tried every combination I can think of. The relevant code for the sort is

    rec.selectAll(".grant, .award")
    .sort(function(a, b) {
      if(a.memberOfClass() && !b.memberOfClass()) {
        return -1;
      } else if(b.memberOfClass()) {
        return 1;
      } else {
        return 0;
      }
    });

How do I apply my class of .currentYear to have it sort correctly?

I feel like I should be able to figure it out from what I've found, but I obviously lack the knowledge right now. Thanks in advance for any help.

Community
  • 1
  • 1
tgerard
  • 293
  • 3
  • 16

1 Answers1

1

In order to bring the selected year's element on the top do it this way:

Instead of your sort code

 rec.selectAll(".grant, .award")
    .sort(function(a, b) {
      if(a.memberOfClass() && !b.memberOfClass()) {
        return -1;
      } else if(b.memberOfClass()) {
        return 1;
      } else {
        return 0;
      }
    });

Add this code which will append the elements on the top.

d3.selectAll("." + selected).each(function()
{
    this.parentNode.parentNode.appendChild(this.parentNode)
});
Cyril Cherian
  • 32,177
  • 7
  • 46
  • 55