问题
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?
回答1:
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));
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.
来源:https://stackoverflow.com/questions/59499903/dc-js-disable-brush-resizing