/**
* Copyright (c) 2019
*
* @summary d3 script for charts of AggreSet
* @author Elitza Vasileva
* @author Bernhard Pointner
*/
class Crossfilter {
constructor(_data) {
this.data = _data;
// necessary data
this.movies = _data.entries;
this.genres = _data.genres;
// num of genres
this.num_genres = this.genres.length;
// crossfilter
this.cf = null;
this.cat_identifier = "g";
this.cat_identifier_start = 1;
// dimensions and groups and descriptions of multi hot array
this.dimensions = {};
this.groups = {};
this.descriptions = {};
this.filters = {};
this.filters_title = {};
this.selected = [];
this.hovered = [];
this.all = null;
this.formatNumber = null;
this.formatChange = null;
this.formatDate = null;
this.formatTime = null;
this.initFormats();
this.initDataTypesOnDimensions();
this.initDimensionsAndGroups();
}
/**
* Initializes the different type formats
*/
initFormats() {
// Various formatters
this.formatNumber = d3.format(",d");
this.formatChange = d3.format("+,d");
this.formatDate = d3.timeFormat("%B %d, %Y");
this.formatTime = d3.timeFormat("%I:%M %p");
}
/**
* Initializes the types of dimensions
*/
initDataTypesOnDimensions() {
let num_genres = this.num_genres;
this.movies.forEach(function(d, i) {
d.index = i;
for(let i=1;i<=num_genres;i++) {
d["g"+i] = +d["g"+i];
}
});
}
/**
* Initializes the dimension and groups according to the data
*/
initDimensionsAndGroups() {
let genres = this.genres;
let cat_identifier = this.cat_identifier;
this.dimensions["genres"] = new Array(this.num_genres);
this.groups["genres"] = new Array(this.num_genres);
this.descriptions["genres"] = new Array(this.num_genres);
this.filters["genres"] = {active : null, preview: null};
this.selected["genres"] = new Array(this.num_genres).fill(false);
this.hovered["genres"] = new Array(this.num_genres).fill(false);
this.filters_title["genres"] = "Genres";
this.dimensions["num_genres"] = null;
this.groups["num_genres"] = null;
this.descriptions["num_genres"] = null;
this.filters["num_genres"] = {active : null, preview: null};
this.selected["num_genres"] = [];
this.hovered["num_genres"] = [];
this.filters_title["genres"] = "# of Genres";
this.dimensions["ratings"] = null;
this.groups["ratings"] = null;
this.descriptions["ratings"] = null;
this.filters["ratings"] = {active : null, preview: null};
this.selected["ratings"] = [];
this.hovered["ratings"] = [];
this.filters_title["ratings"] = "Ratings";
this.dimensions["watched"] = null;
this.groups["watched"] = null;
this.descriptions["watched"] = null;
this.filters["watched"] = {active : null, preview: null};
this.selected["watched"] = [];
this.hovered["watched"] = [];
this.filters_title["watched"] = "Watches";
this.cf = crossfilter(this.movies);
this.all = this.cf.groupAll();
for(let j=0;j<this.num_genres;j++) {
this.dimensions["genres"][j] = this.cf.dimension(function(d) {return d[cat_identifier+genres[j].key];});
this.groups["genres"][j] = this.dimensions["genres"][j].group(function(d) { return d; });
this.descriptions["genres"][j] = this.genres[j];
//console.log(this.groups["genres"][i].all());
}
this.filters["genres"].active = new FilterDimensionsLogicalOperators(this.dimensions["genres"],this.cat_identifier,this.cat_identifier_start);
this.filters["genres"].preview = new FilterDimensionsLogicalOperators(this.dimensions["genres"],this.cat_identifier,this.cat_identifier_start);
let num_genres_per_row = [];
this.dimensions["num_genres"] = this.cf.dimension(function (d) { let num = genres.map(genre => d["g"+genre.key]).reduce((a,b) => a + b, 0);num_genres_per_row.push(num);return num});
this.groups["num_genres"] = this.dimensions["num_genres"].group();
this.descriptions["num_genres"] = this.genres;
this.filters["num_genres"].active = new FilterSumOfDimensions(this.dimensions["genres"],this.cat_identifier,this.cat_identifier_start,num_genres_per_row);
this.filters["num_genres"].preview = new FilterSumOfDimensions(this.dimensions["genres"],this.cat_identifier,this.cat_identifier_start,num_genres_per_row);
this.dimensions["ratings"] = this.cf.dimension(function(d) {return Math.round(d["rating"]);});
this.groups["ratings"] = this.dimensions["ratings"].group();
this.descriptions["ratings"] = this.genres;
this.filters["ratings"].active = new FitlerDefault(this.dimensions["ratings"],this.cat_identifier,this.cat_identifier_start,"rating");
this.filters["ratings"].preview = new FitlerDefault(this.dimensions["ratings"],this.cat_identifier,this.cat_identifier_start,"rating");
//console.log(Math.round(d["watched"]/Math.pow(10,(''+d["watched"]).length))*Math.pow(10,(''+d["watched"]).length));
this.dimensions["watched"] = this.cf.dimension(function(d) { return Math.ceil(d["watched"]/Math.pow(10,(''+d["watched"]).length))*Math.pow(10,(''+d["watched"]).length-1);});
this.groups["watched"] = this.dimensions["watched"].group();
this.descriptions["watched"] = this.genres;
this.filters["watched"].active = new FilterLog(this.dimensions["watched"],this.cat_identifier,this.cat_identifier_start,"watched");
this.filters["watched"].preview = new FilterLog(this.dimensions["watched"],this.cat_identifier,this.cat_identifier_start,"watched");
// TEST - DONT DELETE
/*console.log(this.genres);
let dimension = this.cf.dimension(function(d) { return genres.map(genre => "g"+genre.key+"-"+d["g"+genre.key]) },true);
let group = dimension.group();
console.log(group.all());
let test1 = this.groups["num_genres"].all();
console.log(test1);
//dimension.filter("g1-1");
console.log(dimension.top(Infinity));
let test2 = this.groups["num_genres"].all();
console.log(test2);*/
}
/**
* Filters transmitted data by all available dimensions on available filters
* @param data array of data entries to filter
* @param type 'active' or 'preview'
* @returns {*} .. filtered data entries
*/
filterCustomData(data, type) {
const _this = this;
let filter_keys = Object.keys(this.filters);
let filtered_data = data.filter((row,i) => {
let false_found = filter_keys.filter(key => {
return _this.filters[key][type].evaluateRow(data[i],i) == false;
});
return false_found.length == 0;
});
return filtered_data;
}
/**
* Get all rows which are currently filtered
* @returns {*} filtered rows
*/
getAllFilteredRows() {
return this.cf.allFiltered();
}
/**
* Update global filter array and show filter container
*/
updateGlobalFilterArray() {
const _this = this;
let filter_container = d3.select(".vis-container-header .vis-filter-container");
let active_filters = d3.select(".active-filters");
let filter_keys = Object.keys(this.filters);
if(filter_keys.length !== 0) {
filter_keys.map((key,i) => {
active_filters.text(_this.filters_title[key]);
});
filter_container.style("display","block");
}
}
}