1
votes

I have used this solution to get a toggle legend for a composite line chart and it works perfectly fine. However, after i added a range chart to this composite chart, the deselected legend loses its translucence and becomes normal.

How can i keep the deselected legend object in faded state while filtering?

Here are screenshots for reference:

Before filter: Before Filter After filter: After Filter

This is the code I'm using for charts:

multiLineChart
                .width(1000)
                .height(300)
                .transitionDuration(1000)
                .margins({top: 30, right: 50, bottom: 40, left: 40})
                .x(d3.time.scale().domain([startDate,endDate]))
                .yAxisLabel("Data (Scaled)")
                .xAxisLabel("Date And Time")
                .rangeChart(timeSlider)
                .legend(dc.legend().x(800).y(20).itemHeight(13).gap(5))
                .renderHorizontalGridLines(true)
                //.dimension(DateDim)
                .compose([
                    dc.lineChart(multiLineChart)
                        .dimension(DateDim)
                        .colors('red')
                        .group(Line1Grp, 'Line1'),

                    dc.lineChart(multiLineChart)
                        .dimension(DateDim)
                        .colors('blue')
                        .group(Line2Grp, 'Line2')
                    ])
                .brushOn(false)

                .on('pretransition.hideshow', function(chart) {
                      chart.selectAll('g.dc-legend .dc-legend-item')
                        .on('click.hideshow', function(d, i) {
                          var subchart = chart.select('g.sub._' + i);
                          var visible = subchart.style('visibility') !== 'hidden';
                          subchart.style('visibility', function() {
                            return visible ? 'hidden' : 'visible';
                          });
                          d3.select(this).style('opacity', visible ? 0.2 : 1);
                        });
                    });
                //.xAxis().tickFormat(d3.time.format("%b %d %H:%M"));

            timeSlider  
                .width(1000) 
                .height(50)
                .margins({top: 0, right: 50, bottom: 20, left: 40})
                .dimension(DateDim)
                .group(Line1Grp)
                .x(d3.time.scale().domain([startDate, endDate]))
                .on("filtered", function (chart) {
                    dc.events.trigger(function () {
                        multiLineChart.focus(chart.filter());
                        dc.redrawAll(chart.chartGroup());
                    });
                })
                .xAxis().tickFormat(d3.time.format("%b %d"));

Here is a fiddle for the same. Any help is appreciated.

1

1 Answers

1
votes

Thanks for pointing this out - there was a bad practice in my earlier answer, and I went back and corrected it.

It's always better style, and more robust, to separate event handling and drawing, and always draw everything based on the data, not some event that is in flight.

If you follow these practices, then the code looks more like this:

function drawLegendToggles(chart) {
  chart.selectAll('g.dc-legend .dc-legend-item')
    .style('opacity', function(d, i) {
      var subchart = chart.select('g.sub._' + i);
      var visible = subchart.style('visibility') !== 'hidden';
        return visible ? 1 : 0.2;
    });
}

function legendToggle(chart) {
  chart.selectAll('g.dc-legend .dc-legend-item')
    .on('click.hideshow', function(d, i) {
      var subchart = chart.select('g.sub._' + i);
      var visible = subchart.style('visibility') !== 'hidden';
      subchart.style('visibility', function() {
        return visible ? 'hidden' : 'visible';
      });
      drawLegendToggles(chart);
    })
  drawLegendToggles(chart);
}

multiLineChart
  .on('pretransition.hideshow', legendToggle);

Now, whenever we redraw the composite chart and its legend - no matter what the cause - all of the items in the legend will be updated based on whether the corresponding child chart has been hidden.

And the event handler is only concerned with hiding and showing charts, not drawing.

Fork of your fiddle.