[FIX] spreadsheet: Introducing stacked line charts

Allow users to use stacked line charts. The chart.js configuration
is mimicking the one inside Odoo community.

task 2888350

closes odoo/odoo#102312

X-original-commit: 1ccb2cd685c60eecd767eb15967d4b4c25262ded
Related: odoo/enterprise#32345
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
Signed-off-by: Rémi Rahir (rar) <rar@odoo.com>
This commit is contained in:
Rémi Rahir
2022-10-06 12:04:44 +02:00
parent fdb0079e90
commit e88bc0b040
3 changed files with 79 additions and 9 deletions
@@ -3,21 +3,31 @@
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
import { _t } from "@web/core/l10n/translation";
import { OdooChart } from "./odoo_chart";
import { LINE_FILL_TRANSPARENCY } from "@web/views/graph/graph_renderer";
const { chartRegistry } = spreadsheet.registries;
const { getDefaultChartJsRuntime, chartFontColor, ChartColors } = spreadsheet.helpers;
const {
getDefaultChartJsRuntime,
chartFontColor,
ChartColors,
getFillingMode,
colorToRGBA,
rgbaToHex,
} = spreadsheet.helpers;
export class OdooLineChart extends OdooChart {
constructor(definition, sheetId, getters) {
super(definition, sheetId, getters);
this.verticalAxisPosition = definition.verticalAxisPosition;
this.stacked = definition.stacked;
}
getDefinition() {
return {
...super.getDefinition(),
verticalAxisPosition: this.verticalAxisPosition,
stacked: this.stacked,
};
}
}
@@ -38,14 +48,22 @@ function createOdooChartRuntime(chart, getters) {
const { datasets, labels } = chart.dataSource.getData();
const chartJsConfig = getLineConfiguration(chart, labels);
const colors = new ChartColors();
for (const { label, data } of datasets) {
for (const [index, { label, data }] of datasets.entries()) {
const color = colors.next();
const backgroundRGBA = colorToRGBA(color);
if (chart.stacked) {
// use the transparency of Odoo to keep consistency
backgroundRGBA.a = LINE_FILL_TRANSPARENCY;
}
const backgroundColor = rgbaToHex(backgroundRGBA);
const dataset = {
label,
data,
lineTension: 0,
borderColor: color,
backgroundColor: color,
backgroundColor,
pointBackgroundColor: color,
fill: chart.stacked ? getFillingMode(index) : false,
};
chartJsConfig.data.datasets.push(dataset);
}
@@ -59,7 +77,17 @@ function getLineConfiguration(chart, labels) {
const legend = {
...config.options.legend,
display: chart.legendPosition !== "none",
labels: { fontColor },
labels: {
fontColor,
generateLabels(chart) {
const { data } = chart;
const labels = window.Chart.defaults.global.legend.labels.generateLabels(chart);
for (const [index, label] of labels.entries()) {
label.fillStyle = data.datasets[index].borderColor;
}
return labels;
},
},
};
legend.position = chart.legendPosition;
config.options.legend = legend;
@@ -90,5 +118,8 @@ function getLineConfiguration(chart, labels) {
},
],
};
if (chart.stacked) {
config.options.scales.yAxes[0].stacked = true;
}
return config;
}
@@ -133,11 +133,13 @@ QUnit.module("spreadsheet > odoo chart plugin", {}, () => {
assert.deepEqual(model.getters.getChartRuntime(chartId).chartJsConfig.data, {
datasets: [
{
backgroundColor: "rgb(31,119,180)",
backgroundColor: "#1f77b466",
borderColor: "rgb(31,119,180)",
data: [1, 3],
label: "Count",
lineTension: 0,
fill: "origin",
pointBackgroundColor: "rgb(31,119,180)",
},
],
labels: ["false", "true"],
@@ -362,4 +364,39 @@ QUnit.module("spreadsheet > odoo chart plugin", {}, () => {
"The datasource is also duplicated"
);
});
QUnit.test("Line chart with stacked attribute is supported", async (assert) => {
const { model } = await createSpreadsheetWithGraph({ type: "odoo_line" });
const sheetId = model.getters.getActiveSheetId();
const chartId = model.getters.getChartIds(sheetId)[0];
const definition = model.getters.getChartDefinition(chartId);
model.dispatch("UPDATE_CHART", {
definition: {
...definition,
stacked: true,
},
id: chartId,
sheetId,
});
assert.notOk(
model.getters.getChartRuntime(chartId).chartJsConfig.options.scales.xAxes[0].stacked
);
assert.ok(
model.getters.getChartRuntime(chartId).chartJsConfig.options.scales.yAxes[0].stacked
);
model.dispatch("UPDATE_CHART", {
definition: {
...definition,
stacked: false,
},
id: chartId,
sheetId,
});
assert.notOk(
model.getters.getChartRuntime(chartId).chartJsConfig.options.scales.xAxes[0].stacked
);
assert.notOk(
model.getters.getChartRuntime(chartId).chartJsConfig.options.scales.yAxes[0].stacked
);
});
});
@@ -12,6 +12,8 @@ const { Component, onWillUnmount, useEffect, useRef, onWillStart } = owl;
const NO_DATA = _lt("No data");
export const LINE_FILL_TRANSPARENCY = 0.4;
/**
* @param {Object} chartArea
* @returns {string}
@@ -23,7 +25,7 @@ function getMaxWidth(chartArea) {
/**
* Used to avoid too long legend items.
* @param {string|Strin} label
* @param {string} label
* @returns {string} shortened version of the input label
*/
function shortenLabel(label) {
@@ -325,7 +327,7 @@ export class GraphRenderer extends Component {
if (groupBy.length <= 1 && domains.length > 1) {
if (dataset.originIndex === 0) {
dataset.fill = "origin";
dataset.backgroundColor = hexToRGBA(getColor(0), 0.4);
dataset.backgroundColor = hexToRGBA(getColor(0), LINE_FILL_TRANSPARENCY);
dataset.borderColor = getColor(0);
} else if (dataset.originIndex === 1) {
dataset.borderColor = getColor(1);
@@ -346,7 +348,7 @@ export class GraphRenderer extends Component {
dataset.pointBackgroundColor = dataset.borderColor;
dataset.pointBorderColor = "rgba(0,0,0,0.2)";
if (stacked) {
dataset.backgroundColor = hexToRGBA(dataset.borderColor, 0.4);
dataset.backgroundColor = hexToRGBA(dataset.borderColor, LINE_FILL_TRANSPARENCY);
}
if (cumulated) {
let accumulator = 0;
@@ -359,7 +361,7 @@ export class GraphRenderer extends Component {
if (data.datasets.length === 1 && data.datasets[0].originIndex === 0) {
const dataset = data.datasets[0];
dataset.fill = "origin";
dataset.backgroundColor = hexToRGBA(getColor(0), 0.4);
dataset.backgroundColor = hexToRGBA(getColor(0), LINE_FILL_TRANSPARENCY);
}
// center the points in the chart (without that code they are put
// on the left and the graph seems empty)