2016-10-28 7 views
3

NEW: Сценарий, который я опубликовал в своих решениях (https://jsfiddle.net/jnf84n7c/). Однако, когда я пытаюсь реализовать тактику в своем проекте, у меня возникают проблемы. Когда я нажимаю на график, который не является первым графиком, я получаю сообщение об ошибке.d3/dc.js - Как создать сложную гистограмму при передаче crossfilter для обработки элементов в массиве в виде отдельных записей?

Uncaught TypeError: a.group.all is not a function (error located in dc.min.js)

Любая идея, почему это работает на скрипке, но не применимо в моем приложении ruby-on-rails?

Новый код

var data = [ 
    {"key":"KEY-1","state":"MA","status":["A","R","C"],"items":["orange","meat","bread"],"date":"Y16"}, 
    {"key":"KEY-2","state":"MA","status":["A","O"],"items":["apple","bread"],"date":"Y15"}, 
    {"key":"KEY-3","state":"TX","status":["O"],"items":["bread"],"date":"Y16"}, 
    {"key":"KEY-4","state":"TN","status":["A","R"],"items":["apple","bread"],"date":"Y16"}, 
    {"key":"KEY-5","state":"TN","status":["A","O"],"items":["apple","orange"],"date":"Y15"}, 
    {"key":"KEY-6","state":"TN","status":[],"items":[],"date":"Y14"} 
]; 
var cf = crossfilter(data); 
var dates  = cf.dimension(function(d){ return d.date; }); 
var datesGroup = dates.group(); 
var states  = cf.dimension(function(d){ return d.state; }); 
var statesGroup = states.group(); 
var itemsDim = cf.dimension(function(d){ return d.items; }); 
var itemsGroup = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value(); 
itemsGroup.all = myAllFunction; 
var states_items_group_apple = states.group().reduce(reduceAdd_apple, reduceRemove_apple, reduceInitial_items); 
var states_items_group_bread = states.group().reduce(reduceAdd_bread, reduceRemove_bread, reduceInitial_items); 
var states_items_group_orange = states.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items); 
var states_items_group_meat = states.group().reduce(reduceAdd_meat, reduceRemove_meat, reduceInitial_items); 
var itemsGroup1 = itemsDim.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value(); 
var itemsGroup2 = itemsDim.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value(); 
var itemsGroup3 = itemsDim.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value(); 
itemsGroup1.all = myAllFunction; 
itemsGroup2.all = myAllFunction; 
itemsGroup3.all = myAllFunction; 
var status  = cf.dimension(function(d){ return d.status; }); 
var statusGroup1 = status.groupAll().reduce(reduceAdd_group1, reduceRemove_group1, reduceInitial_group).value(); 
var statusGroup2 = status.groupAll().reduce(reduceAdd_group2, reduceRemove_group2, reduceInitial_group).value(); 
var statusGroup3 = status.groupAll().reduce(reduceAdd_group3, reduceRemove_group3, reduceInitial_group).value(); 
var statusGroup4 = status.groupAll().reduce(reduceAdd_group4, reduceRemove_group4, reduceInitial_group).value(); 
statusGroup1.all = myAllFunction; 
statusGroup2.all = myAllFunction; 
statusGroup3.all = myAllFunction; 
statusGroup4.all = myAllFunction; 
var statusGroup = status.groupAll().reduce(reduceAdd_group, reduceRemove_group, reduceInitial_group).value(); 
statusGroup.all = myAllFunction; 
var row = dc.rowChart("#rowchart"); 
row.height(170) 
    .dimension(itemsDim) 
    .group(itemsGroup) 
    .ordering(function(d){return -d.value;}) 
    .renderLabel(true) 
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"]) 
    .xAxis().ticks(3); 
row.filterHandler(myFilterFunction); 
var pie1 = dc.pieChart("#piechart1"); 
pie1.height(75).width(75) 
    .dimension(dates) 
    .group(datesGroup); 
var pie2 = dc.pieChart("#piechart2"); 
pie2.height(75).width(75) 
    .dimension(states) 
    .group(statesGroup); 
var pie3 = dc.pieChart("#piechart3"); 
pie3.height(75).width(75) 
    .dimension(status) 
    .group(statusGroup); 
pie3.filterHandler(myFilterFunction); 
var bar = dc.barChart("#barchart"); 
bar.width(500).height(200) 
    .dimension(states) 
    .group(states_items_group_bread, 'bread') 
    .stack(states_items_group_orange, 'orange') 
    .stack(states_items_group_apple, 'apple') 
    .stack(states_items_group_meat, 'meat') 
    .valueAccessor(function(p){ return p.value.count; }) 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100)) 
    .gap(10) 
    .elasticX(true).elasticY(true) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .margins({top:30,left:50,right:10,bottom:50});  
var bar2 = dc.barChart("#barchart2"); 
bar2.width(500).height(200) 
    .dimension(itemsDim) 
    .group(itemsGroup1,'MA') 
    .stack(itemsGroup2,'TN') 
    .stack(itemsGroup3,'TX') 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60)) 
    .gap(10) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"]) 
    .margins({top:30,left:50,right:10,bottom:50}); 
bar2.filterHandler(myFilterFunction); 
var bar3 = dc.barChart("#barchart3"); 
bar3.width(500).height(200) 
    .dimension(status) 
    .group(statusGroup1,"bread") 
    .stack(statusGroup2,"apple") 
    .stack(statusGroup3,"orange") 
    .stack(statusGroup4,"meat") 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60)) 
    .gap(10) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .margins({top:30,left:50,right:10,bottom:50}); 
bar3.filterHandler(myFilterFunction); 
dc.renderAll(); 
function reduceAdd(p,v){ 
    if (v.items[0] === "") return p; 
    v.items.forEach(function(val,idx){ 
     p[val] = (p[val] || 0) + 1; 
    }); 
    return p; 
} 
function reduceRemove(p,v){ 
    if (v.items[0] === "") return p; 
    v.items.forEach(function(val,idx){ 
     p[val] = (p[val] || 0) - 1; 
    }); 
    return p; 
} 
function reduceInitial(){ 
    return { 
     bread: 0, 
     apple: 0, 
     orange: 0, 
     meat: 0 
    }; 
} 
function reduceAdd1(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "MA"){ 
     v.items.forEach(function(val,idx){ 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceRemove1(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "MA"){ 
     v.items.forEach(function(val,idx){ 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceAdd2(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TN"){ 
     v.items.forEach(function(val,idx){ 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceRemove2(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TN"){ 
     v.items.forEach(function(val,idx){ 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceAdd3(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TX"){ 
     v.items.forEach(function(val,idx){ 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceRemove3(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TX"){ 
     v.items.forEach(function(val,idx){ 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceAdd_apple(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'apple' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_apple(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'apple' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_bread(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'bread' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_bread(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'bread' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_orange(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'orange' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_orange(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'orange' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_meat(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'meat' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_meat(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'meat' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_group1(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if (val1 === "bread"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceRemove_group1(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if(val1 === "bread"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceAdd_group2(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if(val1 === "apple"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceRemove_group2(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if(val1 === "apple"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceAdd_group3(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if(val1 === "orange"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceRemove_group3(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if(val1 === "orange"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceAdd_group4(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if(val1 === "meat"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceRemove_group4(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.status[0] === "") return p; 
    v.items.forEach(function(val1,idx1){ 
     if(val1 === "meat"){ 
      v.status.forEach(function(val2,idx2){ 
       if(idx1 === idx2){ 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      }); 
     } 
    }); 
    return p; 
} 
function reduceAdd_group(p,v){ 
    if (v.status[0] === "") return p; 
    v.status.forEach(function(val,idx){ 
     p[val] = (p[val] || 0) + 1; 
    }); 
    return p; 
} 
function reduceRemove_group(p,v){ 
    if (v.status[0] === "") return p; 
    v.status.forEach(function(val,idx){ 
     p[val] = (p[val] || 0) - 1; 
    }); 
    return p; 
} 
function reduceInitial_group(){ 
    return { 
     A: 0, 
     O: 0, 
     C: 0, 
     R: 0 
    }; 
} 
function reduceInitial_items(){ 
    return { 
     count: 0, 
     state: '' 
    }; 
} 
//filter function: 
function myFilterFunction(dimension,filters){ 
    dimension.filter(null); 
    if (filters.length === 0) 
     dimension.filter(null); 
    else 
     dimension.filterFunction(function(d){ 
      for(var i=0; i<d.length; i++){ 
       if (filters.indexOf(d[i]) >= 0) return true; 
      } 
      return false; 
     }); 
    return filters; 
} 
function myAllFunction(){ 
    var newObject = []; 
    for(var key in this){ 
     if(this.hasOwnProperty(key) && key != "all"){ 
      newObject.push({ 
       key: key, 
       value: this[key] 
      }); 
     } 
    } 
    return newObject; 
}; 

Старый Вопрос: Я сожалею, чтобы создать еще один вопрос. К сожалению, я не могу комментировать другие сообщения, чтобы задать свой вопрос. Два вопроса, которые похожи на мои, являются: dc.js - how to group by unique id и Is there a way to tell crossfilter to treat elements of array as separate records instead of treating whole array as single key?

Я использую код, как описано в последней. Тем не менее, я хочу, чтобы иметь возможность складывать. Поскольку вы сможете увидеть в jsfiddle, нижняя гистограмма не перечисляет элементы по оси x, укладывая разные значения состояния. Любая помощь будет принята с благодарностью. Спасибо!

Вот оригинальная скрипку: https://jsfiddle.net/7qwqcakr/1/

Я почти иметь его с этой скрипкой: https://jsfiddle.net/wq0ed5hr/ Но уложенные гистограмм все один цвет, даже если легенда имеет их как разные цвета. Как исправить проблему цвета?

Исправлена ​​проблема цвета: https://jsfiddle.net/rmc2zpr4/

Теперь единственная проблема имеет дело с «счетным вопросом», как поясняется в моем решении и комментариях ниже.

Вот обновленный код:

var data = [ 
    {"key":"KEY-1","state":"MA","items":["orange","meat","bread"],"date":"Y16"}, 
    {"key":"KEY-2","state":"MA","items":["apple","bread"],"date":"Y15"}, 
    {"key":"KEY-3","state":"TX","items":["bread"],"date":"Y16"}, 
    {"key":"KEY-4","state":"TN","items":["apple","bread"],"date":"Y16"}, 
    {"key":"KEY-5","state":"TN","items":["apple","orange"],"date":"Y15"}, 
    {"key":"KEY-6","state":"TN","items":[],"date":"Y14"} 
]; 
var cf = crossfilter(data); 
var dates  = cf.dimension(function(d){ return d.date; }); 
var datesGroup = dates.group().reduceCount(function(d){ return d.key; }); 
var states  = cf.dimension(function(d){ return d.state; }); 
var statesGroup = states.group().reduceCount(function(d){ return d.key; }); 
var itemsDim = cf.dimension(function(d){ return d.items; }); 
var itemsGroup = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value(); 
itemsGroup.all = myAllFunction; 
var statesDim = cf.dimension(function(d){ return d.state; }); 
var states_items_group_apple = statesDim.group().reduce(reduceAdd_apple, reduceRemove_apple, reduceInitial_items); 
var states_items_group_bread = statesDim.group().reduce(reduceAdd_bread, reduceRemove_bread, reduceInitial_items); 
var states_items_group_orange = statesDim.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items); 
var states_items_group_meat = statesDim.group().reduce(reduceAdd_meat, reduceRemove_meat, reduceInitial_items); 
var items  = cf.dimension(function(d){ return d.items; }) 
var itemsGroup1 = items.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value(); 
var itemsGroup2 = items.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value(); 
var itemsGroup3 = items.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value(); 
itemsGroup1.all = myAllFunction; 
itemsGroup2.all = myAllFunction; 
itemsGroup3.all = myAllFunction; 
var row = dc.rowChart("#rowchart"); 
row.height(170) 
    .dimension(itemsDim) 
    .group(itemsGroup) 
    .ordering(function(d){return -d.value;}) 
    .renderLabel(true) 
     .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"]) 
    .xAxis().ticks(3); 
row.filterHandler(myFilterFunction); 
var pie1 = dc.pieChart("#piechart1"); 
pie1.height(75).width(75) 
    .dimension(dates) 
    .group(datesGroup); 
var pie2 = dc.pieChart("#piechart2"); 
pie2.height(75).width(75) 
    .dimension(states) 
    .group(statesGroup); 
var bar = dc.barChart("#barchart"); 
bar.width(500).height(200) 
    .dimension(statesDim) 
    .group(states_items_group_bread, 'bread') 
    .stack(states_items_group_orange, 'orange') 
    .stack(states_items_group_apple, 'apple') 
    .stack(states_items_group_meat, 'meat') 
    .valueAccessor(function(p){ return p.value.count; }) 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100)) 
    .gap(10) 
    .elasticX(true).elasticY(true) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .margins({top:30,left:50,right:10,bottom:50}); 
var bar2 = dc.barChart("#barchart2"); 
bar2.width(500).height(200) 
    .dimension(items) 
    .group(itemsGroup1,'MA') 
    .stack(itemsGroup2,'TN') 
    .stack(itemsGroup3,'TX') 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60)) 
    .gap(10) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"]) 
    .margins({top:30,left:50,right:10,bottom:50}); 
bar2.filterHandler(myFilterFunction); 
dc.renderAll(); 
//reduce functions: 
function reduceAdd(p,v){ 
    if (v.items[0] === "") return p; 
    v.items.forEach(function(val,idx){ 
     p[val] = (p[val] || 0) + 1; 
    }); 
    return p; 
} 
function reduceRemove(p,v){ 
    if (v.items[0] === "") return p; 
    v.items.forEach(function(val,idx){ 
     p[val] = (p[val] || 0) - 1; 
    }); 
    return p; 
} 
function reduceInitial(){ 
    return { 
     bread: 0, 
     apple: 0, 
     orange: 0, 
     meat: 0 
    }; 
} 
function reduceAdd1(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "MA"){ 
     v.items.forEach(function(val,idx){ 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceRemove1(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "MA"){ 
     v.items.forEach(function(val, idx){ 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceAdd2(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TN"){ 
     v.items.forEach(function(val,idx){ 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceRemove2(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TN"){ 
     v.items.forEach(function(val,idx){ 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceAdd3(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TX"){ 
     v.items.forEach(function(val,idx){ 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceRemove3(p,v){ 
    if (v.items[0] === "") return p; 
    if (v.state === "TX"){ 
     v.items.forEach(function(val,idx){ 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     }); 
    } 
    return p; 
} 
function reduceAdd_apple(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'apple' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_apple(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'apple' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_bread(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'bread' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_bread(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'bread' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_orange(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'orange' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_orange(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'orange' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_meat(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count += (val === 'meat' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_meat(p,v){ 
    if (v.items[0] === "") return p; 
    p.state = v.state; 
    v.items.forEach(function(val,idx){ 
     p.count -= (val === 'meat' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceInitial_items(){ 
    return { 
     count: 0, 
     state: '' 
    }; 
} 
function myFilterFunction(dimension,filters){ 
    dimension.filter(null); 
    if(filters.length === 0) 
     dimension.filter(null); 
    else 
     dimension.filterFunction(function(d){ 
      for(var i=0; i<d.length; i++){ 
       if(filters.indexOf(d[i]) >= 0) return true; 
      } 
      return false; 
     }); 
    return filters; 
} 
function myAllFunction(){ 
    var newObject = []; 
    for(var key in this){ 
     if(this.hasOwnProperty(key) && key != "all"){ 
      newObject.push({ 
       key: key, 
       value: this[key] 
      }); 
     } 
    } 
    return newObject; 
}; 
+0

Я создал новую скрипку, используя библиотеки, которые я использовал, и проблема цвета была исправлена. Вот скрипка: https://jsfiddle.net/rmc2zpr4/ Я бы предпочел, чтобы проблема с графом была исправлена, но я в основном просто рад, что часть сложенной работы работает. – Casey

ответ

1

Первое, что вам нужно сделать, это обновить:

  • dc.js 2.0 беты
  • Crossfilter 1.4.0-бета. 06 (Crossfilter теперь живет здесь: https://github.com/crossfilter/crossfilter)
  • Reductio (рекомендуется), так что вам не нужно вручную создавать пользовательскую группу gs - это не обязательно, но группировки являются источником множества проблем, поэтому я бы рекомендовал использовать Reductio или Universe, чтобы использовать работу тех, кто пришел раньше.

Далее, со всей этой новой добротой, мы можем упростить вещи в тонну. Вот обновленная скрипка, в которой используются новые функции этих библиотек: https://jsfiddle.net/ff8ox8vq/

Я подробно рассмотрю их в полном примере кода ниже.

var data = [ 
    {"key":"KEY-1","state":"MA", "items":["orange", "meat", "bread"], "date":"Y16"}, 
    {"key":"KEY-2","state":"MA", "items":["apple", "bread"], "date":"Y15"}, 
    {"key":"KEY-3","state":"TX", "items":["bread"], "date":"Y16"}, 
    {"key":"KEY-4","state":"TN", "items":["apple", "bread"], "date":"Y16"}, 
    {"key":"KEY-5","state":"TN", "items":["apple", "orange"], "date":"Y15"}, 
    {"key":"KEY-6","state":"TN", "items": [], "date":"Y14"} 
]; 

var cf = crossfilter(data); 

Без изменений выше.

//dimensions and groups: 
var dates  = cf.dimension(function(d){ return d.date; }); 
var datesGroup = dates.group(); 
var states  = cf.dimension(function(d){ return d.state; }); 
var statesGroup = states.group() 

.reduceCount - значение по умолчанию для группы. Вызов его в новой группе ничего не значит. reduceCount также не принимает никаких параметров (в отличие от reduceSum). Поэтому мы просто избавляемся от этого.

var itemsDim = cf.dimension(function(d){ return d.items; }, true); 
var itemsGroup = itemsDim.group(); 

Здесь начинается интерес. Crossfilter 1.4.0 поддерживает флаг «Размер массива» при вызове измерения. Если мы установим это на true, Crossfilter знает, что items является массивом и будет умным о том, как он его обрабатывает. Вам больше не нужно переопределять метод .all или что-то в этом роде. Он обрабатывается внутри страны.

var addValueGroup = function(reducer, key) { 
    reducer 
    .value(key) 
    .filter(function(d) { return d.items.indexOf(key) !== -1; }) 
    .count(true) 
} 

Полезная функция для добавления элементов к конкретным группам.

// Reductio nest to break down states by item 
var reducer = reductio().count(true) 
addValueGroup(reducer, "orange") 
addValueGroup(reducer, "meat") 
addValueGroup(reducer, "bread") 
addValueGroup(reducer, "apple") 

reducer(statesGroup); 

Настройте группировку statesGroup. Reductio только строит пользовательские функции сокращения. Что происходит здесь, так это то, что мы поддерживаем подсчет верхнего уровня всех записей в состоянии, затем мы создаем фильтрованные подсчеты для каждого типа элемента. Сделайте console.log(statesGroup.all()) после этого, чтобы увидеть структуру результирующей группы.

//graphs: 
var row = dc.rowChart("#rowchart"); 
row 
    .renderLabel(true) 
    .height(200) 
    .dimension(itemsDim) 
    .group(itemsGroup) 
    .ordering(function(d){return -d.value;}) 
    .xAxis().ticks(3); 

var pie1 = dc.pieChart("#piechart1"); 
pie1 
    .height(75) 
    .width(75) 
    .dimension(dates) 
    .group(datesGroup); 

Без изменений.

var pie2 = dc.pieChart("#piechart2"); 
pie2 
    .height(75) 
    .width(75) 
    .dimension(states) 
    .group(statesGroup) 
    .valueAccessor(function(d) { return d.value.count; }); 

Наш Reductio редуктор изменяет структуру группы несколько, поэтому нам нужно valueAccessor.

var bar = dc.barChart("#barchart"); 
bar.width(500).height(200) 
    .dimension(states) 
    .group(statesGroup, 'orange', sel_stack('orange')) 
    .stack(statesGroup, 'meat', sel_stack('meat')) 
    .stack(statesGroup, 'bread', sel_stack('bread')) 
    .stack(statesGroup, 'apple', sel_stack('apple')) 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend()) 
    .gap(10) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal); 

Просто работает без каких-либо особых функций фильтра или чего-либо еще. dc.js и Crossfilter знают, что делать. К сожалению, похоже, что в dc.js есть ошибка в dc.js с ординальными стеклянными гистограммами, поэтому вам нужно будет правильно покрасить столбцы после рендеринга в данный момент :-(Может быть, Гордон включит здесь намек.

dc.renderAll(); 

function sel_stack(i) { 
    return function(d) { 
     return d.value[i] ? d.value[i].count : 0; 
    }; 
} 

Незначительного изменения в связи с обновленной структурой группы, и немного безопасности в случае, если вы неправильно тип один из ключей элементов.

+0

Практически там. Я проверил твою скрипку. Когда я выбираю «хлеб» в таблице строк, гистограмма должна обновляться, чтобы содержать только «хлеб». Это не. Как мы обновляем код, чтобы внести это изменение? – Casey

+0

Чтобы пояснить, что я имею в виду ... Оба наших примера, похоже, показывают общее количество элементов для записей, содержащих выбранный элемент. Например, при выборе «яблоко», «MA» показывает количество 2 - 1 яблока, 1 хлеб (вы можете выделить легенду, чтобы определить их) - и «TN» показывает количество 4 - 1 оранжевого, 1 хлеб, 2 яблока. Как это можно зафиксировать, например, только для подсчета «яблока»? – Casey

+1

В dc.js, когда вы нажимаете на строку, это означает «ограничивать записи, отображаемые в этой строке». В этом случае он ограничивает записи, содержащие «хлеб», но поскольку каждая запись содержит несколько элементов, некоторые из этих записей также содержат яблоки.Показывать только хлеб на самом деле не было бы правильно, не так ли? –

0

Я установил окрашенную проблему стеки и подсчет вопрос к тому, как я хотел бы, чтобы я использую D3.js verison 2.5.5, crossfilter.js версии 1.3.11 и dc.js и dc.css версии 2.1.0 dev. https://jsfiddle.net/jnf84n7c/

var data = [ 
    {"key":"KEY-1","state":"MA", "status":["A","R","C"], "items":["orange", "meat", "bread"], "date":"Y16"}, 
    {"key":"KEY-2","state":"MA", "status":["A","O"], "items":["apple", "bread"], "date":"Y15"}, 
    {"key":"KEY-3","state":"TX", "status":["O"], "items":["bread"], "date":"Y16"}, 
    {"key":"KEY-4","state":"TN", "status":["A","R"], "items":["apple", "bread"], "date":"Y16"}, 
    {"key":"KEY-5","state":"TN", "status":["A","O"], "items":["apple", "orange"], "date":"Y15"}, 
    {"key":"KEY-6","state":"TN", "status":[], "items": [], "date":"Y14"} 
]; 

var cf = crossfilter(data); 

//dimensions and groups: 
var dates  = cf.dimension(function(d){ return d.date; }); 
var datesGroup = dates.group();//.reduceCount(function(d){ return d.key; }); 
var states  = cf.dimension(function(d){ return d.state; }); 
var statesGroup = states.group();//.reduceCount(function(d){ return d.key; }); 
var itemsDim = cf.dimension(function(d){ return d.items; }); 
var itemsGroup = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value(); 
itemsGroup.all = myAllFunction; 
var states_items_group_apple = states.group().reduce(reduceAdd_apple, reduceRemove_apple, reduceInitial_items); 
var states_items_group_bread = states.group().reduce(reduceAdd_bread, reduceRemove_bread, reduceInitial_items); 
var states_items_group_orange = states.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items); 
var states_items_group_meat = states.group().reduce(reduceAdd_meat, reduceRemove_meat, reduceInitial_items); 
var itemsGroup1 = itemsDim.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value(); 
var itemsGroup2 = itemsDim.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value(); 
var itemsGroup3 = itemsDim.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value(); 
itemsGroup1.all = myAllFunction; 
itemsGroup2.all = myAllFunction; 
itemsGroup3.all = myAllFunction; 
var status  = cf.dimension(function(d){ return d.status; }); 
var statusGroup1 = status.groupAll().reduce(reduceAdd_group1, reduceRemove_group1, reduceInitial_group).value(); 
var statusGroup2 = status.groupAll().reduce(reduceAdd_group2, reduceRemove_group2, reduceInitial_group).value(); 
var statusGroup3 = status.groupAll().reduce(reduceAdd_group3, reduceRemove_group3, reduceInitial_group).value(); 
var statusGroup4 = status.groupAll().reduce(reduceAdd_group4, reduceRemove_group4, reduceInitial_group).value(); 
statusGroup1.all = myAllFunction; 
statusGroup2.all = myAllFunction; 
statusGroup3.all = myAllFunction; 
statusGroup4.all = myAllFunction; 
var statusGroup = status.groupAll().reduce(reduceAdd_group, reduceRemove_group, reduceInitial_group).value(); 
statusGroup.all = myAllFunction; 

//graphs: 
var row = dc.rowChart("#rowchart"); 
row.height(170) 
    .dimension(itemsDim) 
    .group(itemsGroup) 
    .ordering(function(d){return -d.value;}) 
    .renderLabel(true) 
     .ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"]) 
    .xAxis().ticks(3); 
row.filterHandler(myFilterFunction); 

var pie1 = dc.pieChart("#piechart1"); 
pie1.height(75).width(75) 
    .dimension(dates) 
    .group(datesGroup); 

var pie2 = dc.pieChart("#piechart2"); 
pie2.height(75).width(75) 
    .dimension(states) 
    .group(statesGroup); 

var pie3 = dc.pieChart("#piechart3"); 
pie3.height(75).width(75) 
    .dimension(status) 
    .group(statusGroup); 
pie3.filterHandler(myFilterFunction); 

var bar = dc.barChart("#barchart"); 
bar.width(500).height(200) 
    .dimension(states) 
    .group(states_items_group_bread, 'bread') 
    .stack(states_items_group_orange, 'orange') 
    .stack(states_items_group_apple, 'apple') 
    .stack(states_items_group_meat, 'meat') 
    .valueAccessor(function(p){ return p.value.count; }) 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100)) 
    .gap(10) 
    .elasticX(true).elasticY(true) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .margins({top:30, left:50, right:10, bottom:50}); 
//bar.filterHandler(myFilterFunction); 
//bar.on("renderlet", function(_chart){ 
// _chart.selectAll("rect.bar").on("click", _chart.onClick); 
//}); 

var bar2 = dc.barChart("#barchart2"); 
bar2.width(500).height(200) 
    .dimension(itemsDim) 
    .group(itemsGroup1, 'MA') 
    .stack(itemsGroup2, 'TN') 
    .stack(itemsGroup3, 'TX') 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60)) 
    .gap(10) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
    .ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"]) 
    .margins({top:30, left:50, right:10, bottom:50}); 
bar2.filterHandler(myFilterFunction); 

var bar3 = dc.barChart("#barchart3"); 
bar3.width(500).height(200) 
    .dimension(status) 
    .group(statusGroup1, "bread") 
    .stack(statusGroup2, "apple") 
    .stack(statusGroup3, "orange") 
    .stack(statusGroup4, "meat") 
    .renderHorizontalGridLines(true) 
    .renderLabel(true) 
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60)) 
    .gap(10) 
    .yAxisLabel("count") 
    .x(d3.scale.ordinal()) 
    .xUnits(dc.units.ordinal) 
// .ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"]) 
    .margins({top:30, left:50, right:10, bottom:50}); 
bar3.filterHandler(myFilterFunction); 

dc.renderAll(); // render graphs 

//reduce functions: 
function reduceAdd(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    v.items.forEach (function(val, idx) { 
     p[val] = (p[val] || 0) + 1; //increment counts 
    }); 
    return p; 
} 
function reduceRemove(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    v.items.forEach (function(val, idx) { 
     p[val] = (p[val] || 0) - 1; //decrement counts 
    }); 
    return p; 
} 
function reduceInitial() { 
    return { 
     bread: 0, 
     apple: 0, 
     orange: 0, 
     meat: 0 
    }; 
} 
function reduceAdd1(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.state === "MA"){ 
     v.items.forEach (function(val, idx) { 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     });  
    } 
    return p; 
} 
function reduceRemove1(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.state === "MA"){ 
     v.items.forEach (function(val, idx) { 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     });  
    } 
    return p; 
} 
function reduceAdd2(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.state === "TN"){ 
     v.items.forEach (function(val, idx) { 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     });  
    } 
    return p; 
} 
function reduceRemove2(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.state === "TN"){ 
     v.items.forEach (function(val, idx) { 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     });  
    } 
    return p; 
} 
function reduceAdd3(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.state === "TX"){ 
     v.items.forEach (function(val, idx) { 
      p.bread += (val === 'bread' ? 1 : 0); 
      p.apple += (val === 'apple' ? 1 : 0); 
      p.orange += (val === 'orange' ? 1 : 0); 
      p.meat += (val === 'meat' ? 1 : 0); 
     });  
    } 
    return p; 
} 
function reduceRemove3(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.state === "TX"){ 
     v.items.forEach (function(val, idx) { 
      p.bread -= (val === 'bread' ? 1 : 0); 
      p.apple -= (val === 'apple' ? 1 : 0); 
      p.orange -= (val === 'orange' ? 1 : 0); 
      p.meat -= (val === 'meat' ? 1 : 0); 
     });  
    } 
    return p; 
} 
function reduceAdd_apple(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count += (val === 'apple' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_apple(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count -= (val === 'apple' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_bread(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count += (val === 'bread' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_bread(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count -= (val === 'bread' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_orange(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count += (val === 'orange' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_orange(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count -= (val === 'orange' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_meat(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count += (val === 'meat' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceRemove_meat(p, v){ 
    if (v.items[0] === "") return p; // skip empty values 
    p.state = v.state; 
    v.items.forEach(function(val, idx){ 
     p.count -= (val === 'meat' ? 1 : 0); 
    }); 
    return p; 
} 
function reduceAdd_group1(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "bread"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2) { 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceRemove_group1(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "bread"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2) { 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceAdd_group2(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "apple"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2) { 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceRemove_group2(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "apple"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2) { 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceAdd_group3(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "orange"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2) { 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceRemove_group3(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "orange"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2){ 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceAdd_group4(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "meat"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2) { 
       p.A += (val2 === 'A' ? 1 : 0); 
       p.O += (val2 === 'O' ? 1 : 0); 
       p.C += (val2 === 'C' ? 1 : 0); 
       p.R += (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceRemove_group4(p, v) { 
    if (v.items[0] === "") return p; // skip empty values 
    if (v.status[0] === "") return p; // skip empty values 
    v.items.forEach(function(val1, idx1){ 
     if (val1 === "meat"){ 
      v.status.forEach (function(val2, idx2) { 
       if (idx1 === idx2) { 
       p.A -= (val2 === 'A' ? 1 : 0); 
       p.O -= (val2 === 'O' ? 1 : 0); 
       p.C -= (val2 === 'C' ? 1 : 0); 
       p.R -= (val2 === 'R' ? 1 : 0); 
       } 
      });  
     } 
    }); 
    return p; 
} 
function reduceAdd_group(p, v) { 
    if (v.status[0] === "") return p; // skip empty values 
    v.status.forEach (function(val, idx) { 
     p[val] = (p[val] || 0) + 1; 
    }); 
    return p; 
} 
function reduceRemove_group(p, v) { 
    if (v.status[0] === "") return p; // skip empty values 
    v.status.forEach (function(val, idx) { 
     p[val] = (p[val] || 0) - 1; 
    }); 
    return p; 
} 
function reduceInitial_group() { 
    return { 
     A: 0, 
     O: 0, 
     C: 0, 
     R: 0 
    }; 
} 
function reduceInitial_items(){ 
    return { 
     count: 0, 
     state: '' 
    }; 
} 


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

//all function: 
function myAllFunction() { 
    var newObject = []; 
    for (var key in this) { 
     if (this.hasOwnProperty(key) && key != "all") { 
      newObject.push({ 
       key: key, 
       value: this[key] 
      }); 
     } 
    } 
    return newObject; 
}; 
+0

Привет, Кейси, ответы, которые фактически являются продолжением вопроса, несут ответственность за удаление на SO. Пожалуйста, обновите свой вопрос этим контентом, чтобы он мог помочь людям в будущем. – Gordon

+0

Я забыл обновить свое решение. Благодаря! – Casey