From 3751379f1e9a4c215fb6eb898b4ccc67659b9ace Mon Sep 17 00:00:00 2001 From: stephanchrst Date: Tue, 10 May 2022 21:51:50 +0700 Subject: initial commit 2 --- .../web_kanban_gauge/static/src/js/kanban_gauge.js | 136 +++++++++++++++++++++ .../web_kanban_gauge/static/tests/gauge_tests.js | 49 ++++++++ 2 files changed, 185 insertions(+) create mode 100644 addons/web_kanban_gauge/static/src/js/kanban_gauge.js create mode 100644 addons/web_kanban_gauge/static/tests/gauge_tests.js (limited to 'addons/web_kanban_gauge/static') diff --git a/addons/web_kanban_gauge/static/src/js/kanban_gauge.js b/addons/web_kanban_gauge/static/src/js/kanban_gauge.js new file mode 100644 index 00000000..b050c71c --- /dev/null +++ b/addons/web_kanban_gauge/static/src/js/kanban_gauge.js @@ -0,0 +1,136 @@ +odoo.define('web_kanban_gauge.widget', function (require) { +"use strict"; + +var AbstractField = require('web.AbstractField'); +var core = require('web.core'); +var field_registry = require('web.field_registry'); +var utils = require('web.utils'); + +var _t = core._t; + +/** + * options + * + * - max_value: maximum value of the gauge [default: 100] + * - max_field: get the max_value from the field that must be present in the + * view; takes over max_value + * - gauge_value_field: if set, the value displayed below the gauge is taken + * from this field instead of the base field used for + * the gauge. This allows to display a number different + * from the gauge. + * - label: lable of the gauge, displayed below the gauge value + * - label_field: get the label from the field that must be present in the + * view; takes over label + * - title: title of the gauge, displayed on top of the gauge + * - style: custom style + */ + +var GaugeWidget = AbstractField.extend({ + className: "oe_gauge", + jsLibs: [ + '/web/static/lib/Chart/Chart.js', + ], + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + * @private + */ + _render: function () { + // current value + var val = this.value; + if (_.isArray(JSON.parse(val))) { + val = JSON.parse(val); + } + var gauge_value = _.isArray(val) && val.length ? val[val.length-1].value : val; + if (this.nodeOptions.gauge_value_field) { + gauge_value = this.recordData[this.nodeOptions.gauge_value_field]; + } + + // max_value + var max_value = this.nodeOptions.max_value || 100; + if (this.nodeOptions.max_field) { + max_value = this.recordData[this.nodeOptions.max_field]; + } + max_value = Math.max(gauge_value, max_value); + + // label + var label = this.nodeOptions.label || ""; + if (this.nodeOptions.label_field) { + label = this.recordData[this.nodeOptions.label_field]; + } + + // title + var title = this.nodeOptions.title || this.field.string; + + var maxLabel = max_value; + if (gauge_value === 0 && max_value === 0) { + max_value = 1; + maxLabel = 0; + } + var config = { + type: 'doughnut', + data: { + datasets: [{ + data: [ + gauge_value, + max_value - gauge_value + ], + backgroundColor: [ + "#1f77b4", "#dddddd" + ], + label: title + }], + }, + options: { + circumference: Math.PI, + rotation: -Math.PI, + responsive: true, + tooltips: { + displayColors: false, + callbacks: { + label: function(tooltipItems) { + if (tooltipItems.index === 0) { + return _t('Value: ') + gauge_value; + } + return _t('Max: ') + maxLabel; + }, + }, + }, + title: { + display: true, + text: title, + padding: 4, + }, + layout: { + padding: { + bottom: 5 + } + }, + maintainAspectRatio: false, + cutoutPercentage: 70, + } + }; + this.$canvas = $(''); + this.$el.empty(); + this.$el.append(this.$canvas); + this.$el.attr('style', this.nodeOptions.style); + this.$el.css({position: 'relative'}); + var context = this.$canvas[0].getContext('2d'); + this.chart = new Chart(context, config); + + var humanValue = utils.human_number(gauge_value, 1); + var $value = $('').text(humanValue); + $value.css({'text-align': 'center', position: 'absolute', left: 0, right: 0, bottom: '6px', 'font-weight': 'bold'}); + this.$el.append($value); + }, +}); + +field_registry.add("gauge", GaugeWidget); + +return GaugeWidget; + +}); diff --git a/addons/web_kanban_gauge/static/tests/gauge_tests.js b/addons/web_kanban_gauge/static/tests/gauge_tests.js new file mode 100644 index 00000000..552e6fab --- /dev/null +++ b/addons/web_kanban_gauge/static/tests/gauge_tests.js @@ -0,0 +1,49 @@ +odoo.define('web_kanban_gauge.gauge_tests', function (require) { +"use strict"; + +var KanbanView = require('web.KanbanView'); +var testUtils = require('web.test_utils'); + +var createView = testUtils.createView; + +QUnit.module('fields', {}, function () { + +QUnit.module('basic_fields', { + beforeEach: function () { + this.data = { + partner: { + fields: { + int_field: {string: "int_field", type: "integer", sortable: true}, + }, + records: [ + {id: 1, int_field: 10}, + {id: 2, int_field: 4}, + ] + }, + }; + } +}, function () { + + QUnit.module('gauge widget'); + + QUnit.test('basic rendering', async function (assert) { + assert.expect(1); + + var kanban = await createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '' + + '
' + + '
', + }); + + assert.containsOnce(kanban, '.o_kanban_record:first .oe_gauge canvas', + "should render the gauge widget"); + + kanban.destroy(); + }); + +}); +}); +}); -- cgit v1.2.3