Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect filtering when using a Dimension that returns a Date from the accessor #497

Closed
mtraynham opened this issue Jan 8, 2014 · 3 comments
Milestone

Comments

@mtraynham
Copy link
Contributor

There is some weirdness when using a Crossfilter dimension that has an accessor function that returns a Date object. It seems to work fine when using Bar Charts with brushing and range filtering, but not Row or Pie. The chart works fine when the accessor returns Date.getTime() (as this is now numeric), but then the labeling is hard to read.

It looks like too many things are being filtered (i.e. dc's baseMixin _filterHandler could improve the value checking, maybe using filter.valueOf()).

Here is a JSFiddle showing most of the weirdness:
http://jsfiddle.net/SjT8E/1/

In the Fiddle, charts 3 and 5 both use the date dimension accessor. Charts 4 and 6 are their Date.getTime() counterparts, respectively. Notice the differences in the other charts when filtering on 3 vs. 4 and 5 vs. 6.

@mtraynham
Copy link
Contributor Author

So a fix for this, update the filter handler to use a valueOf comparison (like the one used in Crossfilter's quicksort)

From Crossfilter.js:
// Note that for value comparison, <, <=, >= and > coerce to a primitive via
// Object.prototype.valueOf; == and === do not, so in order to be consistent
// with natural order (such as for Date objects), we must do two compares.

An updated Fiddle showing off the fix:
http://jsfiddle.net/S96yD/

The changed baseMixin _filterHandler:

    var _filterHandler = function (dimension, filters) {
        dimension.filter(null);

        if (filters.length === 0)
            dimension.filter(null);
        else
            dimension.filterFunction(function (d) {
                for(var i = 0; i < filters.length; i++) {
                    var filter = filters[i];
                    if (filter.isFiltered && filter.isFiltered(d)) {
                        return true;
                    } else if (filter <= d && filter >= d) {
                        return true;
                    }
                }
                return false;
            });

        return filters;
    };

A diff patch:

Index: dc.js
===================================================================
--- dc.js   (revision 59169)
+++ dc.js   (working copy)
@@ -605,7 +605,7 @@
                     var filter = filters[i];
                     if (filter.isFiltered && filter.isFiltered(d)) {
                         return true;
-                    } else if (filter == d) {
+                    } else if (filter <= d && filter >= d) {
                         return true;
                     }
                 }

@mtraynham
Copy link
Contributor Author

Also to add, and this was out of curiosity from Crossfilter's code, using:

filter <= d && filter >= d

is 98% faster in Firefox and 88% faster in Chrome than using:

filter.valueOf() == d.valueOf()

Based on this jsperf:
http://jsperf.com/compare-valueof-vs

@gordonwoodhull
Copy link
Contributor

Fixed via #555 - thanks @mtraynham!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants