crossfilter.js 和 dc.js 在回调组更改时更新图表

crossfilter.js with dc.js update charts on callback group change

我有一个用于创建 dc.js 图表的工厂,它使用绑定到 $scope 的交叉过滤器函数。 Plnkr Example

$scope.updateMyPie = function(data) {
     var cf = crossfilter(data)
     $scope.mypie.dimension = cf.dimension(function(d) { return d.key })
     $scope.mypie.group = 
     $scope.mypie.dimension.group().reduceSum(function(d){ return d.value });
}

图表工厂通过 DOM 通过 angular 指令获取所有图表属性,因此标签就像这样

<mypie id="mypie" chart-dimesion="mypie.dimension" chart-group="mypie.group"...etc

这种方法适用于过滤、初始数据加载、绑定和图表呈现等……但这是一个例外。如果我有类似触发新数据请求的按钮单击事件,然后我将上面的事件用作回调,它会很好地处理数据,但不会更新图表。即使我包含 dc.redrawAll() 或 renderAll() 等

我已经尝试嵌入 redraw()、redrawAll()、验证数据是否正确返回、完全销毁标签并重新创建并附加到 DOM 等。我的假设是我使用这种创建 DC/D3 图表的工厂式实现存在问题,但我假设如果我更新范围内的组 and/or 维度它应该仍然有效?似乎图表对象没有接受对 dim/groups 的更改?我可以通过在初始调用和第二次调用中使用以下内容来验证 $scope.etc 引用的 cf 组值是否已更改:

var print_filter = function(filter) {
    var f = eval(filter);
    if (typeof (f.top) != "undefined") { 
        f = f.top(Infinity);
    }
    if (typeof (f.dimension) != "undefined") { 
        f = f.dimension(function (d) { 
            return ""; 
        }).top(Infinity);
    }

    console.log(filter + "(" + f.length + ") = " + JSON.stringify(f).replace("[", "[\n\t").replace(/}\,/g, "},\n\t").replace("]", "\n]"));
};

更新:添加了 plnkr,并尝试更好地解释=所以在这个例子中,我有一种 "traditional" 构建直流图的方法与我试图使用指令实现的基于服务的方法相比元素。一切正常,除了我试图在 plnkr 中显示的内容...当我请求新数据 (ajax) 时,第一次更新很好,使用基于指令的方法似乎没有任何效果。我尝试了多种方法,但基本上更新 $scope dim/group 应该可以正常工作吗?我相信这是双向绑定,因此这些 "two scopes" 应该共享一个参考?但即使我使用 scope.$parent.my.dimension 等也不会影响它。

您的图表仍然绑定到您的旧交叉过滤器、维度和组。通常,当您加载新数据或替换数据时,不要丢弃您的交叉过滤器、维度或组。使用 crossfilter.removecrossfilter.add 方法添加或删除数据。

修改示例的方法如下:

在创建控制器时先创建交叉过滤器、维度和组,以后不再创建或销毁它们:

myapp.controller('mycontroller', ['$scope', 'dataCaller', function($scope, dataCaller){
      $scope.pageTitle = "Updating DC.js and Crossfilter";

      $scope.currentData1 = "data1.json";
      $scope.currentData2 = "data1.json";

      $scope.my = {};
      $scope.my.cf = crossfilter();
      $scope.my.dimension = $scope.my.cf.dimension(function(d){ return d.key; })
      $scope.my.group = $scope.my.dimension.group().reduceSum(function(d){ return d.value; })

然后更改您的更新函数以仅切换出 Crossfilter 中的数据:

 $scope.factoryBuildPieExample = function(data) {
    $scope.my.cf.remove()
    $scope.my.cf.add(data.response.data)
    dc.redrawAll();
  }

如果您想在执行此操作时维护 dc.js 过滤器,此 question/answer 解释了如何:

这是一个有效的 Plunker:http://plnkr.co/edit/UbfKsuhg9vH678MR6fQT?p=preview