Raphadasilva
Raphadasilva

Reputation: 617

D3js : mouseover of one element change opacity of several others elements

Thanks to previous answers, I've made a map and a related graph with D3js.

The bar and the map are in specific divs, and I don't use the same data source. That's a part of my problem.

For the map, I used queue.js to load several files at a time. One of these files is a .csv which follow specifically the same order than the geojson where polygons are stocked. If I sort differently .csv's data, the correspondance with my .geojson's polygons is bad and my choropleth map become false.

Here's the associated code for the interactive polygons of the map :

  svg.append("g").attr("class","zones")
    .selectAll("path")
    .data(bureaux.features)   //"bureaux" is a reference to the geojson
    .enter()
      .append("path")
      .attr("class", "bureau")
      .attr("d", path)
      .attr("fill", function(d,i){
          if (progression[i].diff_ries<-16.1){  //"progression" is the reference to my .csv
        return colors[0] // colors is a previous array with the choropleth's colors
      }
      else if (progression[i].diff_ries<-12.6){
        return colors[1]
      }
       else if (progression[i].diff_ries<-9){
        return colors[2]
      }
      else {return colors[3]
      }
    })
    .on('mouseover', tip.show) // tip.show and tip.hide are specific functions of d3.js.tip
    .on('mouseout', tip.hide)

};

No problem here, the code works fine. We arrived now to the graph. He used a .json array called at the beginning of the script, like this

var array=[{"id_bureau":905,"diff_keller":4.05,"diff_ries":-15.02},{etc}];

"id_bureau" is the common' index of my .geojson, my .csv and this .json's array. Then, I sort the array with a specific function. Here's a part of the code associated to the graph :

svg2.selectAll(".bar")
.data(array)   
.enter().append("rect")
// I colour on part of the bars like the map
.attr("fill", function(d,i){
          if (array[i].diff_ries<-16.1){
        return colors[0]
      }
      else if (array[i].diff_ries<-12.6){
        return colors[1]
      }
       else if (array[i].diff_ries<-9){
        return colors[2]
      }
      else {return colors[3]
      }
    })
.attr("x", function (d) {
return x(Math.min(0, d.diff_ries));
})
.attr("y", function (d) {
return y(d.id_bureau);
})
.attr("width", function (d) {
return Math.abs(x(d.diff_ries) - x(0));
})
.attr("height", y.rangeBand());

// this part is for the other bars
svg2.selectAll(".bar")
.data(tableau)
.enter().append("rect")
// the others bars are always blue, so I used a simple class
.attr("class", "bar_k")
.attr("x", function (d) {
return x(Math.min(0, d.diff_keller));
})
.attr("y", function (d) {
return y(d.id_bureau);
})
.attr("width", function (d) {
return Math.abs(x(d.diff_keller) - x(0));
})
.attr("height", y.rangeBand());

svg2.append("g")
.attr("class", "x axis")
.call(xAxis);

svg2.append("g")
.attr("class", "y axis")
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y2", height2);

So now, what I wan't to do is, when the mouse is over one polygon, to keep the correspondent bar of the graph more visible than the others with an opacity attribution (and when the mouse out, the opacity of all the graph returns to 1).

Maybe it seems obvious, but I don't get how I can correctly link the map and the graph using the "id_bureau" because they don't follow the same order like in this question : Change class of one element when hover over another element d3.

Does somebody know if I can easily transform the mouseover and mouseout events in the map's part to change at the same time my graph?

Upvotes: 4

Views: 5291

Answers (1)

Pirhoo
Pirhoo

Reputation: 680

To highlight a feature on the map

To perform a focus on one feature, you just need a few line of CSS:

/* Turn off every features */
#carte:hover .bureau {
  opacity:0.5;
}

/* Turn on the one you are specifically hovering */
#carte:hover .bureau:hover {
  opacity:1;
}

To highlight a bar in your second chart

First of all, you need to distinguish the two kind of bar with two classes :

// First set of bars: .bar_k
svg2.selectAll(".bar_j")
    .data(tableau)
    .enter().append("rect")
    // Important: I use a common class "bar" for both sets
    .attr("class", "bar bar_j")
    // etc...

// Second set of bars: .bar_k
svg2.selectAll(".bar_k")
    .data(tableau)
    .enter().append("rect")
    .attr("class", "bar bar_k")
    // etc...

Then you have to change your mouseenter/mouseleave functions accordingly:

svg.append("g").attr("class","zones")
      .selectAll("path")
      .data(bureaux.features)
      .enter()
        // creating paths
        // ...
        // ...
        .on('mouseover', function(d, i) {
          // You have to get the active id to highligth the right bar
          var id = progression[i].id_bureau
          // Then you select every bars (with the common class)
          // to update opacities.
          svg2.selectAll(".bar").style("opacity", function(d) {
            return d.id_bureau == id ? 1 : 0.5;
          });
          tip.show(d,i);
        })
        .on('mouseout',  function(d, i) {
          // To restore the initial states, select every bars and 
          // set the opcitiy to 1
          svg2.selectAll(".bar").style("opacity", 1);
          tip.hide(d,i);
        });

Here is a demo.

Performance issue

This implementation is kind of slow. You might improve it by toggling an "active" class to the bars you want to highlight.

An other good tail might be to gather the two kinds of bar in a single group that you describe singularly with an id (ie bureau187 for instance). That way you could select directly the bar you want into the mouseenter function and turn it on with an "active" class.

With this class you could mimic the strategy I implemented to highlight a feature and then remove svg2.selectAll(".bar").style("opacity", 1); from the mouseleave function :

/* Turn off every bars */
#carte:hover .bar {
  opacity:0.5;
}

/* Turn on the one you want to highligth */
#carte:hover .bar.active {
  opacity:1;
}

Upvotes: 4

Related Questions