dc.js add multiple filters at once
Asked Answered
E

1

1

Is it possible to add a set of filters at once on a dc chart? For instance, say I have a pieChart, and an array of filter values to apply.

var osChart = dc.pieChart('#oschart');

And an input set of filters, say

var filters = ["linux", "mac osx", "windows", "solaris"]

How can I apply filters so that only one "filtered" event is generated? I can do something like

for (var i=0; i < filters.length; i++) {
  osChart.filter(filters[i]);
}

However that would generate 4 filtered event. I am applying filters based on what a user typed on a text box. When a filter is applied, I am making some ajax calls, and this tends to slow down if I apply filters one by one. I can avoid extra ajax calls if the filters can be set at once.

crossfilter has a function filterFunction which can get this task done, but I am not sure how I can apply that on a dc chart. Apply filterFunction on osChart.dimension() did not work. With the latest dc release, I saw some functions like addFilterHandler and removeFilterHandler however I cannot test and deploy that version right now.

What other options do I have?

Ebeneser answered 8/3, 2015 at 18:51 Comment(0)
D
1

From looking at the code, which is somewhat convoluted, you can pass the array inside another array to .filter() (or the undocumented but unmagical .replaceFilter()) without a performance penalty, because it will apply all of the filters before invoking the filtered event.

From the latest .filter() source, which uses handlers but has the same behavior:

    if (_ instanceof Array && _[0] instanceof Array && !_.isFiltered) {
        _[0].forEach(function (d) {
            if (_chart.hasFilter(d)) {
                _removeFilterHandler(_filters, d);
            } else {
                _addFilterHandler(_filters, d);
            }
        });
    } else if (_ === null) {
        _filters = _resetFilterHandler(_filters);
    } else {
        if (_chart.hasFilter(_)) {
            _removeFilterHandler(_filters, _);
        } else {
            _addFilterHandler(_filters, _);
        }
    }
    applyFilters();
    _chart._invokeFilteredListener(_);

So if it finds an array that does not have an isFiltered method, and that array's first element is also an array, it will iterate over the elements in the nested array.

For example, pass [["linux", "mac osx", "windows", "solaris"]] to filter on those four values. (Thanks @marcin for clarifying!)

Distributor answered 9/3, 2015 at 13:1 Comment(4)
ah, so it needs to be array in array, e.g. .replaceFilter([["linux", "mac osx", "windows", "solaris"]])Strumpet
Really @marcin? That's surprising. Which chart are you working with?Distributor
pieChart. The first line of code in this answer (if (_ instanceof Array && _[0] instanceof Array &&) checks if the first element of array is array.Strumpet
OMG it is even more convoluted than I thought. Thanks @marcin, I have edited my answer.Distributor

© 2022 - 2024 — McMap. All rights reserved.