@odoo/o-spreadsheet 17.3.0-alpha.9 → 17.4.0-alpha.0
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 +1600 -603
- package/dist/o-spreadsheet.d.ts +425 -199
- package/dist/o-spreadsheet.esm.js +1600 -603
- package/dist/o-spreadsheet.iife.js +1600 -603
- package/dist/o-spreadsheet.iife.min.js +550 -392
- package/dist/o_spreadsheet.xml +479 -381
- package/package.json +1 -1
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
5
5
|
* @see https://github.com/odoo/o-spreadsheet
|
|
6
|
-
* @version 17.
|
|
7
|
-
* @date 2024-05-
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.4.0-alpha.0
|
|
7
|
+
* @date 2024-05-31T15:37:08.535Z
|
|
8
|
+
* @hash 9094f27
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
@@ -42,6 +42,8 @@ const COMPOSER_ASSISTANT_COLOR = "#9B359B";
|
|
|
42
42
|
const CHART_WATERFALL_POSITIVE_COLOR = "#006FBE";
|
|
43
43
|
const CHART_WATERFALL_NEGATIVE_COLOR = "#E40000";
|
|
44
44
|
const CHART_WATERFALL_SUBTOTAL_COLOR = "#AAAAAA";
|
|
45
|
+
const DEFAULT_CHART_PADDING = 20;
|
|
46
|
+
const DEFAULT_CHART_FONT_SIZE = 22;
|
|
45
47
|
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
46
48
|
const COLOR_PICKER_DEFAULTS = [
|
|
47
49
|
"#000000",
|
|
@@ -1090,6 +1092,44 @@ function darkenColor(color, percentage) {
|
|
|
1090
1092
|
hsla.l = hsla.l - percentage * hsla.l;
|
|
1091
1093
|
return hslaToHex(hsla);
|
|
1092
1094
|
}
|
|
1095
|
+
const ColorsList = [
|
|
1096
|
+
// the same colors as those used in odoo reporting
|
|
1097
|
+
"rgb(31,119,180)",
|
|
1098
|
+
"rgb(255,127,14)",
|
|
1099
|
+
"rgb(174,199,232)",
|
|
1100
|
+
"rgb(255,187,120)",
|
|
1101
|
+
"rgb(44,160,44)",
|
|
1102
|
+
"rgb(152,223,138)",
|
|
1103
|
+
"rgb(214,39,40)",
|
|
1104
|
+
"rgb(255,152,150)",
|
|
1105
|
+
"rgb(148,103,189)",
|
|
1106
|
+
"rgb(197,176,213)",
|
|
1107
|
+
"rgb(140,86,75)",
|
|
1108
|
+
"rgb(196,156,148)",
|
|
1109
|
+
"rgb(227,119,194)",
|
|
1110
|
+
"rgb(247,182,210)",
|
|
1111
|
+
"rgb(127,127,127)",
|
|
1112
|
+
"rgb(199,199,199)",
|
|
1113
|
+
"rgb(188,189,34)",
|
|
1114
|
+
"rgb(219,219,141)",
|
|
1115
|
+
"rgb(23,190,207)",
|
|
1116
|
+
"rgb(158,218,229)",
|
|
1117
|
+
];
|
|
1118
|
+
function getNthColor(index) {
|
|
1119
|
+
return ColorsList[index % ColorsList.length];
|
|
1120
|
+
}
|
|
1121
|
+
class ColorGenerator {
|
|
1122
|
+
currentColorIndex = 0;
|
|
1123
|
+
colors;
|
|
1124
|
+
constructor(colors = []) {
|
|
1125
|
+
this.colors = colors;
|
|
1126
|
+
}
|
|
1127
|
+
next() {
|
|
1128
|
+
return this.colors?.[this.currentColorIndex]
|
|
1129
|
+
? this.colors[this.currentColorIndex++]
|
|
1130
|
+
: getNthColor(this.currentColorIndex++);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1093
1133
|
|
|
1094
1134
|
//------------------------------------------------------------------------------
|
|
1095
1135
|
// Coordinate
|
|
@@ -1935,11 +1975,13 @@ const invalidateEvaluationCommands = new Set([
|
|
|
1935
1975
|
"RENAME_SHEET",
|
|
1936
1976
|
"DELETE_SHEET",
|
|
1937
1977
|
"CREATE_SHEET",
|
|
1978
|
+
"DUPLICATE_SHEET",
|
|
1938
1979
|
"ADD_COLUMNS_ROWS",
|
|
1939
1980
|
"REMOVE_COLUMNS_ROWS",
|
|
1940
1981
|
"UNDO",
|
|
1941
1982
|
"REDO",
|
|
1942
1983
|
"ADD_MERGE",
|
|
1984
|
+
"REMOVE_MERGE",
|
|
1943
1985
|
"UPDATE_LOCALE",
|
|
1944
1986
|
"ADD_PIVOT",
|
|
1945
1987
|
"UPDATE_PIVOT",
|
|
@@ -4878,18 +4920,22 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
|
|
|
4878
4920
|
/**
|
|
4879
4921
|
* Create a range from a xc. If the xc is empty, this function returns undefined.
|
|
4880
4922
|
*/
|
|
4881
|
-
function
|
|
4882
|
-
|
|
4923
|
+
function createValidRange(getters, sheetId, xc) {
|
|
4924
|
+
if (!xc)
|
|
4925
|
+
return;
|
|
4926
|
+
const range = getters.getRangeFromSheetXC(sheetId, xc);
|
|
4927
|
+
return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
|
|
4883
4928
|
}
|
|
4884
4929
|
/**
|
|
4885
4930
|
* Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
|
|
4886
4931
|
* For example, A1:B4 will become [A1:A4, B1:B4]
|
|
4887
4932
|
*/
|
|
4888
|
-
function spreadRange(getters,
|
|
4933
|
+
function spreadRange(getters, dataSets) {
|
|
4889
4934
|
const postProcessedRanges = [];
|
|
4890
|
-
for (const
|
|
4935
|
+
for (const dataSet of dataSets) {
|
|
4936
|
+
const range = dataSet.dataRange;
|
|
4891
4937
|
if (!getters.isRangeValid(range)) {
|
|
4892
|
-
postProcessedRanges.push(
|
|
4938
|
+
postProcessedRanges.push(dataSet); // ignore invalid range
|
|
4893
4939
|
continue;
|
|
4894
4940
|
}
|
|
4895
4941
|
const { sheetName } = splitReference(range);
|
|
@@ -4898,27 +4944,33 @@ function spreadRange(getters, ranges) {
|
|
|
4898
4944
|
if (zone.bottom !== zone.top && zone.left != zone.right) {
|
|
4899
4945
|
if (zone.right) {
|
|
4900
4946
|
for (let j = zone.left; j <= zone.right; ++j) {
|
|
4901
|
-
postProcessedRanges.push(
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4947
|
+
postProcessedRanges.push({
|
|
4948
|
+
...dataSet,
|
|
4949
|
+
dataRange: `${sheetPrefix}${zoneToXc({
|
|
4950
|
+
left: j,
|
|
4951
|
+
right: j,
|
|
4952
|
+
top: zone.top,
|
|
4953
|
+
bottom: zone.bottom,
|
|
4954
|
+
})}`,
|
|
4955
|
+
});
|
|
4907
4956
|
}
|
|
4908
4957
|
}
|
|
4909
4958
|
else {
|
|
4910
4959
|
for (let j = zone.top; j <= zone.bottom; ++j) {
|
|
4911
|
-
postProcessedRanges.push(
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4960
|
+
postProcessedRanges.push({
|
|
4961
|
+
...dataSet,
|
|
4962
|
+
dataRange: `${sheetPrefix}${zoneToXc({
|
|
4963
|
+
left: zone.left,
|
|
4964
|
+
right: zone.right,
|
|
4965
|
+
top: j,
|
|
4966
|
+
bottom: j,
|
|
4967
|
+
})}`,
|
|
4968
|
+
});
|
|
4917
4969
|
}
|
|
4918
4970
|
}
|
|
4919
4971
|
}
|
|
4920
4972
|
else {
|
|
4921
|
-
postProcessedRanges.push(
|
|
4973
|
+
postProcessedRanges.push(dataSet);
|
|
4922
4974
|
}
|
|
4923
4975
|
}
|
|
4924
4976
|
return postProcessedRanges;
|
|
@@ -5037,6 +5089,11 @@ function getDefaultCellHeight(ctx, cell, colSize) {
|
|
|
5037
5089
|
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
5038
5090
|
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
5039
5091
|
}
|
|
5092
|
+
function getDefaultContextFont(fontSize, bold = false, italic = false) {
|
|
5093
|
+
const italicStr = italic ? "italic" : "";
|
|
5094
|
+
const weight = bold ? "bold" : "";
|
|
5095
|
+
return `${italicStr} ${weight} ${fontSize}px ${DEFAULT_FONT}`;
|
|
5096
|
+
}
|
|
5040
5097
|
const textWidthCache = {};
|
|
5041
5098
|
function computeTextWidth(context, text, style, fontUnit = "pt") {
|
|
5042
5099
|
const font = computeTextFont(style, fontUnit);
|
|
@@ -5057,6 +5114,28 @@ function computeCachedTextWidth(context, text) {
|
|
|
5057
5114
|
}
|
|
5058
5115
|
return textWidthCache[font][text];
|
|
5059
5116
|
}
|
|
5117
|
+
const textDimensionsCache = {};
|
|
5118
|
+
function computeTextDimension(context, text, style, fontUnit = "pt") {
|
|
5119
|
+
const font = computeTextFont(style, fontUnit);
|
|
5120
|
+
context.save();
|
|
5121
|
+
context.font = font;
|
|
5122
|
+
const dimensions = computeCachedTextDimension(context, text);
|
|
5123
|
+
context.restore();
|
|
5124
|
+
return dimensions;
|
|
5125
|
+
}
|
|
5126
|
+
function computeCachedTextDimension(context, text) {
|
|
5127
|
+
const font = context.font;
|
|
5128
|
+
if (!textDimensionsCache[font]) {
|
|
5129
|
+
textDimensionsCache[font] = {};
|
|
5130
|
+
}
|
|
5131
|
+
if (textDimensionsCache[font][text] === undefined) {
|
|
5132
|
+
const measure = context.measureText(text);
|
|
5133
|
+
const width = measure.width;
|
|
5134
|
+
const height = measure.fontBoundingBoxAscent + measure.fontBoundingBoxDescent;
|
|
5135
|
+
textDimensionsCache[font][text] = { width, height };
|
|
5136
|
+
}
|
|
5137
|
+
return textDimensionsCache[font][text];
|
|
5138
|
+
}
|
|
5060
5139
|
function fontSizeInPixels(fontSize) {
|
|
5061
5140
|
return Math.round((fontSize * 96) / 72);
|
|
5062
5141
|
}
|
|
@@ -8826,7 +8905,7 @@ function drawHighlight(renderingContext, highlight, rect) {
|
|
|
8826
8905
|
}
|
|
8827
8906
|
}
|
|
8828
8907
|
if (!highlight.noFill) {
|
|
8829
|
-
ctx.fillStyle = setColorAlpha(color, highlight.fillAlpha ?? 0.12);
|
|
8908
|
+
ctx.fillStyle = setColorAlpha(toHex(color), highlight.fillAlpha ?? 0.12);
|
|
8830
8909
|
ctx.fillRect(x, y, width, height);
|
|
8831
8910
|
}
|
|
8832
8911
|
}
|
|
@@ -8875,7 +8954,32 @@ class HighlightStore extends SpreadsheetStore {
|
|
|
8875
8954
|
}
|
|
8876
8955
|
}
|
|
8877
8956
|
|
|
8878
|
-
|
|
8957
|
+
class NotificationStore {
|
|
8958
|
+
mutators = [
|
|
8959
|
+
"notifyUser",
|
|
8960
|
+
"raiseError",
|
|
8961
|
+
"askConfirmation",
|
|
8962
|
+
"updateNotificationCallbacks",
|
|
8963
|
+
];
|
|
8964
|
+
notifyUser = (notification) => window.alert(notification);
|
|
8965
|
+
askConfirmation = (content, confirm, cancel) => {
|
|
8966
|
+
if (window.confirm(content)) {
|
|
8967
|
+
confirm();
|
|
8968
|
+
}
|
|
8969
|
+
else {
|
|
8970
|
+
cancel?.();
|
|
8971
|
+
}
|
|
8972
|
+
};
|
|
8973
|
+
raiseError = (text, callback) => {
|
|
8974
|
+
window.alert(text);
|
|
8975
|
+
callback?.();
|
|
8976
|
+
};
|
|
8977
|
+
updateNotificationCallbacks(methods) {
|
|
8978
|
+
this.notifyUser = methods.notifyUser || this.notifyUser;
|
|
8979
|
+
this.raiseError = methods.raiseError || this.raiseError;
|
|
8980
|
+
this.askConfirmation = methods.askConfirmation || this.askConfirmation;
|
|
8981
|
+
}
|
|
8982
|
+
}
|
|
8879
8983
|
|
|
8880
8984
|
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
|
|
8881
8985
|
class ComposerStore extends SpreadsheetStore {
|
|
@@ -9896,10 +10000,10 @@ function adaptChartRange(range, applyChange) {
|
|
|
9896
10000
|
/**
|
|
9897
10001
|
* Create the dataSet objects from xcs
|
|
9898
10002
|
*/
|
|
9899
|
-
function createDataSets(getters,
|
|
10003
|
+
function createDataSets(getters, customizedDataSets, sheetId, dataSetsHaveTitle) {
|
|
9900
10004
|
const dataSets = [];
|
|
9901
|
-
for (const
|
|
9902
|
-
const dataRange = getters.getRangeFromSheetXC(sheetId,
|
|
10005
|
+
for (const dataSet of customizedDataSets) {
|
|
10006
|
+
const dataRange = getters.getRangeFromSheetXC(sheetId, dataSet.dataRange);
|
|
9903
10007
|
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
|
|
9904
10008
|
if (invalidSheetName || invalidXc) {
|
|
9905
10009
|
continue;
|
|
@@ -9916,26 +10020,36 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
9916
10020
|
left: column,
|
|
9917
10021
|
right: column,
|
|
9918
10022
|
};
|
|
9919
|
-
dataSets.push(
|
|
9920
|
-
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
10023
|
+
dataSets.push({
|
|
10024
|
+
...createDataSet(getters, dataSetSheetId, columnZone, dataSetsHaveTitle
|
|
10025
|
+
? {
|
|
10026
|
+
top: columnZone.top,
|
|
10027
|
+
bottom: columnZone.top,
|
|
10028
|
+
left: columnZone.left,
|
|
10029
|
+
right: columnZone.left,
|
|
10030
|
+
}
|
|
10031
|
+
: undefined),
|
|
10032
|
+
backgroundColor: dataSet.backgroundColor,
|
|
10033
|
+
rightYAxis: dataSet.yAxisId === "y1",
|
|
10034
|
+
customLabel: dataSet.label,
|
|
10035
|
+
});
|
|
9927
10036
|
}
|
|
9928
10037
|
}
|
|
9929
10038
|
else {
|
|
9930
10039
|
/* 1 cell, 1 row or 1 column */
|
|
9931
|
-
dataSets.push(
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
10040
|
+
dataSets.push({
|
|
10041
|
+
...createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
10042
|
+
? {
|
|
10043
|
+
top: zone.top,
|
|
10044
|
+
bottom: zone.top,
|
|
10045
|
+
left: zone.left,
|
|
10046
|
+
right: zone.left,
|
|
10047
|
+
}
|
|
10048
|
+
: undefined),
|
|
10049
|
+
backgroundColor: dataSet.backgroundColor,
|
|
10050
|
+
rightYAxis: dataSet.yAxisId === "y1",
|
|
10051
|
+
customLabel: dataSet.label,
|
|
10052
|
+
});
|
|
9939
10053
|
}
|
|
9940
10054
|
}
|
|
9941
10055
|
return dataSets;
|
|
@@ -9975,11 +10089,24 @@ function toExcelDataset(getters, ds) {
|
|
|
9975
10089
|
}
|
|
9976
10090
|
}
|
|
9977
10091
|
const dataRange = ds.dataRange.clone({ zone: dataZone });
|
|
10092
|
+
let label = {};
|
|
10093
|
+
if (ds.customLabel) {
|
|
10094
|
+
label = {
|
|
10095
|
+
text: ds.customLabel,
|
|
10096
|
+
};
|
|
10097
|
+
}
|
|
10098
|
+
else if (ds.labelCell) {
|
|
10099
|
+
label = {
|
|
10100
|
+
reference: getters.getRangeString(ds.labelCell, "forceSheetReference", {
|
|
10101
|
+
useFixedReference: true,
|
|
10102
|
+
}),
|
|
10103
|
+
};
|
|
10104
|
+
}
|
|
9978
10105
|
return {
|
|
9979
|
-
label
|
|
9980
|
-
? getters.getRangeString(ds.labelCell, "forceSheetReference", { useFixedReference: true })
|
|
9981
|
-
: undefined,
|
|
10106
|
+
label,
|
|
9982
10107
|
range: getters.getRangeString(dataRange, "forceSheetReference", { useFixedReference: true }),
|
|
10108
|
+
backgroundColor: ds.backgroundColor,
|
|
10109
|
+
rightYAxis: ds.rightYAxis,
|
|
9983
10110
|
};
|
|
9984
10111
|
}
|
|
9985
10112
|
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
@@ -10005,45 +10132,16 @@ function transformChartDefinitionWithDataSetsWithZone(definition, executed) {
|
|
|
10005
10132
|
labelRange = labelZone ? zoneToXc(labelZone) : undefined;
|
|
10006
10133
|
}
|
|
10007
10134
|
const dataSets = definition.dataSets
|
|
10008
|
-
.map(toUnboundedZone)
|
|
10135
|
+
.map((ds) => toUnboundedZone(ds.dataRange))
|
|
10009
10136
|
.map((zone) => transformZone(zone, executed))
|
|
10010
10137
|
.filter(isDefined)
|
|
10011
|
-
.map(zoneToXc);
|
|
10138
|
+
.map((xc) => ({ dataRange: zoneToXc(xc) }));
|
|
10012
10139
|
return {
|
|
10013
10140
|
...definition,
|
|
10014
10141
|
labelRange,
|
|
10015
10142
|
dataSets,
|
|
10016
10143
|
};
|
|
10017
10144
|
}
|
|
10018
|
-
const GraphColors = [
|
|
10019
|
-
// the same colors as those used in odoo reporting
|
|
10020
|
-
"rgb(31,119,180)",
|
|
10021
|
-
"rgb(255,127,14)",
|
|
10022
|
-
"rgb(174,199,232)",
|
|
10023
|
-
"rgb(255,187,120)",
|
|
10024
|
-
"rgb(44,160,44)",
|
|
10025
|
-
"rgb(152,223,138)",
|
|
10026
|
-
"rgb(214,39,40)",
|
|
10027
|
-
"rgb(255,152,150)",
|
|
10028
|
-
"rgb(148,103,189)",
|
|
10029
|
-
"rgb(197,176,213)",
|
|
10030
|
-
"rgb(140,86,75)",
|
|
10031
|
-
"rgb(196,156,148)",
|
|
10032
|
-
"rgb(227,119,194)",
|
|
10033
|
-
"rgb(247,182,210)",
|
|
10034
|
-
"rgb(127,127,127)",
|
|
10035
|
-
"rgb(199,199,199)",
|
|
10036
|
-
"rgb(188,189,34)",
|
|
10037
|
-
"rgb(219,219,141)",
|
|
10038
|
-
"rgb(23,190,207)",
|
|
10039
|
-
"rgb(158,218,229)",
|
|
10040
|
-
];
|
|
10041
|
-
class ChartColors {
|
|
10042
|
-
graphColorIndex = 0;
|
|
10043
|
-
next() {
|
|
10044
|
-
return GraphColors[this.graphColorIndex++ % GraphColors.length];
|
|
10045
|
-
}
|
|
10046
|
-
}
|
|
10047
10145
|
/**
|
|
10048
10146
|
* Choose a font color based on a background color.
|
|
10049
10147
|
* The font is white with a dark background.
|
|
@@ -10056,11 +10154,11 @@ function chartFontColor(backgroundColor) {
|
|
|
10056
10154
|
}
|
|
10057
10155
|
function checkDataset(definition) {
|
|
10058
10156
|
if (definition.dataSets) {
|
|
10059
|
-
const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range)) !== undefined;
|
|
10157
|
+
const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined;
|
|
10060
10158
|
if (invalidRanges) {
|
|
10061
10159
|
return "InvalidDataSet" /* CommandResult.InvalidDataSet */;
|
|
10062
10160
|
}
|
|
10063
|
-
const zones = definition.dataSets.map(toUnboundedZone);
|
|
10161
|
+
const zones = definition.dataSets.map((ds) => toUnboundedZone(ds.dataRange));
|
|
10064
10162
|
if (zones.some((zone) => zone.top !== zone.bottom && isFullRow(zone))) {
|
|
10065
10163
|
return "InvalidDataSet" /* CommandResult.InvalidDataSet */;
|
|
10066
10164
|
}
|
|
@@ -10100,6 +10198,35 @@ function getChartPositionAtCenterOfViewport(getters, chartSize) {
|
|
|
10100
10198
|
}; // Position at the center of the scrollable viewport
|
|
10101
10199
|
return position;
|
|
10102
10200
|
}
|
|
10201
|
+
function getChartAxisTitleRuntime(design) {
|
|
10202
|
+
if (design?.title?.text) {
|
|
10203
|
+
const { text, color, align, italic, bold } = design.title;
|
|
10204
|
+
return {
|
|
10205
|
+
display: true,
|
|
10206
|
+
text,
|
|
10207
|
+
color,
|
|
10208
|
+
font: {
|
|
10209
|
+
style: italic ? "italic" : "normal",
|
|
10210
|
+
weight: bold ? "bold" : "normal",
|
|
10211
|
+
},
|
|
10212
|
+
align: align === "left" ? "start" : align === "right" ? "end" : "center",
|
|
10213
|
+
};
|
|
10214
|
+
}
|
|
10215
|
+
return;
|
|
10216
|
+
}
|
|
10217
|
+
function getDefinedAxis(definition) {
|
|
10218
|
+
let useLeftAxis = false, useRightAxis = false;
|
|
10219
|
+
for (const design of definition.dataSets || []) {
|
|
10220
|
+
if (design.yAxisId === "y1") {
|
|
10221
|
+
useRightAxis = true;
|
|
10222
|
+
}
|
|
10223
|
+
else {
|
|
10224
|
+
useLeftAxis = true;
|
|
10225
|
+
}
|
|
10226
|
+
}
|
|
10227
|
+
useLeftAxis ||= !useRightAxis;
|
|
10228
|
+
return { useLeftAxis, useRightAxis };
|
|
10229
|
+
}
|
|
10103
10230
|
|
|
10104
10231
|
function getBaselineText(baseline, keyValue, baselineMode, humanize, locale) {
|
|
10105
10232
|
if (!baseline) {
|
|
@@ -10201,8 +10328,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10201
10328
|
type = "scorecard";
|
|
10202
10329
|
constructor(definition, sheetId, getters) {
|
|
10203
10330
|
super(definition, sheetId, getters);
|
|
10204
|
-
this.keyValue =
|
|
10205
|
-
this.baseline =
|
|
10331
|
+
this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
|
|
10332
|
+
this.baseline = createValidRange(getters, sheetId, definition.baseline);
|
|
10206
10333
|
this.baselineMode = definition.baselineMode;
|
|
10207
10334
|
this.baselineDescr = definition.baselineDescr;
|
|
10208
10335
|
this.background = definition.background;
|
|
@@ -10217,8 +10344,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10217
10344
|
return {
|
|
10218
10345
|
background: context.background,
|
|
10219
10346
|
type: "scorecard",
|
|
10220
|
-
keyValue: context.range ? context.range[0] : undefined,
|
|
10221
|
-
title: context.title || "",
|
|
10347
|
+
keyValue: context.range ? context.range[0].dataRange : undefined,
|
|
10348
|
+
title: context.title || { text: "" },
|
|
10222
10349
|
baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
|
|
10223
10350
|
baselineColorUp: DEFAULT_SCORECARD_BASELINE_COLOR_UP,
|
|
10224
10351
|
baselineColorDown: DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
|
|
@@ -10256,7 +10383,9 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10256
10383
|
getContextCreation() {
|
|
10257
10384
|
return {
|
|
10258
10385
|
...this,
|
|
10259
|
-
range: this.keyValue
|
|
10386
|
+
range: this.keyValue
|
|
10387
|
+
? [{ dataRange: this.getters.getRangeString(this.keyValue, this.sheetId) }]
|
|
10388
|
+
: undefined,
|
|
10260
10389
|
auxiliaryRange: this.baseline
|
|
10261
10390
|
? this.getters.getRangeString(this.baseline, this.sheetId)
|
|
10262
10391
|
: undefined,
|
|
@@ -10303,7 +10432,10 @@ function drawScoreChart(structure, canvas) {
|
|
|
10303
10432
|
if (structure.title) {
|
|
10304
10433
|
ctx.font = structure.title.style.font;
|
|
10305
10434
|
ctx.fillStyle = structure.title.style.color;
|
|
10435
|
+
const baseline = ctx.textBaseline;
|
|
10436
|
+
ctx.textBaseline = "middle";
|
|
10306
10437
|
ctx.fillText(clipTextWithEllipsis(ctx, structure.title.text, canvas.width - structure.title.position.x), structure.title.position.x, structure.title.position.y);
|
|
10438
|
+
ctx.textBaseline = baseline;
|
|
10307
10439
|
}
|
|
10308
10440
|
if (structure.baseline) {
|
|
10309
10441
|
ctx.font = structure.baseline.style.font;
|
|
@@ -10390,7 +10522,10 @@ function createScorecardChartRuntime(chart, getters) {
|
|
|
10390
10522
|
? toNumber(baselineDisplay, locale)
|
|
10391
10523
|
: 0;
|
|
10392
10524
|
return {
|
|
10393
|
-
title:
|
|
10525
|
+
title: {
|
|
10526
|
+
...chart.title,
|
|
10527
|
+
text: _t(chart.title.text ?? ""),
|
|
10528
|
+
},
|
|
10394
10529
|
keyValue: formattedKeyValue,
|
|
10395
10530
|
baselineDisplay,
|
|
10396
10531
|
baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, chart.baselineMode),
|
|
@@ -10422,10 +10557,9 @@ function createScorecardChartRuntime(chart, getters) {
|
|
|
10422
10557
|
}
|
|
10423
10558
|
|
|
10424
10559
|
/* Sizes of boxes containing the texts, in percentage of the Chart size */
|
|
10425
|
-
const TITLE_FONT_SIZE = 18;
|
|
10426
10560
|
const KEY_BOX_HEIGHT_RATIO = 0.8;
|
|
10427
10561
|
/* Padding at the border of the chart */
|
|
10428
|
-
const CHART_PADDING =
|
|
10562
|
+
const CHART_PADDING = DEFAULT_CHART_PADDING;
|
|
10429
10563
|
const BOTTOM_PADDING_RATIO = 0.05;
|
|
10430
10564
|
/**
|
|
10431
10565
|
* Line height (in em)
|
|
@@ -10436,11 +10570,6 @@ function formatBaselineDescr(baselineDescr, baseline) {
|
|
|
10436
10570
|
const _baselineDescr = baselineDescr || "";
|
|
10437
10571
|
return baseline && _baselineDescr ? " " + _baselineDescr : _baselineDescr;
|
|
10438
10572
|
}
|
|
10439
|
-
function getDefaultContextFont(fontSize, bold = false, italic = false) {
|
|
10440
|
-
const italicStr = italic ? "italic" : "";
|
|
10441
|
-
const weight = bold ? "bold" : "";
|
|
10442
|
-
return `${italicStr} ${weight} ${fontSize}px ${DEFAULT_FONT}`;
|
|
10443
|
-
}
|
|
10444
10573
|
function getScorecardConfiguration({ width, height }, runtime) {
|
|
10445
10574
|
const designer = new ScorecardChartConfigBuilder({ width, height }, runtime);
|
|
10446
10575
|
return designer.computeDesign();
|
|
@@ -10468,13 +10597,25 @@ class ScorecardChartConfigBuilder {
|
|
|
10468
10597
|
const style = this.getTextStyles();
|
|
10469
10598
|
let titleHeight = 0;
|
|
10470
10599
|
if (this.title) {
|
|
10471
|
-
|
|
10600
|
+
let x, titleWidth;
|
|
10601
|
+
({ height: titleHeight, width: titleWidth } = this.getFullTextDimensions(this.title, style.title.font));
|
|
10602
|
+
switch (this.runtime.title.align) {
|
|
10603
|
+
case "center":
|
|
10604
|
+
x = (this.width - titleWidth) / 2;
|
|
10605
|
+
break;
|
|
10606
|
+
case "right":
|
|
10607
|
+
x = this.width - titleWidth - CHART_PADDING;
|
|
10608
|
+
break;
|
|
10609
|
+
case "left":
|
|
10610
|
+
default:
|
|
10611
|
+
x = CHART_PADDING;
|
|
10612
|
+
}
|
|
10472
10613
|
structure.title = {
|
|
10473
10614
|
text: this.title,
|
|
10474
10615
|
style: style.title,
|
|
10475
10616
|
position: {
|
|
10476
|
-
x
|
|
10477
|
-
y: CHART_PADDING / 2
|
|
10617
|
+
x,
|
|
10618
|
+
y: CHART_PADDING + titleHeight / 2,
|
|
10478
10619
|
},
|
|
10479
10620
|
};
|
|
10480
10621
|
}
|
|
@@ -10575,7 +10716,7 @@ class ScorecardChartConfigBuilder {
|
|
|
10575
10716
|
return structure;
|
|
10576
10717
|
}
|
|
10577
10718
|
get title() {
|
|
10578
|
-
return this.runtime.title;
|
|
10719
|
+
return this.runtime.title.text ?? "";
|
|
10579
10720
|
}
|
|
10580
10721
|
get keyValue() {
|
|
10581
10722
|
return this.runtime.keyValue;
|
|
@@ -10643,8 +10784,8 @@ class ScorecardChartConfigBuilder {
|
|
|
10643
10784
|
}
|
|
10644
10785
|
return {
|
|
10645
10786
|
title: {
|
|
10646
|
-
font: getDefaultContextFont(
|
|
10647
|
-
color: this.secondaryFontColor,
|
|
10787
|
+
font: getDefaultContextFont(DEFAULT_CHART_FONT_SIZE, this.runtime.title.bold, this.runtime.title.italic),
|
|
10788
|
+
color: this.runtime.title.color ?? this.secondaryFontColor,
|
|
10648
10789
|
},
|
|
10649
10790
|
keyValue: {
|
|
10650
10791
|
color: this.runtime.keyValueStyle?.textColor || this.runtime.fontColor,
|
|
@@ -10677,7 +10818,7 @@ class ScorecardChartConfigBuilder {
|
|
|
10677
10818
|
getDrawableHeight() {
|
|
10678
10819
|
const verticalPadding = CHART_PADDING + this.height * BOTTOM_PADDING_RATIO;
|
|
10679
10820
|
let availableHeight = this.height - 2 * verticalPadding;
|
|
10680
|
-
availableHeight -= this.title ?
|
|
10821
|
+
availableHeight -= this.title ? DEFAULT_CHART_FONT_SIZE * LINE_HEIGHT : 0;
|
|
10681
10822
|
return availableHeight;
|
|
10682
10823
|
}
|
|
10683
10824
|
}
|
|
@@ -12027,7 +12168,7 @@ const COUNTUNIQUEIFS = {
|
|
|
12027
12168
|
compute: function (range, ...args) {
|
|
12028
12169
|
let uniqueValues = new Set();
|
|
12029
12170
|
visitMatchingRanges(args, (i, j) => {
|
|
12030
|
-
const data = range[i][j];
|
|
12171
|
+
const data = range[i]?.[j];
|
|
12031
12172
|
if (isDataNonEmpty(data)) {
|
|
12032
12173
|
uniqueValues.add(data.value);
|
|
12033
12174
|
}
|
|
@@ -12657,7 +12798,7 @@ const SUMIF = {
|
|
|
12657
12798
|
}
|
|
12658
12799
|
let sum = 0;
|
|
12659
12800
|
visitMatchingRanges([criteriaRange, criterion], (i, j) => {
|
|
12660
|
-
const value = sumRange[i][j]
|
|
12801
|
+
const value = sumRange[i]?.[j]?.value;
|
|
12661
12802
|
if (typeof value === "number") {
|
|
12662
12803
|
sum += value;
|
|
12663
12804
|
}
|
|
@@ -12682,7 +12823,7 @@ const SUMIFS = {
|
|
|
12682
12823
|
compute: function (sumRange, ...criters) {
|
|
12683
12824
|
let sum = 0;
|
|
12684
12825
|
visitMatchingRanges(criters, (i, j) => {
|
|
12685
|
-
const value = sumRange[i][j]
|
|
12826
|
+
const value = sumRange[i]?.[j]?.value;
|
|
12686
12827
|
if (typeof value === "number") {
|
|
12687
12828
|
sum += value;
|
|
12688
12829
|
}
|
|
@@ -13229,7 +13370,7 @@ const AVERAGEIF = {
|
|
|
13229
13370
|
let count = 0;
|
|
13230
13371
|
let sum = 0;
|
|
13231
13372
|
visitMatchingRanges([criteriaRange, criterion], (i, j) => {
|
|
13232
|
-
const value = _averageRange[i][j]
|
|
13373
|
+
const value = _averageRange[i]?.[j]?.value;
|
|
13233
13374
|
if (typeof value === "number") {
|
|
13234
13375
|
count += 1;
|
|
13235
13376
|
sum += value;
|
|
@@ -13258,7 +13399,7 @@ const AVERAGEIFS = {
|
|
|
13258
13399
|
let count = 0;
|
|
13259
13400
|
let sum = 0;
|
|
13260
13401
|
visitMatchingRanges(args, (i, j) => {
|
|
13261
|
-
const value = _averageRange[i][j]
|
|
13402
|
+
const value = _averageRange[i]?.[j]?.value;
|
|
13262
13403
|
if (typeof value === "number") {
|
|
13263
13404
|
count += 1;
|
|
13264
13405
|
sum += value;
|
|
@@ -13563,7 +13704,7 @@ const MAXIFS = {
|
|
|
13563
13704
|
compute: function (range, ...args) {
|
|
13564
13705
|
let result = -Infinity;
|
|
13565
13706
|
visitMatchingRanges(args, (i, j) => {
|
|
13566
|
-
const value = range[i][j]
|
|
13707
|
+
const value = range[i]?.[j]?.value;
|
|
13567
13708
|
if (typeof value === "number") {
|
|
13568
13709
|
result = result < value ? value : result;
|
|
13569
13710
|
}
|
|
@@ -13646,7 +13787,7 @@ const MINIFS = {
|
|
|
13646
13787
|
compute: function (range, ...args) {
|
|
13647
13788
|
let result = Infinity;
|
|
13648
13789
|
visitMatchingRanges(args, (i, j) => {
|
|
13649
|
-
const value = range[i][j]
|
|
13790
|
+
const value = range[i]?.[j]?.value;
|
|
13650
13791
|
if (typeof value === "number") {
|
|
13651
13792
|
result = result > value ? value : result;
|
|
13652
13793
|
}
|
|
@@ -22103,9 +22244,9 @@ const GAUGE_TEXT_COLOR_HIGH_CONTRAST = "#C8C8C8";
|
|
|
22103
22244
|
const GAUGE_INFLECTION_MARKER_COLOR = "#666666aa";
|
|
22104
22245
|
const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
|
|
22105
22246
|
const GAUGE_TITLE_SECTION_HEIGHT = 25;
|
|
22106
|
-
const GAUGE_TITLE_FONT_SIZE =
|
|
22107
|
-
const GAUGE_TITLE_PADDING_LEFT =
|
|
22108
|
-
const GAUGE_TITLE_PADDING_TOP =
|
|
22247
|
+
const GAUGE_TITLE_FONT_SIZE = DEFAULT_CHART_FONT_SIZE;
|
|
22248
|
+
const GAUGE_TITLE_PADDING_LEFT = DEFAULT_CHART_PADDING;
|
|
22249
|
+
const GAUGE_TITLE_PADDING_TOP = DEFAULT_CHART_PADDING;
|
|
22109
22250
|
function drawGaugeChart(canvas, runtime) {
|
|
22110
22251
|
const canvasBoundingRect = canvas.getBoundingClientRect();
|
|
22111
22252
|
canvas.width = canvasBoundingRect.width;
|
|
@@ -22180,7 +22321,8 @@ function drawInflectionValues(ctx, config) {
|
|
|
22180
22321
|
function drawTitle(ctx, config) {
|
|
22181
22322
|
ctx.save();
|
|
22182
22323
|
const title = config.title;
|
|
22183
|
-
ctx.font =
|
|
22324
|
+
ctx.font = getDefaultContextFont(title.fontSize, title.bold, title.italic);
|
|
22325
|
+
ctx.textBaseline = "middle";
|
|
22184
22326
|
ctx.fillStyle = title.color;
|
|
22185
22327
|
ctx.fillText(title.label, title.textPosition.x, title.textPosition.y);
|
|
22186
22328
|
ctx.restore();
|
|
@@ -22189,7 +22331,7 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
|
|
|
22189
22331
|
const maxValue = runtime.maxValue;
|
|
22190
22332
|
const minValue = runtime.minValue;
|
|
22191
22333
|
const gaugeValue = runtime.gaugeValue;
|
|
22192
|
-
const gaugeRect = getGaugeRect(boundingRect, runtime.title);
|
|
22334
|
+
const gaugeRect = getGaugeRect(boundingRect, runtime.title.text);
|
|
22193
22335
|
const gaugeArcWidth = gaugeRect.width / 6;
|
|
22194
22336
|
const gaugePercentage = gaugeValue
|
|
22195
22337
|
? (gaugeValue.value - minValue.value) / (maxValue.value - minValue.value)
|
|
@@ -22219,17 +22361,35 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
|
|
|
22219
22361
|
};
|
|
22220
22362
|
const textColor = getContrastedTextColor(runtime.background);
|
|
22221
22363
|
const inflectionValues = getInflectionValues(runtime, gaugeRect, textColor, ctx);
|
|
22364
|
+
let x = 0, titleWidth = 0, titleHeight = 0;
|
|
22365
|
+
if (runtime.title.text) {
|
|
22366
|
+
({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { ...runtime.title, fontSize: GAUGE_TITLE_FONT_SIZE }, "px"));
|
|
22367
|
+
}
|
|
22368
|
+
switch (runtime.title.align) {
|
|
22369
|
+
case "right":
|
|
22370
|
+
x = boundingRect.width - titleWidth - GAUGE_TITLE_PADDING_LEFT;
|
|
22371
|
+
break;
|
|
22372
|
+
case "center":
|
|
22373
|
+
x = (boundingRect.width - titleWidth) / 2;
|
|
22374
|
+
break;
|
|
22375
|
+
case "left":
|
|
22376
|
+
default:
|
|
22377
|
+
x = GAUGE_TITLE_PADDING_LEFT;
|
|
22378
|
+
break;
|
|
22379
|
+
}
|
|
22222
22380
|
return {
|
|
22223
22381
|
width: boundingRect.width,
|
|
22224
22382
|
height: boundingRect.height,
|
|
22225
22383
|
title: {
|
|
22226
|
-
label: runtime.title,
|
|
22384
|
+
label: runtime.title.text ?? "",
|
|
22227
22385
|
fontSize: GAUGE_TITLE_FONT_SIZE,
|
|
22228
22386
|
textPosition: {
|
|
22229
|
-
x
|
|
22230
|
-
y: GAUGE_TITLE_PADDING_TOP +
|
|
22387
|
+
x,
|
|
22388
|
+
y: GAUGE_TITLE_PADDING_TOP + titleHeight / 2,
|
|
22231
22389
|
},
|
|
22232
|
-
color: textColor,
|
|
22390
|
+
color: runtime.title.color ?? textColor,
|
|
22391
|
+
bold: runtime.title.bold,
|
|
22392
|
+
italic: runtime.title.italic,
|
|
22233
22393
|
},
|
|
22234
22394
|
backgroundColor: runtime.background,
|
|
22235
22395
|
gauge: {
|
|
@@ -22519,12 +22679,18 @@ function truncateLabel(label) {
|
|
|
22519
22679
|
* Get a default chart js configuration
|
|
22520
22680
|
*/
|
|
22521
22681
|
function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels }) {
|
|
22682
|
+
const chartTitle = chart.title.text ? chart.title : { ...chart.title, content: "" };
|
|
22522
22683
|
const options = {
|
|
22523
22684
|
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
22524
22685
|
responsive: true, // will resize when its container is resized
|
|
22525
22686
|
maintainAspectRatio: false, // doesn't maintain the aspect ration (width/height =2 by default) so the user has the choice of the exact layout
|
|
22526
22687
|
layout: {
|
|
22527
|
-
padding: {
|
|
22688
|
+
padding: {
|
|
22689
|
+
left: DEFAULT_CHART_PADDING,
|
|
22690
|
+
right: DEFAULT_CHART_PADDING,
|
|
22691
|
+
top: chartTitle.text ? DEFAULT_CHART_PADDING / 2 : DEFAULT_CHART_PADDING + 5,
|
|
22692
|
+
bottom: DEFAULT_CHART_PADDING,
|
|
22693
|
+
},
|
|
22528
22694
|
},
|
|
22529
22695
|
elements: {
|
|
22530
22696
|
line: {
|
|
@@ -22537,10 +22703,15 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
|
|
|
22537
22703
|
animation: false,
|
|
22538
22704
|
plugins: {
|
|
22539
22705
|
title: {
|
|
22540
|
-
display: !!
|
|
22541
|
-
text: _t(
|
|
22542
|
-
color: fontColor,
|
|
22543
|
-
|
|
22706
|
+
display: !!chartTitle.text,
|
|
22707
|
+
text: _t(chartTitle.text),
|
|
22708
|
+
color: chartTitle?.color ?? fontColor,
|
|
22709
|
+
align: chartTitle.align === "center" ? "center" : chartTitle.align === "right" ? "end" : "start",
|
|
22710
|
+
font: {
|
|
22711
|
+
size: DEFAULT_CHART_FONT_SIZE,
|
|
22712
|
+
weight: chartTitle.bold ? "bold" : "normal",
|
|
22713
|
+
style: chartTitle.italic ? "italic" : "normal",
|
|
22714
|
+
},
|
|
22544
22715
|
},
|
|
22545
22716
|
legend: {
|
|
22546
22717
|
// Disable default legend onClick (show/hide dataset), to allow us to set a global onClick on the chart container.
|
|
@@ -22675,9 +22846,10 @@ function chartToImage(runtime, figure, type) {
|
|
|
22675
22846
|
// we have to add the canvas to the DOM otherwise it won't be rendered
|
|
22676
22847
|
document.body.append(div);
|
|
22677
22848
|
if ("chartJsConfig" in runtime) {
|
|
22678
|
-
runtime.chartJsConfig
|
|
22849
|
+
const config = deepCopy(runtime.chartJsConfig);
|
|
22850
|
+
config.plugins = [backgroundColorChartJSPlugin];
|
|
22679
22851
|
// @ts-ignore
|
|
22680
|
-
const chart = new window.Chart(canvas,
|
|
22852
|
+
const chart = new window.Chart(canvas, config);
|
|
22681
22853
|
const imgContent = chart.toBase64Image();
|
|
22682
22854
|
chart.destroy();
|
|
22683
22855
|
div.remove();
|
|
@@ -22718,22 +22890,24 @@ class BarChart extends AbstractChart {
|
|
|
22718
22890
|
dataSets;
|
|
22719
22891
|
labelRange;
|
|
22720
22892
|
background;
|
|
22721
|
-
verticalAxisPosition;
|
|
22722
22893
|
legendPosition;
|
|
22723
22894
|
stacked;
|
|
22724
22895
|
aggregated;
|
|
22725
22896
|
type = "bar";
|
|
22726
22897
|
dataSetsHaveTitle;
|
|
22898
|
+
dataSetDesign;
|
|
22899
|
+
axesDesign;
|
|
22727
22900
|
constructor(definition, sheetId, getters) {
|
|
22728
22901
|
super(definition, sheetId, getters);
|
|
22729
22902
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
22730
|
-
this.labelRange =
|
|
22903
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
22731
22904
|
this.background = definition.background;
|
|
22732
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
22733
22905
|
this.legendPosition = definition.legendPosition;
|
|
22734
22906
|
this.stacked = definition.stacked;
|
|
22735
22907
|
this.aggregated = definition.aggregated;
|
|
22736
22908
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
22909
|
+
this.dataSetDesign = definition.dataSets;
|
|
22910
|
+
this.axesDesign = definition.axesDesign;
|
|
22737
22911
|
}
|
|
22738
22912
|
static transformDefinition(definition, executed) {
|
|
22739
22913
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -22744,21 +22918,28 @@ class BarChart extends AbstractChart {
|
|
|
22744
22918
|
static getDefinitionFromContextCreation(context) {
|
|
22745
22919
|
return {
|
|
22746
22920
|
background: context.background,
|
|
22747
|
-
dataSets: context.range
|
|
22921
|
+
dataSets: context.range ?? [],
|
|
22748
22922
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
22749
22923
|
stacked: context.stacked ?? false,
|
|
22750
22924
|
aggregated: context.aggregated ?? false,
|
|
22751
22925
|
legendPosition: context.legendPosition ?? "top",
|
|
22752
|
-
title: context.title || "",
|
|
22926
|
+
title: context.title || { text: "" },
|
|
22753
22927
|
type: "bar",
|
|
22754
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
22755
22928
|
labelRange: context.auxiliaryRange || undefined,
|
|
22929
|
+
axesDesign: context.axesDesign,
|
|
22756
22930
|
};
|
|
22757
22931
|
}
|
|
22758
22932
|
getContextCreation() {
|
|
22933
|
+
const range = [];
|
|
22934
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
22935
|
+
range.push({
|
|
22936
|
+
...this.dataSetDesign?.[i],
|
|
22937
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
22938
|
+
});
|
|
22939
|
+
}
|
|
22759
22940
|
return {
|
|
22760
22941
|
...this,
|
|
22761
|
-
range
|
|
22942
|
+
range,
|
|
22762
22943
|
auxiliaryRange: this.labelRange
|
|
22763
22944
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
22764
22945
|
: undefined,
|
|
@@ -22778,19 +22959,26 @@ class BarChart extends AbstractChart {
|
|
|
22778
22959
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
22779
22960
|
}
|
|
22780
22961
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
22962
|
+
const ranges = [];
|
|
22963
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
22964
|
+
ranges.push({
|
|
22965
|
+
...this.dataSetDesign?.[i],
|
|
22966
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
22967
|
+
});
|
|
22968
|
+
}
|
|
22781
22969
|
return {
|
|
22782
22970
|
type: "bar",
|
|
22783
22971
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
22784
22972
|
background: this.background,
|
|
22785
|
-
dataSets:
|
|
22973
|
+
dataSets: ranges,
|
|
22786
22974
|
legendPosition: this.legendPosition,
|
|
22787
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
22788
22975
|
labelRange: labelRange
|
|
22789
22976
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
22790
22977
|
: undefined,
|
|
22791
22978
|
title: this.title,
|
|
22792
22979
|
stacked: this.stacked,
|
|
22793
22980
|
aggregated: this.aggregated,
|
|
22981
|
+
axesDesign: this.axesDesign,
|
|
22794
22982
|
};
|
|
22795
22983
|
}
|
|
22796
22984
|
getDefinitionForExcel() {
|
|
@@ -22801,12 +22989,14 @@ class BarChart extends AbstractChart {
|
|
|
22801
22989
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
22802
22990
|
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
22803
22991
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
22992
|
+
const definition = this.getDefinition();
|
|
22804
22993
|
return {
|
|
22805
|
-
...
|
|
22994
|
+
...definition,
|
|
22806
22995
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
22807
22996
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
22808
22997
|
dataSets,
|
|
22809
22998
|
labelRange,
|
|
22999
|
+
verticalAxis: getDefinedAxis(definition),
|
|
22810
23000
|
};
|
|
22811
23001
|
}
|
|
22812
23002
|
updateRanges(applyChange) {
|
|
@@ -22840,30 +23030,51 @@ function getBarConfiguration(chart, labels, localeFormat) {
|
|
|
22840
23030
|
padding: 5,
|
|
22841
23031
|
color: fontColor,
|
|
22842
23032
|
},
|
|
23033
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
22843
23034
|
},
|
|
22844
|
-
|
|
22845
|
-
|
|
22846
|
-
|
|
22847
|
-
|
|
22848
|
-
|
|
22849
|
-
|
|
22850
|
-
|
|
22851
|
-
|
|
22852
|
-
|
|
22853
|
-
|
|
22854
|
-
|
|
22855
|
-
|
|
22856
|
-
|
|
22857
|
-
|
|
22858
|
-
},
|
|
23035
|
+
};
|
|
23036
|
+
const yAxis = {
|
|
23037
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
23038
|
+
ticks: {
|
|
23039
|
+
color: fontColor,
|
|
23040
|
+
callback: (value) => {
|
|
23041
|
+
value = Number(value);
|
|
23042
|
+
if (isNaN(value))
|
|
23043
|
+
return value;
|
|
23044
|
+
const { locale, format } = localeFormat;
|
|
23045
|
+
return formatValue(value, {
|
|
23046
|
+
locale,
|
|
23047
|
+
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23048
|
+
});
|
|
22859
23049
|
},
|
|
22860
23050
|
},
|
|
22861
23051
|
};
|
|
23052
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(chart.getDefinition());
|
|
23053
|
+
if (useLeftAxis) {
|
|
23054
|
+
config.options.scales.y = {
|
|
23055
|
+
...yAxis,
|
|
23056
|
+
position: "left",
|
|
23057
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
23058
|
+
};
|
|
23059
|
+
}
|
|
23060
|
+
if (useRightAxis) {
|
|
23061
|
+
config.options.scales.y1 = {
|
|
23062
|
+
...yAxis,
|
|
23063
|
+
position: "right",
|
|
23064
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
23065
|
+
};
|
|
23066
|
+
}
|
|
22862
23067
|
if (chart.stacked) {
|
|
22863
23068
|
// @ts-ignore chart.js type is broken
|
|
22864
23069
|
config.options.scales.x.stacked = true;
|
|
22865
|
-
|
|
22866
|
-
|
|
23070
|
+
if (useLeftAxis) {
|
|
23071
|
+
// @ts-ignore chart.js type is broken
|
|
23072
|
+
config.options.scales.y.stacked = true;
|
|
23073
|
+
}
|
|
23074
|
+
if (useRightAxis) {
|
|
23075
|
+
// @ts-ignore chart.js type is broken
|
|
23076
|
+
config.options.scales.y1.stacked = true;
|
|
23077
|
+
}
|
|
22867
23078
|
}
|
|
22868
23079
|
return config;
|
|
22869
23080
|
}
|
|
@@ -22883,8 +23094,9 @@ function createBarChartRuntime(chart, getters) {
|
|
|
22883
23094
|
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
|
|
22884
23095
|
const locale = getters.getLocale();
|
|
22885
23096
|
const config = getBarConfiguration(chart, labels, { format: dataSetFormat, locale });
|
|
22886
|
-
const colors = new
|
|
22887
|
-
|
|
23097
|
+
const colors = new ColorGenerator();
|
|
23098
|
+
const definition = chart.getDefinition();
|
|
23099
|
+
for (const { label, data } of dataSetsValues) {
|
|
22888
23100
|
const color = colors.next();
|
|
22889
23101
|
const dataset = {
|
|
22890
23102
|
label,
|
|
@@ -22894,29 +23106,43 @@ function createBarChartRuntime(chart, getters) {
|
|
|
22894
23106
|
};
|
|
22895
23107
|
config.data.datasets.push(dataset);
|
|
22896
23108
|
}
|
|
23109
|
+
for (const [index, dataset] of config.data.datasets.entries()) {
|
|
23110
|
+
if (definition.dataSets?.[index]?.backgroundColor) {
|
|
23111
|
+
const color = definition.dataSets[index].backgroundColor;
|
|
23112
|
+
dataset.backgroundColor = color;
|
|
23113
|
+
dataset.borderColor = color;
|
|
23114
|
+
}
|
|
23115
|
+
if (definition.dataSets?.[index]?.label) {
|
|
23116
|
+
const label = definition.dataSets[index].label;
|
|
23117
|
+
dataset.label = label;
|
|
23118
|
+
}
|
|
23119
|
+
if (definition.dataSets?.[index]?.yAxisId) {
|
|
23120
|
+
dataset["yAxisID"] = definition.dataSets[index].yAxisId;
|
|
23121
|
+
}
|
|
23122
|
+
}
|
|
22897
23123
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
22898
23124
|
}
|
|
22899
23125
|
|
|
22900
23126
|
class ComboChart extends AbstractChart {
|
|
22901
|
-
useBothYAxis;
|
|
22902
23127
|
dataSets;
|
|
22903
23128
|
labelRange;
|
|
22904
23129
|
background;
|
|
22905
|
-
verticalAxisPosition;
|
|
22906
23130
|
legendPosition;
|
|
22907
23131
|
aggregated;
|
|
22908
23132
|
dataSetsHaveTitle;
|
|
23133
|
+
dataSetDesign;
|
|
23134
|
+
axesDesign;
|
|
22909
23135
|
type = "combo";
|
|
22910
23136
|
constructor(definition, sheetId, getters) {
|
|
22911
23137
|
super(definition, sheetId, getters);
|
|
22912
23138
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
22913
|
-
this.labelRange =
|
|
23139
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
22914
23140
|
this.background = definition.background;
|
|
22915
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
22916
23141
|
this.legendPosition = definition.legendPosition;
|
|
22917
23142
|
this.aggregated = definition.aggregated;
|
|
22918
23143
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
22919
|
-
this.
|
|
23144
|
+
this.dataSetDesign = definition.dataSets;
|
|
23145
|
+
this.axesDesign = definition.axesDesign;
|
|
22920
23146
|
}
|
|
22921
23147
|
static transformDefinition(definition, executed) {
|
|
22922
23148
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -22925,9 +23151,16 @@ class ComboChart extends AbstractChart {
|
|
|
22925
23151
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
22926
23152
|
}
|
|
22927
23153
|
getContextCreation() {
|
|
23154
|
+
const range = [];
|
|
23155
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
23156
|
+
range.push({
|
|
23157
|
+
...this.dataSetDesign?.[i],
|
|
23158
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
23159
|
+
});
|
|
23160
|
+
}
|
|
22928
23161
|
return {
|
|
22929
23162
|
...this,
|
|
22930
|
-
range
|
|
23163
|
+
range,
|
|
22931
23164
|
auxiliaryRange: this.labelRange
|
|
22932
23165
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
22933
23166
|
: undefined,
|
|
@@ -22937,19 +23170,25 @@ class ComboChart extends AbstractChart {
|
|
|
22937
23170
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
22938
23171
|
}
|
|
22939
23172
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
23173
|
+
const ranges = [];
|
|
23174
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
23175
|
+
ranges.push({
|
|
23176
|
+
...this.dataSetDesign?.[i],
|
|
23177
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
23178
|
+
});
|
|
23179
|
+
}
|
|
22940
23180
|
return {
|
|
22941
23181
|
type: "combo",
|
|
22942
23182
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
22943
23183
|
background: this.background,
|
|
22944
|
-
dataSets:
|
|
23184
|
+
dataSets: ranges,
|
|
22945
23185
|
legendPosition: this.legendPosition,
|
|
22946
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
22947
23186
|
labelRange: labelRange
|
|
22948
23187
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
22949
23188
|
: undefined,
|
|
22950
23189
|
title: this.title,
|
|
22951
23190
|
aggregated: this.aggregated,
|
|
22952
|
-
|
|
23191
|
+
axesDesign: this.axesDesign,
|
|
22953
23192
|
};
|
|
22954
23193
|
}
|
|
22955
23194
|
getDefinitionForExcel() {
|
|
@@ -22961,12 +23200,14 @@ class ComboChart extends AbstractChart {
|
|
|
22961
23200
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
22962
23201
|
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
22963
23202
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
23203
|
+
const definition = this.getDefinition();
|
|
22964
23204
|
return {
|
|
22965
|
-
...
|
|
23205
|
+
...definition,
|
|
22966
23206
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
22967
23207
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
22968
23208
|
dataSets,
|
|
22969
23209
|
labelRange,
|
|
23210
|
+
verticalAxis: getDefinedAxis(definition),
|
|
22970
23211
|
};
|
|
22971
23212
|
}
|
|
22972
23213
|
updateRanges(applyChange) {
|
|
@@ -22984,11 +23225,10 @@ class ComboChart extends AbstractChart {
|
|
|
22984
23225
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
22985
23226
|
aggregated: context.aggregated,
|
|
22986
23227
|
legendPosition: context.legendPosition ?? "top",
|
|
22987
|
-
title: context.title || "",
|
|
22988
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
23228
|
+
title: context.title || { text: "" },
|
|
22989
23229
|
labelRange: context.auxiliaryRange || undefined,
|
|
22990
23230
|
type: "combo",
|
|
22991
|
-
|
|
23231
|
+
axesDesign: context.axesDesign,
|
|
22992
23232
|
};
|
|
22993
23233
|
}
|
|
22994
23234
|
copyForSheetId(sheetId) {
|
|
@@ -23003,7 +23243,10 @@ class ComboChart extends AbstractChart {
|
|
|
23003
23243
|
}
|
|
23004
23244
|
}
|
|
23005
23245
|
function createComboChartRuntime(chart, getters) {
|
|
23006
|
-
const
|
|
23246
|
+
const mainDataSetFormat = chart.dataSets.length
|
|
23247
|
+
? getChartDatasetFormat(getters, [chart.dataSets[0]])
|
|
23248
|
+
: undefined;
|
|
23249
|
+
const lineDataSetsFormat = getChartDatasetFormat(getters, chart.dataSets.slice(1));
|
|
23007
23250
|
const locale = getters.getLocale();
|
|
23008
23251
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
23009
23252
|
let labels = labelValues.formattedValues;
|
|
@@ -23017,11 +23260,12 @@ function createComboChartRuntime(chart, getters) {
|
|
|
23017
23260
|
if (chart.aggregated) {
|
|
23018
23261
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
23019
23262
|
}
|
|
23020
|
-
const localeFormat = { format:
|
|
23263
|
+
const localeFormat = { format: mainDataSetFormat, locale };
|
|
23021
23264
|
const fontColor = chartFontColor(chart.background);
|
|
23022
23265
|
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
|
|
23023
23266
|
const legend = {
|
|
23024
23267
|
labels: { color: fontColor },
|
|
23268
|
+
reverse: true,
|
|
23025
23269
|
};
|
|
23026
23270
|
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
|
|
23027
23271
|
legend.display = false;
|
|
@@ -23039,52 +23283,64 @@ function createComboChartRuntime(chart, getters) {
|
|
|
23039
23283
|
padding: 5,
|
|
23040
23284
|
color: fontColor,
|
|
23041
23285
|
},
|
|
23286
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
23042
23287
|
},
|
|
23043
23288
|
};
|
|
23044
|
-
const
|
|
23289
|
+
const formatCallback = (format) => {
|
|
23290
|
+
return (value) => {
|
|
23291
|
+
value = Number(value);
|
|
23292
|
+
if (isNaN(value))
|
|
23293
|
+
return value;
|
|
23294
|
+
const { locale } = localeFormat;
|
|
23295
|
+
return formatValue(value, {
|
|
23296
|
+
locale,
|
|
23297
|
+
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23298
|
+
});
|
|
23299
|
+
};
|
|
23300
|
+
};
|
|
23301
|
+
const leftVerticalAxis = {
|
|
23045
23302
|
beginAtZero: true, // the origin of the y axis is always zero
|
|
23046
23303
|
ticks: {
|
|
23047
23304
|
color: fontColor,
|
|
23048
|
-
callback: (
|
|
23049
|
-
value = Number(value);
|
|
23050
|
-
if (isNaN(value))
|
|
23051
|
-
return value;
|
|
23052
|
-
const { locale, format } = localeFormat;
|
|
23053
|
-
return formatValue(value, {
|
|
23054
|
-
locale,
|
|
23055
|
-
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23056
|
-
});
|
|
23057
|
-
},
|
|
23305
|
+
callback: formatCallback(mainDataSetFormat),
|
|
23058
23306
|
},
|
|
23059
23307
|
};
|
|
23060
|
-
|
|
23308
|
+
const rightVerticalAxis = {
|
|
23309
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
23310
|
+
ticks: {
|
|
23311
|
+
color: fontColor,
|
|
23312
|
+
callback: formatCallback(lineDataSetsFormat),
|
|
23313
|
+
},
|
|
23314
|
+
};
|
|
23315
|
+
const definition = chart.getDefinition();
|
|
23316
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(definition);
|
|
23317
|
+
if (useLeftAxis) {
|
|
23061
23318
|
config.options.scales.y = {
|
|
23062
|
-
...
|
|
23319
|
+
...leftVerticalAxis,
|
|
23063
23320
|
position: "left",
|
|
23321
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
23064
23322
|
};
|
|
23323
|
+
}
|
|
23324
|
+
if (useRightAxis) {
|
|
23065
23325
|
config.options.scales.y1 = {
|
|
23066
|
-
...
|
|
23326
|
+
...rightVerticalAxis,
|
|
23067
23327
|
position: "right",
|
|
23068
23328
|
grid: {
|
|
23069
23329
|
display: false,
|
|
23070
23330
|
},
|
|
23331
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
23071
23332
|
};
|
|
23072
23333
|
}
|
|
23073
|
-
|
|
23074
|
-
config.options.scales.y = {
|
|
23075
|
-
...verticalAxis,
|
|
23076
|
-
position: chart.verticalAxisPosition,
|
|
23077
|
-
};
|
|
23078
|
-
}
|
|
23079
|
-
const colors = new ChartColors();
|
|
23334
|
+
const colors = new ColorGenerator();
|
|
23080
23335
|
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
23336
|
+
const design = definition.dataSets[index];
|
|
23081
23337
|
const color = colors.next();
|
|
23082
23338
|
const dataset = {
|
|
23083
|
-
label,
|
|
23339
|
+
label: design?.label ?? label,
|
|
23084
23340
|
data,
|
|
23085
|
-
borderColor: color,
|
|
23086
|
-
backgroundColor: color,
|
|
23087
|
-
yAxisID:
|
|
23341
|
+
borderColor: design?.backgroundColor ?? color,
|
|
23342
|
+
backgroundColor: design.backgroundColor ?? color,
|
|
23343
|
+
yAxisID: design?.yAxisId ?? "y",
|
|
23088
23344
|
type: index === 0 ? "bar" : "line",
|
|
23089
23345
|
order: -index,
|
|
23090
23346
|
};
|
|
@@ -23165,7 +23421,7 @@ class GaugeChart extends AbstractChart {
|
|
|
23165
23421
|
type = "gauge";
|
|
23166
23422
|
constructor(definition, sheetId, getters) {
|
|
23167
23423
|
super(definition, sheetId, getters);
|
|
23168
|
-
this.dataRange =
|
|
23424
|
+
this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
|
|
23169
23425
|
this.sectionRule = definition.sectionRule;
|
|
23170
23426
|
this.background = definition.background;
|
|
23171
23427
|
}
|
|
@@ -23185,9 +23441,9 @@ class GaugeChart extends AbstractChart {
|
|
|
23185
23441
|
static getDefinitionFromContextCreation(context) {
|
|
23186
23442
|
return {
|
|
23187
23443
|
background: context.background,
|
|
23188
|
-
title: context.title || "",
|
|
23444
|
+
title: context.title || { text: "" },
|
|
23189
23445
|
type: "gauge",
|
|
23190
|
-
dataRange: context.range ? context.range[0] : undefined,
|
|
23446
|
+
dataRange: context.range ? context.range[0].dataRange : undefined,
|
|
23191
23447
|
sectionRule: {
|
|
23192
23448
|
colors: {
|
|
23193
23449
|
lowerColor: DEFAULT_GAUGE_LOWER_COLOR,
|
|
@@ -23238,7 +23494,7 @@ class GaugeChart extends AbstractChart {
|
|
|
23238
23494
|
return {
|
|
23239
23495
|
...this,
|
|
23240
23496
|
range: this.dataRange
|
|
23241
|
-
? [this.getters.getRangeString(this.dataRange, this.sheetId)]
|
|
23497
|
+
? [{ dataRange: this.getters.getRangeString(this.dataRange, this.sheetId) }]
|
|
23242
23498
|
: undefined,
|
|
23243
23499
|
};
|
|
23244
23500
|
}
|
|
@@ -23301,7 +23557,7 @@ function createGaugeChartRuntime(chart, getters) {
|
|
|
23301
23557
|
colors.push(chartColors.upperColor);
|
|
23302
23558
|
return {
|
|
23303
23559
|
background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
|
|
23304
|
-
title: chart.title,
|
|
23560
|
+
title: chart.title ?? { text: "" },
|
|
23305
23561
|
minValue: {
|
|
23306
23562
|
value: minValue,
|
|
23307
23563
|
label: formatValue(minValue, { locale, format }),
|
|
@@ -23559,28 +23815,49 @@ function getLineOrScatterConfiguration(chart, labels, options) {
|
|
|
23559
23815
|
padding: 5,
|
|
23560
23816
|
color: fontColor,
|
|
23561
23817
|
},
|
|
23818
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
23562
23819
|
},
|
|
23563
|
-
|
|
23564
|
-
|
|
23565
|
-
|
|
23566
|
-
|
|
23567
|
-
|
|
23568
|
-
|
|
23569
|
-
|
|
23570
|
-
|
|
23571
|
-
|
|
23572
|
-
|
|
23573
|
-
|
|
23574
|
-
|
|
23575
|
-
|
|
23576
|
-
|
|
23577
|
-
},
|
|
23820
|
+
};
|
|
23821
|
+
const yAxis = {
|
|
23822
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
23823
|
+
ticks: {
|
|
23824
|
+
color: fontColor,
|
|
23825
|
+
callback: (value) => {
|
|
23826
|
+
value = Number(value);
|
|
23827
|
+
if (isNaN(value))
|
|
23828
|
+
return value;
|
|
23829
|
+
const { locale, format } = options;
|
|
23830
|
+
return formatValue(value, {
|
|
23831
|
+
locale,
|
|
23832
|
+
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23833
|
+
});
|
|
23578
23834
|
},
|
|
23579
23835
|
},
|
|
23580
23836
|
};
|
|
23581
|
-
|
|
23582
|
-
|
|
23583
|
-
config.options.scales.y
|
|
23837
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(chart.getDefinition());
|
|
23838
|
+
if (useLeftAxis) {
|
|
23839
|
+
config.options.scales.y = {
|
|
23840
|
+
...yAxis,
|
|
23841
|
+
position: "left",
|
|
23842
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
23843
|
+
};
|
|
23844
|
+
}
|
|
23845
|
+
if (useRightAxis) {
|
|
23846
|
+
config.options.scales.y1 = {
|
|
23847
|
+
...yAxis,
|
|
23848
|
+
position: "right",
|
|
23849
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
23850
|
+
};
|
|
23851
|
+
}
|
|
23852
|
+
if ("stacked" in chart && chart.stacked) {
|
|
23853
|
+
if (useLeftAxis) {
|
|
23854
|
+
// @ts-ignore chart.js type is broken
|
|
23855
|
+
config.options.scales.y.stacked = true;
|
|
23856
|
+
}
|
|
23857
|
+
if (useRightAxis) {
|
|
23858
|
+
// @ts-ignore chart.js type is broken
|
|
23859
|
+
config.options.scales.y1.stacked = true;
|
|
23860
|
+
}
|
|
23584
23861
|
}
|
|
23585
23862
|
return config;
|
|
23586
23863
|
}
|
|
@@ -23627,7 +23904,8 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
23627
23904
|
}
|
|
23628
23905
|
const stacked = "stacked" in chart ? chart.stacked : false;
|
|
23629
23906
|
const cumulative = "cumulative" in chart ? chart.cumulative : false;
|
|
23630
|
-
const colors = new
|
|
23907
|
+
const colors = new ColorGenerator();
|
|
23908
|
+
const definition = chart.getDefinition();
|
|
23631
23909
|
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
23632
23910
|
if (["linear", "time"].includes(axisType)) {
|
|
23633
23911
|
// Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
|
|
@@ -23660,6 +23938,22 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
23660
23938
|
};
|
|
23661
23939
|
config.data.datasets.push(dataset);
|
|
23662
23940
|
}
|
|
23941
|
+
for (const [index, dataset] of config.data.datasets.entries()) {
|
|
23942
|
+
if (definition.dataSets?.[index]?.backgroundColor) {
|
|
23943
|
+
const color = definition.dataSets[index].backgroundColor;
|
|
23944
|
+
dataset.backgroundColor = color;
|
|
23945
|
+
dataset.borderColor = color;
|
|
23946
|
+
//@ts-ignore
|
|
23947
|
+
dataset.pointBackgroundColor = color;
|
|
23948
|
+
}
|
|
23949
|
+
if (definition.dataSets?.[index]?.label) {
|
|
23950
|
+
const label = definition.dataSets[index].label;
|
|
23951
|
+
dataset.label = label;
|
|
23952
|
+
}
|
|
23953
|
+
if (definition.dataSets?.[index]?.yAxisId) {
|
|
23954
|
+
dataset["yAxisID"] = definition.dataSets[index].yAxisId;
|
|
23955
|
+
}
|
|
23956
|
+
}
|
|
23663
23957
|
return {
|
|
23664
23958
|
chartJsConfig: config,
|
|
23665
23959
|
background: chart.background || BACKGROUND_CHART_COLOR,
|
|
@@ -23674,7 +23968,6 @@ class LineChart extends AbstractChart {
|
|
|
23674
23968
|
dataSets;
|
|
23675
23969
|
labelRange;
|
|
23676
23970
|
background;
|
|
23677
|
-
verticalAxisPosition;
|
|
23678
23971
|
legendPosition;
|
|
23679
23972
|
labelsAsText;
|
|
23680
23973
|
stacked;
|
|
@@ -23682,18 +23975,21 @@ class LineChart extends AbstractChart {
|
|
|
23682
23975
|
type = "line";
|
|
23683
23976
|
dataSetsHaveTitle;
|
|
23684
23977
|
cumulative;
|
|
23978
|
+
dataSetDesign;
|
|
23979
|
+
axesDesign;
|
|
23685
23980
|
constructor(definition, sheetId, getters) {
|
|
23686
23981
|
super(definition, sheetId, getters);
|
|
23687
23982
|
this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
23688
|
-
this.labelRange =
|
|
23983
|
+
this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
|
|
23689
23984
|
this.background = definition.background;
|
|
23690
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
23691
23985
|
this.legendPosition = definition.legendPosition;
|
|
23692
23986
|
this.labelsAsText = definition.labelsAsText;
|
|
23693
23987
|
this.stacked = definition.stacked;
|
|
23694
23988
|
this.aggregated = definition.aggregated;
|
|
23695
23989
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
23696
23990
|
this.cumulative = definition.cumulative;
|
|
23991
|
+
this.dataSetDesign = definition.dataSets;
|
|
23992
|
+
this.axesDesign = definition.axesDesign;
|
|
23697
23993
|
}
|
|
23698
23994
|
static validateChartDefinition(validator, definition) {
|
|
23699
23995
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -23704,30 +24000,36 @@ class LineChart extends AbstractChart {
|
|
|
23704
24000
|
static getDefinitionFromContextCreation(context) {
|
|
23705
24001
|
return {
|
|
23706
24002
|
background: context.background,
|
|
23707
|
-
dataSets: context.range
|
|
24003
|
+
dataSets: context.range ?? [],
|
|
23708
24004
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
23709
24005
|
labelsAsText: context.labelsAsText ?? false,
|
|
23710
24006
|
legendPosition: context.legendPosition ?? "top",
|
|
23711
|
-
title: context.title || "",
|
|
24007
|
+
title: context.title || { text: "" },
|
|
23712
24008
|
type: "line",
|
|
23713
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
23714
24009
|
labelRange: context.auxiliaryRange || undefined,
|
|
23715
24010
|
stacked: context.stacked ?? false,
|
|
23716
24011
|
aggregated: context.aggregated ?? false,
|
|
23717
24012
|
cumulative: context.cumulative ?? false,
|
|
24013
|
+
axesDesign: context.axesDesign,
|
|
23718
24014
|
};
|
|
23719
24015
|
}
|
|
23720
24016
|
getDefinition() {
|
|
23721
24017
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
23722
24018
|
}
|
|
23723
24019
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
24020
|
+
const ranges = [];
|
|
24021
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
24022
|
+
ranges.push({
|
|
24023
|
+
...this.dataSetDesign?.[i],
|
|
24024
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
24025
|
+
});
|
|
24026
|
+
}
|
|
23724
24027
|
return {
|
|
23725
24028
|
type: "line",
|
|
23726
24029
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
23727
24030
|
background: this.background,
|
|
23728
|
-
dataSets:
|
|
24031
|
+
dataSets: ranges,
|
|
23729
24032
|
legendPosition: this.legendPosition,
|
|
23730
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
23731
24033
|
labelRange: labelRange
|
|
23732
24034
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
23733
24035
|
: undefined,
|
|
@@ -23736,12 +24038,20 @@ class LineChart extends AbstractChart {
|
|
|
23736
24038
|
stacked: this.stacked,
|
|
23737
24039
|
aggregated: this.aggregated,
|
|
23738
24040
|
cumulative: this.cumulative,
|
|
24041
|
+
axesDesign: this.axesDesign,
|
|
23739
24042
|
};
|
|
23740
24043
|
}
|
|
23741
24044
|
getContextCreation() {
|
|
24045
|
+
const range = [];
|
|
24046
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
24047
|
+
range.push({
|
|
24048
|
+
...this.dataSetDesign?.[i],
|
|
24049
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
24050
|
+
});
|
|
24051
|
+
}
|
|
23742
24052
|
return {
|
|
23743
24053
|
...this,
|
|
23744
|
-
range
|
|
24054
|
+
range,
|
|
23745
24055
|
auxiliaryRange: this.labelRange
|
|
23746
24056
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
23747
24057
|
: undefined,
|
|
@@ -23763,12 +24073,14 @@ class LineChart extends AbstractChart {
|
|
|
23763
24073
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
23764
24074
|
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
23765
24075
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
24076
|
+
const definition = this.getDefinition();
|
|
23766
24077
|
return {
|
|
23767
|
-
...
|
|
24078
|
+
...definition,
|
|
23768
24079
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
23769
24080
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
23770
24081
|
dataSets,
|
|
23771
24082
|
labelRange,
|
|
24083
|
+
verticalAxis: getDefinedAxis(definition),
|
|
23772
24084
|
};
|
|
23773
24085
|
}
|
|
23774
24086
|
copyForSheetId(sheetId) {
|
|
@@ -23798,7 +24110,7 @@ class PieChart extends AbstractChart {
|
|
|
23798
24110
|
constructor(definition, sheetId, getters) {
|
|
23799
24111
|
super(definition, sheetId, getters);
|
|
23800
24112
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
23801
|
-
this.labelRange =
|
|
24113
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
23802
24114
|
this.background = definition.background;
|
|
23803
24115
|
this.legendPosition = definition.legendPosition;
|
|
23804
24116
|
this.aggregated = definition.aggregated;
|
|
@@ -23813,10 +24125,10 @@ class PieChart extends AbstractChart {
|
|
|
23813
24125
|
static getDefinitionFromContextCreation(context) {
|
|
23814
24126
|
return {
|
|
23815
24127
|
background: context.background,
|
|
23816
|
-
dataSets: context.range
|
|
24128
|
+
dataSets: context.range ?? [],
|
|
23817
24129
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
23818
24130
|
legendPosition: context.legendPosition ?? "top",
|
|
23819
|
-
title: context.title || "",
|
|
24131
|
+
title: context.title || { text: "" },
|
|
23820
24132
|
type: "pie",
|
|
23821
24133
|
labelRange: context.auxiliaryRange || undefined,
|
|
23822
24134
|
aggregated: context.aggregated ?? false,
|
|
@@ -23828,7 +24140,9 @@ class PieChart extends AbstractChart {
|
|
|
23828
24140
|
getContextCreation() {
|
|
23829
24141
|
return {
|
|
23830
24142
|
...this,
|
|
23831
|
-
range: this.dataSets.map((ds) =>
|
|
24143
|
+
range: this.dataSets.map((ds) => ({
|
|
24144
|
+
dataRange: this.getters.getRangeString(ds.dataRange, this.sheetId),
|
|
24145
|
+
})),
|
|
23832
24146
|
auxiliaryRange: this.labelRange
|
|
23833
24147
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
23834
24148
|
: undefined,
|
|
@@ -23839,7 +24153,9 @@ class PieChart extends AbstractChart {
|
|
|
23839
24153
|
type: "pie",
|
|
23840
24154
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
23841
24155
|
background: this.background,
|
|
23842
|
-
dataSets: dataSets.map((ds) =>
|
|
24156
|
+
dataSets: dataSets.map((ds) => ({
|
|
24157
|
+
dataRange: this.getters.getRangeString(ds.dataRange, targetSheetId || this.sheetId),
|
|
24158
|
+
})),
|
|
23843
24159
|
legendPosition: this.legendPosition,
|
|
23844
24160
|
labelRange: labelRange
|
|
23845
24161
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
@@ -23870,7 +24186,6 @@ class PieChart extends AbstractChart {
|
|
|
23870
24186
|
...this.getDefinition(),
|
|
23871
24187
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
23872
24188
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
23873
|
-
verticalAxisPosition: "left", //TODO ExcelChartDefinition should be adapted, but can be done later
|
|
23874
24189
|
dataSets,
|
|
23875
24190
|
labelRange,
|
|
23876
24191
|
};
|
|
@@ -23971,9 +24286,8 @@ function createPieChartRuntime(chart, getters) {
|
|
|
23971
24286
|
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
|
|
23972
24287
|
const locale = getters.getLocale();
|
|
23973
24288
|
const config = getPieConfiguration(chart, labels, { format: dataSetFormat, locale });
|
|
23974
|
-
const
|
|
23975
|
-
for (
|
|
23976
|
-
const backgroundColor = getPieColors(colors, dataSetsValues);
|
|
24289
|
+
const backgroundColor = getPieColors(new ColorGenerator(), dataSetsValues);
|
|
24290
|
+
for (const { label, data } of dataSetsValues) {
|
|
23977
24291
|
const dataset = {
|
|
23978
24292
|
label,
|
|
23979
24293
|
data,
|
|
@@ -23989,22 +24303,24 @@ class ScatterChart extends AbstractChart {
|
|
|
23989
24303
|
dataSets;
|
|
23990
24304
|
labelRange;
|
|
23991
24305
|
background;
|
|
23992
|
-
verticalAxisPosition;
|
|
23993
24306
|
legendPosition;
|
|
23994
24307
|
labelsAsText;
|
|
23995
24308
|
aggregated;
|
|
23996
24309
|
type = "scatter";
|
|
23997
24310
|
dataSetsHaveTitle;
|
|
24311
|
+
dataSetDesign;
|
|
24312
|
+
axesDesign;
|
|
23998
24313
|
constructor(definition, sheetId, getters) {
|
|
23999
24314
|
super(definition, sheetId, getters);
|
|
24000
24315
|
this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
24001
|
-
this.labelRange =
|
|
24316
|
+
this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
|
|
24002
24317
|
this.background = definition.background;
|
|
24003
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
24004
24318
|
this.legendPosition = definition.legendPosition;
|
|
24005
24319
|
this.labelsAsText = definition.labelsAsText;
|
|
24006
24320
|
this.aggregated = definition.aggregated;
|
|
24007
24321
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
24322
|
+
this.dataSetDesign = definition.dataSets;
|
|
24323
|
+
this.axesDesign = definition.axesDesign;
|
|
24008
24324
|
}
|
|
24009
24325
|
static validateChartDefinition(validator, definition) {
|
|
24010
24326
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -24015,40 +24331,54 @@ class ScatterChart extends AbstractChart {
|
|
|
24015
24331
|
static getDefinitionFromContextCreation(context) {
|
|
24016
24332
|
return {
|
|
24017
24333
|
background: context.background,
|
|
24018
|
-
dataSets: context.range
|
|
24334
|
+
dataSets: context.range ?? [],
|
|
24019
24335
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
24020
24336
|
labelsAsText: context.labelsAsText ?? false,
|
|
24021
24337
|
legendPosition: context.legendPosition ?? "top",
|
|
24022
|
-
title: context.title || "",
|
|
24338
|
+
title: context.title || { text: "" },
|
|
24023
24339
|
type: "scatter",
|
|
24024
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
24025
24340
|
labelRange: context.auxiliaryRange || undefined,
|
|
24026
24341
|
aggregated: context.aggregated ?? false,
|
|
24342
|
+
axesDesign: context.axesDesign,
|
|
24027
24343
|
};
|
|
24028
24344
|
}
|
|
24029
24345
|
getDefinition() {
|
|
24030
24346
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
24031
24347
|
}
|
|
24032
24348
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
24349
|
+
const ranges = [];
|
|
24350
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
24351
|
+
ranges.push({
|
|
24352
|
+
...this.dataSetDesign?.[i],
|
|
24353
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
24354
|
+
});
|
|
24355
|
+
}
|
|
24033
24356
|
return {
|
|
24034
24357
|
type: "scatter",
|
|
24035
24358
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
24036
24359
|
background: this.background,
|
|
24037
|
-
dataSets:
|
|
24360
|
+
dataSets: ranges,
|
|
24038
24361
|
legendPosition: this.legendPosition,
|
|
24039
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
24040
24362
|
labelRange: labelRange
|
|
24041
24363
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
24042
24364
|
: undefined,
|
|
24043
24365
|
title: this.title,
|
|
24044
24366
|
labelsAsText: this.labelsAsText,
|
|
24045
24367
|
aggregated: this.aggregated,
|
|
24368
|
+
axesDesign: this.axesDesign,
|
|
24046
24369
|
};
|
|
24047
24370
|
}
|
|
24048
24371
|
getContextCreation() {
|
|
24372
|
+
const range = [];
|
|
24373
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
24374
|
+
range.push({
|
|
24375
|
+
...this.dataSetDesign?.[i],
|
|
24376
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
24377
|
+
});
|
|
24378
|
+
}
|
|
24049
24379
|
return {
|
|
24050
24380
|
...this,
|
|
24051
|
-
range
|
|
24381
|
+
range,
|
|
24052
24382
|
auxiliaryRange: this.labelRange
|
|
24053
24383
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
24054
24384
|
: undefined,
|
|
@@ -24071,12 +24401,14 @@ class ScatterChart extends AbstractChart {
|
|
|
24071
24401
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
24072
24402
|
.filter((ds) => ds.range !== "");
|
|
24073
24403
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
24404
|
+
const definition = this.getDefinition();
|
|
24074
24405
|
return {
|
|
24075
|
-
...
|
|
24406
|
+
...definition,
|
|
24076
24407
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
24077
24408
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
24078
24409
|
dataSets,
|
|
24079
24410
|
labelRange,
|
|
24411
|
+
verticalAxis: getDefinedAxis(definition),
|
|
24080
24412
|
};
|
|
24081
24413
|
}
|
|
24082
24414
|
copyForSheetId(sheetId) {
|
|
@@ -24096,13 +24428,6 @@ function createScatterChartRuntime(chart, getters) {
|
|
|
24096
24428
|
// have less options than the line chart (it only works with linear labels)
|
|
24097
24429
|
chartJsConfig.type = "line";
|
|
24098
24430
|
const configOptions = chartJsConfig.options;
|
|
24099
|
-
configOptions.elements = {
|
|
24100
|
-
point: {
|
|
24101
|
-
radius: 3,
|
|
24102
|
-
hoverRadius: 3, // chartJS seems bugged, the point starts with the "hoverRadius" value
|
|
24103
|
-
hitRadius: 8,
|
|
24104
|
-
},
|
|
24105
|
-
};
|
|
24106
24431
|
const locale = getters.getLocale();
|
|
24107
24432
|
configOptions.plugins.tooltip.callbacks.title = () => "";
|
|
24108
24433
|
configOptions.plugins.tooltip.callbacks.label = (tooltipItem) => {
|
|
@@ -24139,10 +24464,12 @@ class WaterfallChart extends AbstractChart {
|
|
|
24139
24464
|
positiveValuesColor;
|
|
24140
24465
|
negativeValuesColor;
|
|
24141
24466
|
subTotalValuesColor;
|
|
24467
|
+
dataSetDesign;
|
|
24468
|
+
axesDesign;
|
|
24142
24469
|
constructor(definition, sheetId, getters) {
|
|
24143
24470
|
super(definition, sheetId, getters);
|
|
24144
24471
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
24145
|
-
this.labelRange =
|
|
24472
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
24146
24473
|
this.background = definition.background;
|
|
24147
24474
|
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
24148
24475
|
this.legendPosition = definition.legendPosition;
|
|
@@ -24154,6 +24481,8 @@ class WaterfallChart extends AbstractChart {
|
|
|
24154
24481
|
this.negativeValuesColor = definition.negativeValuesColor;
|
|
24155
24482
|
this.subTotalValuesColor = definition.subTotalValuesColor;
|
|
24156
24483
|
this.firstValueAsSubtotal = definition.firstValueAsSubtotal;
|
|
24484
|
+
this.dataSetDesign = definition.dataSets;
|
|
24485
|
+
this.axesDesign = definition.axesDesign;
|
|
24157
24486
|
}
|
|
24158
24487
|
static transformDefinition(definition, executed) {
|
|
24159
24488
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -24168,19 +24497,27 @@ class WaterfallChart extends AbstractChart {
|
|
|
24168
24497
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
24169
24498
|
aggregated: context.aggregated ?? false,
|
|
24170
24499
|
legendPosition: context.legendPosition ?? "top",
|
|
24171
|
-
title: context.title || "",
|
|
24500
|
+
title: context.title || { text: "" },
|
|
24172
24501
|
type: "waterfall",
|
|
24173
|
-
verticalAxisPosition:
|
|
24502
|
+
verticalAxisPosition: "left",
|
|
24174
24503
|
labelRange: context.auxiliaryRange || undefined,
|
|
24175
24504
|
showSubTotals: context.showSubTotals ?? false,
|
|
24176
24505
|
showConnectorLines: context.showConnectorLines ?? true,
|
|
24177
24506
|
firstValueAsSubtotal: context.firstValueAsSubtotal ?? false,
|
|
24507
|
+
axesDesign: context.axesDesign,
|
|
24178
24508
|
};
|
|
24179
24509
|
}
|
|
24180
24510
|
getContextCreation() {
|
|
24511
|
+
const range = [];
|
|
24512
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
24513
|
+
range.push({
|
|
24514
|
+
...this.dataSetDesign?.[i],
|
|
24515
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
24516
|
+
});
|
|
24517
|
+
}
|
|
24181
24518
|
return {
|
|
24182
24519
|
...this,
|
|
24183
|
-
range
|
|
24520
|
+
range,
|
|
24184
24521
|
auxiliaryRange: this.labelRange
|
|
24185
24522
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
24186
24523
|
: undefined,
|
|
@@ -24200,11 +24537,18 @@ class WaterfallChart extends AbstractChart {
|
|
|
24200
24537
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
24201
24538
|
}
|
|
24202
24539
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
24540
|
+
const ranges = [];
|
|
24541
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
24542
|
+
ranges.push({
|
|
24543
|
+
...this.dataSetDesign?.[i],
|
|
24544
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
24545
|
+
});
|
|
24546
|
+
}
|
|
24203
24547
|
return {
|
|
24204
24548
|
type: "waterfall",
|
|
24205
24549
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
24206
24550
|
background: this.background,
|
|
24207
|
-
dataSets:
|
|
24551
|
+
dataSets: ranges,
|
|
24208
24552
|
legendPosition: this.legendPosition,
|
|
24209
24553
|
verticalAxisPosition: this.verticalAxisPosition,
|
|
24210
24554
|
labelRange: labelRange
|
|
@@ -24218,6 +24562,7 @@ class WaterfallChart extends AbstractChart {
|
|
|
24218
24562
|
negativeValuesColor: this.negativeValuesColor,
|
|
24219
24563
|
subTotalValuesColor: this.subTotalValuesColor,
|
|
24220
24564
|
firstValueAsSubtotal: this.firstValueAsSubtotal,
|
|
24565
|
+
axesDesign: this.axesDesign,
|
|
24221
24566
|
};
|
|
24222
24567
|
}
|
|
24223
24568
|
getDefinitionForExcel() {
|
|
@@ -24277,6 +24622,7 @@ function getWaterfallConfiguration(chart, labels, dataSeriesLabels, localeFormat
|
|
|
24277
24622
|
grid: {
|
|
24278
24623
|
display: false,
|
|
24279
24624
|
},
|
|
24625
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
24280
24626
|
},
|
|
24281
24627
|
y: {
|
|
24282
24628
|
position: chart.verticalAxisPosition,
|
|
@@ -24297,6 +24643,7 @@ function getWaterfallConfiguration(chart, labels, dataSeriesLabels, localeFormat
|
|
|
24297
24643
|
return context.tick.value === 0 ? 2 : 1;
|
|
24298
24644
|
},
|
|
24299
24645
|
},
|
|
24646
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
24300
24647
|
},
|
|
24301
24648
|
};
|
|
24302
24649
|
config.options.plugins.tooltip = {
|
|
@@ -26356,13 +26703,14 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26356
26703
|
if (!singleColumn) {
|
|
26357
26704
|
dataSetZone = { ...zone, left: zone.left + 1 };
|
|
26358
26705
|
}
|
|
26359
|
-
const
|
|
26706
|
+
const dataRange = zoneToXc(dataSetZone);
|
|
26707
|
+
const dataSets = [{ dataRange, yAxisId: "y" }];
|
|
26360
26708
|
const sheetId = getters.getActiveSheetId();
|
|
26361
26709
|
const topLeftCell = getters.getCell({ sheetId, col: zone.left, row: zone.top });
|
|
26362
26710
|
if (getZoneArea(zone) === 1 && topLeftCell?.content) {
|
|
26363
26711
|
return {
|
|
26364
26712
|
type: "scorecard",
|
|
26365
|
-
title: "",
|
|
26713
|
+
title: { text: "" },
|
|
26366
26714
|
background: topLeftCell.style?.fillColor || undefined,
|
|
26367
26715
|
keyValue: zoneToXc(zone),
|
|
26368
26716
|
baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
|
|
@@ -26398,7 +26746,7 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26398
26746
|
const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
|
|
26399
26747
|
if (canChartParseLabels(labelRange, getters)) {
|
|
26400
26748
|
return {
|
|
26401
|
-
title,
|
|
26749
|
+
title: { text: title },
|
|
26402
26750
|
dataSets,
|
|
26403
26751
|
labelsAsText: false,
|
|
26404
26752
|
stacked: false,
|
|
@@ -26407,7 +26755,6 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26407
26755
|
labelRange: labelRangeXc,
|
|
26408
26756
|
type: "line",
|
|
26409
26757
|
dataSetsHaveTitle,
|
|
26410
|
-
verticalAxisPosition: "left",
|
|
26411
26758
|
legendPosition: newLegendPos,
|
|
26412
26759
|
};
|
|
26413
26760
|
}
|
|
@@ -26415,24 +26762,23 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26415
26762
|
if (singleColumn &&
|
|
26416
26763
|
getData(getters, _dataSets[0]).every((e) => typeof e === "string" && !isEvaluationError(e))) {
|
|
26417
26764
|
return {
|
|
26418
|
-
title: "",
|
|
26419
|
-
dataSets,
|
|
26765
|
+
title: { text: "" },
|
|
26766
|
+
dataSets: [{ dataRange }],
|
|
26420
26767
|
aggregated: true,
|
|
26421
|
-
labelRange:
|
|
26768
|
+
labelRange: dataRange,
|
|
26422
26769
|
type: "pie",
|
|
26423
26770
|
legendPosition: "top",
|
|
26424
26771
|
dataSetsHaveTitle: false,
|
|
26425
26772
|
};
|
|
26426
26773
|
}
|
|
26427
26774
|
return {
|
|
26428
|
-
title,
|
|
26775
|
+
title: { text: title },
|
|
26429
26776
|
dataSets,
|
|
26430
26777
|
labelRange: labelRangeXc,
|
|
26431
26778
|
type: "bar",
|
|
26432
26779
|
stacked: false,
|
|
26433
26780
|
aggregated: false,
|
|
26434
26781
|
dataSetsHaveTitle,
|
|
26435
|
-
verticalAxisPosition: "left",
|
|
26436
26782
|
legendPosition: newLegendPos,
|
|
26437
26783
|
};
|
|
26438
26784
|
}
|
|
@@ -29473,6 +29819,41 @@ class OTRegistry extends Registry {
|
|
|
29473
29819
|
}
|
|
29474
29820
|
const otRegistry = new OTRegistry();
|
|
29475
29821
|
|
|
29822
|
+
css /* scss */ `
|
|
29823
|
+
.o-checkbox {
|
|
29824
|
+
display: flex;
|
|
29825
|
+
justify-items: center;
|
|
29826
|
+
input {
|
|
29827
|
+
margin-right: 5px;
|
|
29828
|
+
}
|
|
29829
|
+
}
|
|
29830
|
+
`;
|
|
29831
|
+
class Checkbox extends owl.Component {
|
|
29832
|
+
static template = "o-spreadsheet.Checkbox";
|
|
29833
|
+
static props = {
|
|
29834
|
+
label: { type: String, optional: true },
|
|
29835
|
+
value: { type: Boolean, optional: true },
|
|
29836
|
+
className: { type: String, optional: true },
|
|
29837
|
+
name: { type: String, optional: true },
|
|
29838
|
+
title: { type: String, optional: true },
|
|
29839
|
+
disabled: { type: Boolean, optional: true },
|
|
29840
|
+
onChange: Function,
|
|
29841
|
+
};
|
|
29842
|
+
static defaultProps = { value: false };
|
|
29843
|
+
onChange(ev) {
|
|
29844
|
+
const value = ev.target.checked;
|
|
29845
|
+
this.props.onChange(value);
|
|
29846
|
+
}
|
|
29847
|
+
}
|
|
29848
|
+
|
|
29849
|
+
class Section extends owl.Component {
|
|
29850
|
+
static template = "o_spreadsheet.Section";
|
|
29851
|
+
static props = {
|
|
29852
|
+
class: { type: String, optional: true },
|
|
29853
|
+
slots: Object,
|
|
29854
|
+
};
|
|
29855
|
+
}
|
|
29856
|
+
|
|
29476
29857
|
// The name is misleading and can be confused with the DOM focus.
|
|
29477
29858
|
class FocusStore {
|
|
29478
29859
|
mutators = ["focus", "unfocus"];
|
|
@@ -29497,6 +29878,7 @@ class FocusStore {
|
|
|
29497
29878
|
class SelectionInputStore extends SpreadsheetStore {
|
|
29498
29879
|
initialRanges;
|
|
29499
29880
|
inputHasSingleRange;
|
|
29881
|
+
colors;
|
|
29500
29882
|
mutators = [
|
|
29501
29883
|
"resetWithRanges",
|
|
29502
29884
|
"focusById",
|
|
@@ -29512,10 +29894,11 @@ class SelectionInputStore extends SpreadsheetStore {
|
|
|
29512
29894
|
inputSheetId;
|
|
29513
29895
|
focusStore = this.get(FocusStore);
|
|
29514
29896
|
highlightStore = this.get(HighlightStore);
|
|
29515
|
-
constructor(get, initialRanges = [], inputHasSingleRange = false) {
|
|
29897
|
+
constructor(get, initialRanges = [], inputHasSingleRange = false, colors = []) {
|
|
29516
29898
|
super(get);
|
|
29517
29899
|
this.initialRanges = initialRanges;
|
|
29518
29900
|
this.inputHasSingleRange = inputHasSingleRange;
|
|
29901
|
+
this.colors = colors;
|
|
29519
29902
|
if (inputHasSingleRange && initialRanges.length > 1) {
|
|
29520
29903
|
throw new Error("Input with a single range cannot be instantiated with several range references.");
|
|
29521
29904
|
}
|
|
@@ -29657,11 +30040,12 @@ class SelectionInputStore extends SpreadsheetStore {
|
|
|
29657
30040
|
* e.g. ["A1", "Sheet2!B3", "E12"]
|
|
29658
30041
|
*/
|
|
29659
30042
|
get selectionInputs() {
|
|
30043
|
+
const generator = new ColorGenerator(this.colors);
|
|
29660
30044
|
return this.ranges.map((input, index) => Object.assign({}, input, {
|
|
29661
30045
|
color: this.hasMainFocus &&
|
|
29662
30046
|
this.focusedRangeIndex !== null &&
|
|
29663
30047
|
this.getters.isRangeValid(input.xc)
|
|
29664
|
-
?
|
|
30048
|
+
? generator.next()
|
|
29665
30049
|
: null,
|
|
29666
30050
|
isFocused: this.hasMainFocus && this.focusedRangeIndex === index,
|
|
29667
30051
|
isValidRange: input.xc === "" || this.getters.isRangeValid(input.xc),
|
|
@@ -29738,10 +30122,14 @@ class SelectionInputStore extends SpreadsheetStore {
|
|
|
29738
30122
|
*/
|
|
29739
30123
|
insertNewRange(index, values) {
|
|
29740
30124
|
const currentMaxId = Math.max(0, ...this.ranges.map((range) => Number(range.id)));
|
|
30125
|
+
const colors = new ColorGenerator(this.colors);
|
|
30126
|
+
for (let i = 0; i < index; i++) {
|
|
30127
|
+
colors.next();
|
|
30128
|
+
}
|
|
29741
30129
|
this.ranges.splice(index, 0, ...values.map((xc, i) => ({
|
|
29742
30130
|
xc,
|
|
29743
30131
|
id: currentMaxId + i + 1,
|
|
29744
|
-
color: colors
|
|
30132
|
+
color: colors.next(),
|
|
29745
30133
|
})));
|
|
29746
30134
|
}
|
|
29747
30135
|
/**
|
|
@@ -29885,6 +30273,7 @@ class SelectionInput extends owl.Component {
|
|
|
29885
30273
|
class: { type: String, optional: true },
|
|
29886
30274
|
onSelectionChanged: { type: Function, optional: true },
|
|
29887
30275
|
onSelectionConfirmed: { type: Function, optional: true },
|
|
30276
|
+
colors: { type: Array, optional: true, default: [] },
|
|
29888
30277
|
};
|
|
29889
30278
|
state = owl.useState({
|
|
29890
30279
|
isMissing: false,
|
|
@@ -29909,7 +30298,7 @@ class SelectionInput extends owl.Component {
|
|
|
29909
30298
|
}
|
|
29910
30299
|
setup() {
|
|
29911
30300
|
owl.useEffect(() => this.focusedInput.el?.focus(), () => [this.focusedInput.el]);
|
|
29912
|
-
this.store = useLocalStore(SelectionInputStore, this.props.ranges, this.props.hasSingleRange || false);
|
|
30301
|
+
this.store = useLocalStore(SelectionInputStore, this.props.ranges, this.props.hasSingleRange || false, this.props.colors);
|
|
29913
30302
|
owl.onWillUpdateProps((nextProps) => {
|
|
29914
30303
|
if (nextProps.ranges.join() !== this.store.selectionInputValues.join()) {
|
|
29915
30304
|
this.triggerChange();
|
|
@@ -29984,6 +30373,26 @@ class SelectionInput extends owl.Component {
|
|
|
29984
30373
|
}
|
|
29985
30374
|
}
|
|
29986
30375
|
|
|
30376
|
+
class ChartDataSeries extends owl.Component {
|
|
30377
|
+
static template = "o-spreadsheet.ChartDataSeries";
|
|
30378
|
+
static components = { SelectionInput, Section };
|
|
30379
|
+
static props = {
|
|
30380
|
+
ranges: Array,
|
|
30381
|
+
hasSingleRange: { type: Boolean, optional: true },
|
|
30382
|
+
onSelectionChanged: Function,
|
|
30383
|
+
onSelectionConfirmed: Function,
|
|
30384
|
+
};
|
|
30385
|
+
get ranges() {
|
|
30386
|
+
return this.props.ranges.map((r) => r.dataRange);
|
|
30387
|
+
}
|
|
30388
|
+
get colors() {
|
|
30389
|
+
return this.props.ranges.map((r) => r.backgroundColor);
|
|
30390
|
+
}
|
|
30391
|
+
get title() {
|
|
30392
|
+
return this.props.hasSingleRange ? _t("Data range") : _t("Data series");
|
|
30393
|
+
}
|
|
30394
|
+
}
|
|
30395
|
+
|
|
29987
30396
|
css /* scss */ `
|
|
29988
30397
|
.o-validation-error,
|
|
29989
30398
|
.o-validation-warning {
|
|
@@ -30010,55 +30419,6 @@ class ValidationMessages extends owl.Component {
|
|
|
30010
30419
|
}
|
|
30011
30420
|
}
|
|
30012
30421
|
|
|
30013
|
-
css /* scss */ `
|
|
30014
|
-
.o-checkbox {
|
|
30015
|
-
display: flex;
|
|
30016
|
-
justify-items: center;
|
|
30017
|
-
input {
|
|
30018
|
-
margin-right: 5px;
|
|
30019
|
-
}
|
|
30020
|
-
}
|
|
30021
|
-
`;
|
|
30022
|
-
class Checkbox extends owl.Component {
|
|
30023
|
-
static template = "o-spreadsheet.Checkbox";
|
|
30024
|
-
static props = {
|
|
30025
|
-
label: { type: String, optional: true },
|
|
30026
|
-
value: { type: Boolean, optional: true },
|
|
30027
|
-
className: { type: String, optional: true },
|
|
30028
|
-
name: { type: String, optional: true },
|
|
30029
|
-
title: { type: String, optional: true },
|
|
30030
|
-
disabled: { type: Boolean, optional: true },
|
|
30031
|
-
onChange: Function,
|
|
30032
|
-
};
|
|
30033
|
-
static defaultProps = { value: false };
|
|
30034
|
-
onChange(ev) {
|
|
30035
|
-
const value = ev.target.checked;
|
|
30036
|
-
this.props.onChange(value);
|
|
30037
|
-
}
|
|
30038
|
-
}
|
|
30039
|
-
|
|
30040
|
-
class Section extends owl.Component {
|
|
30041
|
-
static template = "o_spreadsheet.Section";
|
|
30042
|
-
static props = {
|
|
30043
|
-
class: { type: String, optional: true },
|
|
30044
|
-
slots: Object,
|
|
30045
|
-
};
|
|
30046
|
-
}
|
|
30047
|
-
|
|
30048
|
-
class ChartDataSeries extends owl.Component {
|
|
30049
|
-
static template = "o-spreadsheet.ChartDataSeries";
|
|
30050
|
-
static components = { SelectionInput, Section };
|
|
30051
|
-
static props = {
|
|
30052
|
-
ranges: Array,
|
|
30053
|
-
hasSingleRange: { type: Boolean, optional: true },
|
|
30054
|
-
onSelectionChanged: Function,
|
|
30055
|
-
onSelectionConfirmed: Function,
|
|
30056
|
-
};
|
|
30057
|
-
get title() {
|
|
30058
|
-
return this.props.hasSingleRange ? _t("Data range") : _t("Data series");
|
|
30059
|
-
}
|
|
30060
|
-
}
|
|
30061
|
-
|
|
30062
30422
|
class ChartErrorSection extends owl.Component {
|
|
30063
30423
|
static template = "o-spreadsheet.ChartErrorSection";
|
|
30064
30424
|
static components = { Section, ValidationMessages };
|
|
@@ -30087,8 +30447,6 @@ class ChartLabelRange extends owl.Component {
|
|
|
30087
30447
|
class GenericChartConfigPanel extends owl.Component {
|
|
30088
30448
|
static template = "o-spreadsheet-GenericChartConfigPanel";
|
|
30089
30449
|
static components = {
|
|
30090
|
-
SelectionInput,
|
|
30091
|
-
ValidationMessages,
|
|
30092
30450
|
ChartDataSeries,
|
|
30093
30451
|
ChartLabelRange,
|
|
30094
30452
|
Section,
|
|
@@ -30147,7 +30505,10 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
30147
30505
|
* button "confirm" is clicked
|
|
30148
30506
|
*/
|
|
30149
30507
|
onDataSeriesRangesChanged(ranges) {
|
|
30150
|
-
this.dataSeriesRanges = ranges
|
|
30508
|
+
this.dataSeriesRanges = ranges.map((dataRange, i) => ({
|
|
30509
|
+
...this.dataSeriesRanges?.[i],
|
|
30510
|
+
dataRange,
|
|
30511
|
+
}));
|
|
30151
30512
|
this.state.datasetDispatchResult = this.props.canUpdateChart(this.props.figureId, {
|
|
30152
30513
|
dataSets: this.dataSeriesRanges,
|
|
30153
30514
|
});
|
|
@@ -30190,7 +30551,7 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
30190
30551
|
}
|
|
30191
30552
|
const getters = this.env.model.getters;
|
|
30192
30553
|
const sheetId = getters.getActiveSheetId();
|
|
30193
|
-
const labelRange =
|
|
30554
|
+
const labelRange = createValidRange(getters, sheetId, this.labelRange);
|
|
30194
30555
|
const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
|
|
30195
30556
|
if (dataSets.length) {
|
|
30196
30557
|
return dataSets[0].dataRange.zone.top + 1;
|
|
@@ -30219,15 +30580,102 @@ class BarConfigPanel extends GenericChartConfigPanel {
|
|
|
30219
30580
|
}
|
|
30220
30581
|
}
|
|
30221
30582
|
|
|
30583
|
+
const ANGLE_DOWN = /*xml*/ `
|
|
30584
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 224 256">
|
|
30585
|
+
<path d="M201.4 342.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 274.7 86.6 137.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z" transform="translate(0, 9) scale(0.5,0.5)"/>
|
|
30586
|
+
</svg>
|
|
30587
|
+
`;
|
|
30588
|
+
const BACKGROUND_COLOR = "#fdfdfd";
|
|
30589
|
+
const BORDER_COLOR = "#8b8b8b";
|
|
30590
|
+
css /* scss */ `
|
|
30591
|
+
.o_side_panel_collapsible_title {
|
|
30592
|
+
font-size: 16px;
|
|
30593
|
+
font-weight: bold;
|
|
30594
|
+
cursor: pointer;
|
|
30595
|
+
padding: 6px 0px 6px 6px !important;
|
|
30596
|
+
|
|
30597
|
+
.collapsor:before {
|
|
30598
|
+
transform: rotate(-90deg);
|
|
30599
|
+
content: url("data:image/svg+xml,${encodeURIComponent(ANGLE_DOWN)}");
|
|
30600
|
+
width: 12px;
|
|
30601
|
+
display: inline-block;
|
|
30602
|
+
margin: 0 5px 0px 2px;
|
|
30603
|
+
height: 22px;
|
|
30604
|
+
transform-origin: 7px 10px;
|
|
30605
|
+
transition: transform 0.2s ease-in-out;
|
|
30606
|
+
}
|
|
30607
|
+
.collapsor:not(.collapsed):before {
|
|
30608
|
+
transform: rotate(0);
|
|
30609
|
+
}
|
|
30610
|
+
|
|
30611
|
+
.collapsor:not(.collapsed) {
|
|
30612
|
+
background-color: ${BACKGROUND_COLOR};
|
|
30613
|
+
border: solid ${BORDER_COLOR} 1px;
|
|
30614
|
+
margin: -3px 1px -6px -5px;
|
|
30615
|
+
border-radius: 5px 5px 0px 0px;
|
|
30616
|
+
border-bottom: 0px;
|
|
30617
|
+
transition-delay: 0s;
|
|
30618
|
+
}
|
|
30619
|
+
|
|
30620
|
+
.collapsor {
|
|
30621
|
+
width: 100%;
|
|
30622
|
+
margin: -2px 2px -5px -4px;
|
|
30623
|
+
padding: 2px 0 6px 4px;
|
|
30624
|
+
background-color: transparent;
|
|
30625
|
+
border: solid ${BORDER_COLOR} 0px;
|
|
30626
|
+
transition-delay: 0.35s;
|
|
30627
|
+
transition-property: all;
|
|
30628
|
+
}
|
|
30629
|
+
|
|
30630
|
+
.collapsor.collapsed {
|
|
30631
|
+
}
|
|
30632
|
+
}
|
|
30633
|
+
|
|
30634
|
+
.collapsible_section {
|
|
30635
|
+
background-color: #fff;
|
|
30636
|
+
border: solid ${BORDER_COLOR} 1px;
|
|
30637
|
+
border-top: 0;
|
|
30638
|
+
border-radius: 0 0 5px 5px;
|
|
30639
|
+
margin: 0px 1px 0px 1px;
|
|
30640
|
+
|
|
30641
|
+
&.collapsing,
|
|
30642
|
+
&.show {
|
|
30643
|
+
background-color: ${BACKGROUND_COLOR};
|
|
30644
|
+
}
|
|
30645
|
+
|
|
30646
|
+
&.collapsing {
|
|
30647
|
+
transition: height 0.35s, background-color 0.35s !important;
|
|
30648
|
+
}
|
|
30649
|
+
}
|
|
30650
|
+
`;
|
|
30651
|
+
let CURRENT_COLLAPSIBLE_ID = 0;
|
|
30652
|
+
class SidePanelCollapsible extends owl.Component {
|
|
30653
|
+
static template = "o-spreadsheet-SidePanelCollapsible";
|
|
30654
|
+
static props = {
|
|
30655
|
+
slots: Object,
|
|
30656
|
+
collapsedAtInit: { type: Boolean, optional: true },
|
|
30657
|
+
class: { type: String, optional: true },
|
|
30658
|
+
};
|
|
30659
|
+
currentId = (CURRENT_COLLAPSIBLE_ID++).toString();
|
|
30660
|
+
}
|
|
30661
|
+
|
|
30662
|
+
/**
|
|
30663
|
+
* Start listening to pointer events and apply the given callbacks.
|
|
30664
|
+
*
|
|
30665
|
+
* @returns A function to remove the listeners.
|
|
30666
|
+
*/
|
|
30222
30667
|
function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
|
|
30223
|
-
const
|
|
30224
|
-
onMouseUp(ev);
|
|
30668
|
+
const removeListeners = () => {
|
|
30225
30669
|
window.removeEventListener("pointerdown", onMouseDown);
|
|
30226
30670
|
window.removeEventListener("pointerup", _onMouseUp);
|
|
30227
30671
|
window.removeEventListener("dragstart", _onDragStart);
|
|
30228
30672
|
window.removeEventListener("pointermove", onMouseMove);
|
|
30229
30673
|
window.removeEventListener("wheel", onMouseMove);
|
|
30230
30674
|
};
|
|
30675
|
+
const _onMouseUp = (ev) => {
|
|
30676
|
+
onMouseUp(ev);
|
|
30677
|
+
removeListeners();
|
|
30678
|
+
};
|
|
30231
30679
|
function _onDragStart(ev) {
|
|
30232
30680
|
ev.preventDefault();
|
|
30233
30681
|
}
|
|
@@ -30239,6 +30687,7 @@ function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
|
|
|
30239
30687
|
// preventDefault() is not allowed in passive event handler.
|
|
30240
30688
|
// https://chromestatus.com/feature/6662647093133312
|
|
30241
30689
|
window.addEventListener("wheel", onMouseMove, { passive: false });
|
|
30690
|
+
return removeListeners;
|
|
30242
30691
|
}
|
|
30243
30692
|
/**
|
|
30244
30693
|
* Function to be used during a pointerdown event, this function allows to
|
|
@@ -30800,63 +31249,325 @@ class RoundColorPicker extends owl.Component {
|
|
|
30800
31249
|
}
|
|
30801
31250
|
}
|
|
30802
31251
|
|
|
31252
|
+
css /* scss */ `
|
|
31253
|
+
.o-chart-title-designer {
|
|
31254
|
+
> span {
|
|
31255
|
+
height: 30px;
|
|
31256
|
+
}
|
|
31257
|
+
|
|
31258
|
+
.o-menu-item-button.active {
|
|
31259
|
+
background-color: #e6f4ea;
|
|
31260
|
+
color: #188038;
|
|
31261
|
+
}
|
|
31262
|
+
|
|
31263
|
+
.o-dropdown-content {
|
|
31264
|
+
overflow-y: auto;
|
|
31265
|
+
overflow-x: hidden;
|
|
31266
|
+
padding: 2px;
|
|
31267
|
+
z-index: 100;
|
|
31268
|
+
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
|
|
31269
|
+
|
|
31270
|
+
.o-dropdown-line {
|
|
31271
|
+
> span {
|
|
31272
|
+
padding: 4px;
|
|
31273
|
+
}
|
|
31274
|
+
}
|
|
31275
|
+
}
|
|
31276
|
+
}
|
|
31277
|
+
`;
|
|
30803
31278
|
class ChartTitle extends owl.Component {
|
|
30804
31279
|
static template = "o-spreadsheet.ChartTitle";
|
|
30805
|
-
static components = { Section };
|
|
30806
|
-
static props = {
|
|
31280
|
+
static components = { Section, ColorPickerWidget };
|
|
31281
|
+
static props = {
|
|
31282
|
+
title: String,
|
|
31283
|
+
updateTitle: Function,
|
|
31284
|
+
name: { type: String, optional: true },
|
|
31285
|
+
toggleItalic: { type: Function, optional: true },
|
|
31286
|
+
toggleBold: { type: Function, optional: true },
|
|
31287
|
+
updateAlignment: { type: Function, optional: true },
|
|
31288
|
+
updateColor: { type: Function, optional: true },
|
|
31289
|
+
style: { type: Object, optional: true },
|
|
31290
|
+
};
|
|
31291
|
+
openedEl = null;
|
|
31292
|
+
setup() {
|
|
31293
|
+
owl.useExternalListener(window, "click", this.onExternalClick);
|
|
31294
|
+
}
|
|
31295
|
+
state = owl.useState({
|
|
31296
|
+
activeTool: "",
|
|
31297
|
+
});
|
|
30807
31298
|
updateTitle(ev) {
|
|
30808
|
-
this.props.
|
|
31299
|
+
this.props.updateTitle(ev.target.value);
|
|
31300
|
+
}
|
|
31301
|
+
toggleDropdownTool(tool, ev) {
|
|
31302
|
+
const isOpen = this.state.activeTool === tool;
|
|
31303
|
+
this.closeMenus();
|
|
31304
|
+
this.state.activeTool = isOpen ? "" : tool;
|
|
31305
|
+
this.openedEl = isOpen ? null : ev.target;
|
|
31306
|
+
}
|
|
31307
|
+
/**
|
|
31308
|
+
* TODO: This is clearly not a goot way to handle external click, but
|
|
31309
|
+
* we currently have no other way to do it ... Should be done in
|
|
31310
|
+
* another task to handle the fact we want only one menu opened at a
|
|
31311
|
+
* time with something like a menuStore ?
|
|
31312
|
+
*/
|
|
31313
|
+
onExternalClick(ev) {
|
|
31314
|
+
if (this.openedEl === ev.target) {
|
|
31315
|
+
return;
|
|
31316
|
+
}
|
|
31317
|
+
this.closeMenus();
|
|
31318
|
+
}
|
|
31319
|
+
onColorPicked(color) {
|
|
31320
|
+
this.props.updateColor?.(color);
|
|
31321
|
+
this.closeMenus();
|
|
31322
|
+
}
|
|
31323
|
+
updateAlignment(aligment) {
|
|
31324
|
+
this.props.updateAlignment?.(aligment);
|
|
31325
|
+
this.closeMenus();
|
|
31326
|
+
}
|
|
31327
|
+
closeMenus() {
|
|
31328
|
+
this.state.activeTool = "";
|
|
31329
|
+
this.openedEl = null;
|
|
30809
31330
|
}
|
|
30810
31331
|
}
|
|
30811
31332
|
|
|
30812
|
-
class
|
|
30813
|
-
static template = "o-spreadsheet-
|
|
30814
|
-
static components = {
|
|
31333
|
+
class AxisDesignEditor extends owl.Component {
|
|
31334
|
+
static template = "o-spreadsheet-AxisDesignEditor";
|
|
31335
|
+
static components = {
|
|
31336
|
+
Section,
|
|
31337
|
+
ChartTitle,
|
|
31338
|
+
};
|
|
31339
|
+
state = owl.useState({ currentAxis: "x" });
|
|
31340
|
+
get axisTitleStyle() {
|
|
31341
|
+
const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
|
|
31342
|
+
return {
|
|
31343
|
+
color: "",
|
|
31344
|
+
align: "center",
|
|
31345
|
+
...axisDesign.title,
|
|
31346
|
+
};
|
|
31347
|
+
}
|
|
31348
|
+
updateAxisTitleColor(color) {
|
|
31349
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31350
|
+
axesDesign[this.state.currentAxis] = {
|
|
31351
|
+
...axesDesign[this.state.currentAxis],
|
|
31352
|
+
title: {
|
|
31353
|
+
...(axesDesign[this.state.currentAxis]?.title ?? {}),
|
|
31354
|
+
color,
|
|
31355
|
+
},
|
|
31356
|
+
};
|
|
31357
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31358
|
+
}
|
|
31359
|
+
toggleBoldAxisTitle() {
|
|
31360
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31361
|
+
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
31362
|
+
axesDesign[this.state.currentAxis] = {
|
|
31363
|
+
...axesDesign[this.state.currentAxis],
|
|
31364
|
+
title: {
|
|
31365
|
+
...title,
|
|
31366
|
+
bold: !title?.bold,
|
|
31367
|
+
},
|
|
31368
|
+
};
|
|
31369
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31370
|
+
}
|
|
31371
|
+
toggleItalicAxisTitle() {
|
|
31372
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31373
|
+
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
31374
|
+
axesDesign[this.state.currentAxis] = {
|
|
31375
|
+
...axesDesign[this.state.currentAxis],
|
|
31376
|
+
title: {
|
|
31377
|
+
...title,
|
|
31378
|
+
italic: !title?.italic,
|
|
31379
|
+
},
|
|
31380
|
+
};
|
|
31381
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31382
|
+
}
|
|
31383
|
+
updateAxisTitleAlignment(align) {
|
|
31384
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31385
|
+
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
31386
|
+
axesDesign[this.state.currentAxis] = {
|
|
31387
|
+
...axesDesign[this.state.currentAxis],
|
|
31388
|
+
title: {
|
|
31389
|
+
...title,
|
|
31390
|
+
align,
|
|
31391
|
+
},
|
|
31392
|
+
};
|
|
31393
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31394
|
+
}
|
|
31395
|
+
updateAxisEditor(ev) {
|
|
31396
|
+
const axis = ev.target.value;
|
|
31397
|
+
this.state.currentAxis = axis;
|
|
31398
|
+
}
|
|
31399
|
+
getAxisTitle() {
|
|
31400
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31401
|
+
return axesDesign[this.state.currentAxis]?.title.text || "";
|
|
31402
|
+
}
|
|
31403
|
+
updateAxisTitle(text) {
|
|
31404
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31405
|
+
axesDesign[this.state.currentAxis] = {
|
|
31406
|
+
...axesDesign[this.state.currentAxis],
|
|
31407
|
+
title: {
|
|
31408
|
+
...axesDesign?.[this.state.currentAxis]?.title,
|
|
31409
|
+
text,
|
|
31410
|
+
},
|
|
31411
|
+
};
|
|
31412
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31413
|
+
}
|
|
31414
|
+
}
|
|
31415
|
+
|
|
31416
|
+
class GeneralDesignEditor extends owl.Component {
|
|
31417
|
+
static template = "o-spreadsheet-GeneralDesignEditor";
|
|
31418
|
+
static components = {
|
|
31419
|
+
RoundColorPicker,
|
|
31420
|
+
ChartTitle,
|
|
31421
|
+
Section,
|
|
31422
|
+
SidePanelCollapsible,
|
|
31423
|
+
};
|
|
30815
31424
|
static props = {
|
|
30816
31425
|
figureId: String,
|
|
30817
31426
|
definition: Object,
|
|
30818
31427
|
updateChart: Function,
|
|
30819
|
-
|
|
31428
|
+
slots: { type: Object, optional: true },
|
|
30820
31429
|
};
|
|
31430
|
+
state;
|
|
31431
|
+
setup() {
|
|
31432
|
+
this.state = owl.useState({
|
|
31433
|
+
activeTool: "",
|
|
31434
|
+
});
|
|
31435
|
+
}
|
|
30821
31436
|
get title() {
|
|
30822
|
-
return
|
|
31437
|
+
return this.props.definition.title;
|
|
31438
|
+
}
|
|
31439
|
+
toggleDropdownTool(tool, ev) {
|
|
31440
|
+
const isOpen = this.state.activeTool === tool;
|
|
31441
|
+
this.state.activeTool = isOpen ? "" : tool;
|
|
30823
31442
|
}
|
|
30824
31443
|
updateBackgroundColor(color) {
|
|
30825
31444
|
this.props.updateChart(this.props.figureId, {
|
|
30826
31445
|
background: color,
|
|
30827
31446
|
});
|
|
30828
31447
|
}
|
|
30829
|
-
updateTitle(
|
|
31448
|
+
updateTitle(newTitle) {
|
|
31449
|
+
const title = { ...this.title, text: newTitle };
|
|
30830
31450
|
this.props.updateChart(this.props.figureId, { title });
|
|
30831
31451
|
}
|
|
30832
|
-
|
|
30833
|
-
|
|
30834
|
-
|
|
30835
|
-
|
|
31452
|
+
get titleStyle() {
|
|
31453
|
+
return {
|
|
31454
|
+
align: "left",
|
|
31455
|
+
...this.title,
|
|
31456
|
+
};
|
|
30836
31457
|
}
|
|
30837
|
-
|
|
30838
|
-
|
|
31458
|
+
updateChartTitleColor(color) {
|
|
31459
|
+
const title = { ...this.title, color };
|
|
31460
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31461
|
+
this.state.activeTool = "";
|
|
31462
|
+
}
|
|
31463
|
+
toggleBoldChartTitle() {
|
|
31464
|
+
let title = this.title;
|
|
31465
|
+
title = { ...title, bold: !title.bold };
|
|
31466
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31467
|
+
}
|
|
31468
|
+
toggleItalicChartTitle() {
|
|
31469
|
+
let title = this.title;
|
|
31470
|
+
title = { ...title, italic: !title.italic };
|
|
31471
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31472
|
+
}
|
|
31473
|
+
updateChartTitleAlignment(align) {
|
|
31474
|
+
const title = { ...this.title, align };
|
|
31475
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31476
|
+
this.state.activeTool = "";
|
|
30839
31477
|
}
|
|
30840
31478
|
}
|
|
30841
31479
|
|
|
30842
|
-
class
|
|
30843
|
-
static template = "o-spreadsheet-
|
|
30844
|
-
|
|
30845
|
-
|
|
30846
|
-
|
|
30847
|
-
|
|
30848
|
-
|
|
30849
|
-
|
|
31480
|
+
class ChartWithAxisDesignPanel extends owl.Component {
|
|
31481
|
+
static template = "o-spreadsheet-ChartWithAxisDesignPanel";
|
|
31482
|
+
static components = {
|
|
31483
|
+
GeneralDesignEditor,
|
|
31484
|
+
SidePanelCollapsible,
|
|
31485
|
+
Section,
|
|
31486
|
+
AxisDesignEditor,
|
|
31487
|
+
RoundColorPicker,
|
|
31488
|
+
};
|
|
31489
|
+
state = owl.useState({ index: 0 });
|
|
31490
|
+
get axesList() {
|
|
31491
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
|
|
31492
|
+
let axes = [{ id: "x", name: _t("Horizontal axis") }];
|
|
31493
|
+
if (useLeftAxis) {
|
|
31494
|
+
axes.push({ id: "y", name: _t("Vertical (left) axis") });
|
|
31495
|
+
}
|
|
31496
|
+
if (useRightAxis) {
|
|
31497
|
+
axes.push({ id: "y1", name: _t("Vertical (right) axis") });
|
|
31498
|
+
}
|
|
31499
|
+
return axes;
|
|
30850
31500
|
}
|
|
30851
|
-
|
|
31501
|
+
updateLegendPosition(ev) {
|
|
30852
31502
|
this.props.updateChart(this.props.figureId, {
|
|
30853
|
-
|
|
31503
|
+
legendPosition: ev.target.value,
|
|
30854
31504
|
});
|
|
30855
31505
|
}
|
|
30856
|
-
|
|
30857
|
-
|
|
30858
|
-
|
|
30859
|
-
|
|
31506
|
+
getDataSeries() {
|
|
31507
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.figureId);
|
|
31508
|
+
if (!runtime || !("chartJsConfig" in runtime)) {
|
|
31509
|
+
return [];
|
|
31510
|
+
}
|
|
31511
|
+
return runtime.chartJsConfig.data.datasets.map((d) => d.label);
|
|
31512
|
+
}
|
|
31513
|
+
updateSerieEditor(ev) {
|
|
31514
|
+
const chartId = this.props.figureId;
|
|
31515
|
+
const selectedIndex = ev.target.selectedIndex;
|
|
31516
|
+
const runtime = this.env.model.getters.getChartRuntime(chartId);
|
|
31517
|
+
if (!runtime) {
|
|
31518
|
+
return;
|
|
31519
|
+
}
|
|
31520
|
+
this.state.index = selectedIndex;
|
|
31521
|
+
}
|
|
31522
|
+
updateDataSeriesColor(color) {
|
|
31523
|
+
const dataSets = this.props.definition.dataSets;
|
|
31524
|
+
if (!dataSets?.[this.state.index])
|
|
31525
|
+
return;
|
|
31526
|
+
dataSets[this.state.index] = {
|
|
31527
|
+
...dataSets[this.state.index],
|
|
31528
|
+
backgroundColor: color,
|
|
31529
|
+
};
|
|
31530
|
+
this.props.updateChart(this.props.figureId, { dataSets });
|
|
31531
|
+
}
|
|
31532
|
+
getDataSerieColor() {
|
|
31533
|
+
const dataSets = this.props.definition.dataSets;
|
|
31534
|
+
if (!dataSets?.[this.state.index])
|
|
31535
|
+
return "";
|
|
31536
|
+
const color = dataSets[this.state.index].backgroundColor;
|
|
31537
|
+
return color ? toHex(color) : getNthColor(this.state.index);
|
|
31538
|
+
}
|
|
31539
|
+
updateDataSeriesAxis(ev) {
|
|
31540
|
+
const axis = ev.target.value;
|
|
31541
|
+
const dataSets = this.props.definition.dataSets;
|
|
31542
|
+
if (!dataSets?.[this.state.index])
|
|
31543
|
+
return;
|
|
31544
|
+
dataSets[this.state.index] = {
|
|
31545
|
+
...dataSets[this.state.index],
|
|
31546
|
+
yAxisId: axis === "left" ? "y" : "y1",
|
|
31547
|
+
};
|
|
31548
|
+
this.props.updateChart(this.props.figureId, { dataSets });
|
|
31549
|
+
}
|
|
31550
|
+
getDataSerieAxis() {
|
|
31551
|
+
const dataSets = this.props.definition.dataSets;
|
|
31552
|
+
if (!dataSets?.[this.state.index])
|
|
31553
|
+
return "left";
|
|
31554
|
+
return dataSets[this.state.index].yAxisId === "y1" ? "right" : "left";
|
|
31555
|
+
}
|
|
31556
|
+
updateDataSeriesLabel(ev) {
|
|
31557
|
+
const label = ev.target.value;
|
|
31558
|
+
const dataSets = this.props.definition.dataSets;
|
|
31559
|
+
if (!dataSets?.[this.state.index])
|
|
31560
|
+
return;
|
|
31561
|
+
dataSets[this.state.index] = {
|
|
31562
|
+
...dataSets[this.state.index],
|
|
31563
|
+
label,
|
|
31564
|
+
};
|
|
31565
|
+
this.props.updateChart(this.props.figureId, { dataSets });
|
|
31566
|
+
}
|
|
31567
|
+
getDataSerieLabel() {
|
|
31568
|
+
const dataSets = this.props.definition.dataSets;
|
|
31569
|
+
return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
|
|
31570
|
+
}
|
|
30860
31571
|
}
|
|
30861
31572
|
|
|
30862
31573
|
class GaugeChartConfigPanel extends owl.Component {
|
|
@@ -30891,7 +31602,7 @@ class GaugeChartConfigPanel extends owl.Component {
|
|
|
30891
31602
|
});
|
|
30892
31603
|
}
|
|
30893
31604
|
getDataRange() {
|
|
30894
|
-
return this.dataRange || "";
|
|
31605
|
+
return { dataRange: this.dataRange || "" };
|
|
30895
31606
|
}
|
|
30896
31607
|
}
|
|
30897
31608
|
|
|
@@ -30933,24 +31644,24 @@ css /* scss */ `
|
|
|
30933
31644
|
class GaugeChartDesignPanel extends owl.Component {
|
|
30934
31645
|
static template = "o-spreadsheet-GaugeChartDesignPanel";
|
|
30935
31646
|
static components = {
|
|
30936
|
-
|
|
30937
|
-
RoundColorPicker,
|
|
30938
|
-
ChartTitle,
|
|
31647
|
+
SidePanelCollapsible,
|
|
30939
31648
|
Section,
|
|
31649
|
+
RoundColorPicker,
|
|
31650
|
+
GeneralDesignEditor,
|
|
31651
|
+
ChartErrorSection,
|
|
30940
31652
|
};
|
|
30941
31653
|
static props = {
|
|
30942
31654
|
figureId: String,
|
|
30943
31655
|
definition: Object,
|
|
30944
31656
|
updateChart: Function,
|
|
30945
|
-
canUpdateChart: Function,
|
|
31657
|
+
canUpdateChart: { type: Function, optional: true },
|
|
30946
31658
|
};
|
|
30947
|
-
state
|
|
30948
|
-
|
|
30949
|
-
|
|
30950
|
-
|
|
30951
|
-
|
|
30952
|
-
|
|
30953
|
-
return _t(this.props.definition.title);
|
|
31659
|
+
state;
|
|
31660
|
+
setup() {
|
|
31661
|
+
this.state = owl.useState({
|
|
31662
|
+
sectionRuleDispatchResult: undefined,
|
|
31663
|
+
sectionRule: deepCopy(this.props.definition.sectionRule),
|
|
31664
|
+
});
|
|
30954
31665
|
}
|
|
30955
31666
|
get designErrorMessages() {
|
|
30956
31667
|
const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
|
|
@@ -30961,8 +31672,8 @@ class GaugeChartDesignPanel extends owl.Component {
|
|
|
30961
31672
|
background: color,
|
|
30962
31673
|
});
|
|
30963
31674
|
}
|
|
30964
|
-
updateTitle(
|
|
30965
|
-
this.props.updateChart(this.props.figureId, { title });
|
|
31675
|
+
updateTitle(content) {
|
|
31676
|
+
this.props.updateChart(this.props.figureId, { title: { text: content } });
|
|
30966
31677
|
}
|
|
30967
31678
|
isRangeMinInvalid() {
|
|
30968
31679
|
return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
|
|
@@ -31057,8 +31768,23 @@ class LineConfigPanel extends GenericChartConfigPanel {
|
|
|
31057
31768
|
}
|
|
31058
31769
|
}
|
|
31059
31770
|
|
|
31060
|
-
class
|
|
31061
|
-
static template = "o-spreadsheet-
|
|
31771
|
+
class PieChartDesignPanel extends owl.Component {
|
|
31772
|
+
static template = "o-spreadsheet-PieChartDesignPanel";
|
|
31773
|
+
static components = {
|
|
31774
|
+
GeneralDesignEditor,
|
|
31775
|
+
Section,
|
|
31776
|
+
};
|
|
31777
|
+
static props = {
|
|
31778
|
+
figureId: String,
|
|
31779
|
+
definition: Object,
|
|
31780
|
+
updateChart: Function,
|
|
31781
|
+
canUpdateChart: { type: Function, optional: true },
|
|
31782
|
+
};
|
|
31783
|
+
updateLegendPosition(ev) {
|
|
31784
|
+
this.props.updateChart(this.props.figureId, {
|
|
31785
|
+
legendPosition: ev.target.value,
|
|
31786
|
+
});
|
|
31787
|
+
}
|
|
31062
31788
|
}
|
|
31063
31789
|
|
|
31064
31790
|
class ScatterConfigPanel extends GenericChartConfigPanel {
|
|
@@ -31152,16 +31878,19 @@ class ScorecardChartConfigPanel extends owl.Component {
|
|
|
31152
31878
|
|
|
31153
31879
|
class ScorecardChartDesignPanel extends owl.Component {
|
|
31154
31880
|
static template = "o-spreadsheet-ScorecardChartDesignPanel";
|
|
31155
|
-
static components = {
|
|
31881
|
+
static components = {
|
|
31882
|
+
GeneralDesignEditor,
|
|
31883
|
+
RoundColorPicker,
|
|
31884
|
+
SidePanelCollapsible,
|
|
31885
|
+
Section,
|
|
31886
|
+
Checkbox,
|
|
31887
|
+
};
|
|
31156
31888
|
static props = {
|
|
31157
31889
|
figureId: String,
|
|
31158
31890
|
definition: Object,
|
|
31159
31891
|
updateChart: Function,
|
|
31160
|
-
canUpdateChart: Function,
|
|
31892
|
+
canUpdateChart: { type: Function, optional: true },
|
|
31161
31893
|
};
|
|
31162
|
-
get title() {
|
|
31163
|
-
return _t(this.props.definition.title);
|
|
31164
|
-
}
|
|
31165
31894
|
get colorsSectionTitle() {
|
|
31166
31895
|
return this.props.definition.baselineMode === "progress"
|
|
31167
31896
|
? _t("Progress bar colors")
|
|
@@ -31170,8 +31899,8 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
31170
31899
|
get humanizeNumbersLabel() {
|
|
31171
31900
|
return _t("Humanize numbers");
|
|
31172
31901
|
}
|
|
31173
|
-
updateTitle(
|
|
31174
|
-
this.props.updateChart(this.props.figureId, { title });
|
|
31902
|
+
updateTitle(content) {
|
|
31903
|
+
this.props.updateChart(this.props.figureId, { title: { text: content } });
|
|
31175
31904
|
}
|
|
31176
31905
|
updateHumanizeNumbers(humanize) {
|
|
31177
31906
|
this.props.updateChart(this.props.figureId, { humanize });
|
|
@@ -31200,14 +31929,22 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
31200
31929
|
}
|
|
31201
31930
|
}
|
|
31202
31931
|
|
|
31203
|
-
class WaterfallChartDesignPanel extends
|
|
31932
|
+
class WaterfallChartDesignPanel extends owl.Component {
|
|
31204
31933
|
static template = "o-spreadsheet-WaterfallChartDesignPanel";
|
|
31205
|
-
static components = {
|
|
31206
|
-
|
|
31207
|
-
|
|
31208
|
-
|
|
31209
|
-
|
|
31210
|
-
|
|
31934
|
+
static components = {
|
|
31935
|
+
GeneralDesignEditor,
|
|
31936
|
+
Checkbox,
|
|
31937
|
+
SidePanelCollapsible,
|
|
31938
|
+
Section,
|
|
31939
|
+
RoundColorPicker,
|
|
31940
|
+
AxisDesignEditor,
|
|
31941
|
+
};
|
|
31942
|
+
static props = {
|
|
31943
|
+
figureId: String,
|
|
31944
|
+
definition: Object,
|
|
31945
|
+
updateChart: Function,
|
|
31946
|
+
canUpdateChart: { type: Function, optional: true },
|
|
31947
|
+
};
|
|
31211
31948
|
onUpdateShowSubTotals(showSubTotals) {
|
|
31212
31949
|
this.props.updateChart(this.props.figureId, { showSubTotals });
|
|
31213
31950
|
}
|
|
@@ -31220,11 +31957,11 @@ class WaterfallChartDesignPanel extends GenericChartDesignPanel {
|
|
|
31220
31957
|
updateColor(colorName, color) {
|
|
31221
31958
|
this.props.updateChart(this.props.figureId, { [colorName]: color });
|
|
31222
31959
|
}
|
|
31223
|
-
|
|
31224
|
-
|
|
31225
|
-
|
|
31226
|
-
|
|
31227
|
-
|
|
31960
|
+
get axesList() {
|
|
31961
|
+
return [
|
|
31962
|
+
{ id: "x", name: _t("Horizontal axis") },
|
|
31963
|
+
{ id: "y", name: _t("Vertical axis") },
|
|
31964
|
+
];
|
|
31228
31965
|
}
|
|
31229
31966
|
get positiveValuesColor() {
|
|
31230
31967
|
return (this.props.definition.positiveValuesColor ||
|
|
@@ -31238,29 +31975,39 @@ class WaterfallChartDesignPanel extends GenericChartDesignPanel {
|
|
|
31238
31975
|
return (this.props.definition.subTotalValuesColor ||
|
|
31239
31976
|
CHART_WATERFALL_SUBTOTAL_COLOR);
|
|
31240
31977
|
}
|
|
31978
|
+
updateLegendPosition(ev) {
|
|
31979
|
+
this.props.updateChart(this.props.figureId, {
|
|
31980
|
+
legendPosition: ev.target.value,
|
|
31981
|
+
});
|
|
31982
|
+
}
|
|
31983
|
+
updateVerticalAxisPosition(ev) {
|
|
31984
|
+
this.props.updateChart(this.props.figureId, {
|
|
31985
|
+
verticalAxisPosition: ev.target.value,
|
|
31986
|
+
});
|
|
31987
|
+
}
|
|
31241
31988
|
}
|
|
31242
31989
|
|
|
31243
31990
|
const chartSidePanelComponentRegistry = new Registry();
|
|
31244
31991
|
chartSidePanelComponentRegistry
|
|
31245
31992
|
.add("line", {
|
|
31246
31993
|
configuration: LineConfigPanel,
|
|
31247
|
-
design:
|
|
31994
|
+
design: ChartWithAxisDesignPanel,
|
|
31248
31995
|
})
|
|
31249
31996
|
.add("scatter", {
|
|
31250
31997
|
configuration: ScatterConfigPanel,
|
|
31251
|
-
design:
|
|
31998
|
+
design: ChartWithAxisDesignPanel,
|
|
31252
31999
|
})
|
|
31253
32000
|
.add("bar", {
|
|
31254
32001
|
configuration: BarConfigPanel,
|
|
31255
|
-
design:
|
|
32002
|
+
design: ChartWithAxisDesignPanel,
|
|
31256
32003
|
})
|
|
31257
32004
|
.add("combo", {
|
|
31258
|
-
configuration:
|
|
31259
|
-
design:
|
|
32005
|
+
configuration: GenericChartConfigPanel,
|
|
32006
|
+
design: ChartWithAxisDesignPanel,
|
|
31260
32007
|
})
|
|
31261
32008
|
.add("pie", {
|
|
31262
32009
|
configuration: GenericChartConfigPanel,
|
|
31263
|
-
design:
|
|
32010
|
+
design: PieChartDesignPanel,
|
|
31264
32011
|
})
|
|
31265
32012
|
.add("gauge", {
|
|
31266
32013
|
configuration: GaugeChartConfigPanel,
|
|
@@ -31546,6 +32293,7 @@ function useDragAndDropListItems() {
|
|
|
31546
32293
|
state.itemsStyle = {};
|
|
31547
32294
|
document.body.style.cursor = previousCursor;
|
|
31548
32295
|
args.onCancel?.();
|
|
32296
|
+
cleanUp();
|
|
31549
32297
|
};
|
|
31550
32298
|
const onDragEnd = (itemId, indexAtEnd) => {
|
|
31551
32299
|
state.draggedItemId = undefined;
|
|
@@ -31566,7 +32314,8 @@ function useDragAndDropListItems() {
|
|
|
31566
32314
|
onDragEnd,
|
|
31567
32315
|
onCancel: state.cancel,
|
|
31568
32316
|
});
|
|
31569
|
-
startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
|
|
32317
|
+
const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
|
|
32318
|
+
cleanupFns.push(stopListening);
|
|
31570
32319
|
const onScroll = dndHelper.onScroll.bind(dndHelper);
|
|
31571
32320
|
args.containerEl.addEventListener("scroll", onScroll);
|
|
31572
32321
|
cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
|
|
@@ -31643,7 +32392,7 @@ class DOMDndHelper {
|
|
|
31643
32392
|
this.moveDraggedItemToPosition(this.currentMousePosition + this.scrollOffset);
|
|
31644
32393
|
}
|
|
31645
32394
|
onMouseMove(ev) {
|
|
31646
|
-
if (ev.button
|
|
32395
|
+
if (ev.button > 1) {
|
|
31647
32396
|
this.onCancel();
|
|
31648
32397
|
return;
|
|
31649
32398
|
}
|
|
@@ -34386,7 +35135,7 @@ class SpreadsheetPivotTable {
|
|
|
34386
35135
|
* This function converts a list of data entry into a spreadsheet pivot table.
|
|
34387
35136
|
*/
|
|
34388
35137
|
function dataEntriesToSpreadsheetPivotTable(dataEntries, definition) {
|
|
34389
|
-
const columnsTree =
|
|
35138
|
+
const columnsTree = dataEntriesToColumnsTree(dataEntries, definition.columns, 0);
|
|
34390
35139
|
computeWidthOfColumnsNodes(columnsTree, definition.measures.length);
|
|
34391
35140
|
const cols = columnsTreeToColumns(columnsTree, definition);
|
|
34392
35141
|
const rows = dataEntriesToRows(dataEntries, 0, definition.rows, [], []);
|
|
@@ -34437,7 +35186,7 @@ function dataEntriesToRows(dataEntries, index, rows, fields, values) {
|
|
|
34437
35186
|
/**
|
|
34438
35187
|
* Create the columns tree from data entries.
|
|
34439
35188
|
*/
|
|
34440
|
-
function
|
|
35189
|
+
function dataEntriesToColumnsTree(dataEntries, columns, index) {
|
|
34441
35190
|
if (index >= columns.length) {
|
|
34442
35191
|
return [];
|
|
34443
35192
|
}
|
|
@@ -34449,7 +35198,7 @@ function dateEntriesToColumnsTree(dataEntries, columns, index) {
|
|
|
34449
35198
|
return {
|
|
34450
35199
|
value,
|
|
34451
35200
|
field: colName,
|
|
34452
|
-
children:
|
|
35201
|
+
children: dataEntriesToColumnsTree(groups[value] || [], columns, index + 1),
|
|
34453
35202
|
width: 0,
|
|
34454
35203
|
};
|
|
34455
35204
|
});
|
|
@@ -34956,7 +35705,12 @@ class SpreadsheetPivot {
|
|
|
34956
35705
|
if (!field) {
|
|
34957
35706
|
throw new Error(`Field ${this.fieldKeys[index]} does not exist`);
|
|
34958
35707
|
}
|
|
34959
|
-
|
|
35708
|
+
if (cell.value === "") {
|
|
35709
|
+
entry[field.name] = { value: null, type: CellValueType.empty };
|
|
35710
|
+
}
|
|
35711
|
+
else {
|
|
35712
|
+
entry[field.name] = cell;
|
|
35713
|
+
}
|
|
34960
35714
|
}
|
|
34961
35715
|
entry["__count"] = { value: 1, type: CellValueType.number };
|
|
34962
35716
|
dataEntries.push(entry);
|
|
@@ -36712,14 +37466,15 @@ class FigureComponent extends owl.Component {
|
|
|
36712
37466
|
}
|
|
36713
37467
|
onKeyDown(ev) {
|
|
36714
37468
|
const figure = this.props.figure;
|
|
36715
|
-
|
|
37469
|
+
const keyDownShortcut = keyboardEventToShortcutString(ev);
|
|
37470
|
+
switch (keyDownShortcut) {
|
|
36716
37471
|
case "Delete":
|
|
37472
|
+
case "Backspace":
|
|
36717
37473
|
this.env.model.dispatch("DELETE_FIGURE", {
|
|
36718
37474
|
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
36719
37475
|
id: figure.id,
|
|
36720
37476
|
});
|
|
36721
37477
|
this.props.onFigureDeleted();
|
|
36722
|
-
ev.stopPropagation();
|
|
36723
37478
|
ev.preventDefault();
|
|
36724
37479
|
ev.stopPropagation();
|
|
36725
37480
|
break;
|
|
@@ -36740,7 +37495,22 @@ class FigureComponent extends owl.Component {
|
|
|
36740
37495
|
x: figure.x + delta[0],
|
|
36741
37496
|
y: figure.y + delta[1],
|
|
36742
37497
|
});
|
|
37498
|
+
ev.preventDefault();
|
|
37499
|
+
ev.stopPropagation();
|
|
37500
|
+
break;
|
|
37501
|
+
case "Ctrl+A":
|
|
37502
|
+
// Maybe in the future we will implement a way to select all figures
|
|
37503
|
+
ev.preventDefault();
|
|
36743
37504
|
ev.stopPropagation();
|
|
37505
|
+
break;
|
|
37506
|
+
case "Ctrl+Y":
|
|
37507
|
+
case "Ctrl+Z":
|
|
37508
|
+
if (keyDownShortcut === "Ctrl+Y") {
|
|
37509
|
+
this.env.model.dispatch("REQUEST_REDO");
|
|
37510
|
+
}
|
|
37511
|
+
else if (keyDownShortcut === "Ctrl+Z") {
|
|
37512
|
+
this.env.model.dispatch("REQUEST_UNDO");
|
|
37513
|
+
}
|
|
36744
37514
|
ev.preventDefault();
|
|
36745
37515
|
ev.stopPropagation();
|
|
36746
37516
|
break;
|
|
@@ -38020,9 +38790,6 @@ class FilterIcon extends owl.Component {
|
|
|
38020
38790
|
|
|
38021
38791
|
class FilterIconsOverlay extends owl.Component {
|
|
38022
38792
|
static template = "o-spreadsheet-FilterIconsOverlay";
|
|
38023
|
-
static props = {
|
|
38024
|
-
onMouseDown: Function,
|
|
38025
|
-
};
|
|
38026
38793
|
static components = {
|
|
38027
38794
|
GridCellIcon,
|
|
38028
38795
|
FilterIcon,
|
|
@@ -38262,6 +39029,7 @@ class GridOverlay extends owl.Component {
|
|
|
38262
39029
|
};
|
|
38263
39030
|
gridOverlay = owl.useRef("gridOverlay");
|
|
38264
39031
|
gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
|
|
39032
|
+
cellPopovers;
|
|
38265
39033
|
setup() {
|
|
38266
39034
|
useCellHovered(this.env, this.gridOverlay, this.props.onCellHovered);
|
|
38267
39035
|
const resizeObserver = new ResizeObserver(() => {
|
|
@@ -38283,6 +39051,7 @@ class GridOverlay extends owl.Component {
|
|
|
38283
39051
|
const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
|
|
38284
39052
|
return scrollY > 0;
|
|
38285
39053
|
});
|
|
39054
|
+
this.cellPopovers = useStore(CellPopoverStore);
|
|
38286
39055
|
}
|
|
38287
39056
|
get gridOverlayEl() {
|
|
38288
39057
|
if (!this.gridOverlay.el) {
|
|
@@ -38296,16 +39065,18 @@ class GridOverlay extends owl.Component {
|
|
|
38296
39065
|
get isPaintingFormat() {
|
|
38297
39066
|
return this.env.model.getters.isPaintingFormat();
|
|
38298
39067
|
}
|
|
38299
|
-
onMouseDown(ev
|
|
39068
|
+
onMouseDown(ev) {
|
|
38300
39069
|
if (ev.button > 0) {
|
|
38301
39070
|
// not main button, probably a context menu
|
|
38302
39071
|
return;
|
|
38303
39072
|
}
|
|
39073
|
+
if (ev.target === this.gridOverlay.el && this.cellPopovers.isOpen) {
|
|
39074
|
+
this.cellPopovers.close();
|
|
39075
|
+
}
|
|
38304
39076
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
38305
39077
|
this.props.onCellClicked(col, row, {
|
|
38306
39078
|
expandZone: ev.shiftKey,
|
|
38307
39079
|
addZone: isCtrlKey(ev),
|
|
38308
|
-
closePopover: modifiers?.closePopover ?? true,
|
|
38309
39080
|
});
|
|
38310
39081
|
}
|
|
38311
39082
|
onDoubleClick(ev) {
|
|
@@ -40449,9 +41220,6 @@ class Grid extends owl.Component {
|
|
|
40449
41220
|
// Zone selection with mouse
|
|
40450
41221
|
// ---------------------------------------------------------------------------
|
|
40451
41222
|
onCellClicked(col, row, modifiers) {
|
|
40452
|
-
if (modifiers.closePopover && this.cellPopovers.isOpen) {
|
|
40453
|
-
this.cellPopovers.close();
|
|
40454
|
-
}
|
|
40455
41223
|
if (this.composerStore.editionMode === "editing") {
|
|
40456
41224
|
this.composerStore.stopEdition();
|
|
40457
41225
|
}
|
|
@@ -42324,11 +43092,20 @@ function isImageData(data) {
|
|
|
42324
43092
|
return "imageSrc" in data;
|
|
42325
43093
|
}
|
|
42326
43094
|
function convertChartData(chartData) {
|
|
42327
|
-
const dataSetsHaveTitle = chartData.dataSets
|
|
43095
|
+
const dataSetsHaveTitle = chartData.dataSets.some((ds) => "reference" in (ds.label ?? {}));
|
|
42328
43096
|
const labelRange = chartData.labelRange
|
|
42329
43097
|
? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
|
|
42330
43098
|
: undefined;
|
|
42331
|
-
|
|
43099
|
+
const dataSets = chartData.dataSets.map((data) => {
|
|
43100
|
+
let label = undefined;
|
|
43101
|
+
if (data.label && "text" in data.label) {
|
|
43102
|
+
label = data.label.text;
|
|
43103
|
+
}
|
|
43104
|
+
return {
|
|
43105
|
+
dataRange: convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle),
|
|
43106
|
+
label,
|
|
43107
|
+
};
|
|
43108
|
+
});
|
|
42332
43109
|
// For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
|
|
42333
43110
|
if (chartData.type === "pie") {
|
|
42334
43111
|
dataSets.reverse();
|
|
@@ -42337,10 +43114,9 @@ function convertChartData(chartData) {
|
|
|
42337
43114
|
dataSets,
|
|
42338
43115
|
dataSetsHaveTitle,
|
|
42339
43116
|
labelRange,
|
|
42340
|
-
title: chartData.title
|
|
43117
|
+
title: chartData.title ?? { text: "" },
|
|
42341
43118
|
type: chartData.type,
|
|
42342
43119
|
background: convertColor({ rgb: chartData.backgroundColor }) || "#FFFFFF",
|
|
42343
|
-
verticalAxisPosition: chartData.verticalAxisPosition,
|
|
42344
43120
|
legendPosition: chartData.legendPosition,
|
|
42345
43121
|
stacked: chartData.stacked || false,
|
|
42346
43122
|
aggregated: false,
|
|
@@ -43455,25 +44231,20 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43455
44231
|
return this.extractComboChart(rootChartElement);
|
|
43456
44232
|
}
|
|
43457
44233
|
// Title can be separated into multiple xml elements (for styling and such), we only import the text
|
|
43458
|
-
const chartTitle = this.mapOnElements({ parent: rootChartElement, query: "c:title a:t" }, (textElement) => {
|
|
44234
|
+
const chartTitle = this.mapOnElements({ parent: rootChartElement, query: "c:chart > c:title a:t" }, (textElement) => {
|
|
43459
44235
|
return textElement.textContent || "";
|
|
43460
44236
|
}).join("");
|
|
43461
44237
|
const barChartGrouping = this.extractChildAttr(rootChartElement, "c:grouping", "val", {
|
|
43462
44238
|
default: "clustered",
|
|
43463
44239
|
}).asString();
|
|
43464
44240
|
return {
|
|
43465
|
-
title: chartTitle,
|
|
44241
|
+
title: { text: chartTitle },
|
|
43466
44242
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
43467
|
-
dataSets: this.extractChartDatasets(this.
|
|
44243
|
+
dataSets: this.extractChartDatasets(this.querySelectorAll(rootChartElement, `c:${chartType}`), chartType),
|
|
43468
44244
|
labelRange: this.extractChildTextContent(rootChartElement, `c:ser ${chartType === "scatterChart" ? "c:numRef" : "c:cat"} c:f`),
|
|
43469
44245
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
43470
44246
|
default: "ffffff",
|
|
43471
44247
|
}).asString(),
|
|
43472
|
-
verticalAxisPosition: this.extractChildAttr(rootChartElement, "c:valAx > c:axPos", "val", {
|
|
43473
|
-
default: "l",
|
|
43474
|
-
}).asString() === "r"
|
|
43475
|
-
? "right"
|
|
43476
|
-
: "left",
|
|
43477
44248
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
|
|
43478
44249
|
default: "b",
|
|
43479
44250
|
}).asString()],
|
|
@@ -43491,21 +44262,16 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43491
44262
|
default: "clustered",
|
|
43492
44263
|
}).asString();
|
|
43493
44264
|
return {
|
|
43494
|
-
title: chartTitle,
|
|
44265
|
+
title: { text: chartTitle },
|
|
43495
44266
|
type: "combo",
|
|
43496
44267
|
dataSets: [
|
|
43497
|
-
...this.extractChartDatasets(this.
|
|
43498
|
-
...this.extractChartDatasets(this.
|
|
44268
|
+
...this.extractChartDatasets(this.querySelectorAll(chartElement, `c:barChart`), "comboChart"),
|
|
44269
|
+
...this.extractChartDatasets(this.querySelectorAll(chartElement, `c:lineChart`), "comboChart"),
|
|
43499
44270
|
],
|
|
43500
44271
|
labelRange: this.extractChildTextContent(chartElement, "c:ser c:cat c:f"),
|
|
43501
44272
|
backgroundColor: this.extractChildAttr(chartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
43502
44273
|
default: "ffffff",
|
|
43503
44274
|
}).asString(),
|
|
43504
|
-
verticalAxisPosition: this.extractChildAttr(chartElement, "c:valAx > c:axPos", "val", {
|
|
43505
|
-
default: "l",
|
|
43506
|
-
}).asString() === "r"
|
|
43507
|
-
? "right"
|
|
43508
|
-
: "left",
|
|
43509
44275
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
|
|
43510
44276
|
default: "b",
|
|
43511
44277
|
}).asString()],
|
|
@@ -43513,21 +44279,49 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43513
44279
|
fontColor: "000000",
|
|
43514
44280
|
};
|
|
43515
44281
|
}
|
|
43516
|
-
extractChartDatasets(
|
|
43517
|
-
|
|
43518
|
-
|
|
43519
|
-
|
|
43520
|
-
|
|
43521
|
-
|
|
43522
|
-
|
|
43523
|
-
|
|
43524
|
-
|
|
43525
|
-
|
|
44282
|
+
extractChartDatasets(chartElements, chartType) {
|
|
44283
|
+
return Array.from(chartElements)
|
|
44284
|
+
.map((element) => {
|
|
44285
|
+
if (chartType === "scatterChart") {
|
|
44286
|
+
return this.extractScatterChartDatasets(element);
|
|
44287
|
+
}
|
|
44288
|
+
return this.mapOnElements({ parent: element, query: "c:ser" }, (chartDataElement) => {
|
|
44289
|
+
let label = {};
|
|
44290
|
+
const reference = this.extractChildTextContent(chartDataElement, "c:tx c:f");
|
|
44291
|
+
if (reference) {
|
|
44292
|
+
label = { reference };
|
|
44293
|
+
}
|
|
44294
|
+
else {
|
|
44295
|
+
const text = this.extractChildTextContent(chartDataElement, "c:tx c:v");
|
|
44296
|
+
if (text) {
|
|
44297
|
+
label = { text };
|
|
44298
|
+
}
|
|
44299
|
+
}
|
|
44300
|
+
return {
|
|
44301
|
+
label,
|
|
44302
|
+
range: this.extractChildTextContent(chartDataElement, "c:val c:f", {
|
|
44303
|
+
required: true,
|
|
44304
|
+
}),
|
|
44305
|
+
};
|
|
44306
|
+
});
|
|
44307
|
+
})
|
|
44308
|
+
.flat();
|
|
43526
44309
|
}
|
|
43527
44310
|
extractScatterChartDatasets(chartElement) {
|
|
43528
44311
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
44312
|
+
let label = {};
|
|
44313
|
+
const reference = this.extractChildTextContent(chartDataElement, "c:tx c:f");
|
|
44314
|
+
if (reference) {
|
|
44315
|
+
label = { reference };
|
|
44316
|
+
}
|
|
44317
|
+
else {
|
|
44318
|
+
const text = this.extractChildTextContent(chartDataElement, "c:tx c:v");
|
|
44319
|
+
if (text) {
|
|
44320
|
+
label = { text };
|
|
44321
|
+
}
|
|
44322
|
+
}
|
|
43529
44323
|
return {
|
|
43530
|
-
label
|
|
44324
|
+
label,
|
|
43531
44325
|
range: this.extractChildTextContent(chartDataElement, "c:yVal c:f", { required: true }),
|
|
43532
44326
|
};
|
|
43533
44327
|
});
|
|
@@ -44259,7 +45053,7 @@ function getRelationFile(file, xmls) {
|
|
|
44259
45053
|
return relsFile;
|
|
44260
45054
|
}
|
|
44261
45055
|
|
|
44262
|
-
const EXCEL_IMPORT_VERSION =
|
|
45056
|
+
const EXCEL_IMPORT_VERSION = 16;
|
|
44263
45057
|
class XlsxReader {
|
|
44264
45058
|
warningManager;
|
|
44265
45059
|
xmls;
|
|
@@ -44737,6 +45531,30 @@ const MIGRATIONS = [
|
|
|
44737
45531
|
return data;
|
|
44738
45532
|
},
|
|
44739
45533
|
},
|
|
45534
|
+
{
|
|
45535
|
+
description: "transform chart data structure (2)",
|
|
45536
|
+
from: 16,
|
|
45537
|
+
to: 17,
|
|
45538
|
+
applyMigration(data) {
|
|
45539
|
+
for (const sheet of data.sheets || []) {
|
|
45540
|
+
for (const f in sheet.figures || []) {
|
|
45541
|
+
const figure = sheet.figures[f];
|
|
45542
|
+
if ("title" in figure.data && typeof figure.data.title === "string") {
|
|
45543
|
+
figure.data.title = { text: figure.data.title };
|
|
45544
|
+
}
|
|
45545
|
+
const figureType = figure.data.type;
|
|
45546
|
+
if (!["line", "bar", "pie", "scatter", "waterfall", "combo"].includes(figureType)) {
|
|
45547
|
+
continue;
|
|
45548
|
+
}
|
|
45549
|
+
const { dataSets, ...newData } = sheet.figures[f].data;
|
|
45550
|
+
const newDataSets = dataSets.map((dataRange) => ({ dataRange }));
|
|
45551
|
+
newData.dataSets = newDataSets;
|
|
45552
|
+
sheet.figures[f].data = newData;
|
|
45553
|
+
}
|
|
45554
|
+
}
|
|
45555
|
+
return data;
|
|
45556
|
+
},
|
|
45557
|
+
},
|
|
44740
45558
|
];
|
|
44741
45559
|
/**
|
|
44742
45560
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -48348,6 +49166,9 @@ class RangeAdapter {
|
|
|
48348
49166
|
if (range.invalidXc) {
|
|
48349
49167
|
return range.invalidXc;
|
|
48350
49168
|
}
|
|
49169
|
+
if (!this.getters.tryGetSheet(range.sheetId)) {
|
|
49170
|
+
return CellErrorType.InvalidReference;
|
|
49171
|
+
}
|
|
48351
49172
|
if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
|
|
48352
49173
|
return CellErrorType.InvalidReference;
|
|
48353
49174
|
}
|
|
@@ -51766,7 +52587,6 @@ class PositionSet {
|
|
|
51766
52587
|
*
|
|
51767
52588
|
*/
|
|
51768
52589
|
class SpreadingRelation {
|
|
51769
|
-
createEmptyPositionSet;
|
|
51770
52590
|
/**
|
|
51771
52591
|
* Internal structure:
|
|
51772
52592
|
* For something like
|
|
@@ -51797,9 +52617,6 @@ class SpreadingRelation {
|
|
|
51797
52617
|
*/
|
|
51798
52618
|
resultsToArrayFormulas = new PositionMap();
|
|
51799
52619
|
arrayFormulasToResults = new PositionMap();
|
|
51800
|
-
constructor(createEmptyPositionSet) {
|
|
51801
|
-
this.createEmptyPositionSet = createEmptyPositionSet;
|
|
51802
|
-
}
|
|
51803
52620
|
getFormulaPositionsSpreadingOn(resultPosition) {
|
|
51804
52621
|
return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
|
|
51805
52622
|
}
|
|
@@ -51818,13 +52635,13 @@ class SpreadingRelation {
|
|
|
51818
52635
|
*/
|
|
51819
52636
|
addRelation({ arrayFormulaPosition, resultPosition, }) {
|
|
51820
52637
|
if (!this.resultsToArrayFormulas.has(resultPosition)) {
|
|
51821
|
-
this.resultsToArrayFormulas.set(resultPosition,
|
|
52638
|
+
this.resultsToArrayFormulas.set(resultPosition, []);
|
|
51822
52639
|
}
|
|
51823
|
-
this.resultsToArrayFormulas.get(resultPosition)?.
|
|
52640
|
+
this.resultsToArrayFormulas.get(resultPosition)?.push(arrayFormulaPosition);
|
|
51824
52641
|
if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
|
|
51825
|
-
this.arrayFormulasToResults.set(arrayFormulaPosition,
|
|
52642
|
+
this.arrayFormulasToResults.set(arrayFormulaPosition, []);
|
|
51826
52643
|
}
|
|
51827
|
-
this.arrayFormulasToResults.get(arrayFormulaPosition)?.
|
|
52644
|
+
this.arrayFormulasToResults.get(arrayFormulaPosition)?.push(resultPosition);
|
|
51828
52645
|
}
|
|
51829
52646
|
hasArrayFormulaResult(position) {
|
|
51830
52647
|
return this.resultsToArrayFormulas.has(position);
|
|
@@ -51845,7 +52662,7 @@ class Evaluator {
|
|
|
51845
52662
|
evaluatedCells = new PositionMap();
|
|
51846
52663
|
formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
|
|
51847
52664
|
blockedArrayFormulas = new PositionSet({});
|
|
51848
|
-
spreadingRelations = new SpreadingRelation(
|
|
52665
|
+
spreadingRelations = new SpreadingRelation();
|
|
51849
52666
|
constructor(context, getters) {
|
|
51850
52667
|
this.context = context;
|
|
51851
52668
|
this.getters = getters;
|
|
@@ -51939,7 +52756,7 @@ class Evaluator {
|
|
|
51939
52756
|
}
|
|
51940
52757
|
buildDependencyGraph() {
|
|
51941
52758
|
this.blockedArrayFormulas = this.createEmptyPositionSet();
|
|
51942
|
-
this.spreadingRelations = new SpreadingRelation(
|
|
52759
|
+
this.spreadingRelations = new SpreadingRelation();
|
|
51943
52760
|
this.formulaDependencies = lazy(() => {
|
|
51944
52761
|
const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
|
|
51945
52762
|
.filter((range) => !range.invalidSheetName && !range.invalidXc)
|
|
@@ -52071,6 +52888,7 @@ class Evaluator {
|
|
|
52071
52888
|
const nbColumns = formulaReturn.length;
|
|
52072
52889
|
const nbRows = formulaReturn[0].length;
|
|
52073
52890
|
forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
|
|
52891
|
+
this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
|
|
52074
52892
|
forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
|
|
52075
52893
|
forEachSpreadPositionInMatrix(nbColumns, nbRows,
|
|
52076
52894
|
// thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
|
|
@@ -52093,6 +52911,18 @@ class Evaluator {
|
|
|
52093
52911
|
}
|
|
52094
52912
|
throw new SplillBlockedError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
|
|
52095
52913
|
}
|
|
52914
|
+
assertNoMergedCellsInSpreadZone({ sheetId, col, row }, matrixResult) {
|
|
52915
|
+
const mergedCells = this.getters.getMergesInZone(sheetId, {
|
|
52916
|
+
top: row,
|
|
52917
|
+
bottom: row + matrixResult.length,
|
|
52918
|
+
left: col,
|
|
52919
|
+
right: col + matrixResult[0].length,
|
|
52920
|
+
});
|
|
52921
|
+
if (mergedCells.length === 0) {
|
|
52922
|
+
return;
|
|
52923
|
+
}
|
|
52924
|
+
throw new SplillBlockedError(_t("Merged cells found in the spill zone. Please unmerge cells before using array formulas."));
|
|
52925
|
+
}
|
|
52096
52926
|
updateSpreadRelation({ sheetId, col, row, }) {
|
|
52097
52927
|
const arrayFormulaPosition = { sheetId, col, row };
|
|
52098
52928
|
return (i, j) => {
|
|
@@ -52330,10 +53160,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
52330
53160
|
this.evaluator.updateDependencies(cmd);
|
|
52331
53161
|
}
|
|
52332
53162
|
break;
|
|
52333
|
-
case "DUPLICATE_SHEET":
|
|
52334
|
-
case "CREATE_SHEET":
|
|
52335
|
-
this.shouldRebuildDependenciesGraph = true;
|
|
52336
|
-
break;
|
|
52337
53163
|
case "EVALUATE_CELLS":
|
|
52338
53164
|
this.evaluator.evaluateAllCells();
|
|
52339
53165
|
break;
|
|
@@ -52434,16 +53260,22 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
52434
53260
|
let newContent = undefined;
|
|
52435
53261
|
let newFormat = undefined;
|
|
52436
53262
|
let isExported = true;
|
|
53263
|
+
const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
|
|
52437
53264
|
const formulaCell = this.getCorrespondingFormulaCell(position);
|
|
52438
53265
|
if (formulaCell) {
|
|
52439
53266
|
isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
|
|
52440
53267
|
isFormula = isExported;
|
|
52441
53268
|
if (!isExported) {
|
|
52442
|
-
|
|
52443
|
-
|
|
53269
|
+
// If the cell contains a non-exported formula and that is evaluates to
|
|
53270
|
+
// nothing* ,we don't export it.
|
|
53271
|
+
// * non-falsy value are relevant and so are 0 and FALSE, which only leaves
|
|
53272
|
+
// the empty string.
|
|
53273
|
+
if (value !== "") {
|
|
53274
|
+
newContent = (value ?? "").toString();
|
|
53275
|
+
newFormat = evaluatedCell.format;
|
|
53276
|
+
}
|
|
52444
53277
|
}
|
|
52445
53278
|
}
|
|
52446
|
-
const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
|
|
52447
53279
|
const exportedCellData = exportedSheetData.cells[xc] || {};
|
|
52448
53280
|
const format = newFormat
|
|
52449
53281
|
? getItemId(newFormat, data.formats)
|
|
@@ -57066,7 +57898,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57066
57898
|
paintFormatStatus = "inactive";
|
|
57067
57899
|
originSheetId;
|
|
57068
57900
|
copiedData;
|
|
57069
|
-
_isCutOperation;
|
|
57901
|
+
_isCutOperation = false;
|
|
57070
57902
|
// ---------------------------------------------------------------------------
|
|
57071
57903
|
// Command Handling
|
|
57072
57904
|
// ---------------------------------------------------------------------------
|
|
@@ -57078,14 +57910,17 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57078
57910
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
57079
57911
|
const copiedData = this.convertOSClipboardData(cmd.text);
|
|
57080
57912
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57081
|
-
return this.isPasteAllowed(cmd.target, copiedData, { pasteOption });
|
|
57913
|
+
return this.isPasteAllowed(cmd.target, copiedData, { pasteOption, isCutOperation: false });
|
|
57082
57914
|
}
|
|
57083
57915
|
case "PASTE": {
|
|
57084
57916
|
if (!this.copiedData) {
|
|
57085
57917
|
return "EmptyClipboard" /* CommandResult.EmptyClipboard */;
|
|
57086
57918
|
}
|
|
57087
57919
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57088
|
-
return this.isPasteAllowed(cmd.target, this.copiedData, {
|
|
57920
|
+
return this.isPasteAllowed(cmd.target, this.copiedData, {
|
|
57921
|
+
pasteOption: pasteOption,
|
|
57922
|
+
isCutOperation: this._isCutOperation,
|
|
57923
|
+
});
|
|
57089
57924
|
}
|
|
57090
57925
|
case "COPY_PASTE_CELLS_ABOVE": {
|
|
57091
57926
|
const zones = this.getters.getSelectedZones();
|
|
@@ -57103,13 +57938,13 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57103
57938
|
}
|
|
57104
57939
|
case "INSERT_CELL": {
|
|
57105
57940
|
const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57106
|
-
const copiedData = this.copy(
|
|
57107
|
-
return this.isPasteAllowed(paste, copiedData, {});
|
|
57941
|
+
const copiedData = this.copy(cut);
|
|
57942
|
+
return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
|
|
57108
57943
|
}
|
|
57109
57944
|
case "DELETE_CELL": {
|
|
57110
57945
|
const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57111
|
-
const copiedData = this.copy(
|
|
57112
|
-
return this.isPasteAllowed(paste, copiedData, {});
|
|
57946
|
+
const copiedData = this.copy(cut);
|
|
57947
|
+
return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
|
|
57113
57948
|
}
|
|
57114
57949
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
57115
57950
|
if (this.paintFormatStatus !== "inactive") {
|
|
@@ -57127,23 +57962,27 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57127
57962
|
const zones = this.getters.getSelectedZones();
|
|
57128
57963
|
this.status = "visible";
|
|
57129
57964
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57130
|
-
this.copiedData = this.copy(
|
|
57965
|
+
this.copiedData = this.copy(zones);
|
|
57966
|
+
this._isCutOperation = cmd.type === "CUT";
|
|
57131
57967
|
break;
|
|
57132
57968
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
57969
|
+
this._isCutOperation = false;
|
|
57133
57970
|
this.copiedData = this.convertOSClipboardData(cmd.text);
|
|
57134
57971
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57135
|
-
this.paste(cmd.target, {
|
|
57972
|
+
this.paste(cmd.target, this.copiedData, {
|
|
57136
57973
|
pasteOption,
|
|
57137
57974
|
selectTarget: true,
|
|
57975
|
+
isCutOperation: false,
|
|
57138
57976
|
});
|
|
57139
57977
|
this.status = "invisible";
|
|
57140
57978
|
break;
|
|
57141
57979
|
}
|
|
57142
57980
|
case "PASTE": {
|
|
57143
57981
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57144
|
-
this.paste(cmd.target, {
|
|
57982
|
+
this.paste(cmd.target, this.copiedData, {
|
|
57145
57983
|
pasteOption,
|
|
57146
57984
|
selectTarget: true,
|
|
57985
|
+
isCutOperation: this._isCutOperation,
|
|
57147
57986
|
});
|
|
57148
57987
|
if (this.paintFormatStatus === "oneOff") {
|
|
57149
57988
|
this.paintFormatStatus = "inactive";
|
|
@@ -57164,9 +58003,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57164
58003
|
top: multipleRowsInSelection ? zone.top : zone.top - 1,
|
|
57165
58004
|
};
|
|
57166
58005
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57167
|
-
|
|
57168
|
-
this.paste([zone], {
|
|
57169
|
-
|
|
58006
|
+
const copiedData = this.copy([copyTarget]);
|
|
58007
|
+
this.paste([zone], copiedData, {
|
|
58008
|
+
isCutOperation: false,
|
|
57170
58009
|
selectTarget: true,
|
|
57171
58010
|
});
|
|
57172
58011
|
}
|
|
@@ -57181,9 +58020,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57181
58020
|
left: multipleColsInSelection ? zone.left : zone.left - 1,
|
|
57182
58021
|
};
|
|
57183
58022
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57184
|
-
|
|
57185
|
-
this.paste([zone], {
|
|
57186
|
-
|
|
58023
|
+
const copiedData = this.copy([copyTarget]);
|
|
58024
|
+
this.paste([zone], copiedData, {
|
|
58025
|
+
isCutOperation: false,
|
|
57187
58026
|
selectTarget: true,
|
|
57188
58027
|
});
|
|
57189
58028
|
}
|
|
@@ -57199,14 +58038,14 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57199
58038
|
}
|
|
57200
58039
|
break;
|
|
57201
58040
|
}
|
|
57202
|
-
|
|
57203
|
-
this.paste(paste, {});
|
|
58041
|
+
const copiedData = this.copy(cut);
|
|
58042
|
+
this.paste(paste, copiedData, { isCutOperation: true });
|
|
57204
58043
|
break;
|
|
57205
58044
|
}
|
|
57206
58045
|
case "INSERT_CELL": {
|
|
57207
58046
|
const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57208
|
-
|
|
57209
|
-
this.paste(paste, {});
|
|
58047
|
+
const copiedData = this.copy(cut);
|
|
58048
|
+
this.paste(paste, copiedData, { isCutOperation: true });
|
|
57210
58049
|
break;
|
|
57211
58050
|
}
|
|
57212
58051
|
case "ADD_COLUMNS_ROWS": {
|
|
@@ -57238,7 +58077,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57238
58077
|
break;
|
|
57239
58078
|
}
|
|
57240
58079
|
case "REPEAT_PASTE": {
|
|
57241
|
-
this.paste(cmd.target, {
|
|
58080
|
+
this.paste(cmd.target, this.copiedData, {
|
|
58081
|
+
isCutOperation: false,
|
|
57242
58082
|
pasteOption: cmd.pasteOption,
|
|
57243
58083
|
selectTarget: true,
|
|
57244
58084
|
});
|
|
@@ -57246,7 +58086,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57246
58086
|
}
|
|
57247
58087
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
57248
58088
|
const zones = this.getters.getSelectedZones();
|
|
57249
|
-
this.copiedData = this.copy(
|
|
58089
|
+
this.copiedData = this.copy(zones);
|
|
57250
58090
|
this.status = "visible";
|
|
57251
58091
|
if (cmd.persistent) {
|
|
57252
58092
|
this.paintFormatStatus = "persistent";
|
|
@@ -57277,7 +58117,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57277
58117
|
}
|
|
57278
58118
|
}
|
|
57279
58119
|
convertOSClipboardData(clipboardData) {
|
|
57280
|
-
this._isCutOperation = false;
|
|
57281
58120
|
const handlers = clipboardHandlersRegistries.figureHandlers
|
|
57282
58121
|
.getAll()
|
|
57283
58122
|
.map((handler) => new handler(this.getters, this.dispatch));
|
|
@@ -57315,7 +58154,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57315
58154
|
for (const handler of this.selectClipboardHandlers(copiedData)) {
|
|
57316
58155
|
const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
|
|
57317
58156
|
...options,
|
|
57318
|
-
isCutOperation: this.isCutOperation(),
|
|
57319
58157
|
});
|
|
57320
58158
|
if (result !== "Success" /* CommandResult.Success */) {
|
|
57321
58159
|
return result;
|
|
@@ -57338,9 +58176,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57338
58176
|
}
|
|
57339
58177
|
return false;
|
|
57340
58178
|
}
|
|
57341
|
-
copy(
|
|
58179
|
+
copy(zones) {
|
|
57342
58180
|
let copiedData = {};
|
|
57343
|
-
this._isCutOperation = operation === "CUT";
|
|
57344
58181
|
const clipboardData = this.getClipboardData(zones);
|
|
57345
58182
|
for (const handler of this.selectClipboardHandlers(clipboardData)) {
|
|
57346
58183
|
const data = handler.copy(clipboardData);
|
|
@@ -57348,8 +58185,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57348
58185
|
}
|
|
57349
58186
|
return copiedData;
|
|
57350
58187
|
}
|
|
57351
|
-
paste(zones, options) {
|
|
57352
|
-
if (!
|
|
58188
|
+
paste(zones, copiedData, options) {
|
|
58189
|
+
if (!copiedData) {
|
|
57353
58190
|
return;
|
|
57354
58191
|
}
|
|
57355
58192
|
let zone = undefined;
|
|
@@ -57357,12 +58194,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57357
58194
|
let target = {
|
|
57358
58195
|
zones,
|
|
57359
58196
|
};
|
|
57360
|
-
const handlers = this.selectClipboardHandlers(
|
|
58197
|
+
const handlers = this.selectClipboardHandlers(copiedData);
|
|
57361
58198
|
for (const handler of handlers) {
|
|
57362
|
-
const currentTarget = handler.getPasteTarget(zones,
|
|
57363
|
-
...options,
|
|
57364
|
-
isCutOperation: this.isCutOperation(),
|
|
57365
|
-
});
|
|
58199
|
+
const currentTarget = handler.getPasteTarget(zones, copiedData, options);
|
|
57366
58200
|
if (currentTarget.figureId) {
|
|
57367
58201
|
target.figureId = currentTarget.figureId;
|
|
57368
58202
|
}
|
|
@@ -57378,7 +58212,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57378
58212
|
if (zone !== undefined) {
|
|
57379
58213
|
this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
|
|
57380
58214
|
}
|
|
57381
|
-
handlers.forEach((handler) => handler.paste(target,
|
|
58215
|
+
handlers.forEach((handler) => handler.paste(target, copiedData, options));
|
|
57382
58216
|
if (!options?.selectTarget) {
|
|
57383
58217
|
return;
|
|
57384
58218
|
}
|
|
@@ -59764,6 +60598,7 @@ class BottomBarSheet extends owl.Component {
|
|
|
59764
60598
|
sheetDivRef = owl.useRef("sheetDiv");
|
|
59765
60599
|
sheetNameRef = owl.useRef("sheetNameSpan");
|
|
59766
60600
|
editionState = "initializing";
|
|
60601
|
+
DOMFocusableElementStore;
|
|
59767
60602
|
setup() {
|
|
59768
60603
|
owl.onMounted(() => {
|
|
59769
60604
|
if (this.isSheetActive) {
|
|
@@ -59776,6 +60611,7 @@ class BottomBarSheet extends owl.Component {
|
|
|
59776
60611
|
this.focusInputAndSelectContent();
|
|
59777
60612
|
}
|
|
59778
60613
|
});
|
|
60614
|
+
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
|
|
59779
60615
|
}
|
|
59780
60616
|
focusInputAndSelectContent() {
|
|
59781
60617
|
if (!this.state.isEditing || !this.sheetNameRef.el)
|
|
@@ -59817,9 +60653,11 @@ class BottomBarSheet extends owl.Component {
|
|
|
59817
60653
|
if (ev.key === "Enter") {
|
|
59818
60654
|
ev.preventDefault();
|
|
59819
60655
|
this.stopEdition();
|
|
60656
|
+
this.DOMFocusableElementStore.focus();
|
|
59820
60657
|
}
|
|
59821
60658
|
if (ev.key === "Escape") {
|
|
59822
60659
|
this.cancelEdition();
|
|
60660
|
+
this.DOMFocusableElementStore.focus();
|
|
59823
60661
|
}
|
|
59824
60662
|
}
|
|
59825
60663
|
onClickSheetName(ev) {
|
|
@@ -61868,6 +62706,9 @@ class Spreadsheet extends owl.Component {
|
|
|
61868
62706
|
static template = "o-spreadsheet-Spreadsheet";
|
|
61869
62707
|
static props = {
|
|
61870
62708
|
model: Object,
|
|
62709
|
+
notifyUser: { type: Function, optional: true },
|
|
62710
|
+
raiseError: { type: Function, optional: true },
|
|
62711
|
+
askConfirmation: { type: Function, optional: true },
|
|
61871
62712
|
};
|
|
61872
62713
|
static components = {
|
|
61873
62714
|
TopBar,
|
|
@@ -61914,7 +62755,11 @@ class Spreadsheet extends owl.Component {
|
|
|
61914
62755
|
toggleSidePanel: this.sidePanel.toggle.bind(this.sidePanel),
|
|
61915
62756
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
61916
62757
|
startCellEdition: (content) => this.composerFocusStore.focusGridComposerCell(content),
|
|
62758
|
+
notifyUser: (notification) => this.notificationStore.notifyUser(notification),
|
|
62759
|
+
askConfirmation: (text, confirm, cancel) => this.notificationStore.askConfirmation(text, confirm, cancel),
|
|
62760
|
+
raiseError: (text, cb) => this.notificationStore.raiseError(text, cb),
|
|
61917
62761
|
});
|
|
62762
|
+
this.notificationStore.updateNotificationCallbacks({ ...this.props });
|
|
61918
62763
|
owl.useEffect(() => {
|
|
61919
62764
|
/**
|
|
61920
62765
|
* Only refocus the grid if the active element is not a child of the spreadsheet
|
|
@@ -61937,6 +62782,9 @@ class Spreadsheet extends owl.Component {
|
|
|
61937
62782
|
if (nextProps.model !== this.props.model) {
|
|
61938
62783
|
throw new Error("Changing the props model is not supported at the moment.");
|
|
61939
62784
|
}
|
|
62785
|
+
if (!deepEquals(nextProps, this.props)) {
|
|
62786
|
+
this.notificationStore.updateNotificationCallbacks({ ...nextProps });
|
|
62787
|
+
}
|
|
61940
62788
|
});
|
|
61941
62789
|
const render = batched(this.render.bind(this, true));
|
|
61942
62790
|
owl.onMounted(() => {
|
|
@@ -61954,7 +62802,7 @@ class Spreadsheet extends owl.Component {
|
|
|
61954
62802
|
bindModelEvents() {
|
|
61955
62803
|
this.model.on("update", this, () => this.render(true));
|
|
61956
62804
|
this.model.on("notify-ui", this, (notification) => this.notificationStore.notifyUser(notification));
|
|
61957
|
-
this.model.on("raise-error-ui", this, ({ text }) => this.
|
|
62805
|
+
this.model.on("raise-error-ui", this, ({ text }) => this.notificationStore.raiseError(text));
|
|
61958
62806
|
}
|
|
61959
62807
|
unbindModelEvents() {
|
|
61960
62808
|
this.model.off("update", this);
|
|
@@ -63509,10 +64357,13 @@ function createChart(chart, chartSheetIndex, data) {
|
|
|
63509
64357
|
});
|
|
63510
64358
|
// <manualLayout/> to manually position the chart in the figure container
|
|
63511
64359
|
let title = escapeXml ``;
|
|
63512
|
-
if (chart.data.title) {
|
|
64360
|
+
if (chart.data.title?.text) {
|
|
64361
|
+
const color = chart.data.title.color
|
|
64362
|
+
? toXlsxHexColor(chart.data.title.color)
|
|
64363
|
+
: chart.data.fontColor;
|
|
63513
64364
|
title = escapeXml /*xml*/ `
|
|
63514
64365
|
<c:title>
|
|
63515
|
-
${insertText(chart.data.title, chart.data.
|
|
64366
|
+
${insertText(chart.data.title.text, color, DEFAULT_CHART_FONT_SIZE, chart.data.title)}
|
|
63516
64367
|
<c:overlay val="0" />
|
|
63517
64368
|
</c:title>
|
|
63518
64369
|
`;
|
|
@@ -63600,7 +64451,7 @@ function lineAttributes(params) {
|
|
|
63600
64451
|
</a:ln>
|
|
63601
64452
|
`;
|
|
63602
64453
|
}
|
|
63603
|
-
function insertText(text, fontColor = "000000", fontsize =
|
|
64454
|
+
function insertText(text, fontColor = "000000", fontsize = DEFAULT_CHART_FONT_SIZE, style = {}) {
|
|
63604
64455
|
return escapeXml /*xml*/ `
|
|
63605
64456
|
<c:tx>
|
|
63606
64457
|
<c:rich>
|
|
@@ -63608,13 +64459,13 @@ function insertText(text, fontColor = "000000", fontsize = 22) {
|
|
|
63608
64459
|
<a:lstStyle />
|
|
63609
64460
|
<a:p>
|
|
63610
64461
|
<a:pPr lvl="0">
|
|
63611
|
-
<a:defRPr b="0">
|
|
64462
|
+
<a:defRPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}">
|
|
63612
64463
|
${solidFill(fontColor)}
|
|
63613
64464
|
<a:latin typeface="+mn-lt"/>
|
|
63614
64465
|
</a:defRPr>
|
|
63615
64466
|
</a:pPr>
|
|
63616
64467
|
<a:r> <!-- Runs -->
|
|
63617
|
-
<a:rPr sz="${fontsize * 100}"/>
|
|
64468
|
+
<a:rPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}" sz="${fontsize * 100}"/>
|
|
63618
64469
|
<a:t>${text}</a:t>
|
|
63619
64470
|
</a:r>
|
|
63620
64471
|
</a:p>
|
|
@@ -63643,6 +64494,24 @@ function insertTextProperties(fontsize = 12, fontColor = "000000", bold = false,
|
|
|
63643
64494
|
</c:txPr>
|
|
63644
64495
|
`;
|
|
63645
64496
|
}
|
|
64497
|
+
function extractDataSetLabel(label) {
|
|
64498
|
+
if (!label) {
|
|
64499
|
+
return escapeXml /*xml*/ ``;
|
|
64500
|
+
}
|
|
64501
|
+
if ("text" in label && label.text) {
|
|
64502
|
+
return escapeXml /*xml*/ `
|
|
64503
|
+
<c:tx><c:v>${label.text}</c:v></c:tx>
|
|
64504
|
+
`;
|
|
64505
|
+
}
|
|
64506
|
+
if ("reference" in label && label.reference) {
|
|
64507
|
+
return escapeXml /*xml*/ `
|
|
64508
|
+
<c:tx>
|
|
64509
|
+
${stringRef(label.reference)}
|
|
64510
|
+
</c:tx>
|
|
64511
|
+
`;
|
|
64512
|
+
}
|
|
64513
|
+
return escapeXml /*xml*/ ``;
|
|
64514
|
+
}
|
|
63646
64515
|
function addBarChart(chart) {
|
|
63647
64516
|
// gapWitdh and overlap that define the space between clusters (in %) and the overlap between datasets (from -100: completely scattered to 100, completely overlapped)
|
|
63648
64517
|
// see gapWidth : https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_gapWidth_topic_ID0EFVEQB.html#topic_ID0EFVEQB
|
|
@@ -63650,46 +64519,72 @@ function addBarChart(chart) {
|
|
|
63650
64519
|
//
|
|
63651
64520
|
// overlap and gapWitdh seems to be by default at -20 and 20 in chart.js.
|
|
63652
64521
|
// See https://www.chartjs.org/docs/latest/charts/bar.html and https://www.chartjs.org/docs/latest/charts/bar.html#barpercentage-vs-categorypercentage
|
|
63653
|
-
const
|
|
63654
|
-
const
|
|
64522
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64523
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64524
|
+
const leftDataSetsNodes = [];
|
|
64525
|
+
const rightDataSetsNodes = [];
|
|
63655
64526
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
63656
64527
|
const color = toXlsxHexColor(colors.next());
|
|
63657
64528
|
const dataShapeProperty = shapeProperty({
|
|
63658
64529
|
backgroundColor: color,
|
|
63659
64530
|
line: { color },
|
|
63660
64531
|
});
|
|
63661
|
-
|
|
64532
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63662
64533
|
<c:ser>
|
|
63663
64534
|
<c:idx val="${dsIndex}"/>
|
|
63664
64535
|
<c:order val="${dsIndex}"/>
|
|
63665
|
-
${
|
|
64536
|
+
${extractDataSetLabel(dataset.label)}
|
|
63666
64537
|
${dataShapeProperty}
|
|
63667
64538
|
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63668
64539
|
<c:val> <!-- x-coordinate values -->
|
|
63669
64540
|
${numberRef(dataset.range)}
|
|
63670
64541
|
</c:val>
|
|
63671
64542
|
</c:ser>
|
|
63672
|
-
|
|
64543
|
+
`;
|
|
64544
|
+
if (dataset.rightYAxis) {
|
|
64545
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64546
|
+
}
|
|
64547
|
+
else {
|
|
64548
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64549
|
+
}
|
|
63673
64550
|
}
|
|
63674
|
-
// Excel does not support this feature
|
|
63675
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63676
64551
|
const grouping = chart.stacked ? "stacked" : "clustered";
|
|
63677
64552
|
const overlap = chart.stacked ? 100 : -20;
|
|
63678
64553
|
return escapeXml /*xml*/ `
|
|
63679
|
-
|
|
63680
|
-
|
|
63681
|
-
|
|
63682
|
-
|
|
63683
|
-
|
|
63684
|
-
|
|
63685
|
-
|
|
63686
|
-
|
|
63687
|
-
|
|
63688
|
-
|
|
63689
|
-
|
|
63690
|
-
|
|
63691
|
-
|
|
63692
|
-
|
|
64554
|
+
${leftDataSetsNodes.length
|
|
64555
|
+
? escapeXml /*xml*/ `
|
|
64556
|
+
<c:barChart>
|
|
64557
|
+
<c:barDir val="col"/>
|
|
64558
|
+
<c:grouping val="${grouping}"/>
|
|
64559
|
+
<c:overlap val="${overlap}"/>
|
|
64560
|
+
<c:gapWidth val="70"/>
|
|
64561
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64562
|
+
<c:varyColors val="0"/>
|
|
64563
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64564
|
+
<c:axId val="${catAxId}" />
|
|
64565
|
+
<c:axId val="${valAxId}" />
|
|
64566
|
+
</c:barChart>
|
|
64567
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64568
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64569
|
+
`
|
|
64570
|
+
: ""}
|
|
64571
|
+
${rightDataSetsNodes.length
|
|
64572
|
+
? escapeXml /*xml*/ `
|
|
64573
|
+
<c:barChart>
|
|
64574
|
+
<c:barDir val="col"/>
|
|
64575
|
+
<c:grouping val="${grouping}"/>
|
|
64576
|
+
<c:overlap val="${overlap}"/>
|
|
64577
|
+
<c:gapWidth val="70"/>
|
|
64578
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64579
|
+
<c:varyColors val="0"/>
|
|
64580
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64581
|
+
<c:axId val="${catAxId + 1}" />
|
|
64582
|
+
<c:axId val="${valAxId + 1}" />
|
|
64583
|
+
</c:barChart>
|
|
64584
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64585
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64586
|
+
`
|
|
64587
|
+
: ""}`;
|
|
63693
64588
|
}
|
|
63694
64589
|
function addComboChart(chart) {
|
|
63695
64590
|
// gapWitdh and overlap that define the space between clusters (in %) and the overlap between datasets (from -100: completely scattered to 100, completely overlapped)
|
|
@@ -63698,28 +64593,38 @@ function addComboChart(chart) {
|
|
|
63698
64593
|
//
|
|
63699
64594
|
// overlap and gapWitdh seems to be by default at -20 and 20 in chart.js.
|
|
63700
64595
|
// See https://www.chartjs.org/docs/latest/charts/bar.html and https://www.chartjs.org/docs/latest/charts/bar.html#barpercentage-vs-categorypercentage
|
|
63701
|
-
const
|
|
63702
|
-
const
|
|
63703
|
-
|
|
64596
|
+
const dataSets = chart.dataSets;
|
|
64597
|
+
const dataSetsColors = dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64598
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64599
|
+
let dataSet = dataSets[0];
|
|
64600
|
+
const firstColor = toXlsxHexColor(colors.next());
|
|
64601
|
+
const useRightAxisForBarSerie = dataSet.rightYAxis ?? false;
|
|
64602
|
+
const barDataSetNode = escapeXml /*xml*/ `
|
|
64603
|
+
<c:ser>
|
|
64604
|
+
<c:idx val="0"/>
|
|
64605
|
+
<c:order val="0"/>
|
|
64606
|
+
${extractDataSetLabel(dataSet.label)}
|
|
64607
|
+
${shapeProperty({
|
|
64608
|
+
backgroundColor: firstColor,
|
|
64609
|
+
line: { color: firstColor },
|
|
64610
|
+
})}
|
|
64611
|
+
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
64612
|
+
<!-- x-coordinate values -->
|
|
64613
|
+
<c:val>
|
|
64614
|
+
${numberRef(dataSet.range)}
|
|
64615
|
+
</c:val>
|
|
64616
|
+
</c:ser>
|
|
64617
|
+
`;
|
|
64618
|
+
const leftDataSetsNodes = [];
|
|
64619
|
+
const rightDataSetsNodes = [];
|
|
64620
|
+
for (let dsIndex = 1; dsIndex < dataSets.length; dsIndex++) {
|
|
64621
|
+
dataSet = dataSets[dsIndex];
|
|
63704
64622
|
const color = toXlsxHexColor(colors.next());
|
|
63705
64623
|
const dataShapeProperty = shapeProperty({
|
|
63706
64624
|
backgroundColor: color,
|
|
63707
64625
|
line: { color },
|
|
63708
64626
|
});
|
|
63709
|
-
|
|
63710
|
-
? escapeXml /*xml*/ `
|
|
63711
|
-
<c:ser>
|
|
63712
|
-
<c:idx val="${dsIndex}"/>
|
|
63713
|
-
<c:order val="${dsIndex}"/>
|
|
63714
|
-
${dataset.label ? escapeXml /*xml*/ `<c:tx>${stringRef(dataset.label)}</c:tx>` : ""}
|
|
63715
|
-
${dataShapeProperty}
|
|
63716
|
-
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63717
|
-
<c:val> <!-- x-coordinate values -->
|
|
63718
|
-
${numberRef(dataset.range)}
|
|
63719
|
-
</c:val>
|
|
63720
|
-
</c:ser>
|
|
63721
|
-
`
|
|
63722
|
-
: escapeXml /*xml*/ `
|
|
64627
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63723
64628
|
<c:ser>
|
|
63724
64629
|
<c:idx val="${dsIndex}"/>
|
|
63725
64630
|
<c:order val="${dsIndex}"/>
|
|
@@ -63727,18 +64632,24 @@ function addComboChart(chart) {
|
|
|
63727
64632
|
<c:marker>
|
|
63728
64633
|
<c:symbol val="circle" />
|
|
63729
64634
|
<c:size val="5"/>
|
|
64635
|
+
${dataShapeProperty}
|
|
63730
64636
|
</c:marker>
|
|
63731
|
-
${
|
|
64637
|
+
${extractDataSetLabel(dataSet.label)}
|
|
63732
64638
|
${dataShapeProperty}
|
|
63733
|
-
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
63734
|
-
|
|
63735
|
-
|
|
64639
|
+
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
64640
|
+
<!-- x-coordinate values -->
|
|
64641
|
+
<c:val>
|
|
64642
|
+
${numberRef(dataSet.range)}
|
|
63736
64643
|
</c:val>
|
|
63737
64644
|
</c:ser>
|
|
63738
|
-
|
|
64645
|
+
`;
|
|
64646
|
+
if (dataSet.rightYAxis) {
|
|
64647
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64648
|
+
}
|
|
64649
|
+
else {
|
|
64650
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64651
|
+
}
|
|
63739
64652
|
}
|
|
63740
|
-
// Excel does not support this feature
|
|
63741
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63742
64653
|
const overlap = chart.stacked ? 100 : -20;
|
|
63743
64654
|
return escapeXml /*xml*/ `
|
|
63744
64655
|
<c:barChart>
|
|
@@ -63748,34 +64659,63 @@ function addComboChart(chart) {
|
|
|
63748
64659
|
<c:gapWidth val="70"/>
|
|
63749
64660
|
<!-- each data marker in the series does not have a different color -->
|
|
63750
64661
|
<c:varyColors val="0"/>
|
|
63751
|
-
${
|
|
63752
|
-
<c:axId val="${catAxId}" />
|
|
63753
|
-
<c:axId val="${valAxId}" />
|
|
64662
|
+
${barDataSetNode}
|
|
64663
|
+
<c:axId val="${catAxId + (useRightAxisForBarSerie ? 1 : 0)}" />
|
|
64664
|
+
<c:axId val="${valAxId + (useRightAxisForBarSerie ? 1 : 0)}" />
|
|
63754
64665
|
</c:barChart>
|
|
63755
|
-
|
|
63756
|
-
|
|
63757
|
-
|
|
63758
|
-
|
|
63759
|
-
|
|
63760
|
-
|
|
63761
|
-
|
|
63762
|
-
|
|
63763
|
-
|
|
63764
|
-
|
|
64666
|
+
${leftDataSetsNodes.length
|
|
64667
|
+
? escapeXml /*xml*/ `
|
|
64668
|
+
<c:lineChart>
|
|
64669
|
+
<c:grouping val="standard"/>
|
|
64670
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64671
|
+
<c:varyColors val="0"/>
|
|
64672
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64673
|
+
<c:axId val="${catAxId}" />
|
|
64674
|
+
<c:axId val="${valAxId}" />
|
|
64675
|
+
</c:lineChart>
|
|
64676
|
+
`
|
|
64677
|
+
: ""}
|
|
64678
|
+
${rightDataSetsNodes.length
|
|
64679
|
+
? escapeXml /*xml*/ `
|
|
64680
|
+
<c:lineChart>
|
|
64681
|
+
<c:grouping val="standard"/>
|
|
64682
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64683
|
+
<c:varyColors val="0"/>
|
|
64684
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64685
|
+
<c:axId val="${catAxId + 1}" />
|
|
64686
|
+
<c:axId val="${valAxId + 1}" />
|
|
64687
|
+
</c:lineChart>
|
|
64688
|
+
`
|
|
64689
|
+
: ""}
|
|
64690
|
+
${!useRightAxisForBarSerie || leftDataSetsNodes.length
|
|
64691
|
+
? escapeXml /*xml*/ `
|
|
64692
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64693
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64694
|
+
`
|
|
64695
|
+
: ""}
|
|
64696
|
+
${useRightAxisForBarSerie || rightDataSetsNodes.length
|
|
64697
|
+
? escapeXml /*xml*/ `
|
|
64698
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length || !useRightAxisForBarSerie ? 1 : 0)}
|
|
64699
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64700
|
+
`
|
|
64701
|
+
: ""}
|
|
63765
64702
|
`;
|
|
63766
64703
|
}
|
|
63767
64704
|
function addLineChart(chart) {
|
|
63768
|
-
const
|
|
63769
|
-
const
|
|
64705
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64706
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64707
|
+
const leftDataSetsNodes = [];
|
|
64708
|
+
const rightDataSetsNodes = [];
|
|
63770
64709
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
64710
|
+
const color = toXlsxHexColor(colors.next());
|
|
63771
64711
|
const dataShapeProperty = shapeProperty({
|
|
63772
64712
|
line: {
|
|
63773
64713
|
width: 2.5,
|
|
63774
64714
|
style: "solid",
|
|
63775
|
-
color
|
|
64715
|
+
color,
|
|
63776
64716
|
},
|
|
63777
64717
|
});
|
|
63778
|
-
|
|
64718
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63779
64719
|
<c:ser>
|
|
63780
64720
|
<c:idx val="${dsIndex}"/>
|
|
63781
64721
|
<c:order val="${dsIndex}"/>
|
|
@@ -63783,37 +64723,63 @@ function addLineChart(chart) {
|
|
|
63783
64723
|
<c:marker>
|
|
63784
64724
|
<c:symbol val="circle" />
|
|
63785
64725
|
<c:size val="5"/>
|
|
64726
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
63786
64727
|
</c:marker>
|
|
63787
|
-
${
|
|
64728
|
+
${extractDataSetLabel(dataset.label)}
|
|
63788
64729
|
${dataShapeProperty}
|
|
63789
64730
|
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63790
64731
|
<c:val> <!-- x-coordinate values -->
|
|
63791
64732
|
${numberRef(dataset.range)}
|
|
63792
64733
|
</c:val>
|
|
63793
64734
|
</c:ser>
|
|
63794
|
-
|
|
64735
|
+
`;
|
|
64736
|
+
if (dataset.rightYAxis) {
|
|
64737
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64738
|
+
}
|
|
64739
|
+
else {
|
|
64740
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64741
|
+
}
|
|
63795
64742
|
}
|
|
63796
|
-
// Excel does not support this feature
|
|
63797
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63798
64743
|
const grouping = chart.stacked ? "stacked" : "standard";
|
|
63799
64744
|
return escapeXml /*xml*/ `
|
|
63800
|
-
|
|
63801
|
-
|
|
63802
|
-
|
|
63803
|
-
|
|
63804
|
-
|
|
63805
|
-
|
|
63806
|
-
|
|
63807
|
-
|
|
63808
|
-
|
|
63809
|
-
|
|
64745
|
+
${leftDataSetsNodes.length
|
|
64746
|
+
? escapeXml /*xml*/ `
|
|
64747
|
+
<c:lineChart>
|
|
64748
|
+
<c:grouping val="${grouping}"/>
|
|
64749
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64750
|
+
<c:varyColors val="0"/>
|
|
64751
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64752
|
+
<c:axId val="${catAxId}" />
|
|
64753
|
+
<c:axId val="${valAxId}" />
|
|
64754
|
+
</c:lineChart>
|
|
64755
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64756
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64757
|
+
`
|
|
64758
|
+
: ""}
|
|
64759
|
+
${rightDataSetsNodes.length
|
|
64760
|
+
? escapeXml /*xml*/ `
|
|
64761
|
+
<c:lineChart>
|
|
64762
|
+
<c:grouping val="${grouping}"/>
|
|
64763
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64764
|
+
<c:varyColors val="0"/>
|
|
64765
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64766
|
+
<c:axId val="${catAxId + 1}" />
|
|
64767
|
+
<c:axId val="${valAxId + 1}" />
|
|
64768
|
+
</c:lineChart>
|
|
64769
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64770
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64771
|
+
`
|
|
64772
|
+
: ""}
|
|
63810
64773
|
`;
|
|
63811
64774
|
}
|
|
63812
64775
|
function addScatterChart(chart) {
|
|
63813
|
-
const
|
|
63814
|
-
const
|
|
64776
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64777
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64778
|
+
const leftDataSetsNodes = [];
|
|
64779
|
+
const rightDataSetsNodes = [];
|
|
63815
64780
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
63816
|
-
|
|
64781
|
+
const color = toXlsxHexColor(colors.next());
|
|
64782
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63817
64783
|
<c:ser>
|
|
63818
64784
|
<c:idx val="${dsIndex}"/>
|
|
63819
64785
|
<c:order val="${dsIndex}"/>
|
|
@@ -63828,8 +64794,9 @@ function addScatterChart(chart) {
|
|
|
63828
64794
|
<c:marker>
|
|
63829
64795
|
<c:symbol val="circle" />
|
|
63830
64796
|
<c:size val="5"/>
|
|
63831
|
-
${shapeProperty({ backgroundColor:
|
|
64797
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
63832
64798
|
</c:marker>
|
|
64799
|
+
${extractDataSetLabel(dataset.label)}
|
|
63833
64800
|
${chart.labelRange
|
|
63834
64801
|
? escapeXml /*xml*/ `<c:xVal> <!-- x-coordinate values -->
|
|
63835
64802
|
${numberRef(chart.labelRange)}
|
|
@@ -63839,24 +64806,46 @@ function addScatterChart(chart) {
|
|
|
63839
64806
|
${numberRef(dataset.range)}
|
|
63840
64807
|
</c:yVal>
|
|
63841
64808
|
</c:ser>
|
|
63842
|
-
|
|
64809
|
+
`;
|
|
64810
|
+
if (dataset.rightYAxis) {
|
|
64811
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64812
|
+
}
|
|
64813
|
+
else {
|
|
64814
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64815
|
+
}
|
|
63843
64816
|
}
|
|
63844
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63845
64817
|
return escapeXml /*xml*/ `
|
|
63846
|
-
|
|
63847
|
-
|
|
63848
|
-
<c:
|
|
63849
|
-
|
|
63850
|
-
|
|
63851
|
-
|
|
63852
|
-
|
|
63853
|
-
|
|
63854
|
-
|
|
63855
|
-
|
|
63856
|
-
|
|
64818
|
+
${leftDataSetsNodes.length
|
|
64819
|
+
? escapeXml /*xml*/ `
|
|
64820
|
+
<c:scatterChart>
|
|
64821
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64822
|
+
<c:varyColors val="0"/>
|
|
64823
|
+
<c:scatterStyle val="lineMarker"/>
|
|
64824
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64825
|
+
<c:axId val="${catAxId}" />
|
|
64826
|
+
<c:axId val="${valAxId}" />
|
|
64827
|
+
</c:scatterChart>
|
|
64828
|
+
${addAx("b", "c:valAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64829
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64830
|
+
`
|
|
64831
|
+
: ""}
|
|
64832
|
+
${rightDataSetsNodes.length
|
|
64833
|
+
? escapeXml /*xml*/ `
|
|
64834
|
+
<c:scatterChart>
|
|
64835
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64836
|
+
<c:varyColors val="0"/>
|
|
64837
|
+
<c:scatterStyle val="lineMarker"/>
|
|
64838
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64839
|
+
<c:axId val="${catAxId + 1}" />
|
|
64840
|
+
<c:axId val="${valAxId + 1}" />
|
|
64841
|
+
</c:scatterChart>
|
|
64842
|
+
${addAx("b", "c:valAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64843
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64844
|
+
`
|
|
64845
|
+
: ""}`;
|
|
63857
64846
|
}
|
|
63858
64847
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
63859
|
-
const colors = new
|
|
64848
|
+
const colors = new ColorGenerator();
|
|
63860
64849
|
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
63861
64850
|
const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
|
|
63862
64851
|
const dataSetsNodes = [];
|
|
@@ -63880,7 +64869,7 @@ function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSiz
|
|
|
63880
64869
|
<c:ser>
|
|
63881
64870
|
<c:idx val="${dsIndex}"/>
|
|
63882
64871
|
<c:order val="${dsIndex}"/>
|
|
63883
|
-
${
|
|
64872
|
+
${extractDataSetLabel(dataset.label)}
|
|
63884
64873
|
${joinXmlNodes(dataPoints)}
|
|
63885
64874
|
${insertDataLabels({ showLeaderLines: true })}
|
|
63886
64875
|
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
@@ -63912,14 +64901,16 @@ function insertDataLabels({ showLeaderLines } = { showLeaderLines: false }) {
|
|
|
63912
64901
|
</dLbls>
|
|
63913
64902
|
`;
|
|
63914
64903
|
}
|
|
63915
|
-
function addAx(position, axisName, axId, crossAxId,
|
|
64904
|
+
function addAx(position, axisName, axId, crossAxId, title, defaultFontColor, deleteAxis = 0) {
|
|
63916
64905
|
// Each Axis present inside a graph needs to be identified by an unsigned integer in order to be referenced by its crossAxis.
|
|
63917
64906
|
// I.e. x-axis, will reference y-axis and vice-versa.
|
|
64907
|
+
const color = title?.color ? toXlsxHexColor(title.color) : defaultFontColor;
|
|
63918
64908
|
return escapeXml /*xml*/ `
|
|
63919
64909
|
<${axisName}>
|
|
63920
64910
|
<c:axId val="${axId}"/>
|
|
63921
64911
|
<c:crossAx val="${crossAxId}"/> <!-- reference to the other axe of the chart -->
|
|
63922
|
-
<c:
|
|
64912
|
+
<c:crosses val="${position === "b" || position === "l" ? "min" : "max"}"/>
|
|
64913
|
+
<c:delete val="${deleteAxis}"/> <!-- by default, axis are not displayed -->
|
|
63923
64914
|
<c:scaling>
|
|
63924
64915
|
<c:orientation val="minMax" />
|
|
63925
64916
|
</c:scaling>
|
|
@@ -63929,9 +64920,9 @@ function addAx(position, axisName, axId, crossAxId, { fontColor }) {
|
|
|
63929
64920
|
<c:minorTickMark val="none" />
|
|
63930
64921
|
<c:numFmt formatCode="General" sourceLinked="1" />
|
|
63931
64922
|
<c:title>
|
|
63932
|
-
${insertText("")}
|
|
64923
|
+
${insertText(title?.text ?? "", color, 10, title)}
|
|
63933
64924
|
</c:title>
|
|
63934
|
-
${insertTextProperties(10,
|
|
64925
|
+
${insertTextProperties(10, defaultFontColor)}
|
|
63935
64926
|
</${axisName}>
|
|
63936
64927
|
<!-- <tickLblPos/> omitted -->
|
|
63937
64928
|
`;
|
|
@@ -64812,7 +65803,11 @@ function addRows(construct, data, sheet) {
|
|
|
64812
65803
|
let cellNode = escapeXml ``;
|
|
64813
65804
|
// Either formula or static value inside the cell
|
|
64814
65805
|
if (cell.isFormula) {
|
|
64815
|
-
|
|
65806
|
+
const res = addFormula(cell);
|
|
65807
|
+
if (!res) {
|
|
65808
|
+
continue;
|
|
65809
|
+
}
|
|
65810
|
+
({ attrs: additionalAttrs, node: cellNode } = res);
|
|
64816
65811
|
}
|
|
64817
65812
|
else if (cell.content && isMarkdownLink(cell.content)) {
|
|
64818
65813
|
const { label } = parseMarkdownLink(cell.content);
|
|
@@ -65818,13 +66813,14 @@ const helpers = {
|
|
|
65818
66813
|
UuidGenerator,
|
|
65819
66814
|
formatValue,
|
|
65820
66815
|
createCurrencyFormat,
|
|
66816
|
+
ColorGenerator,
|
|
65821
66817
|
computeTextWidth,
|
|
65822
66818
|
createEmptyWorkbookData,
|
|
65823
66819
|
createEmptySheet,
|
|
65824
66820
|
createEmptyExcelSheet,
|
|
65825
66821
|
getDefaultChartJsRuntime,
|
|
65826
66822
|
chartFontColor,
|
|
65827
|
-
|
|
66823
|
+
getChartAxisTitleRuntime,
|
|
65828
66824
|
getFillingMode,
|
|
65829
66825
|
rgbaToHex,
|
|
65830
66826
|
colorToRGBA,
|
|
@@ -65881,9 +66877,10 @@ const components = {
|
|
|
65881
66877
|
GridOverlay,
|
|
65882
66878
|
ScorecardChart,
|
|
65883
66879
|
LineConfigPanel,
|
|
65884
|
-
GenericChartDesignPanel,
|
|
65885
66880
|
BarConfigPanel,
|
|
66881
|
+
PieChartDesignPanel,
|
|
65886
66882
|
GenericChartConfigPanel,
|
|
66883
|
+
ChartWithAxisDesignPanel,
|
|
65887
66884
|
GaugeChartConfigPanel,
|
|
65888
66885
|
GaugeChartDesignPanel,
|
|
65889
66886
|
ScorecardChartConfigPanel,
|
|
@@ -65982,6 +66979,6 @@ exports.tokenColors = tokenColors;
|
|
|
65982
66979
|
exports.tokenize = tokenize;
|
|
65983
66980
|
|
|
65984
66981
|
|
|
65985
|
-
__info__.version = "17.
|
|
65986
|
-
__info__.date = "2024-05-
|
|
65987
|
-
__info__.hash = "
|
|
66982
|
+
__info__.version = "17.4.0-alpha.0";
|
|
66983
|
+
__info__.date = "2024-05-31T15:37:08.535Z";
|
|
66984
|
+
__info__.hash = "9094f27";
|