1

I am trying to disable brush extent on a line chart and set a fixed width.

I am aware this subject has been discussed several times. I have tried without success to work on this answer: Disable brush resize (DC.js, D3.js) but I couldn't find a solution matching my situation.

If it makes any difference, I am expanding on the brushable ordinal chart discussed in this question: DC.js - Custom ordering of ordinal scale line chart

Here is the chart initialization code:

    line
        .width(950)
        .height(350)
        .margins({top: 10, right: 50, bottom: 35, left: 30})
        .dimension(graphDim)            
        .keyAccessor(function(kv) { return  graphGroup.ord2int(kv.key); })
        .group(graphGroup)
        .x(d3.scaleLinear().domain(linear_domain))
        .xAxisLabel("Chronologie")
        .yAxisLabel("Effectif")
        .brushOn(true)
        .renderArea(true)
        .renderHorizontalGridLines(true)
        .renderVerticalGridLines(true)
        .elasticY(true)
        .filter(dc.filters.RangedFilter(0,0.9));

    line.yAxis().ticks(4);

    line.xAxis()
        .tickValues(d3.range(data.length))
        .tickFormat(function(d) { return graphGroup.int2ord(d); });

    line.filterHandler(function(dimension, filters) {
        if(!filters || !filters.length) {
            dimension.filter(null);
            return filters;
        }
        console.assert(filters.length === 1);
        console.assert(filters[0].filterType === 'RangedFilter');
        var inside = graphGroup.all().filter(function(kv) {
            var i = graphGroup.ord2int(kv.key);
            return filters[0][0] <= i && i < filters[0][1];
        }).map(function(kv) { return kv.key; });
        dimension.filterFunction(function(d) {
            return inside.indexOf(d) >= 0;
        });
        return filters;
    })

And the fiddle: https://jsfiddle.net/bob_magnus_1/sr7hmnvf/9/`

Is there a simple way to override coordinateGridMixin.extendBrush function in such a chart?

Gordon
  • 19,811
  • 4
  • 36
  • 74
  • What is different about the answer you linked? Or were you just not able to get it to work? – Gordon Dec 27 '19 at 16:05
  • Please add more detail when asking a question, and add a relevant chunk of code so that SO will let you post the fiddle link. I've edited your question. – Gordon Dec 28 '19 at 12:14
  • I must confess I didn't get that part when I tried to post my link. Thanks for the explanation ! – Miguel Rodriguez Dec 29 '19 at 10:39

1 Answers1

2

The previous question was for DCv2. Fixed-width brushes are even easier in DCv3+ (because of improvements to d3-brush in D3v4).

It's the same technique as before: look at how extendBrush is implemented, and then replace it. Here's how it looks in DCv3:

_chart.extendBrush = function (brushSelection) {
    if (brushSelection && _chart.round()) {
        brushSelection[0] = _chart.round()(brushSelection[0]);
        brushSelection[1] = _chart.round()(brushSelection[1]);
    }
    return brushSelection;
};

(source)

It takes a selection – an array of two elements – and returns a new selection.

In your case, your data is ordinal but the scale is linear in order to enable brushing. The brush should match the scale.

To keep it at 0.9 width:

line.extendBrush = function(brushSelection) {
  brushSelection[1] = brushSelection[0] + 0.9;
  return brushSelection;
};

Hiding the brush handles (which have weird behavior) with CSS:

.brush .custom-brush-handle {
  display: none;
} 

Fork of your fiddle.

Ordinal brush with snapping

I realized (looking at your 0.9 width brush) that you probably want proper ordinal brushing where it snaps to the region around the one selected point.

You can do this by setting the begin and end of the selection:

line.extendBrush = function(brushSelection) {
  brushSelection[0] = Math.round(brushSelection[0]) - 0.5;
  brushSelection[1] = brushSelection[0] + 1;
  return brushSelection;
};

We find the the currently hovered point by rounding, and then set the begin to 0.5 before it, and the end to 0.5 after it.

Initialize the filter to surround the zero point:

line
  .filter(dc.filters.RangedFilter(-0.5,0.5));

ordinal snapping brush

Revised fiddle.

Floating point bug fix

I noticed that if you select 20/30 above (linear value 3), brushSelection[0] will have changed from 2.5 to 2.49999999, causing the brush to jump back by one. Some numbers don't represent correctly in floating point.

It's safer to use the average of begin and end:

    line.extendBrush = function(brushSelection) {
      const point = Math.round((brushSelection[0] + brushSelection[1])/2);
      return [
        point - 0.5,
        point + 0.5
      ];
    };

Fiddle version with 20/30 selectable.

Gordon
  • 19,811
  • 4
  • 36
  • 74