diff --git a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js
index 3eca9b9a018..92f54ff461d 100644
--- a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js
+++ b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js
@@ -3475,14 +3475,15 @@
createChart(chartData) {
const canvas = this.canvas.el;
const ctx = canvas.getContext("2d");
+ // @ts-ignore
this.chart = new window.Chart(ctx, chartData);
}
updateChartJs(chartRuntime) {
const chartData = chartRuntime.chartJsConfig;
if (chartData.data && chartData.data.datasets) {
this.chart.data = chartData.data;
- if (chartData.options?.title) {
- this.chart.config.options.title = chartData.options.title;
+ if (chartData.options?.plugins?.title) {
+ this.chart.config.options.plugins.title = chartData.options.plugins.title;
}
if (chartData.options && "valueLabel" in chartData.options) {
if (chartData.options?.valueLabel) {
@@ -3492,12 +3493,13 @@
}
}
else {
- this.chart.data.datasets = undefined;
+ this.chart.data.datasets = [];
}
- this.chart.config.options.tooltips = chartData.options?.tooltips;
- this.chart.config.options.legend = chartData.options?.legend;
+ this.chart.config.options.plugins.tooltip = chartData.options.plugins.tooltip;
+ this.chart.config.options.plugins.legend = chartData.options.plugins.legend;
this.chart.config.options.scales = chartData.options?.scales;
- this.chart.update({ duration: 0 });
+ // ?
+ this.chart.update("active");
}
}
ChartJsComponent.props = {
@@ -16179,49 +16181,40 @@
* Get a default chart js configuration
*/
function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale }) {
- return {
- type: chart.type,
- options: {
- // https://www.chartjs.org/docs/latest/general/responsive.html
- responsive: true,
- maintainAspectRatio: false,
- layout: {
- padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
+ const options = {
+ // https://www.chartjs.org/docs/latest/general/responsive.html
+ responsive: true,
+ maintainAspectRatio: false,
+ layout: {
+ padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
+ },
+ elements: {
+ line: {
+ fill: false, // do not fill the area under line charts
},
- elements: {
- line: {
- fill: false, // do not fill the area under line charts
- },
- point: {
- hitRadius: 15, // increased hit radius to display point tooltip when hovering nearby
- },
+ point: {
+ hitRadius: 15, // increased hit radius to display point tooltip when hovering nearby
},
- animation: {
- duration: 0, // general animation time
- },
- hover: {
- animationDuration: 10, // duration of animations when hovering an item
- },
- responsiveAnimationDuration: 0,
+ },
+ animation: false,
+ plugins: {
title: {
display: !!chart.title,
- fontSize: 22,
- fontStyle: "normal",
text: _t(chart.title),
- fontColor,
+ color: fontColor,
+ font: { size: 22, weight: "normal" },
},
legend: {
// Disable default legend onClick (show/hide dataset), to allow us to set a global onClick on the chart container.
// If we want to re-enable this in the future, we need to override the default onClick to stop the event propagation
- onClick: undefined,
+ onClick: () => { },
},
- tooltips: {
+ tooltip: {
callbacks: {
- label: function (tooltipItem, data) {
- let xLabel = data.datasets?.[tooltipItem.datasetIndex || 0]?.label;
- const yLabel = tooltipItem.yLabel !== ""
- ? tooltipItem.yLabel
- : data.datasets?.[tooltipItem.datasetIndex || 0]?.data?.[tooltipItem.index || 0];
+ label: function (tooltipItem) {
+ let xLabel = tooltipItem.label;
+ // tooltipItem.parsed.y can be an object or a number for pie charts
+ const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
const yLabelStr = format && typeof yLabel === "number"
? formatValue(yLabel, { format, locale })
: yLabel?.toLocaleString() || "";
@@ -16230,10 +16223,15 @@
},
},
},
+ };
+ return {
+ type: chart.type,
+ options,
data: {
labels: labels.map(truncateLabel),
datasets: [],
},
+ plugins: [],
};
}
function getChartLabelFormat(getters, range) {
@@ -16430,7 +16428,7 @@
const fontColor = chartFontColor(chart.background);
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
const legend = {
- labels: { fontColor },
+ labels: { color: fontColor },
};
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
legend.display = false;
@@ -16438,42 +16436,35 @@
else {
legend.position = chart.legendPosition;
}
- config.options.legend = { ...config.options?.legend, ...legend };
+ config.options.plugins.legend = { ...config.options.plugins?.legend, ...legend };
config.options.layout = {
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
};
config.options.scales = {
- xAxes: [
- {
- ticks: {
- // x axis configuration
- maxRotation: 60,
- minRotation: 15,
- padding: 5,
- labelOffset: 2,
- fontColor,
+ x: {
+ ticks: {
+ padding: 5,
+ color: fontColor,
+ },
+ },
+ y: {
+ position: chart.verticalAxisPosition,
+ beginAtZero: true,
+ ticks: {
+ color: fontColor,
+ callback: (value) => {
+ return localeFormat.format
+ ? formatValue(value, localeFormat)
+ : value?.toLocaleString() || value;
},
},
- ],
- yAxes: [
- {
- position: chart.verticalAxisPosition,
- ticks: {
- fontColor,
- // y axis configuration
- beginAtZero: true,
- callback: (value) => {
- return localeFormat.format
- ? formatValue(value, localeFormat)
- : value?.toLocaleString() || value;
- },
- },
- },
- ],
+ },
};
if (chart.stacked) {
- config.options.scales.xAxes[0].stacked = true;
- config.options.scales.yAxes[0].stacked = true;
+ // @ts-ignore chart.js type is broken
+ config.options.scales.x.stacked = true;
+ // @ts-ignore chart.js type is broken
+ config.options.scales.y.stacked = true;
}
return config;
}
@@ -16677,17 +16668,18 @@
padding: { left: 30, right: 30, top: chart.title ? 10 : 25, bottom: 25 },
};
config.options.needle = {
- radiusPercentage: 2,
- widthPercentage: 3.2,
- lengthPercentage: 80,
- color: "#000000",
+ width: 10,
+ borderColor: "#000000",
+ backgroundColor: "#000000",
};
config.options.valueLabel = {
display: false,
- formatter: null,
- color: "#FFFFFF",
+ font: {
+ size: 30,
+ color: "#FFFFFF",
+ },
backgroundColor: "#000000",
- fontSize: 30,
+ borderColor: "#000000",
borderRadius: 5,
padding: {
top: 5,
@@ -16695,7 +16687,6 @@
bottom: 5,
left: 5,
},
- bottomMarginPercentage: 5,
};
return config;
}
@@ -16737,16 +16728,12 @@
data.push(point.value);
backgroundColor.push(point.color);
});
- // There's a bug in gauge lib when the last element in `data` is 0 (i.e. when the range maximum is 0).
- // The value wrongly fallbacks to 1 because 0 is falsy
- // See https://github.com/haiiaaa/chartjs-gauge/pull/33
- // https://github.com/haiiaaa/chartjs-gauge/blob/2ea50541d754d710cb30c2502fa690ac5dc27afd/src/controllers/controller.gauge.js#L52
data.push(maxNeedleValue);
backgroundColor.push(colors.upperColor);
const dataRange = chart.dataRange;
const deltaBeyondRangeLimit = needleCoverage / 30;
let needleValue = minNeedleValue - deltaBeyondRangeLimit; // make needle value always at the minimum by default
- let cellFormatter = null;
+ let cellFormatter = undefined;
let displayValue = false;
if (dataRange !== undefined) {
const cell = getters.getEvaluatedCell({
@@ -16761,6 +16748,7 @@
// smaller and slightly larger than minRange and maxRange to mark the fact
// that the needle is out of the range limits
needleValue = clip(cell.value, minNeedleValue - deltaBeyondRangeLimit, maxNeedleValue + deltaBeyondRangeLimit);
+ // show the original value, not the clipped one
cellFormatter = () => getters.getRangeFormattedValues(dataRange)[0];
displayValue = true;
}
@@ -16808,31 +16796,29 @@
},
};
/**
- * Regex to test if a format string is a date format that can be translated into a moment time format
+ * Regex to test if a format string is a date format that can be translated into a luxon time format
*/
- const timeFormatMomentCompatible = /^((d|dd|m|mm|yyyy|yy|hh|h|ss|a)(-|:|\s|\/))*(d|dd|m|mm|yyyy|yy|hh|h|ss|a)$/i;
+ const timeFormatLuxonCompatible = /^((d|dd|m|mm|yyyy|yy|hh|h|ss|a)(-|:|\s|\/))*(d|dd|m|mm|yyyy|yy|hh|h|ss|a)$/i;
/** Get the time options for the XAxis of ChartJS */
function getChartTimeOptions(labels, labelFormat, locale) {
- const momentFormat = convertDateFormatForMoment(labelFormat);
- const timeUnit = getBestTimeUnitForScale(labels, momentFormat, locale);
+ const luxonFormat = convertDateFormatForLuxon(labelFormat);
+ const timeUnit = getBestTimeUnitForScale(labels, luxonFormat, locale);
const displayFormats = {};
if (timeUnit) {
- displayFormats[timeUnit] = momentFormat;
+ displayFormats[timeUnit] = luxonFormat;
}
return {
- parser: momentFormat,
+ parser: luxonFormat,
displayFormats,
- unit: timeUnit,
+ unit: timeUnit ?? false,
};
}
/**
* Convert the given date format into a format that moment.js understands.
*
- * https://momentjs.com/docs/#/parsing/string-format/
+ * https://github.com/moment/luxon/blob/master/docs/formatting.md#table-of-tokens
*/
- function convertDateFormatForMoment(format) {
- format = format.replace(/y/g, "Y");
- format = format.replace(/d/g, "D");
+ function convertDateFormatForLuxon(format) {
// "m" before "h" === month, "m" after "h" === minute
const indexH = format.indexOf("h");
if (indexH >= 0) {
@@ -16903,6 +16889,8 @@
return "year";
}
+ // @ts-ignore
+ const Chart = window.Chart;
class LineChart extends AbstractChart {
dataSets;
labelRange;
@@ -17032,7 +17020,7 @@
return canBeDateChart(labelRange, getters) || canBeLinearChart(labelRange, getters);
}
function getChartAxisType(chart, getters) {
- if (isDateChart(chart, getters)) {
+ if (isDateChart(chart, getters) && isLuxonTimeAdapterInstalled()) {
return "time";
}
if (isLinearChart(chart, getters)) {
@@ -17055,7 +17043,7 @@
col: labelRange.zone.left,
row: labelRange.zone.top,
}).format;
- return Boolean(labelFormat && timeFormatMomentCompatible.test(labelFormat));
+ return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
}
function canBeLinearChart(labelRange, getters) {
if (!labelRange) {
@@ -17075,10 +17063,11 @@
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
const legend = {
labels: {
- fontColor,
+ color: fontColor,
generateLabels(chart) {
+ // color the legend labels with the dataset color, without any transparency
const { data } = chart;
- const labels = window.Chart.defaults.global.legend.labels.generateLabels(chart);
+ const labels = Chart.defaults.plugins.legend.labels.generateLabels(chart);
for (const [index, label] of labels.entries()) {
label.fillStyle = data.datasets[index].borderColor;
}
@@ -17092,41 +17081,33 @@
else {
legend.position = chart.legendPosition;
}
- config.options.legend = { ...config.options?.legend, ...legend };
+ Object.assign(config.options.plugins.legend || {}, legend);
config.options.layout = {
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
};
config.options.scales = {
- xAxes: [
- {
- ticks: {
- // x axis configuration
- maxRotation: 60,
- minRotation: 15,
- padding: 5,
- labelOffset: 2,
- fontColor,
+ x: {
+ ticks: {
+ padding: 5,
+ color: fontColor,
+ },
+ },
+ y: {
+ position: chart.verticalAxisPosition,
+ beginAtZero: true,
+ ticks: {
+ color: fontColor,
+ callback: (value) => {
+ return localeFormat.format
+ ? formatValue(value, localeFormat)
+ : value?.toLocaleString() || value;
},
},
- ],
- yAxes: [
- {
- position: chart.verticalAxisPosition,
- ticks: {
- fontColor,
- // y axis configuration
- beginAtZero: true,
- callback: (value) => {
- return localeFormat.format
- ? formatValue(value, localeFormat)
- : value?.toLocaleString() || value;
- },
- },
- },
- ],
+ },
};
- if (chart.stacked) {
- config.options.scales.yAxes[0].stacked = true;
+ if (chart.stacked && config.options?.scales?.y) {
+ // @ts-ignore chart.js type is wrong
+ config.options.scales.y.stacked = true;
}
return config;
}
@@ -17153,15 +17134,18 @@
const config = getLineConfiguration(chart, labels, localeFormat);
const labelFormat = getChartLabelFormat(getters, chart.labelRange);
if (axisType === "time") {
- config.options.scales.xAxes[0].type = "time";
- config.options.scales.xAxes[0].time = getChartTimeOptions(labels, labelFormat, locale);
- config.options.scales.xAxes[0].ticks.maxTicksLimit = 15;
+ const axis = {
+ type: "time",
+ time: getChartTimeOptions(labels, labelFormat, locale),
+ };
+ Object.assign(config.options.scales.x, axis);
+ config.options.scales.x.ticks.maxTicksLimit = 15;
}
else if (axisType === "linear") {
- config.options.scales.xAxes[0].type = "linear";
- config.options.scales.xAxes[0].ticks.callback = (value) => formatValue(value, localeFormat);
- config.options.tooltips.callbacks.title = (tooltipItem) => {
- return formatValue(tooltipItem[0]?.xLabel || "", localeFormat);
+ config.options.scales.x.type = "linear";
+ config.options.scales.x.ticks.callback = (value) => formatValue(value, { format: labelFormat, locale });
+ config.options.plugins.tooltip.callbacks.title = (tooltipItem) => {
+ return formatValue(tooltipItem[0]?.label || "", localeFormat);
};
}
const colors = new ChartColors();
@@ -17179,7 +17163,7 @@
const dataset = {
label,
data,
- lineTension: 0,
+ tension: 0,
borderColor: color,
backgroundColor,
pointBackgroundColor: color,
@@ -17189,6 +17173,22 @@
}
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
}
+ let missingTimeAdapterAlreadyWarned = false;
+ function isLuxonTimeAdapterInstalled() {
+ // @ts-ignore
+ if (!window.Chart) {
+ return false;
+ }
+ // @ts-ignore
+ const adapter = new window.Chart._adapters._date({});
+ // @ts-ignore
+ const isInstalled = adapter._id === "luxon";
+ if (!isInstalled && !missingTimeAdapterAlreadyWarned) {
+ missingTimeAdapterAlreadyWarned = true;
+ console.warn("'chartjs-adapter-luxon' time adapter is not installed. Time scale axes are disabled.");
+ }
+ return isInstalled;
+ }
class PieChart extends AbstractChart {
dataSets;
@@ -17292,7 +17292,7 @@
const fontColor = chartFontColor(chart.background);
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
const legend = {
- labels: { fontColor },
+ labels: { color: fontColor },
};
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
legend.display = false;
@@ -17300,12 +17300,12 @@
else {
legend.position = chart.legendPosition;
}
- config.options.legend = { ...config.options?.legend, ...legend };
+ Object.assign(config.options.plugins.legend || {}, legend);
config.options.layout = {
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
};
- config.options.tooltips.callbacks.title = function (tooltipItems, data) {
- return data.datasets[tooltipItems[0].datasetIndex].label;
+ config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
+ return tooltipItems[0].dataset.label;
};
return config;
}
@@ -18069,6 +18069,278 @@
};
}
+ // @ts-ignore
+ if (window.Chart) {
+ // @ts-ignore
+ const DoughnutController = window.Chart?.DoughnutController;
+ /**
+ * Example :
+ * const chart = new Chart(ctx, {
+ * type: "gauge",
+ * data: {
+ * datasets: [
+ * {
+ * borderWidth: 5,
+ * data: [10, 20, 10],
+ * value: 23,
+ * backgroundColor: [
+ * "#dc3545", //red
+ * "#ffc107", //orange
+ * "#28a745", //green
+ * ],
+ * },
+ * ],
+ * },
+ * options: {
+ * plugins: {
+ * title: {
+ * display: true,
+ * text: "Custom Chart Title",
+ * padding: {
+ * top: 10,
+ * bottom: 30,
+ * },
+ * font : {
+ * size : 30
+ * }
+ * },
+ * },
+ * valueLabel: {
+ * display: true,
+ * format: (value) => {
+ * return value.toFixed(2) + "%";
+ * },
+ * font : {
+ * size : 35,
+ * family : "Arial",
+ * color : "#FC0",
+ * },
+ * backgroundColor : "#ccc",
+ * borderColor : "#090",
+ * borderRadius : 50
+ * },
+ * needle: {
+ * display: true,
+ * width: 50,
+ * color: "#DC5",
+ * backgroundColor : "#ccc",
+ * },
+ * },
+ * });
+ */
+ class GaugeController extends DoughnutController {
+ static id = "gauge";
+ static defaults = {
+ ...DoughnutController.defaults,
+ circumference: 180,
+ rotation: 270,
+ };
+ static overrides = {
+ aspectRatio: 2,
+ plugins: {
+ legend: {
+ display: false,
+ },
+ tooltip: {
+ enabled: false,
+ },
+ },
+ };
+ get chartHeight() {
+ return Math.abs(this.chart.chartArea.top - this.chart.chartArea.bottom);
+ }
+ get chartWidth() {
+ return Math.abs(this.chart.chartArea.left - this.chart.chartArea.right);
+ }
+ get needleOptions() {
+ const { config } = this.chart;
+ const options = config.options;
+ // @ts-ignore
+ return options?.needle || {};
+ }
+ get valueLabelOptions() {
+ const { config } = this.chart;
+ const options = config.options;
+ // @ts-ignore
+ return options?.valueLabel || {};
+ }
+ get minValue() {
+ const dataset = this.getDataset();
+ // @ts-ignore
+ return dataset.minValue || 0;
+ }
+ getValueAngleInPercent(value) {
+ const dataset = this.getDataset();
+ const data = dataset.data || [];
+ const max = Math.max(...data);
+ const min = this.minValue;
+ return (value - min) / (max - min);
+ }
+ drawValueLabel(params) {
+ const { ctx } = this.chart;
+ if (this.valueLabelOptions.display === false) {
+ return;
+ }
+ // draw background rectangle
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = params.valueLabel.backgroundColor;
+ ctx.strokeStyle = params.valueLabel.borderColor;
+ ctx.roundRect(params.valueLabel.rect.x, params.valueLabel.rect.y, params.valueLabel.rect.width, params.valueLabel.rect.height, params.valueLabel.borderRadius);
+ ctx.stroke();
+ ctx.fill();
+ // draw value text
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.font = params.valueLabel.font;
+ ctx.fillStyle = params.valueLabel.textColor;
+ ctx.fillText(params.valueLabel.valueText, params.valueLabel.textPosition.x, params.valueLabel.textPosition.y);
+ ctx.restore();
+ }
+ drawNeedle(params) {
+ const { ctx } = this.chart;
+ if (this.needleOptions.display === false) {
+ return;
+ }
+ // translate & rotate next paths
+ ctx.save();
+ ctx.translate(params.needle.position.x, params.needle.position.y);
+ ctx.rotate(-Math.PI / 2 + Math.PI * params.needle.percent);
+ // draw circle
+ ctx.beginPath();
+ ctx.fillStyle = params.needle.backgroundColor;
+ ctx.strokeStyle = params.needle.borderColor;
+ ctx.ellipse(0, 0, params.needle.width / 2, params.needle.width / 2, 0, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ ctx.closePath();
+ // draw needle
+ ctx.fillStyle = params.needle.backgroundColor;
+ ctx.strokeStyle = params.needle.borderColor;
+ ctx.beginPath();
+ ctx.moveTo(-params.needle.width / 2, 0);
+ ctx.lineTo(0, -params.needle.height + 10);
+ ctx.lineTo(+params.needle.width / 2, 0);
+ ctx.closePath();
+ ctx.fill();
+ ctx.stroke();
+ ctx.restore();
+ }
+ computeRenderingParams() {
+ const { ctx, config } = this.chart;
+ const options = config.options;
+ options.layout = options.layout || {};
+ options.layout.padding = options.layout.padding || {};
+ const formatter = this.valueLabelOptions.formatter;
+ const fmt = typeof formatter === "function" ? formatter : (value) => value;
+ const dataset = this.getDataset();
+ // @ts-ignore value is a custom property for gauge charts
+ const value = dataset.value || 0;
+ const valueText = fmt(value).toString();
+ const percent = this.getValueAngleInPercent(value);
+ const fontFamily = this.valueLabelOptions.font?.family || "Arial";
+ const optionsFontSize = this.valueLabelOptions.font?.size || 0;
+ const fontSize = optionsFontSize >= 1 ? optionsFontSize : 30;
+ const font = `${fontSize}px ${fontFamily}`;
+ const padding = {
+ right: 0,
+ left: 0,
+ top: 0,
+ bottom: 0,
+ ...this.valueLabelOptions.padding,
+ };
+ padding.left = padding.left >= 0 ? padding.left : 10;
+ padding.right = padding.right >= 0 ? padding.right : 10;
+ padding.top = padding.top >= 0 ? padding.top : 10;
+ padding.bottom = padding.bottom >= 0 ? padding.bottom : 10;
+ const chartArea = this.chart.chartArea;
+ const offsetX = this.offsetX || 0;
+ const offsetY = this.offsetY || 0;
+ const centerX = (chartArea.left + chartArea.right) / 2;
+ const centerY = (chartArea.top + chartArea.bottom) / 2;
+ const center = {
+ x: centerX + offsetX,
+ y: centerY + offsetY,
+ };
+ const textPosition = {
+ x: center.x,
+ y: center.y,
+ };
+ ctx.save();
+ ctx.font = font;
+ const metrics = ctx.measureText(valueText);
+ ctx.restore();
+ const textHeight = metrics.fontBoundingBoxAscent - metrics.fontBoundingBoxDescent;
+ return {
+ needle: {
+ borderColor: this.needleOptions.borderColor || "#000",
+ backgroundColor: this.needleOptions.backgroundColor || "#000",
+ width: this.needleOptions.width || 10,
+ height: Math.min(this.chartHeight, this.chartWidth / 2),
+ position: {
+ x: textPosition.x,
+ y: textPosition.y,
+ },
+ percent,
+ },
+ valueLabel: {
+ textColor: this.valueLabelOptions.font?.color || "#FFF",
+ backgroundColor: this.valueLabelOptions.backgroundColor || "#000",
+ borderColor: this.valueLabelOptions.borderColor || "#000",
+ borderRadius: this.valueLabelOptions.borderRadius || 10,
+ rect: {
+ x: center.x - metrics.width / 2 - padding.left,
+ y: center.y + textHeight / 2 + padding.top,
+ width: metrics.width + padding.left + padding.right,
+ height: -(textHeight + 6 + padding.top + padding.bottom),
+ },
+ valueText,
+ textPosition,
+ textHeight,
+ font,
+ },
+ };
+ }
+ draw() {
+ super.draw();
+ const params = this.computeRenderingParams();
+ this.drawNeedle(params);
+ this.drawValueLabel(params);
+ }
+ updateElements(elements, start, count, mode) {
+ super.updateElements(elements, start, count, mode);
+ const dataset = this.getDataset();
+ const data = this.getDataset().data;
+ // @ts-ignore
+ const minValue = dataset.minValue;
+ // @ts-ignore
+ const rotation = this.chart.options.rotation || 0;
+ // @ts-ignore
+ const circumference = this.chart.options.circumference || 0;
+ for (let arcIndex = 0; arcIndex < data.length; arcIndex++) {
+ const previousValue = arcIndex === 0 ? minValue : data[arcIndex - 1];
+ const startAngleInPercent = this.getValueAngleInPercent(previousValue);
+ const endAngleInPercent = this.getValueAngleInPercent(data[arcIndex]);
+ const startAngle = degreesToRadians(rotation + circumference * startAngleInPercent) - Math.PI / 2;
+ const endAngle = degreesToRadians(rotation + circumference * endAngleInPercent) - Math.PI / 2;
+ const arcCircumference = endAngle - startAngle;
+ const arc = elements[arcIndex];
+ const propertiesUpdates = {
+ startAngle,
+ endAngle,
+ circumference: arcCircumference,
+ };
+ this.updateElement(arc, arcIndex, propertiesUpdates, mode);
+ }
+ }
+ }
+ function degreesToRadians(degrees) {
+ return (degrees * Math.PI) / 180;
+ }
+ // @ts-ignore
+ window.Chart.register(GaugeController);
+ }
+
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
@@ -36418,7 +36690,8 @@
if (!chart) {
throw new Error(`No chart for the given id: ${figureId}`);
}
- this.history.update("charts", figureId, this.createRuntimeChart(chart));
+ const runtime = this.createRuntimeChart(chart);
+ this.history.update("charts", figureId, runtime);
}
return this.charts[figureId];
}
@@ -49506,7 +49779,14 @@
`;
}
- const TABLE_DEFAULT_STYLE = escapeXml /*xml*/ ``;
+ const TABLE_DEFAULT_ATTRS = [
+ ["name", "TableStyleLight8"],
+ ["showFirstColumn", "0"],
+ ["showLastColumn", "0"],
+ ["showRowStripes", "0"],
+ ["showColumnStripes", "0"],
+ ];
+ const TABLE_DEFAULT_STYLE = escapeXml /*xml*/ ``;
function createTable(table, tableId, sheetData) {
const tableAttributes = [
["id", tableId],
@@ -50625,9 +50905,9 @@
Object.defineProperty(exports, '__esModule', { value: true });
- __info__.version = '16.5.0-alpha.3';
- __info__.date = '2023-08-09T12:01:15.162Z';
- __info__.hash = 'b0e8fd5';
+ __info__.version = '16.5.0-alpha.4';
+ __info__.date = '2023-08-10T09:44:45.710Z';
+ __info__.hash = 'c8db018';
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
diff --git a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml
index 2691fa8d62e..bde7ae6acf1 100644
--- a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml
+++ b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml
@@ -3951,7 +3951,7 @@