[REF] reimplement journal dashboard 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 2af74a5f53
commit 769806ad13
4 changed files with 112 additions and 308 deletions
+96 -119
View File
@@ -2483,35 +2483,16 @@ var FieldToggleBoolean = AbstractField.extend({
var JournalDashboardGraph = AbstractField.extend({
className: "o_dashboard_graph",
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',
],
init: function () {
this._super.apply(this, arguments);
this.graph_type = this.attrs.graph_type;
this.data = JSON.parse(this.value);
},
start: function () {
this._onResize = this._onResize.bind(this);
nv.utils.windowResize(this._onResize);
return this._super.apply(this, arguments);
},
destroy: function () {
if ('nv' in window && nv.utils && nv.utils.offWindowResize) {
// if the widget is destroyed before the lazy loaded libs (nv) are
// actually loaded (i.e. after the widget has actually started),
// nv is undefined, but the handler isn't bound yet anyway
nv.utils.offWindowResize(this._onResize);
}
this._super.apply(this, arguments);
},
/**
* The widget view uses the nv(d3) lib to render the graph. This lib
* The widget view uses the ChartJS lib to render the graph. This lib
* requires that the rendering is done directly into the DOM (so that it can
* correctly compute positions). However, the views are always rendered in
* fragments, and appended to the DOM once ready (to prevent them from
@@ -2535,23 +2516,7 @@ var JournalDashboardGraph = AbstractField.extend({
//--------------------------------------------------------------------------
/**
* @private
*/
_customizeChart: function () {
if (this.graph_type === 'bar') {
// Add classes related to time on each bar of the bar chart
var bar_classes = _.map(this.data[0].values, function (v) {return v.type; });
_.each(this.$('.nv-bar'), function (v, k){
// classList doesn't work with phantomJS & addClass doesn't work with a SVG element
$(v).attr('class', $(v).attr('class') + ' ' + bar_classes[k]);
});
}
},
/**
* Render the widget only when it is in the DOM. This is because nvd3
* renders graph only when it is in DOM, apparently to compute available
* height and width for instance.
* Render the widget only when it is in the DOM.
*
* @override
* @private
@@ -2568,89 +2533,101 @@ var JournalDashboardGraph = AbstractField.extend({
* @private
*/
_renderInDOM: 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;
this.$el.empty();
this.chart = null;
nv.addGraph(function () {
self.$svg = self.$el.append('<svg>');
switch (self.graph_type) {
case "line":
self.$svg.addClass('o_graph_linechart');
self.chart = nv.models.lineChart();
self.chart.forceY([0]);
self.chart.options({
x: function (d, u) { return u; },
margin: {'left': 0, 'right': 0, 'top': 5, 'bottom': 0},
showYAxis: false,
showLegend: false,
});
self.chart.xAxis.tickFormat(function (d) {
var label = '';
_.each(self.data, function (v){
if (v.values[d] && v.values[d].x){
label = v.values[d].x;
}
});
return label;
});
self.chart.yAxis.tickFormat(d3.format(',.2f'));
self.chart.tooltip.contentGenerator(function (key) {
return qweb.render('GraphCustomTooltip', {
'color': key.point.color,
'key': self.data[0].key,
'value': d3.format(',.2f')(key.point.y)
});
});
break;
case "bar":
self.$svg.addClass('o_graph_barchart');
self.chart = nv.models.discreteBarChart()
.x(function (d) { return d.label; })
.y(function (d) { return d.value; })
.showValues(false)
.showYAxis(false)
.color(['#875A7B', '#526774', '#FA8072'])
.margin({'left': 0, 'right': 0, 'top': 20, 'bottom': 20});
self.chart.xAxis.axisLabel(self.data[0].title);
self.chart.yAxis.tickFormat(d3.format(',.2f'));
self.chart.tooltip.contentGenerator(function (key) {
return qweb.render('GraphCustomTooltip', {
'color': key.color,
'key': self.data[0].key,
'value': d3.format(',.2f')(key.data.value)
});
});
break;
}
d3.select(self.$('svg')[0])
.datum(self.data)
.transition().duration(600)
.call(self.chart);
self._customizeChart();
});
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
*/
_onResize: function () {
if (this.chart) {
this.chart.update();
this._customizeChart();
var config, cssClass;
if (this.graph_type === 'line') {
config = this._getLineChartConfig();
cssClass = 'o_graph_linechart';
} else if (this.graph_type === 'bar') {
config = this._getBarChartConfig();
cssClass = 'o_graph_barchart';
}
this.$canvas = $('<canvas/>');
this.$el.addClass(cssClass);
this.$el.empty();
this.$el.append(this.$canvas);
var context = this.$canvas[0].getContext('2d');
this.chart = new Chart(context, config);
},
_getLineChartConfig: function () {
var labels = this.data[0].values.map(function (pt) {
return pt.x;
});
var borderColor = this.data[0].is_sample_data ? '#dddddd' : '#875a7b';
var backgroundColor = this.data[0].is_sample_data ? '#ebebeb' : '#dcd0d9';
return {
type: 'line',
data: {
labels: labels,
datasets: [{
data: this.data[0].values,
fill: 'start',
label: this.data[0].key,
backgroundColor: backgroundColor,
borderColor: borderColor,
borderWidth: 2,
}]
},
options: {
legend: {display: false},
scales: {
yAxes: [{display: false}],
xAxes: [{display: false}]
},
maintainAspectRatio: false,
elements: {
line: {
tension: 0.000001
}
},
tooltips: {
intersect: false,
position: 'nearest',
caretSize: 0,
},
},
};
},
_getBarChartConfig: function () {
var data = [];
var labels = [];
var backgroundColor = [];
this.data[0].values.forEach(function (pt) {
data.push(pt.value);
labels.push(pt.label);
var color = pt.type === 'past' ? '#ccbdc8' : (pt.type === 'future' ? '#a5d8d7' : '#ebebeb');
backgroundColor.push(color);
});
return {
type: 'bar',
data: {
labels: labels,
datasets: [{
data: data,
fill: 'start',
label: this.data[0].key,
backgroundColor: backgroundColor,
}]
},
options: {
legend: {display: false},
scales: {
yAxes: [{display: false}],
},
maintainAspectRatio: false,
tooltips: {
intersect: false,
position: 'nearest',
caretSize: 0,
},
elements: {
line: {
tension: 0.000001
}
},
},
};
},
});