@odoo/o-spreadsheet 16.5.0-alpha.3 → 16.5.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +418 -138
- package/dist/o-spreadsheet.d.ts +31 -23
- package/dist/o-spreadsheet.esm.js +418 -138
- package/dist/o-spreadsheet.iife.js +418 -138
- package/dist/o-spreadsheet.iife.min.js +241 -241
- package/package.json +5 -4
|
@@ -3475,14 +3475,15 @@
|
|
|
3475
3475
|
createChart(chartData) {
|
|
3476
3476
|
const canvas = this.canvas.el;
|
|
3477
3477
|
const ctx = canvas.getContext("2d");
|
|
3478
|
+
// @ts-ignore
|
|
3478
3479
|
this.chart = new window.Chart(ctx, chartData);
|
|
3479
3480
|
}
|
|
3480
3481
|
updateChartJs(chartRuntime) {
|
|
3481
3482
|
const chartData = chartRuntime.chartJsConfig;
|
|
3482
3483
|
if (chartData.data && chartData.data.datasets) {
|
|
3483
3484
|
this.chart.data = chartData.data;
|
|
3484
|
-
if (chartData.options?.title) {
|
|
3485
|
-
this.chart.config.options.title = chartData.options.title;
|
|
3485
|
+
if (chartData.options?.plugins?.title) {
|
|
3486
|
+
this.chart.config.options.plugins.title = chartData.options.plugins.title;
|
|
3486
3487
|
}
|
|
3487
3488
|
if (chartData.options && "valueLabel" in chartData.options) {
|
|
3488
3489
|
if (chartData.options?.valueLabel) {
|
|
@@ -3492,12 +3493,13 @@
|
|
|
3492
3493
|
}
|
|
3493
3494
|
}
|
|
3494
3495
|
else {
|
|
3495
|
-
this.chart.data.datasets =
|
|
3496
|
+
this.chart.data.datasets = [];
|
|
3496
3497
|
}
|
|
3497
|
-
this.chart.config.options.
|
|
3498
|
-
this.chart.config.options.legend = chartData.options
|
|
3498
|
+
this.chart.config.options.plugins.tooltip = chartData.options.plugins.tooltip;
|
|
3499
|
+
this.chart.config.options.plugins.legend = chartData.options.plugins.legend;
|
|
3499
3500
|
this.chart.config.options.scales = chartData.options?.scales;
|
|
3500
|
-
|
|
3501
|
+
// ?
|
|
3502
|
+
this.chart.update("active");
|
|
3501
3503
|
}
|
|
3502
3504
|
}
|
|
3503
3505
|
ChartJsComponent.props = {
|
|
@@ -16179,49 +16181,40 @@
|
|
|
16179
16181
|
* Get a default chart js configuration
|
|
16180
16182
|
*/
|
|
16181
16183
|
function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale }) {
|
|
16182
|
-
|
|
16183
|
-
|
|
16184
|
-
|
|
16185
|
-
|
|
16186
|
-
|
|
16187
|
-
|
|
16188
|
-
|
|
16189
|
-
|
|
16190
|
-
|
|
16191
|
-
|
|
16192
|
-
line: {
|
|
16193
|
-
fill: false, // do not fill the area under line charts
|
|
16194
|
-
},
|
|
16195
|
-
point: {
|
|
16196
|
-
hitRadius: 15, // increased hit radius to display point tooltip when hovering nearby
|
|
16197
|
-
},
|
|
16198
|
-
},
|
|
16199
|
-
animation: {
|
|
16200
|
-
duration: 0, // general animation time
|
|
16184
|
+
const options = {
|
|
16185
|
+
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
16186
|
+
responsive: true,
|
|
16187
|
+
maintainAspectRatio: false,
|
|
16188
|
+
layout: {
|
|
16189
|
+
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
16190
|
+
},
|
|
16191
|
+
elements: {
|
|
16192
|
+
line: {
|
|
16193
|
+
fill: false, // do not fill the area under line charts
|
|
16201
16194
|
},
|
|
16202
|
-
|
|
16203
|
-
|
|
16195
|
+
point: {
|
|
16196
|
+
hitRadius: 15, // increased hit radius to display point tooltip when hovering nearby
|
|
16204
16197
|
},
|
|
16205
|
-
|
|
16198
|
+
},
|
|
16199
|
+
animation: false,
|
|
16200
|
+
plugins: {
|
|
16206
16201
|
title: {
|
|
16207
16202
|
display: !!chart.title,
|
|
16208
|
-
fontSize: 22,
|
|
16209
|
-
fontStyle: "normal",
|
|
16210
16203
|
text: _t(chart.title),
|
|
16211
|
-
fontColor,
|
|
16204
|
+
color: fontColor,
|
|
16205
|
+
font: { size: 22, weight: "normal" },
|
|
16212
16206
|
},
|
|
16213
16207
|
legend: {
|
|
16214
16208
|
// Disable default legend onClick (show/hide dataset), to allow us to set a global onClick on the chart container.
|
|
16215
16209
|
// If we want to re-enable this in the future, we need to override the default onClick to stop the event propagation
|
|
16216
|
-
onClick:
|
|
16210
|
+
onClick: () => { },
|
|
16217
16211
|
},
|
|
16218
|
-
|
|
16212
|
+
tooltip: {
|
|
16219
16213
|
callbacks: {
|
|
16220
|
-
label: function (tooltipItem
|
|
16221
|
-
let xLabel =
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
: data.datasets?.[tooltipItem.datasetIndex || 0]?.data?.[tooltipItem.index || 0];
|
|
16214
|
+
label: function (tooltipItem) {
|
|
16215
|
+
let xLabel = tooltipItem.label;
|
|
16216
|
+
// tooltipItem.parsed.y can be an object or a number for pie charts
|
|
16217
|
+
const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
|
|
16225
16218
|
const yLabelStr = format && typeof yLabel === "number"
|
|
16226
16219
|
? formatValue(yLabel, { format, locale })
|
|
16227
16220
|
: yLabel?.toLocaleString() || "";
|
|
@@ -16230,10 +16223,15 @@
|
|
|
16230
16223
|
},
|
|
16231
16224
|
},
|
|
16232
16225
|
},
|
|
16226
|
+
};
|
|
16227
|
+
return {
|
|
16228
|
+
type: chart.type,
|
|
16229
|
+
options,
|
|
16233
16230
|
data: {
|
|
16234
16231
|
labels: labels.map(truncateLabel),
|
|
16235
16232
|
datasets: [],
|
|
16236
16233
|
},
|
|
16234
|
+
plugins: [],
|
|
16237
16235
|
};
|
|
16238
16236
|
}
|
|
16239
16237
|
function getChartLabelFormat(getters, range) {
|
|
@@ -16430,7 +16428,7 @@
|
|
|
16430
16428
|
const fontColor = chartFontColor(chart.background);
|
|
16431
16429
|
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
|
|
16432
16430
|
const legend = {
|
|
16433
|
-
labels: { fontColor },
|
|
16431
|
+
labels: { color: fontColor },
|
|
16434
16432
|
};
|
|
16435
16433
|
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
|
|
16436
16434
|
legend.display = false;
|
|
@@ -16438,42 +16436,35 @@
|
|
|
16438
16436
|
else {
|
|
16439
16437
|
legend.position = chart.legendPosition;
|
|
16440
16438
|
}
|
|
16441
|
-
config.options.legend = { ...config.options?.legend, ...legend };
|
|
16439
|
+
config.options.plugins.legend = { ...config.options.plugins?.legend, ...legend };
|
|
16442
16440
|
config.options.layout = {
|
|
16443
16441
|
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
16444
16442
|
};
|
|
16445
16443
|
config.options.scales = {
|
|
16446
|
-
|
|
16447
|
-
{
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
maxRotation: 60,
|
|
16451
|
-
minRotation: 15,
|
|
16452
|
-
padding: 5,
|
|
16453
|
-
labelOffset: 2,
|
|
16454
|
-
fontColor,
|
|
16455
|
-
},
|
|
16444
|
+
x: {
|
|
16445
|
+
ticks: {
|
|
16446
|
+
padding: 5,
|
|
16447
|
+
color: fontColor,
|
|
16456
16448
|
},
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
? formatValue(value, localeFormat)
|
|
16468
|
-
: value?.toLocaleString() || value;
|
|
16469
|
-
},
|
|
16449
|
+
},
|
|
16450
|
+
y: {
|
|
16451
|
+
position: chart.verticalAxisPosition,
|
|
16452
|
+
beginAtZero: true,
|
|
16453
|
+
ticks: {
|
|
16454
|
+
color: fontColor,
|
|
16455
|
+
callback: (value) => {
|
|
16456
|
+
return localeFormat.format
|
|
16457
|
+
? formatValue(value, localeFormat)
|
|
16458
|
+
: value?.toLocaleString() || value;
|
|
16470
16459
|
},
|
|
16471
16460
|
},
|
|
16472
|
-
|
|
16461
|
+
},
|
|
16473
16462
|
};
|
|
16474
16463
|
if (chart.stacked) {
|
|
16475
|
-
|
|
16476
|
-
config.options.scales.
|
|
16464
|
+
// @ts-ignore chart.js type is broken
|
|
16465
|
+
config.options.scales.x.stacked = true;
|
|
16466
|
+
// @ts-ignore chart.js type is broken
|
|
16467
|
+
config.options.scales.y.stacked = true;
|
|
16477
16468
|
}
|
|
16478
16469
|
return config;
|
|
16479
16470
|
}
|
|
@@ -16677,17 +16668,18 @@
|
|
|
16677
16668
|
padding: { left: 30, right: 30, top: chart.title ? 10 : 25, bottom: 25 },
|
|
16678
16669
|
};
|
|
16679
16670
|
config.options.needle = {
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
color: "#000000",
|
|
16671
|
+
width: 10,
|
|
16672
|
+
borderColor: "#000000",
|
|
16673
|
+
backgroundColor: "#000000",
|
|
16684
16674
|
};
|
|
16685
16675
|
config.options.valueLabel = {
|
|
16686
16676
|
display: false,
|
|
16687
|
-
|
|
16688
|
-
|
|
16677
|
+
font: {
|
|
16678
|
+
size: 30,
|
|
16679
|
+
color: "#FFFFFF",
|
|
16680
|
+
},
|
|
16689
16681
|
backgroundColor: "#000000",
|
|
16690
|
-
|
|
16682
|
+
borderColor: "#000000",
|
|
16691
16683
|
borderRadius: 5,
|
|
16692
16684
|
padding: {
|
|
16693
16685
|
top: 5,
|
|
@@ -16695,7 +16687,6 @@
|
|
|
16695
16687
|
bottom: 5,
|
|
16696
16688
|
left: 5,
|
|
16697
16689
|
},
|
|
16698
|
-
bottomMarginPercentage: 5,
|
|
16699
16690
|
};
|
|
16700
16691
|
return config;
|
|
16701
16692
|
}
|
|
@@ -16737,16 +16728,12 @@
|
|
|
16737
16728
|
data.push(point.value);
|
|
16738
16729
|
backgroundColor.push(point.color);
|
|
16739
16730
|
});
|
|
16740
|
-
// There's a bug in gauge lib when the last element in `data` is 0 (i.e. when the range maximum is 0).
|
|
16741
|
-
// The value wrongly fallbacks to 1 because 0 is falsy
|
|
16742
|
-
// See https://github.com/haiiaaa/chartjs-gauge/pull/33
|
|
16743
|
-
// https://github.com/haiiaaa/chartjs-gauge/blob/2ea50541d754d710cb30c2502fa690ac5dc27afd/src/controllers/controller.gauge.js#L52
|
|
16744
16731
|
data.push(maxNeedleValue);
|
|
16745
16732
|
backgroundColor.push(colors.upperColor);
|
|
16746
16733
|
const dataRange = chart.dataRange;
|
|
16747
16734
|
const deltaBeyondRangeLimit = needleCoverage / 30;
|
|
16748
16735
|
let needleValue = minNeedleValue - deltaBeyondRangeLimit; // make needle value always at the minimum by default
|
|
16749
|
-
let cellFormatter =
|
|
16736
|
+
let cellFormatter = undefined;
|
|
16750
16737
|
let displayValue = false;
|
|
16751
16738
|
if (dataRange !== undefined) {
|
|
16752
16739
|
const cell = getters.getEvaluatedCell({
|
|
@@ -16761,6 +16748,7 @@
|
|
|
16761
16748
|
// smaller and slightly larger than minRange and maxRange to mark the fact
|
|
16762
16749
|
// that the needle is out of the range limits
|
|
16763
16750
|
needleValue = clip(cell.value, minNeedleValue - deltaBeyondRangeLimit, maxNeedleValue + deltaBeyondRangeLimit);
|
|
16751
|
+
// show the original value, not the clipped one
|
|
16764
16752
|
cellFormatter = () => getters.getRangeFormattedValues(dataRange)[0];
|
|
16765
16753
|
displayValue = true;
|
|
16766
16754
|
}
|
|
@@ -16808,31 +16796,29 @@
|
|
|
16808
16796
|
},
|
|
16809
16797
|
};
|
|
16810
16798
|
/**
|
|
16811
|
-
* Regex to test if a format string is a date format that can be translated into a
|
|
16799
|
+
* Regex to test if a format string is a date format that can be translated into a luxon time format
|
|
16812
16800
|
*/
|
|
16813
|
-
const
|
|
16801
|
+
const timeFormatLuxonCompatible = /^((d|dd|m|mm|yyyy|yy|hh|h|ss|a)(-|:|\s|\/))*(d|dd|m|mm|yyyy|yy|hh|h|ss|a)$/i;
|
|
16814
16802
|
/** Get the time options for the XAxis of ChartJS */
|
|
16815
16803
|
function getChartTimeOptions(labels, labelFormat, locale) {
|
|
16816
|
-
const
|
|
16817
|
-
const timeUnit = getBestTimeUnitForScale(labels,
|
|
16804
|
+
const luxonFormat = convertDateFormatForLuxon(labelFormat);
|
|
16805
|
+
const timeUnit = getBestTimeUnitForScale(labels, luxonFormat, locale);
|
|
16818
16806
|
const displayFormats = {};
|
|
16819
16807
|
if (timeUnit) {
|
|
16820
|
-
displayFormats[timeUnit] =
|
|
16808
|
+
displayFormats[timeUnit] = luxonFormat;
|
|
16821
16809
|
}
|
|
16822
16810
|
return {
|
|
16823
|
-
parser:
|
|
16811
|
+
parser: luxonFormat,
|
|
16824
16812
|
displayFormats,
|
|
16825
|
-
unit: timeUnit,
|
|
16813
|
+
unit: timeUnit ?? false,
|
|
16826
16814
|
};
|
|
16827
16815
|
}
|
|
16828
16816
|
/**
|
|
16829
16817
|
* Convert the given date format into a format that moment.js understands.
|
|
16830
16818
|
*
|
|
16831
|
-
* https://
|
|
16819
|
+
* https://github.com/moment/luxon/blob/master/docs/formatting.md#table-of-tokens
|
|
16832
16820
|
*/
|
|
16833
|
-
function
|
|
16834
|
-
format = format.replace(/y/g, "Y");
|
|
16835
|
-
format = format.replace(/d/g, "D");
|
|
16821
|
+
function convertDateFormatForLuxon(format) {
|
|
16836
16822
|
// "m" before "h" === month, "m" after "h" === minute
|
|
16837
16823
|
const indexH = format.indexOf("h");
|
|
16838
16824
|
if (indexH >= 0) {
|
|
@@ -16903,6 +16889,8 @@
|
|
|
16903
16889
|
return "year";
|
|
16904
16890
|
}
|
|
16905
16891
|
|
|
16892
|
+
// @ts-ignore
|
|
16893
|
+
const Chart = window.Chart;
|
|
16906
16894
|
class LineChart extends AbstractChart {
|
|
16907
16895
|
dataSets;
|
|
16908
16896
|
labelRange;
|
|
@@ -17032,7 +17020,7 @@
|
|
|
17032
17020
|
return canBeDateChart(labelRange, getters) || canBeLinearChart(labelRange, getters);
|
|
17033
17021
|
}
|
|
17034
17022
|
function getChartAxisType(chart, getters) {
|
|
17035
|
-
if (isDateChart(chart, getters)) {
|
|
17023
|
+
if (isDateChart(chart, getters) && isLuxonTimeAdapterInstalled()) {
|
|
17036
17024
|
return "time";
|
|
17037
17025
|
}
|
|
17038
17026
|
if (isLinearChart(chart, getters)) {
|
|
@@ -17055,7 +17043,7 @@
|
|
|
17055
17043
|
col: labelRange.zone.left,
|
|
17056
17044
|
row: labelRange.zone.top,
|
|
17057
17045
|
}).format;
|
|
17058
|
-
return Boolean(labelFormat &&
|
|
17046
|
+
return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
|
|
17059
17047
|
}
|
|
17060
17048
|
function canBeLinearChart(labelRange, getters) {
|
|
17061
17049
|
if (!labelRange) {
|
|
@@ -17075,10 +17063,11 @@
|
|
|
17075
17063
|
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
|
|
17076
17064
|
const legend = {
|
|
17077
17065
|
labels: {
|
|
17078
|
-
fontColor,
|
|
17066
|
+
color: fontColor,
|
|
17079
17067
|
generateLabels(chart) {
|
|
17068
|
+
// color the legend labels with the dataset color, without any transparency
|
|
17080
17069
|
const { data } = chart;
|
|
17081
|
-
const labels =
|
|
17070
|
+
const labels = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
17082
17071
|
for (const [index, label] of labels.entries()) {
|
|
17083
17072
|
label.fillStyle = data.datasets[index].borderColor;
|
|
17084
17073
|
}
|
|
@@ -17092,41 +17081,33 @@
|
|
|
17092
17081
|
else {
|
|
17093
17082
|
legend.position = chart.legendPosition;
|
|
17094
17083
|
}
|
|
17095
|
-
config.options.legend
|
|
17084
|
+
Object.assign(config.options.plugins.legend || {}, legend);
|
|
17096
17085
|
config.options.layout = {
|
|
17097
17086
|
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
17098
17087
|
};
|
|
17099
17088
|
config.options.scales = {
|
|
17100
|
-
|
|
17101
|
-
{
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
maxRotation: 60,
|
|
17105
|
-
minRotation: 15,
|
|
17106
|
-
padding: 5,
|
|
17107
|
-
labelOffset: 2,
|
|
17108
|
-
fontColor,
|
|
17109
|
-
},
|
|
17089
|
+
x: {
|
|
17090
|
+
ticks: {
|
|
17091
|
+
padding: 5,
|
|
17092
|
+
color: fontColor,
|
|
17110
17093
|
},
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
? formatValue(value, localeFormat)
|
|
17122
|
-
: value?.toLocaleString() || value;
|
|
17123
|
-
},
|
|
17094
|
+
},
|
|
17095
|
+
y: {
|
|
17096
|
+
position: chart.verticalAxisPosition,
|
|
17097
|
+
beginAtZero: true,
|
|
17098
|
+
ticks: {
|
|
17099
|
+
color: fontColor,
|
|
17100
|
+
callback: (value) => {
|
|
17101
|
+
return localeFormat.format
|
|
17102
|
+
? formatValue(value, localeFormat)
|
|
17103
|
+
: value?.toLocaleString() || value;
|
|
17124
17104
|
},
|
|
17125
17105
|
},
|
|
17126
|
-
|
|
17106
|
+
},
|
|
17127
17107
|
};
|
|
17128
|
-
if (chart.stacked) {
|
|
17129
|
-
|
|
17108
|
+
if (chart.stacked && config.options?.scales?.y) {
|
|
17109
|
+
// @ts-ignore chart.js type is wrong
|
|
17110
|
+
config.options.scales.y.stacked = true;
|
|
17130
17111
|
}
|
|
17131
17112
|
return config;
|
|
17132
17113
|
}
|
|
@@ -17153,15 +17134,18 @@
|
|
|
17153
17134
|
const config = getLineConfiguration(chart, labels, localeFormat);
|
|
17154
17135
|
const labelFormat = getChartLabelFormat(getters, chart.labelRange);
|
|
17155
17136
|
if (axisType === "time") {
|
|
17156
|
-
|
|
17157
|
-
|
|
17158
|
-
|
|
17137
|
+
const axis = {
|
|
17138
|
+
type: "time",
|
|
17139
|
+
time: getChartTimeOptions(labels, labelFormat, locale),
|
|
17140
|
+
};
|
|
17141
|
+
Object.assign(config.options.scales.x, axis);
|
|
17142
|
+
config.options.scales.x.ticks.maxTicksLimit = 15;
|
|
17159
17143
|
}
|
|
17160
17144
|
else if (axisType === "linear") {
|
|
17161
|
-
config.options.scales.
|
|
17162
|
-
config.options.scales.
|
|
17163
|
-
config.options.
|
|
17164
|
-
return formatValue(tooltipItem[0]?.
|
|
17145
|
+
config.options.scales.x.type = "linear";
|
|
17146
|
+
config.options.scales.x.ticks.callback = (value) => formatValue(value, { format: labelFormat, locale });
|
|
17147
|
+
config.options.plugins.tooltip.callbacks.title = (tooltipItem) => {
|
|
17148
|
+
return formatValue(tooltipItem[0]?.label || "", localeFormat);
|
|
17165
17149
|
};
|
|
17166
17150
|
}
|
|
17167
17151
|
const colors = new ChartColors();
|
|
@@ -17179,7 +17163,7 @@
|
|
|
17179
17163
|
const dataset = {
|
|
17180
17164
|
label,
|
|
17181
17165
|
data,
|
|
17182
|
-
|
|
17166
|
+
tension: 0,
|
|
17183
17167
|
borderColor: color,
|
|
17184
17168
|
backgroundColor,
|
|
17185
17169
|
pointBackgroundColor: color,
|
|
@@ -17188,6 +17172,22 @@
|
|
|
17188
17172
|
config.data.datasets.push(dataset);
|
|
17189
17173
|
}
|
|
17190
17174
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
17175
|
+
}
|
|
17176
|
+
let missingTimeAdapterAlreadyWarned = false;
|
|
17177
|
+
function isLuxonTimeAdapterInstalled() {
|
|
17178
|
+
// @ts-ignore
|
|
17179
|
+
if (!window.Chart) {
|
|
17180
|
+
return false;
|
|
17181
|
+
}
|
|
17182
|
+
// @ts-ignore
|
|
17183
|
+
const adapter = new window.Chart._adapters._date({});
|
|
17184
|
+
// @ts-ignore
|
|
17185
|
+
const isInstalled = adapter._id === "luxon";
|
|
17186
|
+
if (!isInstalled && !missingTimeAdapterAlreadyWarned) {
|
|
17187
|
+
missingTimeAdapterAlreadyWarned = true;
|
|
17188
|
+
console.warn("'chartjs-adapter-luxon' time adapter is not installed. Time scale axes are disabled.");
|
|
17189
|
+
}
|
|
17190
|
+
return isInstalled;
|
|
17191
17191
|
}
|
|
17192
17192
|
|
|
17193
17193
|
class PieChart extends AbstractChart {
|
|
@@ -17292,7 +17292,7 @@
|
|
|
17292
17292
|
const fontColor = chartFontColor(chart.background);
|
|
17293
17293
|
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
|
|
17294
17294
|
const legend = {
|
|
17295
|
-
labels: { fontColor },
|
|
17295
|
+
labels: { color: fontColor },
|
|
17296
17296
|
};
|
|
17297
17297
|
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
|
|
17298
17298
|
legend.display = false;
|
|
@@ -17300,12 +17300,12 @@
|
|
|
17300
17300
|
else {
|
|
17301
17301
|
legend.position = chart.legendPosition;
|
|
17302
17302
|
}
|
|
17303
|
-
config.options.legend
|
|
17303
|
+
Object.assign(config.options.plugins.legend || {}, legend);
|
|
17304
17304
|
config.options.layout = {
|
|
17305
17305
|
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
17306
17306
|
};
|
|
17307
|
-
config.options.
|
|
17308
|
-
return
|
|
17307
|
+
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
17308
|
+
return tooltipItems[0].dataset.label;
|
|
17309
17309
|
};
|
|
17310
17310
|
return config;
|
|
17311
17311
|
}
|
|
@@ -18069,6 +18069,278 @@
|
|
|
18069
18069
|
};
|
|
18070
18070
|
}
|
|
18071
18071
|
|
|
18072
|
+
// @ts-ignore
|
|
18073
|
+
if (window.Chart) {
|
|
18074
|
+
// @ts-ignore
|
|
18075
|
+
const DoughnutController = window.Chart?.DoughnutController;
|
|
18076
|
+
/**
|
|
18077
|
+
* Example :
|
|
18078
|
+
* const chart = new Chart(ctx, {
|
|
18079
|
+
* type: "gauge",
|
|
18080
|
+
* data: {
|
|
18081
|
+
* datasets: [
|
|
18082
|
+
* {
|
|
18083
|
+
* borderWidth: 5,
|
|
18084
|
+
* data: [10, 20, 10],
|
|
18085
|
+
* value: 23,
|
|
18086
|
+
* backgroundColor: [
|
|
18087
|
+
* "#dc3545", //red
|
|
18088
|
+
* "#ffc107", //orange
|
|
18089
|
+
* "#28a745", //green
|
|
18090
|
+
* ],
|
|
18091
|
+
* },
|
|
18092
|
+
* ],
|
|
18093
|
+
* },
|
|
18094
|
+
* options: {
|
|
18095
|
+
* plugins: {
|
|
18096
|
+
* title: {
|
|
18097
|
+
* display: true,
|
|
18098
|
+
* text: "Custom Chart Title",
|
|
18099
|
+
* padding: {
|
|
18100
|
+
* top: 10,
|
|
18101
|
+
* bottom: 30,
|
|
18102
|
+
* },
|
|
18103
|
+
* font : {
|
|
18104
|
+
* size : 30
|
|
18105
|
+
* }
|
|
18106
|
+
* },
|
|
18107
|
+
* },
|
|
18108
|
+
* valueLabel: {
|
|
18109
|
+
* display: true,
|
|
18110
|
+
* format: (value) => {
|
|
18111
|
+
* return value.toFixed(2) + "%";
|
|
18112
|
+
* },
|
|
18113
|
+
* font : {
|
|
18114
|
+
* size : 35,
|
|
18115
|
+
* family : "Arial",
|
|
18116
|
+
* color : "#FC0",
|
|
18117
|
+
* },
|
|
18118
|
+
* backgroundColor : "#ccc",
|
|
18119
|
+
* borderColor : "#090",
|
|
18120
|
+
* borderRadius : 50
|
|
18121
|
+
* },
|
|
18122
|
+
* needle: {
|
|
18123
|
+
* display: true,
|
|
18124
|
+
* width: 50,
|
|
18125
|
+
* color: "#DC5",
|
|
18126
|
+
* backgroundColor : "#ccc",
|
|
18127
|
+
* },
|
|
18128
|
+
* },
|
|
18129
|
+
* });
|
|
18130
|
+
*/
|
|
18131
|
+
class GaugeController extends DoughnutController {
|
|
18132
|
+
static id = "gauge";
|
|
18133
|
+
static defaults = {
|
|
18134
|
+
...DoughnutController.defaults,
|
|
18135
|
+
circumference: 180,
|
|
18136
|
+
rotation: 270,
|
|
18137
|
+
};
|
|
18138
|
+
static overrides = {
|
|
18139
|
+
aspectRatio: 2,
|
|
18140
|
+
plugins: {
|
|
18141
|
+
legend: {
|
|
18142
|
+
display: false,
|
|
18143
|
+
},
|
|
18144
|
+
tooltip: {
|
|
18145
|
+
enabled: false,
|
|
18146
|
+
},
|
|
18147
|
+
},
|
|
18148
|
+
};
|
|
18149
|
+
get chartHeight() {
|
|
18150
|
+
return Math.abs(this.chart.chartArea.top - this.chart.chartArea.bottom);
|
|
18151
|
+
}
|
|
18152
|
+
get chartWidth() {
|
|
18153
|
+
return Math.abs(this.chart.chartArea.left - this.chart.chartArea.right);
|
|
18154
|
+
}
|
|
18155
|
+
get needleOptions() {
|
|
18156
|
+
const { config } = this.chart;
|
|
18157
|
+
const options = config.options;
|
|
18158
|
+
// @ts-ignore
|
|
18159
|
+
return options?.needle || {};
|
|
18160
|
+
}
|
|
18161
|
+
get valueLabelOptions() {
|
|
18162
|
+
const { config } = this.chart;
|
|
18163
|
+
const options = config.options;
|
|
18164
|
+
// @ts-ignore
|
|
18165
|
+
return options?.valueLabel || {};
|
|
18166
|
+
}
|
|
18167
|
+
get minValue() {
|
|
18168
|
+
const dataset = this.getDataset();
|
|
18169
|
+
// @ts-ignore
|
|
18170
|
+
return dataset.minValue || 0;
|
|
18171
|
+
}
|
|
18172
|
+
getValueAngleInPercent(value) {
|
|
18173
|
+
const dataset = this.getDataset();
|
|
18174
|
+
const data = dataset.data || [];
|
|
18175
|
+
const max = Math.max(...data);
|
|
18176
|
+
const min = this.minValue;
|
|
18177
|
+
return (value - min) / (max - min);
|
|
18178
|
+
}
|
|
18179
|
+
drawValueLabel(params) {
|
|
18180
|
+
const { ctx } = this.chart;
|
|
18181
|
+
if (this.valueLabelOptions.display === false) {
|
|
18182
|
+
return;
|
|
18183
|
+
}
|
|
18184
|
+
// draw background rectangle
|
|
18185
|
+
ctx.save();
|
|
18186
|
+
ctx.beginPath();
|
|
18187
|
+
ctx.fillStyle = params.valueLabel.backgroundColor;
|
|
18188
|
+
ctx.strokeStyle = params.valueLabel.borderColor;
|
|
18189
|
+
ctx.roundRect(params.valueLabel.rect.x, params.valueLabel.rect.y, params.valueLabel.rect.width, params.valueLabel.rect.height, params.valueLabel.borderRadius);
|
|
18190
|
+
ctx.stroke();
|
|
18191
|
+
ctx.fill();
|
|
18192
|
+
// draw value text
|
|
18193
|
+
ctx.textAlign = "center";
|
|
18194
|
+
ctx.textBaseline = "middle";
|
|
18195
|
+
ctx.font = params.valueLabel.font;
|
|
18196
|
+
ctx.fillStyle = params.valueLabel.textColor;
|
|
18197
|
+
ctx.fillText(params.valueLabel.valueText, params.valueLabel.textPosition.x, params.valueLabel.textPosition.y);
|
|
18198
|
+
ctx.restore();
|
|
18199
|
+
}
|
|
18200
|
+
drawNeedle(params) {
|
|
18201
|
+
const { ctx } = this.chart;
|
|
18202
|
+
if (this.needleOptions.display === false) {
|
|
18203
|
+
return;
|
|
18204
|
+
}
|
|
18205
|
+
// translate & rotate next paths
|
|
18206
|
+
ctx.save();
|
|
18207
|
+
ctx.translate(params.needle.position.x, params.needle.position.y);
|
|
18208
|
+
ctx.rotate(-Math.PI / 2 + Math.PI * params.needle.percent);
|
|
18209
|
+
// draw circle
|
|
18210
|
+
ctx.beginPath();
|
|
18211
|
+
ctx.fillStyle = params.needle.backgroundColor;
|
|
18212
|
+
ctx.strokeStyle = params.needle.borderColor;
|
|
18213
|
+
ctx.ellipse(0, 0, params.needle.width / 2, params.needle.width / 2, 0, 0, 2 * Math.PI);
|
|
18214
|
+
ctx.fill();
|
|
18215
|
+
ctx.stroke();
|
|
18216
|
+
ctx.closePath();
|
|
18217
|
+
// draw needle
|
|
18218
|
+
ctx.fillStyle = params.needle.backgroundColor;
|
|
18219
|
+
ctx.strokeStyle = params.needle.borderColor;
|
|
18220
|
+
ctx.beginPath();
|
|
18221
|
+
ctx.moveTo(-params.needle.width / 2, 0);
|
|
18222
|
+
ctx.lineTo(0, -params.needle.height + 10);
|
|
18223
|
+
ctx.lineTo(+params.needle.width / 2, 0);
|
|
18224
|
+
ctx.closePath();
|
|
18225
|
+
ctx.fill();
|
|
18226
|
+
ctx.stroke();
|
|
18227
|
+
ctx.restore();
|
|
18228
|
+
}
|
|
18229
|
+
computeRenderingParams() {
|
|
18230
|
+
const { ctx, config } = this.chart;
|
|
18231
|
+
const options = config.options;
|
|
18232
|
+
options.layout = options.layout || {};
|
|
18233
|
+
options.layout.padding = options.layout.padding || {};
|
|
18234
|
+
const formatter = this.valueLabelOptions.formatter;
|
|
18235
|
+
const fmt = typeof formatter === "function" ? formatter : (value) => value;
|
|
18236
|
+
const dataset = this.getDataset();
|
|
18237
|
+
// @ts-ignore value is a custom property for gauge charts
|
|
18238
|
+
const value = dataset.value || 0;
|
|
18239
|
+
const valueText = fmt(value).toString();
|
|
18240
|
+
const percent = this.getValueAngleInPercent(value);
|
|
18241
|
+
const fontFamily = this.valueLabelOptions.font?.family || "Arial";
|
|
18242
|
+
const optionsFontSize = this.valueLabelOptions.font?.size || 0;
|
|
18243
|
+
const fontSize = optionsFontSize >= 1 ? optionsFontSize : 30;
|
|
18244
|
+
const font = `${fontSize}px ${fontFamily}`;
|
|
18245
|
+
const padding = {
|
|
18246
|
+
right: 0,
|
|
18247
|
+
left: 0,
|
|
18248
|
+
top: 0,
|
|
18249
|
+
bottom: 0,
|
|
18250
|
+
...this.valueLabelOptions.padding,
|
|
18251
|
+
};
|
|
18252
|
+
padding.left = padding.left >= 0 ? padding.left : 10;
|
|
18253
|
+
padding.right = padding.right >= 0 ? padding.right : 10;
|
|
18254
|
+
padding.top = padding.top >= 0 ? padding.top : 10;
|
|
18255
|
+
padding.bottom = padding.bottom >= 0 ? padding.bottom : 10;
|
|
18256
|
+
const chartArea = this.chart.chartArea;
|
|
18257
|
+
const offsetX = this.offsetX || 0;
|
|
18258
|
+
const offsetY = this.offsetY || 0;
|
|
18259
|
+
const centerX = (chartArea.left + chartArea.right) / 2;
|
|
18260
|
+
const centerY = (chartArea.top + chartArea.bottom) / 2;
|
|
18261
|
+
const center = {
|
|
18262
|
+
x: centerX + offsetX,
|
|
18263
|
+
y: centerY + offsetY,
|
|
18264
|
+
};
|
|
18265
|
+
const textPosition = {
|
|
18266
|
+
x: center.x,
|
|
18267
|
+
y: center.y,
|
|
18268
|
+
};
|
|
18269
|
+
ctx.save();
|
|
18270
|
+
ctx.font = font;
|
|
18271
|
+
const metrics = ctx.measureText(valueText);
|
|
18272
|
+
ctx.restore();
|
|
18273
|
+
const textHeight = metrics.fontBoundingBoxAscent - metrics.fontBoundingBoxDescent;
|
|
18274
|
+
return {
|
|
18275
|
+
needle: {
|
|
18276
|
+
borderColor: this.needleOptions.borderColor || "#000",
|
|
18277
|
+
backgroundColor: this.needleOptions.backgroundColor || "#000",
|
|
18278
|
+
width: this.needleOptions.width || 10,
|
|
18279
|
+
height: Math.min(this.chartHeight, this.chartWidth / 2),
|
|
18280
|
+
position: {
|
|
18281
|
+
x: textPosition.x,
|
|
18282
|
+
y: textPosition.y,
|
|
18283
|
+
},
|
|
18284
|
+
percent,
|
|
18285
|
+
},
|
|
18286
|
+
valueLabel: {
|
|
18287
|
+
textColor: this.valueLabelOptions.font?.color || "#FFF",
|
|
18288
|
+
backgroundColor: this.valueLabelOptions.backgroundColor || "#000",
|
|
18289
|
+
borderColor: this.valueLabelOptions.borderColor || "#000",
|
|
18290
|
+
borderRadius: this.valueLabelOptions.borderRadius || 10,
|
|
18291
|
+
rect: {
|
|
18292
|
+
x: center.x - metrics.width / 2 - padding.left,
|
|
18293
|
+
y: center.y + textHeight / 2 + padding.top,
|
|
18294
|
+
width: metrics.width + padding.left + padding.right,
|
|
18295
|
+
height: -(textHeight + 6 + padding.top + padding.bottom),
|
|
18296
|
+
},
|
|
18297
|
+
valueText,
|
|
18298
|
+
textPosition,
|
|
18299
|
+
textHeight,
|
|
18300
|
+
font,
|
|
18301
|
+
},
|
|
18302
|
+
};
|
|
18303
|
+
}
|
|
18304
|
+
draw() {
|
|
18305
|
+
super.draw();
|
|
18306
|
+
const params = this.computeRenderingParams();
|
|
18307
|
+
this.drawNeedle(params);
|
|
18308
|
+
this.drawValueLabel(params);
|
|
18309
|
+
}
|
|
18310
|
+
updateElements(elements, start, count, mode) {
|
|
18311
|
+
super.updateElements(elements, start, count, mode);
|
|
18312
|
+
const dataset = this.getDataset();
|
|
18313
|
+
const data = this.getDataset().data;
|
|
18314
|
+
// @ts-ignore
|
|
18315
|
+
const minValue = dataset.minValue;
|
|
18316
|
+
// @ts-ignore
|
|
18317
|
+
const rotation = this.chart.options.rotation || 0;
|
|
18318
|
+
// @ts-ignore
|
|
18319
|
+
const circumference = this.chart.options.circumference || 0;
|
|
18320
|
+
for (let arcIndex = 0; arcIndex < data.length; arcIndex++) {
|
|
18321
|
+
const previousValue = arcIndex === 0 ? minValue : data[arcIndex - 1];
|
|
18322
|
+
const startAngleInPercent = this.getValueAngleInPercent(previousValue);
|
|
18323
|
+
const endAngleInPercent = this.getValueAngleInPercent(data[arcIndex]);
|
|
18324
|
+
const startAngle = degreesToRadians(rotation + circumference * startAngleInPercent) - Math.PI / 2;
|
|
18325
|
+
const endAngle = degreesToRadians(rotation + circumference * endAngleInPercent) - Math.PI / 2;
|
|
18326
|
+
const arcCircumference = endAngle - startAngle;
|
|
18327
|
+
const arc = elements[arcIndex];
|
|
18328
|
+
const propertiesUpdates = {
|
|
18329
|
+
startAngle,
|
|
18330
|
+
endAngle,
|
|
18331
|
+
circumference: arcCircumference,
|
|
18332
|
+
};
|
|
18333
|
+
this.updateElement(arc, arcIndex, propertiesUpdates, mode);
|
|
18334
|
+
}
|
|
18335
|
+
}
|
|
18336
|
+
}
|
|
18337
|
+
function degreesToRadians(degrees) {
|
|
18338
|
+
return (degrees * Math.PI) / 180;
|
|
18339
|
+
}
|
|
18340
|
+
// @ts-ignore
|
|
18341
|
+
window.Chart.register(GaugeController);
|
|
18342
|
+
}
|
|
18343
|
+
|
|
18072
18344
|
//------------------------------------------------------------------------------
|
|
18073
18345
|
// Helpers
|
|
18074
18346
|
//------------------------------------------------------------------------------
|
|
@@ -36418,7 +36690,8 @@
|
|
|
36418
36690
|
if (!chart) {
|
|
36419
36691
|
throw new Error(`No chart for the given id: ${figureId}`);
|
|
36420
36692
|
}
|
|
36421
|
-
|
|
36693
|
+
const runtime = this.createRuntimeChart(chart);
|
|
36694
|
+
this.history.update("charts", figureId, runtime);
|
|
36422
36695
|
}
|
|
36423
36696
|
return this.charts[figureId];
|
|
36424
36697
|
}
|
|
@@ -49506,7 +49779,14 @@
|
|
|
49506
49779
|
`;
|
|
49507
49780
|
}
|
|
49508
49781
|
|
|
49509
|
-
const
|
|
49782
|
+
const TABLE_DEFAULT_ATTRS = [
|
|
49783
|
+
["name", "TableStyleLight8"],
|
|
49784
|
+
["showFirstColumn", "0"],
|
|
49785
|
+
["showLastColumn", "0"],
|
|
49786
|
+
["showRowStripes", "0"],
|
|
49787
|
+
["showColumnStripes", "0"],
|
|
49788
|
+
];
|
|
49789
|
+
const TABLE_DEFAULT_STYLE = escapeXml /*xml*/ `<tableStyleInfo ${formatAttributes(TABLE_DEFAULT_ATTRS)}/>`;
|
|
49510
49790
|
function createTable(table, tableId, sheetData) {
|
|
49511
49791
|
const tableAttributes = [
|
|
49512
49792
|
["id", tableId],
|
|
@@ -50625,9 +50905,9 @@
|
|
|
50625
50905
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
50626
50906
|
|
|
50627
50907
|
|
|
50628
|
-
__info__.version = '16.5.0-alpha.
|
|
50629
|
-
__info__.date = '2023-08-
|
|
50630
|
-
__info__.hash = '
|
|
50908
|
+
__info__.version = '16.5.0-alpha.4';
|
|
50909
|
+
__info__.date = '2023-08-10T09:39:12.478Z';
|
|
50910
|
+
__info__.hash = 'c8db018';
|
|
50631
50911
|
|
|
50632
50912
|
|
|
50633
50913
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|