dc-js / dc.js

Multi-Dimensional charting built to work natively with crossfilter rendered with d3.js
Apache License 2.0
7.42k stars 1.81k forks source link

Filtering a lineChart with time can overrun extent #659

Open wjaspers opened 10 years ago

wjaspers commented 10 years ago

If I define an extent and disable brushing on the chart I want, but enable mouse zooming, I can force the chart to overrun the x.domain. This results in the X axis generating ticks beyond my d3.extent, and displaying them backwards.

This is against the current "master" tip.

gordonwoodhull commented 9 years ago

Sorry for the slow reply & Thanks for the report. Will look into it.

trent2 commented 9 years ago

I think this can be reproduced with the scatter-series example by mouse-dragging the chart to the right.

I've played around with this quite a while and I think the main problem is due to the combination of "constrainRange" along with mouse-dragging the chart too much to the right/left. Mouse-panning sets a _zoom.translate() vector in d3. The x-value of this vector needs to be restricted to have a correct restraining effect. Otherwise the scale will just go "off-limit".

The constrainRange-function in dc is responsible for displaying the scale backwards because it doesn't correctly take into account the case that the parameters "range" and "constraint" (which are intervals) may not intersect. Then using d3.max..., d3.min in this fashion "inverts" the domain.

Ex.: Assume range = [-10, 20], restraint = [30, 50] The code from constrainRange

constrainedRange[0] = d3.max([range[0], constraint[0]]);
constrainedRange[1] = d3.min([range[1], constraint[1]]);
return constrainedRange;

then returns [30, 20].

I've worked around this in dc, function zoomHandler, by replacing

 function zoomHandler () {
        _refocused = true;
        if (_zoomOutRestrict) {
            _chart.x().domain(constrainRange(_chart.x().domain(), _xOriginalDomain));

with

 function zoomHandler () {
        _refocused = true;
        if (_zoomOutRestrict) {
                var zxr = _zoom.x().range();
                var zsc = _zoom.scale();
                var zxt = _zoom.translate();

                zxt[0] = Math.min(Math.max(zxt[0], -(zxr[1]*zsc - zxr[1] + 1)), 0);
                _zoom.translate([zxt[0],zxt[1]]);
                _zoom.scale(Math.max(1, zsc));

(but leaving the following _rangeChart-if untouched, because I do not know about it). This actually fixes some strange zoom-related behaviour because it restricts the translate vector in a more "natural" manner. Maybe it's worth to have a look.

indrimuska commented 8 years ago

I created #1026 to fix this using a similar solution.