1
votes

I'm trying to recreate the single select bar on a dc.js composite chart as shown here

https://dc-js.github.io/dc.js/examples/bar-single-select.html

I've tried adding a filter handler to the child chart but it never gets called when I click on the bar. I've also tried adding a filter handler to the Composite chart itself with no luck. Is there any way I can select a bar on a composite chart or do I have to assign it a colour and then color the other bars grey manually and redraw the graph based on what was clicked?

This is the initialization of the graph in my component.

The data goes through a formatting process where I parse the date using the formatData function. I also pass in a dimensions prop (apologies for the bad naming) which tells the component what kind of chart should correspond to the chart name and the color of the dataset.

dimensions={
    {"Data1": ["line", AppStyles.color.warning], 
     "Data2": ["line", AppStyles.color.danger], 
     "Data3": ["bar", AppStyles.color.blue]
    }
}

formatData = (data) => {
    let formattedData = [];
    for(let key in data) {
        formattedData.push({
            ...data[key],
            x: this.parseDate.parse(data[key].x)
        })
    }
    return formattedData;
}

componentDidMount(){
    let data = this.formatData(this.props.data);
    this.ndx = crossfilter.crossfilter(data);
    this.chart = dc.compositeChart(this.multiLineChartContainer);
    this.dimension = this.ndx.dimension((d) => {
        return d.x;
    });
    let minDate = this.dimension.bottom(1)[0].x;
    let maxDate = this.dimension.top(1)[0].x;

    let composeGroup = [];
    Object.keys(this.props.dimensions).map((dim,i) => {
        let grp = this.dimension.group().reduceSum((d) => {
            return d[dim];
        });
        if(this.props.dimensions[dim][0] === "bar"){
            composeGroup.push(dc.barChart(this.multiLineChartContainer)
            .group(grp, dim)
            .colors("blue")
            .centerBar(true)
            .addFilterHandler(function(filters, filter) {return [filter];})
            )
        } else {
            composeGroup.push(dc.lineChart(this.multiLineChartContainer)
            .group(grp, dim)
            .colors(this.props.dimensions[dim][1])
            .useRightYAxis(true)

        );
        }
    });

    this.chart.width(this.props.width)
    .height(this.props.height)
    .renderHorizontalGridLines(true)
    .x(d3.time.scale().domain([minDate, maxDate]))
    .elasticY(true)
    .elasticX(true)
    .xAxisLabel("Cohort")
    .brushOn(false)
    .yAxisLabel("Left")
    .rightYAxisLabel("Right")
    .xUnits(()=>{
        return 30;
    })
    .legend(dc.legend().x(this.chart.width()- 130))
    .compose(composeGroup)

    this.chart.renderlet((chart) => {
        chart.selectAll('circle, rect.bar').on("click", (event) => {
            this.props.dataSelect(event);
          });
    });
    this.chart.xAxis().ticks(5)
    this.chart.render();
}
1

1 Answers

2
votes

Please consider adding your code (or better, a running example) next time you ask a question on SO.

It would also help to spell out what "no luck" means - wrong click behavior? No chart displayed at all?

It's hard to guess what might be going wrong for you.

This works fine for me, although ordinal scales are a little bit tricky, and composing them in a composite chart even more so.

Is the problem that you were not using an ordinal scale? Because currently the kind of selection (brush or click) is determined by the scale/xUnits and it's hard to get around it.

composite
    .width(768)
    .height(480)
    .x(d3.scaleOrdinal().domain(d3.range(1,21)))
    .xUnits(dc.units.ordinal)
    .yAxisLabel("The Y Axis")
    .legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
    .brushOn(true)
    .renderHorizontalGridLines(true)
    .compose([
        dc.barChart(composite)
            .dimension(dim)
            .colors('blue')
            .group(grp2, "Bars")
            .addFilterHandler(function(filters, filter) {return [filter];})
            .centerBar(true),
        dc.lineChart(composite)
            .dimension(dim)
            .colors('red')
            .group(grp1, "Dots")
            .dashStyle([2,2])
        ])
    .render();

https://jsfiddle.net/gordonwoodhull/ronqfyj0/39/