[REF] web_kanban_gauge: reimplement gauge widget with Chart.js

This commit is one part of the task 'removing nvd3'.
We use now Chart.js to draw charts.

Task ID: 1946138
This commit is contained in:
Géry Debongnie
2019-04-01 14:40:51 +00:00
committed by Mathieu Duckerts-Antoine
parent 3ab3082a32
commit 2af74a5f53
2 changed files with 80 additions and 88 deletions
@@ -2,9 +2,12 @@ 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
*
@@ -24,13 +27,8 @@ var utils = require('web.utils');
var GaugeWidget = AbstractField.extend({
className: "oe_gauge",
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'
'/web/static/lib/Chart/Chart.js',
],
//--------------------------------------------------------------------------
@@ -42,98 +40,92 @@ var GaugeWidget = AbstractField.extend({
* @private
*/
_render: function () {
// parameters
var max_value = this.nodeOptions.max_value || 100;
if (this.nodeOptions.max_field) {
max_value = this.recordData[this.nodeOptions.max_field];
}
var label = this.nodeOptions.label || "";
if (this.nodeOptions.label_field) {
label = this.recordData[this.nodeOptions.label_field];
}
var title = this.nodeOptions.title || this.field.string;
// current gauge value
// current value
var val = this.value;
if (_.isArray(JSON.parse(val))) {
val = JSON.parse(val);
}
var value = _.isArray(val) && val.length ? val[val.length-1].value : val;
// displayed value under gauge
var gauge_value = value;
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];
}
var degree = Math.PI/180,
width = 200,
height = 150,
outerRadius = Math.min(width, height)*0.5,
innerRadius = outerRadius*0.7,
fontSize = height/7;
this.$el.empty().attr('style', this.nodeOptions.style + ';position:relative; display:inline-block;');
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(-90*degree);
var svg = d3.select(this.$el[0])
.append("svg")
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox','0 0 '+width +' '+height )
.attr('preserveAspectRatio','xMinYMin')
.append("g")
.attr("transform", "translate(" + (width/2) + "," + (height-(width-height)/2-12) + ")");
function addText(text, fontSize, dx, dy) {
return svg.append("text")
.attr("text-anchor", "middle")
.style("font-size", fontSize+'px')
.attr("dy", dy)
.attr("dx", dx)
.text(text);
// max_value
var max_value = this.nodeOptions.max_value || 100;
if (this.nodeOptions.max_field) {
max_value = this.recordData[this.nodeOptions.max_field];
}
// top title
addText(title, 16, 0, -outerRadius-16).style("font-weight",'bold');
max_value = Math.max(gauge_value, max_value);
// center value
addText(utils.human_number(value, 1), fontSize, 0, -2).style("font-weight",'bold');
// bottom label
addText(0, 8, -(outerRadius+innerRadius)/2, 12);
addText(label, 8, 0, 12);
addText(utils.human_number(max_value, 1), 8, (outerRadius+innerRadius)/2, 12);
// chart
svg.append("path")
.datum({endAngle: Math.PI/2})
.style("fill", "#ddd")
.attr("d", arc);
var foreground = svg.append("path")
.datum({endAngle: 0})
.style("fill", "hsl(0,80%,50%)")
.attr("d", arc);
var ratio = max_value ? value/max_value : 0;
var hue = Math.round(ratio*120);
foreground.transition()
.style("fill", "hsl(" + hue + ",80%,50%)")
.duration(1500)
.call(arcTween, (ratio-0.5)*Math.PI);
function arcTween (transition, newAngle) {
transition.attrTween("d", function(d) {
var interpolate = d3.interpolate(d.endAngle, newAngle);
return function (t) {
d.endAngle = interpolate(t);
return arc(d);
};
});
// 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 = $('<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 = $('<span class="o_gauge_value">').text(humanValue);
$value.css({'text-align': 'center', position: 'absolute', left: 0, right: 0, bottom: '6px', 'font-weight': 'bold'});
this.$el.append($value);
},
});
@@ -38,7 +38,7 @@ QUnit.module('basic_fields', {
'</t></templates></kanban>',
});
assert.containsOnce(kanban, '.o_kanban_record:first .oe_gauge svg',
assert.containsOnce(kanban, '.o_kanban_record:first .oe_gauge canvas',
"should render the gauge widget");
kanban.destroy();