diff --git a/addons/web/__manifest__.py b/addons/web/__manifest__.py index bbfe3a134a0..e14aa45c82e 100644 --- a/addons/web/__manifest__.py +++ b/addons/web/__manifest__.py @@ -25,6 +25,7 @@ This module provides the core of the Odoo Web Client. "static/src/xml/base.xml", "static/src/xml/kanban.xml", "static/src/xml/menu.xml", + "static/src/xml/pie_chart.xml", "static/src/xml/rainbow_man.xml", "static/src/xml/report.xml", "static/src/xml/web_calendar.xml", diff --git a/addons/web/static/src/js/widgets/pie_chart.js b/addons/web/static/src/js/widgets/pie_chart.js index def6147fb05..85e4a8121ec 100644 --- a/addons/web/static/src/js/widgets/pie_chart.js +++ b/addons/web/static/src/js/widgets/pie_chart.js @@ -4,187 +4,83 @@ odoo.define('web.PieChart', function (require) { /** * This widget render a Pie Chart. It is used in the dashboard view. */ -var ajax = require('web.ajax'); -var config = require('web.config'); + +var core = require('web.core'); +var Domain = require('web.Domain'); +var viewRegistry = require('web.view_registry'); var Widget = require('web.Widget'); var widgetRegistry = require('web.widget_registry'); -var GROUPABLE_TYPES = ['many2one', 'char', 'boolean', 'selection', 'date', 'datetime']; +var qweb = core.qweb; var PieChart = Widget.extend({ className: 'o_pie_chart', - cssLibs: [ - '/web/static/lib/nvd3/nv.d3.css' - ], - jsLibs: [ - '/web/static/lib/nvd3/d3.v3.js', - '/web/static/lib/nvd3/nv.d3.js', - '/web/static/src/js/libs/nvd3.js' - ], + xmlDependencies: ['/web/static/src/xml/pie_chart.xml'], /** - * override - * + * @override * @param {Widget} parent * @param {Object} record - * @param {Object} node + * @param {Object} node node from arch */ init: function (parent, record, node) { - this._super(parent); + this._super.apply(this, arguments); - this.record = record; - this.model = record.model; + var modifiers = node.attrs.modifiers; + var domain = record.domain.concat( + Domain.prototype.stringToArray(modifiers.domain || '[]')); + var arch = qweb.render('web.PieChart', { + modifiers: modifiers, + }); - if (node.attrs.modifiers) { - this.measure = node.attrs.modifiers.measure || ''; - this.measureField = this.record.fields[this.measure]; - this.groupBy = node.attrs.modifiers.groupby.split(':')[0] || ''; - this.interval = node.attrs.modifiers.groupby.split(':')[1]; + this.subViewParams = { + context: record.context, + domain: domain, + groupBy: [], + modelName: record.model, + withControlPanel: false, + isEmbedded: true, + mode: 'pie', + title: modifiers.title || modifiers.measure || '', + }; - if (!_.contains(Object.keys(this.record.fields), this.groupBy)) { - return; - } - - this.groupByField = this.record.fields[this.groupBy]; - this.groupByType = this.groupByField.type; - this.title = node.attrs.modifiers.title || this.measure || ''; - this.trueLabel = node.attrs.modifiers.trueLabel || 'True'; - this.falseLabel = node.attrs.modifiers.falseLabel || 'False'; - } + this.viewInfo = { + arch: arch, + fields: record.fields, + viewFields: record.fieldsInfo.dashboard, + }; }, /** - * override + * Instantiates the pie chart view and starts the graph controller. + * + * @override */ willStart: function () { var self = this; - this.data = []; + var def1 = this._super.apply(this, arguments); - var query = { - model: this.model, - method: 'read_group', - domain: [], - groupBy: [this.groupBy + (this.interval ? ':' + this.interval : '')], - fields: [this.measure], - lazy: false, - }; - - // Handle case where measure attribute is missing. - query.fields = this.measure ? [this.measure] : []; - - return $.when(this._rpc(query), ajax.loadLibs(this)).then( - function (result) { - if (result) { - if (_.contains(GROUPABLE_TYPES, self.groupByType)) { - for (var i = 0; i < result.length; i++) { - var value = result[i][self.measure]; - var label = undefined; - var interval = self.interval ? ':' + self.interval : ''; - var groupby = self.groupBy + interval; - - switch (self.groupByType) { - case 'boolean': - label = ['False', 'True'][i]; - break; - case 'many2one': - label = result[i][groupby][1]; - break; - default: - label = result[i][groupby]; - } - - self.data.push({ - 'label': label, - 'value': value, - }); - } - } - } - }); - }, - - /** - * This method ensure that Pie Chart is attached to DOM before being rendered. - * - * If we don't do that, Pie Chart can be rendered without being aware of the - * size of its container, it is then rendered with a size of 0 0 and remains - * invisible (even with a good lens). - */ - on_attach_callback: function() { - this._render(); - }, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - /** - * @private - */ - _render: function () { - // Note: The rendering of this widget is aynchronous as NVD3 does a - // setTimeout(0) before executing the callback given to addGraph. - var self = this; - if(!this.data || !_.isArray(this.data)) { - return; - } - - var $label = this._renderLabel(this.title); - this.$el.empty(); - $label.appendTo(this.$el); - $('').appendTo(this.$el); - - var legend_right = config.device.size_class > config.device.SIZES.XS; - var legendPosition = legend_right ? 'right' : 'top'; - var color = d3.scale.category10().range(); - - nv.addGraph(function () { - self.chart = nv.models.pieChart() - .x(function(d) { return d.label }) - .y(function(d) { return d.value }) - .legendPosition(legendPosition) - .labelType('percent') - .showLabels(true) - .showLegend(true) - .color(color); - - self.chart.legend.rightAlign(false); - self.chart.legend.align(true); - self.chart.legend.expanded(true); - - d3.select(self.$('svg')[0]) - .datum(self.data) - .transition().duration(0) - .call(self.chart); - self.chart.update(); + var SubView = viewRegistry.get('graph'); + var subView = new SubView(this.viewInfo, this.subViewParams); + var def2 = subView.getController(this).then(function (controller) { + self.controller = controller; + return self.controller.appendTo(document.createDocumentFragment()); }); + return $.when(def1, def2); }, /** - * @private - * @param {any} value - * @param {any} field - * @returns {string} + * @override */ - _getNumberedValue: function (value, field) { - var id = value[0]; - var name = value[1]; - this.numbering[field] = this.numbering[field] || {}; - this.numbering[field][name] = this.numbering[field][name] || {}; - var numbers = this.numbering[field][name]; - numbers[id] = numbers[id] || _.size(numbers) + 1; - return name + (numbers[id] > 1 ? " (" + numbers[id] + ")" : ""); + start: function () { + this.$el.append(this.controller.$el); + return this._super.apply(this, arguments); }, - /** - * Renders a pie chart's label. + /** + * Call `on_attach_callback` for each subview * - * @private - * @param {String} title - * @returns {jQueryElement} + * @override */ - _renderLabel: function (title) { - var $result = $('