问题
I have a factory for creating dc.js charts which uses crossfilters functions bound to $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 });
}
chart factory takes all chart properties through the DOM via angular directive so the tags are like so
<mypie id="mypie" chart-dimesion="mypie.dimension" chart-group="mypie.group"...etc
this approach works fine for filtering, initial data loading, binding and chart rendering, etc....however this is one exception. If I have something like a button click event that fires a new data request, and then I use the above as the callback it takes and processes the data fine, but doesn't update the chart. Even if I include dc.redrawAll() or renderAll(), etc.
I have tried embedding redraw(), redrawAll(), verified the data is coming back correctly, destroying the tag entirely and re-creating and appending to DOM,etc. My assumption is there is an issue with my usage of this factory-style implementation of creating the DC/D3 charts, but I would assume that if I updated the group and/or dimenstion in the scope it should still work? It seems as though the chart objects don't pick up the changes to the dim/groups? I can verify that the cf group values referenced by the $scope.etc have changed by using the following in both the initial call and second call:
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]"));
};
UPDATE: added plnkr, and attempt to better explain= so with the example I have sort of a "traditional" way to build the dc chart versus the service based approach I am trying to achieve using a directive and element. Everything works except what I have attempted to show in the plnkr...when I request new data (ajax) the first updates fine, with the directive based approach nothing seems to work. I have tried numerous ways but essentially updating the $scope dim/group should be working right? I believe it is two way binding therefore these "two scopes" should share a reference?? But even if I use scope.$parent.my.dimension, etc it doesn't affect it.
回答1:
Your chart is still bound to your old crossfilter, dimension, and groups. Generally, when you load new data or replace data, don't throw away your crossfilter, dimension, or groups. Use the crossfilter.remove
and crossfilter.add
methods to add or remove data.
Here's how to modify your example:
Create your Crossfilter, dimensions, and groups up front when you create your controller, then don't create or destroy any more of them in the future:
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; })
Then change your update function to just switch out the data in the Crossfilter:
$scope.factoryBuildPieExample = function(data) {
$scope.my.cf.remove()
$scope.my.cf.add(data.response.data)
dc.redrawAll();
}
If you want to maintain your dc.js filters when you do this, this question/answer explains how: Updating dc.js data and reapplying original filters
Here is a working Plunker: http://plnkr.co/edit/UbfKsuhg9vH678MR6fQT?p=preview
来源:https://stackoverflow.com/questions/43494686/crossfilter-js-with-dc-js-update-charts-on-callback-group-change