[IMP] separates the pivot table drawing from the pivot table 'computing' (width, cells, colors,...). This will be useful for the export functionality : the table can be easily serialized in json (addon web_graph)
bzr revid: ged@openerp.com-20140204113135-1igakgqdxewey3aj
This commit is contained in:
parent
6ddbb1f8c6
commit
cfef034321
|
@ -89,8 +89,8 @@ openerp.web_graph.Graph = openerp.web.Widget.extend({
|
|||
groupbys = _.flatten(_.map(filters, function (filter) {
|
||||
var groupby = py.eval(filter.attrs.context).group_by;
|
||||
if (!(groupby instanceof Array)) { groupby = [groupby]; }
|
||||
return _.map(groupby, function(g) {
|
||||
return {field: g, filter: filter};
|
||||
return _.map(groupby, function(g) {
|
||||
return {field: g, filter: filter};
|
||||
});
|
||||
}));
|
||||
|
||||
|
@ -362,6 +362,104 @@ openerp.web_graph.Graph = openerp.web.Widget.extend({
|
|||
this.graph_view.register_groupby(this.pivot.rows.groupby, this.pivot.cols.groupby);
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Convert Pivot data structure into table structure :
|
||||
// compute rows, cols, colors, cell width, cell height, ...
|
||||
// ----------------------------------------------------------------------
|
||||
build_table: function() {
|
||||
return {
|
||||
headers: this.build_headers(),
|
||||
measure_row: this.build_measure_row(),
|
||||
rows: this.build_rows(),
|
||||
};
|
||||
},
|
||||
|
||||
build_headers: function () {
|
||||
var pivot = this.pivot,
|
||||
nbr_measures = pivot.measures.length,
|
||||
height = _.max(_.map(pivot.cols.headers, function(g) {return g.path.length;})),
|
||||
rows = [];
|
||||
|
||||
_.each(pivot.cols.headers, function (col) {
|
||||
if (col.path.length === 0) { return;}
|
||||
var cell_width = nbr_measures * (col.expanded ? pivot.get_ancestor_leaves(col).length : 1),
|
||||
cell_height = col.expanded ? 1 : height - col.path.length + 1,
|
||||
cell = {width: cell_width, height: cell_height, title: col.title, id: col.id, expanded: col.expanded};
|
||||
if (rows[col.path.length - 1]) {
|
||||
rows[col.path.length - 1].push(cell);
|
||||
} else {
|
||||
rows[col.path.length - 1] = [cell];
|
||||
}
|
||||
});
|
||||
|
||||
if (pivot.get_cols_leaves().length > 1) {
|
||||
rows[0].push({width:nbr_measures, height:height, title: _t('Total'), id: pivot.cols.headers[0].id });
|
||||
}
|
||||
if (pivot.cols.headers.length === 1) {
|
||||
rows = [[{width:nbr_measures, height:1, title: _t('Total'), id: pivot.cols.headers[0].id, expanded: false}]];
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
|
||||
build_measure_row: function () {
|
||||
var nbr_leaves = this.pivot.get_cols_leaves().length,
|
||||
nbr_cols = nbr_leaves + ((nbr_leaves > 1) ? 1 : 0),
|
||||
result = [],
|
||||
add_total = this.pivot.get_cols_leaves().length > 1,
|
||||
i, m;
|
||||
for (i = 0; i < nbr_cols; i++) {
|
||||
for (m = 0; m < this.pivot.measures.length; m++) {
|
||||
result.push({
|
||||
text:this.pivot.measures[m].string,
|
||||
is_bold: add_total && (i === nbr_cols - 1)
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
add_color: function (cell, row, col, index) {
|
||||
if (this.heatmap_mode === 'none') { return cell; }
|
||||
var total = (this.heatmap_mode === 'both') ? this.pivot.get_total()[index]
|
||||
: (this.heatmap_mode === 'row') ? this.pivot.get_total(row)[index]
|
||||
: this.pivot.get_total(col)[index];
|
||||
var color = Math.floor(90 + 165*(total - Math.abs(cell.value))/total);
|
||||
if (color < 255) {
|
||||
cell.color = color;
|
||||
}
|
||||
return cell;
|
||||
},
|
||||
|
||||
build_rows: function () {
|
||||
var self = this,
|
||||
pivot = this.pivot,
|
||||
m,
|
||||
add_total = pivot.get_cols_leaves().length > 1;
|
||||
|
||||
return _.map(pivot.rows.headers, function (row) {
|
||||
var cells = [];
|
||||
_.each(pivot.get_cols_leaves(), function (col) {
|
||||
var values = pivot.get_values(row.id, col.id);
|
||||
for (m = 0; m < pivot.measures.length; m++) {
|
||||
cells.push(self.add_color({value:values[m], type:pivot.measures[m].type}, row,col,m));
|
||||
}
|
||||
});
|
||||
if (add_total) {
|
||||
var totals = pivot.get_total(row);
|
||||
for (m = 0; m < pivot.measures.length; m++) {
|
||||
cells.push(self.add_color({value:totals[m], type:pivot.measures[m].type, is_bold:true},row,pivot.main_col(),m));
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: row.id,
|
||||
indent: row.path.length,
|
||||
title: row.title,
|
||||
expanded: row.expanded,
|
||||
cells: cells,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Main display method
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -391,159 +489,76 @@ openerp.web_graph.Graph = openerp.web.Widget.extend({
|
|||
// Drawing the table
|
||||
// ----------------------------------------------------------------------
|
||||
draw_table: function () {
|
||||
this.draw_top_headers();
|
||||
_.each(this.pivot.rows.headers, this.proxy('draw_row'));
|
||||
var table = this.build_table();
|
||||
this.draw_headers(table.headers);
|
||||
this.draw_measure_row(table.measure_row);
|
||||
this.draw_rows(table.rows);
|
||||
},
|
||||
|
||||
make_border_cell: function (colspan, rowspan, headercell) {
|
||||
var tag = (headercell) ? $('<th>') : $('<td>');
|
||||
return tag.addClass('graph_border')
|
||||
.attr('colspan', colspan || 1)
|
||||
.attr('rowspan', rowspan || 1);
|
||||
},
|
||||
|
||||
make_header_title: function (header) {
|
||||
return $('<span> ')
|
||||
.addClass('web_graph_click')
|
||||
.attr('href', '#')
|
||||
.addClass((header.expanded) ? 'fa fa-minus-square' : 'fa fa-plus-square')
|
||||
.text(' ' + (header.title || 'Undefined'));
|
||||
},
|
||||
|
||||
draw_top_headers: function () {
|
||||
var self = this,
|
||||
thead = $('<thead>'),
|
||||
pivot = this.pivot,
|
||||
height = _.max(_.map(pivot.cols.headers, function(g) {return g.path.length;})),
|
||||
header_cells = [[this.make_border_cell(1, height, true)]];
|
||||
|
||||
function set_dim (cols) {
|
||||
_.each(cols.children, set_dim);
|
||||
if (cols.children.length === 0) {
|
||||
cols.height = height - cols.path.length + 1;
|
||||
cols.width = 1;
|
||||
} else {
|
||||
cols.height = 1;
|
||||
cols.width = _.reduce(cols.children, function (sum,c) { return sum + c.width;}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function make_col_header (col) {
|
||||
var cell = self.make_border_cell(col.width*pivot.measures.length, col.height, true);
|
||||
return cell.append(self.make_header_title(col).attr('data-id', col.id));
|
||||
}
|
||||
|
||||
function make_cells (queue, level) {
|
||||
var col = queue[0];
|
||||
queue = _.rest(queue).concat(col.children);
|
||||
if (col.path.length == level) {
|
||||
_.last(header_cells).push(make_col_header(col));
|
||||
} else {
|
||||
level +=1;
|
||||
header_cells.push([make_col_header(col)]);
|
||||
}
|
||||
if (queue.length !== 0) {
|
||||
make_cells(queue, level);
|
||||
}
|
||||
}
|
||||
|
||||
set_dim(pivot.main_col()); // add width and height info to columns headers
|
||||
if (pivot.main_col().children.length === 0) {
|
||||
make_cells(pivot.cols.headers, 0);
|
||||
make_header_cell: function (header) {
|
||||
var cell = (_.has(header, 'cells') ? $('<td>') : $('<th>'))
|
||||
.addClass('graph_border')
|
||||
.attr('rowspan', header.height)
|
||||
.attr('colspan', header.width);
|
||||
var content = $('<span>').addClass('web_graph_click')
|
||||
.attr('href','#')
|
||||
.text(' ' + (header.title || _t('Undefined')))
|
||||
.attr('data-id', header.id);
|
||||
if (_.has(header, 'expanded')) {
|
||||
content.addClass(header.expanded ? 'fa fa-minus-square' : 'fa fa-plus-square');
|
||||
} else {
|
||||
make_cells(pivot.main_col().children, 1);
|
||||
if (pivot.get_cols_leaves().length > 1) {
|
||||
header_cells[0].push(self.make_border_cell(pivot.measures.length, height, true).text(_t('Total')).css('font-weight', 'bold'));
|
||||
}
|
||||
content.css('font-weight', 'bold');
|
||||
}
|
||||
|
||||
_.each(header_cells, function (cells) {
|
||||
thead.append($('<tr>').append(cells));
|
||||
});
|
||||
|
||||
if (pivot.measures.length >= 2) {
|
||||
thead.append(self.make_measure_row());
|
||||
if (_.has(header, 'indent')) {
|
||||
for (var i = 0; i < header.indent; i++) { cell.prepend($('<span>', {class:'web_graph_indent'})); }
|
||||
}
|
||||
|
||||
self.table.append(thead);
|
||||
return cell.append(content);
|
||||
},
|
||||
|
||||
make_measure_cells: function () {
|
||||
return _.map(this.pivot.measures, function (measure) {
|
||||
return $('<th>').addClass('measure_row').text(measure.string);
|
||||
draw_headers: function (headers) {
|
||||
var make_cell = this.make_header_cell,
|
||||
empty_cell = $('<th>').attr('rowspan', headers.length),
|
||||
thead = $('<thead>');
|
||||
|
||||
_.each(headers, function (row) {
|
||||
var html_row = $('<tr>');
|
||||
_.each(row, function (header) {
|
||||
html_row.append(make_cell(header));
|
||||
});
|
||||
thead.append(html_row);
|
||||
});
|
||||
thead.children(':first').prepend(empty_cell);
|
||||
this.table.append(thead);
|
||||
},
|
||||
|
||||
make_measure_row: function() {
|
||||
var self = this,
|
||||
cols = this.pivot.cols.headers,
|
||||
measure_row = $('<tr>');
|
||||
|
||||
measure_row.append($('<th>'));
|
||||
|
||||
_.each(cols, function (col) {
|
||||
if (!col.children.length) {
|
||||
measure_row.append(self.make_measure_cells());
|
||||
}
|
||||
|
||||
draw_measure_row: function (measure_row) {
|
||||
if (this.pivot.measures.length === 1) { return; }
|
||||
var html_row = $('<tr>').append('<th>');
|
||||
_.each(measure_row, function (cell) {
|
||||
var measure_cell = $('<th>').addClass('measure_row').text(cell.text);
|
||||
if (cell.is_bold) {measure_cell.css('font-weight', 'bold');}
|
||||
html_row.append(measure_cell);
|
||||
});
|
||||
|
||||
if (this.pivot.get_cols_leaves().length > 1) {
|
||||
measure_row.append(self.make_measure_cells());
|
||||
}
|
||||
return measure_row;
|
||||
this.$('thead').append(html_row);
|
||||
},
|
||||
|
||||
draw_rows: function (rows) {
|
||||
var table = this.table,
|
||||
make_cell = this.make_header_cell;
|
||||
|
||||
draw_row: function (row) {
|
||||
var self = this,
|
||||
pivot = this.pivot,
|
||||
measure_types = _.pluck(this.pivot.measures, 'type'),
|
||||
html_row = $('<tr>'),
|
||||
row_header = this.make_border_cell(1,1)
|
||||
.append(this.make_header_title(row).attr('data-id', row.id))
|
||||
.addClass('graph_border');
|
||||
|
||||
for (var i = 0; i < row.path.length; i++) {
|
||||
row_header.prepend($('<span>', {class:'web_graph_indent'}));
|
||||
}
|
||||
|
||||
html_row.append(row_header);
|
||||
|
||||
_.each(pivot.cols.headers, function (col) {
|
||||
if (!col.children.length) {
|
||||
var values = pivot.get_values(row.id, col.id);
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
html_row.append(make_cell(values[i], measure_types[i], i, col));
|
||||
_.each(rows, function (row) {
|
||||
var html_row = $('<tr>').append(make_cell(row));
|
||||
_.each(row.cells, function (cell) {
|
||||
var value = openerp.web.format_value(cell.value, {type: cell.type}),
|
||||
html_cell = $('<td>').text(value);
|
||||
if (_.has(cell, 'color')) {
|
||||
html_cell.css('background-color', $.Color(255, cell.color, cell.color));
|
||||
}
|
||||
}
|
||||
if (cell.is_bold) { html_cell.css('font-weight', 'bold'); }
|
||||
html_row.append(html_cell);
|
||||
});
|
||||
table.append(html_row);
|
||||
});
|
||||
|
||||
if (pivot.get_cols_leaves().length > 1) {
|
||||
var total_vals = pivot.get_total(row);
|
||||
for (var j = 0; j < total_vals.length; j++) {
|
||||
var cell = make_cell(total_vals[j], measure_types[j], j, pivot.cols[0]).css('font-weight', 'bold');
|
||||
html_row.append(cell);
|
||||
}
|
||||
}
|
||||
|
||||
this.table.append(html_row);
|
||||
|
||||
function make_cell (value, measure_type, index, col) {
|
||||
var cell = $('<td>');
|
||||
if (value === undefined) {
|
||||
return cell;
|
||||
}
|
||||
cell.text(openerp.web.format_value(value, {type: measure_type}));
|
||||
var total = (self.heatmap_mode === 'both') ? pivot.get_total()[index]
|
||||
: (self.heatmap_mode === 'row') ? pivot.get_total(row)[index]
|
||||
: (self.heatmap_mode === 'col') ? pivot.get_total(col)[index]
|
||||
: undefined;
|
||||
|
||||
if (self.heatmap_mode !== 'none') {
|
||||
var color = Math.floor(90 + 165*(total - Math.abs(value))/total);
|
||||
cell.css('background-color', $.Color(255, color, color));
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -700,96 +715,11 @@ openerp.web_graph.Graph = openerp.web.Widget.extend({
|
|||
});
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Convert Pivot data structure into table structure
|
||||
// table = {headers: [header_rows],
|
||||
// measure_row: [_],
|
||||
// rows: [row]}
|
||||
// header_rows = [header_cells],
|
||||
// header_cells = {width:_, height:_, title:_, id:_}
|
||||
// rows = {id:_, indent:_, title:_, cells: [cell]}
|
||||
// cell = {row_id:_, col_id:_, value:_}
|
||||
// ----------------------------------------------------------------------
|
||||
build_table: function() {
|
||||
return {
|
||||
headers: this.build_headers(),
|
||||
measure_row: this.build_measure_row(),
|
||||
rows: this.build_rows()
|
||||
};
|
||||
},
|
||||
|
||||
build_headers: function () {
|
||||
var pivot = this.pivot,
|
||||
height = _.max(_.map(pivot.cols.headers, function(g) {return g.path.length;})),
|
||||
rows = [];
|
||||
|
||||
_.each(pivot.cols.headers, function (col) {
|
||||
if (col.path.length === 0) { return;}
|
||||
var cell_width = col.expanded ? pivot.get_ancestor_leaves(col).length : 1,
|
||||
cell_height = col.expanded ? 1 : height - col.path.length + 1,
|
||||
cell = {width: cell_width, height: cell_height, title: col.title, id: col.id};
|
||||
if (rows[col.path.length - 1]) {
|
||||
rows[col.path.length - 1].push(cell);
|
||||
} else {
|
||||
rows[col.path.length - 1] = [cell];
|
||||
}
|
||||
});
|
||||
|
||||
if (pivot.get_cols_leaves().length > 1) {
|
||||
rows[0].push({width:1, height:1, title: _t('Total'), id: pivot.cols.headers[0].id });
|
||||
}
|
||||
if (pivot.cols.headers.length === 1) {
|
||||
rows = [{width:1, height:1, title: _t('Total'), id: pivot.cols.headers[0].id }];
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
|
||||
build_measure_row: function () {
|
||||
var nbr_leaves = this.pivot.get_cols_leaves().length,
|
||||
nbr_cols = nbr_leaves + ((nbr_leaves > 1) ? 1 : 0),
|
||||
result = [],
|
||||
i, m;
|
||||
for (i = 0; i < nbr_cols; i++) {
|
||||
for (m = 0; m < this.pivot.measures.length; m++) {
|
||||
result.push(this.pivot.measures[m].string);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
build_rows: function () {
|
||||
var pivot = this.pivot;
|
||||
var m;
|
||||
var add_total = pivot.get_cols_leaves().length > 1;
|
||||
|
||||
return _.map(pivot.rows.headers, function (row) {
|
||||
var cells = [];
|
||||
_.each(pivot.get_cols_leaves(), function (col) {
|
||||
var values = pivot.get_values(row.id, col.id);
|
||||
for (m = 0; m < pivot.measures.length; m++) {
|
||||
cells.push({value:values[m], type:pivot.measures[m].type})
|
||||
}
|
||||
});
|
||||
if (add_total) {
|
||||
var totals = pivot.get_total(row);
|
||||
for (m = 0; m < pivot.measures.length; m++) {
|
||||
cells.push({value:totals[m], type:pivot.measures[m].type})
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: row.id,
|
||||
indent: row.path.length,
|
||||
title: row.title,
|
||||
cells: cells
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Controller stuff...
|
||||
// ----------------------------------------------------------------------
|
||||
export_xls: function() {
|
||||
openerp.web.blockUI();
|
||||
openerp.web.blockUI();
|
||||
this.session.get_file({
|
||||
url: '/web_graph/export_xls',
|
||||
data: {data: JSON.stringify(this.build_table())},
|
||||
|
@ -798,9 +728,6 @@ openerp.web_graph.Graph = openerp.web.Widget.extend({
|
|||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
// Utility function: returns true if the beginning of array2 is array1 and
|
||||
|
|
Loading…
Reference in New Issue