1 /*---------------------------------------------------------
3 *---------------------------------------------------------*/
5 /* jshint undef: false */
8 openerp.web_graph = function (instance) {
11 var _lt = instance.web._lt;
12 var _t = instance.web._t;
13 var QWeb = instance.web.qweb;
15 instance.web.views.add('graph', 'instance.web_graph.GraphView');
18 * GraphView view. It mostly contains a widget (PivotTable), some data, and
19 * calls to charts function.
21 instance.web_graph.GraphView = instance.web.View.extend({
22 template: 'GraphView',
23 display_name: _lt('Graph'),
27 'click .graph_mode_selection li' : function (event) {
28 event.preventDefault();
29 var mode = event.target.attributes['data-mode'].nodeValue;
30 this.switch_mode(mode);
33 'click .graph_expand_selection li' : function (event) {
34 event.preventDefault();
35 switch (event.target.attributes['data-choice'].nodeValue) {
37 this.pivot_table.fold_cols();
41 this.pivot_table.fold_rows();
45 this.pivot_table.fold_all();
49 this.pivot_table.expand_all().then(this.proxy('draw_table'));
54 'click .graph_options_selection li' : function (event) {
55 event.preventDefault();
56 switch (event.target.attributes['data-choice'].nodeValue) {
58 this.pivot_table.swap_axis();
62 this.pivot_table.update_values().then(this.proxy('draw_table'));
65 // Export code... To do...
70 'click .web_graph_click' : function (event) {
71 event.preventDefault();
72 var id = event.target.attributes['data-id'].nodeValue;
73 this.handle_header_event({id:id, event:event});
76 'click a.field-selection' : function (event) {
77 var id = event.target.attributes['data-id'].nodeValue,
78 field_id = event.target.attributes['data-field-id'].nodeValue;
79 event.preventDefault();
80 this.dropdown.remove();
81 this.pivot_table.expand(id, field_id)
82 .then(this.proxy('draw_table'));
86 view_loading: function (fields_view_get) {
88 model = new instance.web.Model(fields_view_get.model, {group_by_no_leaf: true}),
92 important_fields = [],
95 this.pivot_table = null;
96 this.heat_map_mode = false;
99 // get the default groupbys and measure defined in the field view
100 _.each(fields_view_get.arch.children, function (field) {
101 if ('name' in field.attrs) {
102 if ('operator' in field.attrs) {
103 measure = field.attrs.name;
105 row_groupby.push(field.attrs.name);
110 // get the most important fields (of the model) by looking at the
111 // groupby filters defined in the search view
112 var load_view = instance.web.fields_view_get({
117 var important_fields_def = $.when(load_view).then(function (search_view) {
118 var groups = _.select(search_view.arch.children, function (c) {
119 return (c.tag == 'group') && (c.attrs.string != 'Display');
121 _.each(groups, function(g) {
122 _.each(g.children, function (g) {
123 if (g.attrs.context) {
124 var field_id = py.eval(g.attrs.context).group_by;
125 important_fields.push(field_id);
131 // get the fields descriptions from the model
132 var field_descr_def = model.call('fields_get', [])
133 .then(function (fs) { fields = fs; });
135 return $.when(important_fields_def, field_descr_def)
141 important_fields: important_fields,
143 measure_label: fields[measure].string,
145 row_groupby: row_groupby,
153 this.table = $('<table></table>');
154 this.svg = $('<div><svg></svg></div>');
155 this.$el.filter('.graph_main_content').append(this.table);
156 this.$el.filter('.graph_main_content').append(this.svg);
157 return this.load_view();
160 do_search: function (domain, context, group_by) {
162 this.data.domain = new instance.web.CompoundDomain(domain);
164 if (!this.pivot_table) {
165 self.pivot_table = new PivotTable(self.data);
166 self.pivot_table.start().then(self.proxy('draw_table'));
168 this.pivot_table.domain = domain;
169 this.pivot_table.update_values().done(function () {
175 do_show: function () {
176 this.do_push_state({});
177 return this._super();
180 switch_mode: function (mode) {
182 var table_modes = ['pivot', 'heatmap', 'row_heatmap', 'col_heatmap'];
183 if (_.contains(table_modes, mode)) {
185 this.table.css('display', 'block');
186 this.svg.css('display','none');
188 this.table.css('display', 'none');
190 this.svg = $('<div><svg></svg></div>');
191 this.$el.filter('.graph_main_content').append(this.svg);
192 draw_chart(mode, this.pivot_table);
197 handle_header_event: function (options) {
198 var pivot = this.pivot_table,
200 header = pivot.get_header(id);
202 if (header.is_expanded) {
206 if (header.path.length < header.root.groupby.length) {
207 var field = header.root.groupby[header.path.length];
208 pivot.expand(id, field).then(this.proxy('draw_table'));
210 this.display_dropdown({id:header.id,
211 target: $(options.event.target),
212 x: options.event.pageX,
213 y: options.event.pageY});
218 display_dropdown: function (options) {
220 pivot = this.pivot_table,
221 already_grouped = pivot.rows.groupby.concat(pivot.cols.groupby),
222 possible_groups = _.difference(self.data.important_fields, already_grouped),
224 header_id: options.id,
225 fields: _.map(possible_groups, function (field) {
226 return {id: field, value: self.data.fields[field].string};
229 this.dropdown = $(QWeb.render('field_selection', dropdown_options));
230 options.target.after(this.dropdown);
231 this.dropdown.css({position:'absolute',
234 $('.field-selection').next('.dropdown-menu').toggle();
237 draw_table: function () {
239 this.draw_top_headers();
240 _.each(this.pivot_table.rows.headers, this.proxy('draw_row'));
243 make_border_cell: function (colspan, rowspan) {
244 return $('<td></td>').addClass('graph_border')
245 .attr('colspan', colspan)
246 .attr('rowspan', rowspan);
249 make_header_title: function (header) {
250 return $('<span> </span>')
251 .addClass('web_graph_click')
253 .addClass((header.is_expanded) ? 'icon-minus-sign' : 'icon-plus-sign')
254 .append((header.title !== undefined) ? header.title : 'Undefined');
257 draw_top_headers: function () {
259 pivot = this.pivot_table,
260 height = _.max(_.map(pivot.cols.headers, function(g) {return g.path.length;})),
261 header_cells = [[this.make_border_cell(1, height)]];
263 function set_dim (cols) {
264 _.each(cols.children, set_dim);
265 if (cols.children.length === 0) {
266 cols.height = height - cols.path.length + 1;
270 cols.width = _.reduce(cols.children, function (sum,c) { return sum + c.width;}, 0);
274 function make_col_header (col) {
275 var cell = self.make_border_cell(col.width, col.height);
276 return cell.append(self.make_header_title(col).attr('data-id', col.id));
279 function make_cells (queue, level) {
281 queue = _.rest(queue).concat(col.children);
282 if (col.path.length == level) {
283 _.last(header_cells).push(make_col_header(col));
286 header_cells.push([make_col_header(col)]);
288 if (queue.length !== 0) {
289 make_cells(queue, level);
293 set_dim(pivot.cols.main); // add width and height info to columns headers
294 if (pivot.cols.main.children.length === 0) {
295 make_cells(pivot.cols.headers, 0);
297 make_cells(pivot.cols.main.children, 1);
298 header_cells[0].push(self.make_border_cell(1, height).append('Total').css('font-weight', 'bold'));
301 _.each(header_cells, function (cells) {
302 self.table.append($('<tr></tr>').append(cells));
306 draw_row: function (row) {
308 pivot = this.pivot_table,
309 html_row = $('<tr></tr>'),
310 row_header = this.make_border_cell(1,1)
311 .append(this.make_header_title(row).attr('data-id', row.id))
312 .addClass('graph_border');
314 for (var i in _.range(row.path.length)) {
315 row_header.prepend($('<span/>', {class:'web_graph_indent'}));
318 html_row.append(row_header);
320 _.each(pivot.cols.headers, function (col) {
321 if (col.children.length === 0) {
322 var value = pivot.get_value(row.id, col.id),
323 cell = $('<td></td>');
325 cell.append((value === undefined) ? '' : value);
326 if ((self.mode == 'heatmap') && (value !== undefined)) {
327 var color = Math.floor(50 + 205*(pivot.total - value)/pivot.total);
328 cell.css('background-color', 'rgb(255,' + color + ',' + color + ')');
330 if (row.is_expanded && (row.path.length <= 2)) {
331 var color = row.path.length * 5 + 240;
332 cell.css('background-color', 'rgb(' + [color, color, color].join() + ')');
334 html_row.append(cell);
337 var total = pivot.get_value(row.id, pivot.cols.main.id);
338 var cell = $('<td></td>')
340 .css('font-weight', 'bold');
341 if (row.is_expanded && (row.path.length <= 2)) {
342 var color = row.path.length * 5 + 240;
343 cell.css('background-color', 'rgb(' + [color, color, color].join() + ')');
344 } else if (self.heat_map_mode) {
345 var color = Math.floor(50 + 205*(pivot.total - total)/pivot.total);
346 cell.css('background-color', 'rgb(255,' + color + ',' + color + ')');
349 if (pivot.cols.main.children.length > 0) {
350 html_row.append(cell);
353 this.table.append(html_row);