Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
698 views
in Technique[技术] by (71.8m points)

javascript - crossfilter: how to use crossfilters for start date and end date columns simultaneously

I have a similar situation as in this question . Considering the same dataset, how can I perform this functionality through crossfilters. I am new to dc.js and crossfilter. I am trying to implement the bar and area plot as in this example. Even this example is using 1 date column. I am able to do it with the startdate only. However, my requirement is to filter datasets based on startdate and enddate. I could not found many resources that talk about the same issue.

Any assistance and suggestions will be highly appreciated.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You might expect this to be simple, but actually keeping track of intervals is one of the classic tricky problems of computer science and it requires a specialized data structure called an interval tree to do it properly.

It's a pretty common request, so out of curiosity, I looked for a JavaScript library for interval trees and found one by Mikola Lysenko.

I've incorporated it into a new example here. (source)

The important parts of the example are, first, to use groupAll to populate the interval tree:

      projectsPerMonthTree = ndx.groupAll().reduce(
          function(v, d) {
              v.insert(d.interval);
              return v;
          },
          function(v, d) {
              v.remove(d.interval);
              return v;
          },
          function() {
              return lysenkoIntervalTree(null);
          }
      )

Next we populate a fake group using the start and end dates, counting all the intervals which intersect with each month:

  function intervalTreeGroup(tree, firstDate, lastDate) {
      return {
          all: function() {
              var begin = d3.time.month(firstDate), end = d3.time.month(lastDate);
              var i = new Date(begin);
              var ret = [], count;
              do {
                  next = new Date(i);
                  next.setMonth(next.getMonth()+1);
                  count = 0;
                  tree.queryInterval(i.getTime(), next.getTime(), function() {
                      ++count;
                  });
                  ret.push({key: i, value: count});
                  i = next;
              }
              while(i.getTime() <= end.getTime());
              return ret;
          }
      };
  }

      projectsPerMonthGroup = intervalTreeGroup(projectsPerMonthTree.value(), firstDate, lastDate),

(This could probably be simpler and cheaper if we used lower-level access to the interval tree, or if it had a richer API that allowed walking the intervals in order. But this should be fast enough.)

Finally, we set a filterFunction so that we choose the intervals which intersect with a given date range:

  monthChart.filterHandler(function(dim, filters) {
      if(filters && filters.length) {
          if(filters.length !== 1)
              throw new Error('not expecting more than one range filter');
          var range = filters[0];
          dim.filterFunction(function(i) {
              return !(i[1] < range[0].getTime() || i[0] > range[1].getTime());
          })
      }
      else dim.filterAll();
      return filters;
  });

I've set it up so that it filters the month chart to show all projects which intersect with its own date range. If this is not desired, the groupAll can be put on the intervalDimension instead.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...