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 .web_graph_click' : function (event) {
34 event.preventDefault();
35 if (event.target.attributes['data-row-id'] !== undefined) {
36 this.handle_header_event({type:'row', event:event});
39 if (event.target.attributes['data-col-id'] !== undefined) {
40 this.handle_header_event({type:'col', event:event});
44 'click a.field-selection' : function (event) {
46 field_id = event.target.attributes['data-field-id'].nodeValue;
47 event.preventDefault();
48 this.dropdown.remove();
49 if (event.target.attributes['data-row-id'] !== undefined) {
50 id = event.target.attributes['data-row-id'].nodeValue;
51 this.pivot_table.expand_row(id, field_id)
52 .then(this.proxy('draw_table'));
54 if (event.target.attributes['data-col-id'] !== undefined) {
55 id = event.target.attributes['data-col-id'].nodeValue;
56 this.pivot_table.expand_col(id, field_id)
57 .then(this.proxy('draw_table'));
61 'click label.graph_swap_axis' : function (event) {
62 this.pivot_table.swap_axis();
66 'click label.graph_clear_all' : function (event) {
67 this.pivot_table.clear_all();
72 view_loading: function (fields_view_get) {
74 model = new instance.web.Model(fields_view_get.model, {group_by_no_leaf: true}),
78 important_fields = [],
82 this.pivot_table = null;
84 // get the default groupbys and measure defined in the field view
85 _.each(fields_view_get.arch.children, function (field) {
86 if ('name' in field.attrs) {
87 if ('operator' in field.attrs) {
88 measure = field.attrs.name;
90 row_groupby.push(field.attrs.name);
95 // get the most important fields (of the model) by looking at the
96 // groupby filters defined in the search view
97 var load_view = instance.web.fields_view_get({
102 var important_fields_def = $.when(load_view).then(function (search_view) {
103 var groups = _.select(search_view.arch.children, function (c) {
104 return (c.tag == 'group') && (c.attrs.string != 'Display');
106 _.each(groups, function(g) {
107 _.each(g.children, function (g) {
108 if (g.attrs.context) {
109 var field_id = py.eval(g.attrs.context).group_by;
110 important_fields.push(field_id);
116 // get the fields descriptions from the model
117 var field_descr_def = model.call('fields_get', [])
118 .then(function (fs) { fields = fs; });
120 return $.when(important_fields_def, field_descr_def)
126 important_fields: important_fields,
128 measure_label: fields[measure].string,
130 row_groupby: row_groupby,
138 this.table = $('<table></table>');
139 this.svg = $('<div><svg></svg></div>');
140 this.$el.filter('.graph_main_content').append(this.table);
141 this.$el.filter('.graph_main_content').append(this.svg);
142 return this.load_view();
145 do_search: function (domain, context, group_by) {
147 this.data.domain = new instance.web.CompoundDomain(domain);
149 if (!this.pivot_table) {
150 self.pivot_table = new PivotTable(self.data);
151 self.pivot_table.start().then(self.proxy('draw_table'));
153 this.pivot_table.update_values.done(function () {
159 do_show: function () {
160 this.do_push_state({});
161 return this._super();
164 switch_mode: function (mode) {
167 if (mode === 'pivot') {
168 this.table.css('display', 'block');
169 this.svg.css('display','none');
171 this.table.css('display', 'none');
173 this.svg = $('<div><svg></svg></div>');
174 this.$el.filter('.graph_main_content').append(this.svg);
175 Charts[mode](this.pivot_table);
180 handle_header_event: function (options) {
181 var pivot = this.pivot_table,
182 id = options.event.target.attributes['data-' + options.type + '-id'].nodeValue,
183 header = pivot['get_' + options.type](id);
185 if (header.is_expanded) {
186 pivot['fold_' + options.type](header);
189 if (header.path.length < pivot[options.type + '_groupby'].length) {
190 // expand the corresponding header
191 var field = pivot[options.type + '_groupby'][header.path.length];
192 pivot['expand_' + options.type](id, field)
193 .then(this.proxy('draw_table'));
195 // display dropdown to query field to expand
196 this.display_dropdown({id:header.id,
198 target: $(event.target),
205 display_dropdown: function (options) {
207 pivot = this.pivot_table,
208 already_grouped = pivot.row_groupby.concat(pivot.col_groupby),
209 possible_groups = _.difference(self.data.important_fields, already_grouped),
211 fields: _.map(possible_groups, function (field) {
212 return {id: field, value: self.data.fields[field].string};
214 dropdown_options[options.type + '_id'] = options.id;
216 this.dropdown = $(QWeb.render('field_selection', dropdown_options));
217 options.target.after(this.dropdown);
218 this.dropdown.css({position:'absolute',
221 $('.field-selection').next('.dropdown-menu').toggle();
224 draw_table: function () {
226 this.draw_top_headers();
227 _.each(this.pivot_table.rows, this.proxy('draw_row'));
230 make_border_cell: function (colspan, rowspan) {
231 return $('<td></td>').addClass('graph_border')
232 .attr('colspan', colspan)
233 .attr('rowspan', rowspan);
236 make_header_title: function (header) {
237 return $('<span> </span>')
238 .addClass('web_graph_click')
240 .addClass((header.is_expanded) ? 'icon-minus-sign' : 'icon-plus-sign')
241 .append(header.name);
244 draw_top_headers: function () {
246 pivot = this.pivot_table,
247 height = _.max(_.map(pivot.cols, function(g) {return g.path.length;})),
248 header_cells = [[this.make_border_cell(1, height)]];
250 function set_dim (cols) {
251 _.each(cols.children, set_dim);
252 if (cols.children.length === 0) {
253 cols.height = height - cols.path.length + 1;
257 cols.width = _.reduce(cols.children, function (sum,c) { return sum + c.width;}, 0);
261 function make_col_header (col) {
262 var cell = self.make_border_cell(col.width, col.height);
263 return cell.append(self.make_header_title(col).attr('data-col-id', col.id));
266 function make_cells (queue, level) {
268 queue = _.rest(queue).concat(col.children);
269 if (col.path.length == level) {
270 _.last(header_cells).push(make_col_header(col));
273 header_cells.push([make_col_header(col)]);
275 if (queue.length !== 0) {
276 make_cells(queue, level);
280 set_dim(pivot.cols[0]); // add width and height info to columns headers
281 if (pivot.cols[0].children.length === 0) {
282 make_cells(pivot.cols, 0);
284 make_cells(pivot.cols[0].children, 1);
287 _.each(header_cells, function (cells) {
288 self.table.append($("<tr></tr>").append(cells));
292 draw_row: function (row) {
293 var pivot = this.pivot_table,
294 html_row = $('<tr></tr>'),
295 row_header = this.make_border_cell(1,1)
296 .append(this.make_header_title(row).attr('data-row-id', row.id))
297 .addClass('graph_border');
299 for (var i in _.range(row.path.length)) {
300 row_header.prepend($('<span/>', {class:'web_graph_indent'}));
303 html_row.append(row_header);
305 _.each(pivot.cols, function (col) {
306 if (col.children.length === 0) {
307 var cell = $('<td></td>').append(pivot.get_value(row.id, col.id));
308 html_row.append(cell);
311 this.table.append(html_row);