@odoo/o-spreadsheet 17.3.0-alpha.9 → 17.3.1
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 +1611 -604
- package/dist/o-spreadsheet.d.ts +427 -200
- package/dist/o-spreadsheet.esm.js +1611 -604
- package/dist/o-spreadsheet.iife.js +1611 -604
- package/dist/o-spreadsheet.iife.min.js +550 -392
- package/dist/o_spreadsheet.xml +479 -381
- package/package.json +2 -2
|
@@ -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.3.
|
|
7
|
-
* @date 2024-
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.3.1
|
|
7
|
+
* @date 2024-06-03T15:28:03.284Z
|
|
8
|
+
* @hash 605d098
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -40,6 +40,8 @@ const COMPOSER_ASSISTANT_COLOR = "#9B359B";
|
|
|
40
40
|
const CHART_WATERFALL_POSITIVE_COLOR = "#006FBE";
|
|
41
41
|
const CHART_WATERFALL_NEGATIVE_COLOR = "#E40000";
|
|
42
42
|
const CHART_WATERFALL_SUBTOTAL_COLOR = "#AAAAAA";
|
|
43
|
+
const DEFAULT_CHART_PADDING = 20;
|
|
44
|
+
const DEFAULT_CHART_FONT_SIZE = 22;
|
|
43
45
|
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
44
46
|
const COLOR_PICKER_DEFAULTS = [
|
|
45
47
|
"#000000",
|
|
@@ -1088,6 +1090,44 @@ function darkenColor(color, percentage) {
|
|
|
1088
1090
|
hsla.l = hsla.l - percentage * hsla.l;
|
|
1089
1091
|
return hslaToHex(hsla);
|
|
1090
1092
|
}
|
|
1093
|
+
const ColorsList = [
|
|
1094
|
+
// the same colors as those used in odoo reporting
|
|
1095
|
+
"rgb(31,119,180)",
|
|
1096
|
+
"rgb(255,127,14)",
|
|
1097
|
+
"rgb(174,199,232)",
|
|
1098
|
+
"rgb(255,187,120)",
|
|
1099
|
+
"rgb(44,160,44)",
|
|
1100
|
+
"rgb(152,223,138)",
|
|
1101
|
+
"rgb(214,39,40)",
|
|
1102
|
+
"rgb(255,152,150)",
|
|
1103
|
+
"rgb(148,103,189)",
|
|
1104
|
+
"rgb(197,176,213)",
|
|
1105
|
+
"rgb(140,86,75)",
|
|
1106
|
+
"rgb(196,156,148)",
|
|
1107
|
+
"rgb(227,119,194)",
|
|
1108
|
+
"rgb(247,182,210)",
|
|
1109
|
+
"rgb(127,127,127)",
|
|
1110
|
+
"rgb(199,199,199)",
|
|
1111
|
+
"rgb(188,189,34)",
|
|
1112
|
+
"rgb(219,219,141)",
|
|
1113
|
+
"rgb(23,190,207)",
|
|
1114
|
+
"rgb(158,218,229)",
|
|
1115
|
+
];
|
|
1116
|
+
function getNthColor(index) {
|
|
1117
|
+
return ColorsList[index % ColorsList.length];
|
|
1118
|
+
}
|
|
1119
|
+
class ColorGenerator {
|
|
1120
|
+
currentColorIndex = 0;
|
|
1121
|
+
colors;
|
|
1122
|
+
constructor(colors = []) {
|
|
1123
|
+
this.colors = colors;
|
|
1124
|
+
}
|
|
1125
|
+
next() {
|
|
1126
|
+
return this.colors?.[this.currentColorIndex]
|
|
1127
|
+
? this.colors[this.currentColorIndex++]
|
|
1128
|
+
: getNthColor(this.currentColorIndex++);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1091
1131
|
|
|
1092
1132
|
//------------------------------------------------------------------------------
|
|
1093
1133
|
// Coordinate
|
|
@@ -1933,11 +1973,13 @@ const invalidateEvaluationCommands = new Set([
|
|
|
1933
1973
|
"RENAME_SHEET",
|
|
1934
1974
|
"DELETE_SHEET",
|
|
1935
1975
|
"CREATE_SHEET",
|
|
1976
|
+
"DUPLICATE_SHEET",
|
|
1936
1977
|
"ADD_COLUMNS_ROWS",
|
|
1937
1978
|
"REMOVE_COLUMNS_ROWS",
|
|
1938
1979
|
"UNDO",
|
|
1939
1980
|
"REDO",
|
|
1940
1981
|
"ADD_MERGE",
|
|
1982
|
+
"REMOVE_MERGE",
|
|
1941
1983
|
"UPDATE_LOCALE",
|
|
1942
1984
|
"ADD_PIVOT",
|
|
1943
1985
|
"UPDATE_PIVOT",
|
|
@@ -4876,18 +4918,22 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
|
|
|
4876
4918
|
/**
|
|
4877
4919
|
* Create a range from a xc. If the xc is empty, this function returns undefined.
|
|
4878
4920
|
*/
|
|
4879
|
-
function
|
|
4880
|
-
|
|
4921
|
+
function createValidRange(getters, sheetId, xc) {
|
|
4922
|
+
if (!xc)
|
|
4923
|
+
return;
|
|
4924
|
+
const range = getters.getRangeFromSheetXC(sheetId, xc);
|
|
4925
|
+
return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
|
|
4881
4926
|
}
|
|
4882
4927
|
/**
|
|
4883
4928
|
* Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
|
|
4884
4929
|
* For example, A1:B4 will become [A1:A4, B1:B4]
|
|
4885
4930
|
*/
|
|
4886
|
-
function spreadRange(getters,
|
|
4931
|
+
function spreadRange(getters, dataSets) {
|
|
4887
4932
|
const postProcessedRanges = [];
|
|
4888
|
-
for (const
|
|
4933
|
+
for (const dataSet of dataSets) {
|
|
4934
|
+
const range = dataSet.dataRange;
|
|
4889
4935
|
if (!getters.isRangeValid(range)) {
|
|
4890
|
-
postProcessedRanges.push(
|
|
4936
|
+
postProcessedRanges.push(dataSet); // ignore invalid range
|
|
4891
4937
|
continue;
|
|
4892
4938
|
}
|
|
4893
4939
|
const { sheetName } = splitReference(range);
|
|
@@ -4896,27 +4942,33 @@ function spreadRange(getters, ranges) {
|
|
|
4896
4942
|
if (zone.bottom !== zone.top && zone.left != zone.right) {
|
|
4897
4943
|
if (zone.right) {
|
|
4898
4944
|
for (let j = zone.left; j <= zone.right; ++j) {
|
|
4899
|
-
postProcessedRanges.push(
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4945
|
+
postProcessedRanges.push({
|
|
4946
|
+
...dataSet,
|
|
4947
|
+
dataRange: `${sheetPrefix}${zoneToXc({
|
|
4948
|
+
left: j,
|
|
4949
|
+
right: j,
|
|
4950
|
+
top: zone.top,
|
|
4951
|
+
bottom: zone.bottom,
|
|
4952
|
+
})}`,
|
|
4953
|
+
});
|
|
4905
4954
|
}
|
|
4906
4955
|
}
|
|
4907
4956
|
else {
|
|
4908
4957
|
for (let j = zone.top; j <= zone.bottom; ++j) {
|
|
4909
|
-
postProcessedRanges.push(
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4958
|
+
postProcessedRanges.push({
|
|
4959
|
+
...dataSet,
|
|
4960
|
+
dataRange: `${sheetPrefix}${zoneToXc({
|
|
4961
|
+
left: zone.left,
|
|
4962
|
+
right: zone.right,
|
|
4963
|
+
top: j,
|
|
4964
|
+
bottom: j,
|
|
4965
|
+
})}`,
|
|
4966
|
+
});
|
|
4915
4967
|
}
|
|
4916
4968
|
}
|
|
4917
4969
|
}
|
|
4918
4970
|
else {
|
|
4919
|
-
postProcessedRanges.push(
|
|
4971
|
+
postProcessedRanges.push(dataSet);
|
|
4920
4972
|
}
|
|
4921
4973
|
}
|
|
4922
4974
|
return postProcessedRanges;
|
|
@@ -5035,6 +5087,11 @@ function getDefaultCellHeight(ctx, cell, colSize) {
|
|
|
5035
5087
|
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
5036
5088
|
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
5037
5089
|
}
|
|
5090
|
+
function getDefaultContextFont(fontSize, bold = false, italic = false) {
|
|
5091
|
+
const italicStr = italic ? "italic" : "";
|
|
5092
|
+
const weight = bold ? "bold" : "";
|
|
5093
|
+
return `${italicStr} ${weight} ${fontSize}px ${DEFAULT_FONT}`;
|
|
5094
|
+
}
|
|
5038
5095
|
const textWidthCache = {};
|
|
5039
5096
|
function computeTextWidth(context, text, style, fontUnit = "pt") {
|
|
5040
5097
|
const font = computeTextFont(style, fontUnit);
|
|
@@ -5055,6 +5112,28 @@ function computeCachedTextWidth(context, text) {
|
|
|
5055
5112
|
}
|
|
5056
5113
|
return textWidthCache[font][text];
|
|
5057
5114
|
}
|
|
5115
|
+
const textDimensionsCache = {};
|
|
5116
|
+
function computeTextDimension(context, text, style, fontUnit = "pt") {
|
|
5117
|
+
const font = computeTextFont(style, fontUnit);
|
|
5118
|
+
context.save();
|
|
5119
|
+
context.font = font;
|
|
5120
|
+
const dimensions = computeCachedTextDimension(context, text);
|
|
5121
|
+
context.restore();
|
|
5122
|
+
return dimensions;
|
|
5123
|
+
}
|
|
5124
|
+
function computeCachedTextDimension(context, text) {
|
|
5125
|
+
const font = context.font;
|
|
5126
|
+
if (!textDimensionsCache[font]) {
|
|
5127
|
+
textDimensionsCache[font] = {};
|
|
5128
|
+
}
|
|
5129
|
+
if (textDimensionsCache[font][text] === undefined) {
|
|
5130
|
+
const measure = context.measureText(text);
|
|
5131
|
+
const width = measure.width;
|
|
5132
|
+
const height = measure.fontBoundingBoxAscent + measure.fontBoundingBoxDescent;
|
|
5133
|
+
textDimensionsCache[font][text] = { width, height };
|
|
5134
|
+
}
|
|
5135
|
+
return textDimensionsCache[font][text];
|
|
5136
|
+
}
|
|
5058
5137
|
function fontSizeInPixels(fontSize) {
|
|
5059
5138
|
return Math.round((fontSize * 96) / 72);
|
|
5060
5139
|
}
|
|
@@ -8824,7 +8903,7 @@ function drawHighlight(renderingContext, highlight, rect) {
|
|
|
8824
8903
|
}
|
|
8825
8904
|
}
|
|
8826
8905
|
if (!highlight.noFill) {
|
|
8827
|
-
ctx.fillStyle = setColorAlpha(color, highlight.fillAlpha ?? 0.12);
|
|
8906
|
+
ctx.fillStyle = setColorAlpha(toHex(color), highlight.fillAlpha ?? 0.12);
|
|
8828
8907
|
ctx.fillRect(x, y, width, height);
|
|
8829
8908
|
}
|
|
8830
8909
|
}
|
|
@@ -8873,7 +8952,32 @@ class HighlightStore extends SpreadsheetStore {
|
|
|
8873
8952
|
}
|
|
8874
8953
|
}
|
|
8875
8954
|
|
|
8876
|
-
|
|
8955
|
+
class NotificationStore {
|
|
8956
|
+
mutators = [
|
|
8957
|
+
"notifyUser",
|
|
8958
|
+
"raiseError",
|
|
8959
|
+
"askConfirmation",
|
|
8960
|
+
"updateNotificationCallbacks",
|
|
8961
|
+
];
|
|
8962
|
+
notifyUser = (notification) => window.alert(notification.text);
|
|
8963
|
+
askConfirmation = (content, confirm, cancel) => {
|
|
8964
|
+
if (window.confirm(content)) {
|
|
8965
|
+
confirm();
|
|
8966
|
+
}
|
|
8967
|
+
else {
|
|
8968
|
+
cancel?.();
|
|
8969
|
+
}
|
|
8970
|
+
};
|
|
8971
|
+
raiseError = (text, callback) => {
|
|
8972
|
+
window.alert(text);
|
|
8973
|
+
callback?.();
|
|
8974
|
+
};
|
|
8975
|
+
updateNotificationCallbacks(methods) {
|
|
8976
|
+
this.notifyUser = methods.notifyUser || this.notifyUser;
|
|
8977
|
+
this.raiseError = methods.raiseError || this.raiseError;
|
|
8978
|
+
this.askConfirmation = methods.askConfirmation || this.askConfirmation;
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8877
8981
|
|
|
8878
8982
|
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
|
|
8879
8983
|
class ComposerStore extends SpreadsheetStore {
|
|
@@ -9894,10 +9998,10 @@ function adaptChartRange(range, applyChange) {
|
|
|
9894
9998
|
/**
|
|
9895
9999
|
* Create the dataSet objects from xcs
|
|
9896
10000
|
*/
|
|
9897
|
-
function createDataSets(getters,
|
|
10001
|
+
function createDataSets(getters, customizedDataSets, sheetId, dataSetsHaveTitle) {
|
|
9898
10002
|
const dataSets = [];
|
|
9899
|
-
for (const
|
|
9900
|
-
const dataRange = getters.getRangeFromSheetXC(sheetId,
|
|
10003
|
+
for (const dataSet of customizedDataSets) {
|
|
10004
|
+
const dataRange = getters.getRangeFromSheetXC(sheetId, dataSet.dataRange);
|
|
9901
10005
|
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
|
|
9902
10006
|
if (invalidSheetName || invalidXc) {
|
|
9903
10007
|
continue;
|
|
@@ -9914,26 +10018,36 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
9914
10018
|
left: column,
|
|
9915
10019
|
right: column,
|
|
9916
10020
|
};
|
|
9917
|
-
dataSets.push(
|
|
9918
|
-
|
|
9919
|
-
|
|
9920
|
-
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
10021
|
+
dataSets.push({
|
|
10022
|
+
...createDataSet(getters, dataSetSheetId, columnZone, dataSetsHaveTitle
|
|
10023
|
+
? {
|
|
10024
|
+
top: columnZone.top,
|
|
10025
|
+
bottom: columnZone.top,
|
|
10026
|
+
left: columnZone.left,
|
|
10027
|
+
right: columnZone.left,
|
|
10028
|
+
}
|
|
10029
|
+
: undefined),
|
|
10030
|
+
backgroundColor: dataSet.backgroundColor,
|
|
10031
|
+
rightYAxis: dataSet.yAxisId === "y1",
|
|
10032
|
+
customLabel: dataSet.label,
|
|
10033
|
+
});
|
|
9925
10034
|
}
|
|
9926
10035
|
}
|
|
9927
10036
|
else {
|
|
9928
10037
|
/* 1 cell, 1 row or 1 column */
|
|
9929
|
-
dataSets.push(
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
10038
|
+
dataSets.push({
|
|
10039
|
+
...createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
10040
|
+
? {
|
|
10041
|
+
top: zone.top,
|
|
10042
|
+
bottom: zone.top,
|
|
10043
|
+
left: zone.left,
|
|
10044
|
+
right: zone.left,
|
|
10045
|
+
}
|
|
10046
|
+
: undefined),
|
|
10047
|
+
backgroundColor: dataSet.backgroundColor,
|
|
10048
|
+
rightYAxis: dataSet.yAxisId === "y1",
|
|
10049
|
+
customLabel: dataSet.label,
|
|
10050
|
+
});
|
|
9937
10051
|
}
|
|
9938
10052
|
}
|
|
9939
10053
|
return dataSets;
|
|
@@ -9973,11 +10087,24 @@ function toExcelDataset(getters, ds) {
|
|
|
9973
10087
|
}
|
|
9974
10088
|
}
|
|
9975
10089
|
const dataRange = ds.dataRange.clone({ zone: dataZone });
|
|
10090
|
+
let label = {};
|
|
10091
|
+
if (ds.customLabel) {
|
|
10092
|
+
label = {
|
|
10093
|
+
text: ds.customLabel,
|
|
10094
|
+
};
|
|
10095
|
+
}
|
|
10096
|
+
else if (ds.labelCell) {
|
|
10097
|
+
label = {
|
|
10098
|
+
reference: getters.getRangeString(ds.labelCell, "forceSheetReference", {
|
|
10099
|
+
useFixedReference: true,
|
|
10100
|
+
}),
|
|
10101
|
+
};
|
|
10102
|
+
}
|
|
9976
10103
|
return {
|
|
9977
|
-
label
|
|
9978
|
-
? getters.getRangeString(ds.labelCell, "forceSheetReference", { useFixedReference: true })
|
|
9979
|
-
: undefined,
|
|
10104
|
+
label,
|
|
9980
10105
|
range: getters.getRangeString(dataRange, "forceSheetReference", { useFixedReference: true }),
|
|
10106
|
+
backgroundColor: ds.backgroundColor,
|
|
10107
|
+
rightYAxis: ds.rightYAxis,
|
|
9981
10108
|
};
|
|
9982
10109
|
}
|
|
9983
10110
|
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
@@ -10003,45 +10130,16 @@ function transformChartDefinitionWithDataSetsWithZone(definition, executed) {
|
|
|
10003
10130
|
labelRange = labelZone ? zoneToXc(labelZone) : undefined;
|
|
10004
10131
|
}
|
|
10005
10132
|
const dataSets = definition.dataSets
|
|
10006
|
-
.map(toUnboundedZone)
|
|
10133
|
+
.map((ds) => toUnboundedZone(ds.dataRange))
|
|
10007
10134
|
.map((zone) => transformZone(zone, executed))
|
|
10008
10135
|
.filter(isDefined)
|
|
10009
|
-
.map(zoneToXc);
|
|
10136
|
+
.map((xc) => ({ dataRange: zoneToXc(xc) }));
|
|
10010
10137
|
return {
|
|
10011
10138
|
...definition,
|
|
10012
10139
|
labelRange,
|
|
10013
10140
|
dataSets,
|
|
10014
10141
|
};
|
|
10015
10142
|
}
|
|
10016
|
-
const GraphColors = [
|
|
10017
|
-
// the same colors as those used in odoo reporting
|
|
10018
|
-
"rgb(31,119,180)",
|
|
10019
|
-
"rgb(255,127,14)",
|
|
10020
|
-
"rgb(174,199,232)",
|
|
10021
|
-
"rgb(255,187,120)",
|
|
10022
|
-
"rgb(44,160,44)",
|
|
10023
|
-
"rgb(152,223,138)",
|
|
10024
|
-
"rgb(214,39,40)",
|
|
10025
|
-
"rgb(255,152,150)",
|
|
10026
|
-
"rgb(148,103,189)",
|
|
10027
|
-
"rgb(197,176,213)",
|
|
10028
|
-
"rgb(140,86,75)",
|
|
10029
|
-
"rgb(196,156,148)",
|
|
10030
|
-
"rgb(227,119,194)",
|
|
10031
|
-
"rgb(247,182,210)",
|
|
10032
|
-
"rgb(127,127,127)",
|
|
10033
|
-
"rgb(199,199,199)",
|
|
10034
|
-
"rgb(188,189,34)",
|
|
10035
|
-
"rgb(219,219,141)",
|
|
10036
|
-
"rgb(23,190,207)",
|
|
10037
|
-
"rgb(158,218,229)",
|
|
10038
|
-
];
|
|
10039
|
-
class ChartColors {
|
|
10040
|
-
graphColorIndex = 0;
|
|
10041
|
-
next() {
|
|
10042
|
-
return GraphColors[this.graphColorIndex++ % GraphColors.length];
|
|
10043
|
-
}
|
|
10044
|
-
}
|
|
10045
10143
|
/**
|
|
10046
10144
|
* Choose a font color based on a background color.
|
|
10047
10145
|
* The font is white with a dark background.
|
|
@@ -10054,11 +10152,11 @@ function chartFontColor(backgroundColor) {
|
|
|
10054
10152
|
}
|
|
10055
10153
|
function checkDataset(definition) {
|
|
10056
10154
|
if (definition.dataSets) {
|
|
10057
|
-
const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range)) !== undefined;
|
|
10155
|
+
const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined;
|
|
10058
10156
|
if (invalidRanges) {
|
|
10059
10157
|
return "InvalidDataSet" /* CommandResult.InvalidDataSet */;
|
|
10060
10158
|
}
|
|
10061
|
-
const zones = definition.dataSets.map(toUnboundedZone);
|
|
10159
|
+
const zones = definition.dataSets.map((ds) => toUnboundedZone(ds.dataRange));
|
|
10062
10160
|
if (zones.some((zone) => zone.top !== zone.bottom && isFullRow(zone))) {
|
|
10063
10161
|
return "InvalidDataSet" /* CommandResult.InvalidDataSet */;
|
|
10064
10162
|
}
|
|
@@ -10098,6 +10196,35 @@ function getChartPositionAtCenterOfViewport(getters, chartSize) {
|
|
|
10098
10196
|
}; // Position at the center of the scrollable viewport
|
|
10099
10197
|
return position;
|
|
10100
10198
|
}
|
|
10199
|
+
function getChartAxisTitleRuntime(design) {
|
|
10200
|
+
if (design?.title?.text) {
|
|
10201
|
+
const { text, color, align, italic, bold } = design.title;
|
|
10202
|
+
return {
|
|
10203
|
+
display: true,
|
|
10204
|
+
text,
|
|
10205
|
+
color,
|
|
10206
|
+
font: {
|
|
10207
|
+
style: italic ? "italic" : "normal",
|
|
10208
|
+
weight: bold ? "bold" : "normal",
|
|
10209
|
+
},
|
|
10210
|
+
align: align === "left" ? "start" : align === "right" ? "end" : "center",
|
|
10211
|
+
};
|
|
10212
|
+
}
|
|
10213
|
+
return;
|
|
10214
|
+
}
|
|
10215
|
+
function getDefinedAxis(definition) {
|
|
10216
|
+
let useLeftAxis = false, useRightAxis = false;
|
|
10217
|
+
for (const design of definition.dataSets || []) {
|
|
10218
|
+
if (design.yAxisId === "y1") {
|
|
10219
|
+
useRightAxis = true;
|
|
10220
|
+
}
|
|
10221
|
+
else {
|
|
10222
|
+
useLeftAxis = true;
|
|
10223
|
+
}
|
|
10224
|
+
}
|
|
10225
|
+
useLeftAxis ||= !useRightAxis;
|
|
10226
|
+
return { useLeftAxis, useRightAxis };
|
|
10227
|
+
}
|
|
10101
10228
|
|
|
10102
10229
|
function getBaselineText(baseline, keyValue, baselineMode, humanize, locale) {
|
|
10103
10230
|
if (!baseline) {
|
|
@@ -10199,8 +10326,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10199
10326
|
type = "scorecard";
|
|
10200
10327
|
constructor(definition, sheetId, getters) {
|
|
10201
10328
|
super(definition, sheetId, getters);
|
|
10202
|
-
this.keyValue =
|
|
10203
|
-
this.baseline =
|
|
10329
|
+
this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
|
|
10330
|
+
this.baseline = createValidRange(getters, sheetId, definition.baseline);
|
|
10204
10331
|
this.baselineMode = definition.baselineMode;
|
|
10205
10332
|
this.baselineDescr = definition.baselineDescr;
|
|
10206
10333
|
this.background = definition.background;
|
|
@@ -10215,8 +10342,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10215
10342
|
return {
|
|
10216
10343
|
background: context.background,
|
|
10217
10344
|
type: "scorecard",
|
|
10218
|
-
keyValue: context.range ? context.range[0] : undefined,
|
|
10219
|
-
title: context.title || "",
|
|
10345
|
+
keyValue: context.range ? context.range[0].dataRange : undefined,
|
|
10346
|
+
title: context.title || { text: "" },
|
|
10220
10347
|
baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
|
|
10221
10348
|
baselineColorUp: DEFAULT_SCORECARD_BASELINE_COLOR_UP,
|
|
10222
10349
|
baselineColorDown: DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
|
|
@@ -10254,7 +10381,9 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10254
10381
|
getContextCreation() {
|
|
10255
10382
|
return {
|
|
10256
10383
|
...this,
|
|
10257
|
-
range: this.keyValue
|
|
10384
|
+
range: this.keyValue
|
|
10385
|
+
? [{ dataRange: this.getters.getRangeString(this.keyValue, this.sheetId) }]
|
|
10386
|
+
: undefined,
|
|
10258
10387
|
auxiliaryRange: this.baseline
|
|
10259
10388
|
? this.getters.getRangeString(this.baseline, this.sheetId)
|
|
10260
10389
|
: undefined,
|
|
@@ -10301,7 +10430,10 @@ function drawScoreChart(structure, canvas) {
|
|
|
10301
10430
|
if (structure.title) {
|
|
10302
10431
|
ctx.font = structure.title.style.font;
|
|
10303
10432
|
ctx.fillStyle = structure.title.style.color;
|
|
10433
|
+
const baseline = ctx.textBaseline;
|
|
10434
|
+
ctx.textBaseline = "middle";
|
|
10304
10435
|
ctx.fillText(clipTextWithEllipsis(ctx, structure.title.text, canvas.width - structure.title.position.x), structure.title.position.x, structure.title.position.y);
|
|
10436
|
+
ctx.textBaseline = baseline;
|
|
10305
10437
|
}
|
|
10306
10438
|
if (structure.baseline) {
|
|
10307
10439
|
ctx.font = structure.baseline.style.font;
|
|
@@ -10388,7 +10520,10 @@ function createScorecardChartRuntime(chart, getters) {
|
|
|
10388
10520
|
? toNumber(baselineDisplay, locale)
|
|
10389
10521
|
: 0;
|
|
10390
10522
|
return {
|
|
10391
|
-
title:
|
|
10523
|
+
title: {
|
|
10524
|
+
...chart.title,
|
|
10525
|
+
text: _t(chart.title.text ?? ""),
|
|
10526
|
+
},
|
|
10392
10527
|
keyValue: formattedKeyValue,
|
|
10393
10528
|
baselineDisplay,
|
|
10394
10529
|
baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, chart.baselineMode),
|
|
@@ -10420,10 +10555,9 @@ function createScorecardChartRuntime(chart, getters) {
|
|
|
10420
10555
|
}
|
|
10421
10556
|
|
|
10422
10557
|
/* Sizes of boxes containing the texts, in percentage of the Chart size */
|
|
10423
|
-
const TITLE_FONT_SIZE = 18;
|
|
10424
10558
|
const KEY_BOX_HEIGHT_RATIO = 0.8;
|
|
10425
10559
|
/* Padding at the border of the chart */
|
|
10426
|
-
const CHART_PADDING =
|
|
10560
|
+
const CHART_PADDING = DEFAULT_CHART_PADDING;
|
|
10427
10561
|
const BOTTOM_PADDING_RATIO = 0.05;
|
|
10428
10562
|
/**
|
|
10429
10563
|
* Line height (in em)
|
|
@@ -10434,11 +10568,6 @@ function formatBaselineDescr(baselineDescr, baseline) {
|
|
|
10434
10568
|
const _baselineDescr = baselineDescr || "";
|
|
10435
10569
|
return baseline && _baselineDescr ? " " + _baselineDescr : _baselineDescr;
|
|
10436
10570
|
}
|
|
10437
|
-
function getDefaultContextFont(fontSize, bold = false, italic = false) {
|
|
10438
|
-
const italicStr = italic ? "italic" : "";
|
|
10439
|
-
const weight = bold ? "bold" : "";
|
|
10440
|
-
return `${italicStr} ${weight} ${fontSize}px ${DEFAULT_FONT}`;
|
|
10441
|
-
}
|
|
10442
10571
|
function getScorecardConfiguration({ width, height }, runtime) {
|
|
10443
10572
|
const designer = new ScorecardChartConfigBuilder({ width, height }, runtime);
|
|
10444
10573
|
return designer.computeDesign();
|
|
@@ -10466,13 +10595,25 @@ class ScorecardChartConfigBuilder {
|
|
|
10466
10595
|
const style = this.getTextStyles();
|
|
10467
10596
|
let titleHeight = 0;
|
|
10468
10597
|
if (this.title) {
|
|
10469
|
-
|
|
10598
|
+
let x, titleWidth;
|
|
10599
|
+
({ height: titleHeight, width: titleWidth } = this.getFullTextDimensions(this.title, style.title.font));
|
|
10600
|
+
switch (this.runtime.title.align) {
|
|
10601
|
+
case "center":
|
|
10602
|
+
x = (this.width - titleWidth) / 2;
|
|
10603
|
+
break;
|
|
10604
|
+
case "right":
|
|
10605
|
+
x = this.width - titleWidth - CHART_PADDING;
|
|
10606
|
+
break;
|
|
10607
|
+
case "left":
|
|
10608
|
+
default:
|
|
10609
|
+
x = CHART_PADDING;
|
|
10610
|
+
}
|
|
10470
10611
|
structure.title = {
|
|
10471
10612
|
text: this.title,
|
|
10472
10613
|
style: style.title,
|
|
10473
10614
|
position: {
|
|
10474
|
-
x
|
|
10475
|
-
y: CHART_PADDING / 2
|
|
10615
|
+
x,
|
|
10616
|
+
y: CHART_PADDING + titleHeight / 2,
|
|
10476
10617
|
},
|
|
10477
10618
|
};
|
|
10478
10619
|
}
|
|
@@ -10573,7 +10714,7 @@ class ScorecardChartConfigBuilder {
|
|
|
10573
10714
|
return structure;
|
|
10574
10715
|
}
|
|
10575
10716
|
get title() {
|
|
10576
|
-
return this.runtime.title;
|
|
10717
|
+
return this.runtime.title.text ?? "";
|
|
10577
10718
|
}
|
|
10578
10719
|
get keyValue() {
|
|
10579
10720
|
return this.runtime.keyValue;
|
|
@@ -10641,8 +10782,8 @@ class ScorecardChartConfigBuilder {
|
|
|
10641
10782
|
}
|
|
10642
10783
|
return {
|
|
10643
10784
|
title: {
|
|
10644
|
-
font: getDefaultContextFont(
|
|
10645
|
-
color: this.secondaryFontColor,
|
|
10785
|
+
font: getDefaultContextFont(DEFAULT_CHART_FONT_SIZE, this.runtime.title.bold, this.runtime.title.italic),
|
|
10786
|
+
color: this.runtime.title.color ?? this.secondaryFontColor,
|
|
10646
10787
|
},
|
|
10647
10788
|
keyValue: {
|
|
10648
10789
|
color: this.runtime.keyValueStyle?.textColor || this.runtime.fontColor,
|
|
@@ -10675,7 +10816,7 @@ class ScorecardChartConfigBuilder {
|
|
|
10675
10816
|
getDrawableHeight() {
|
|
10676
10817
|
const verticalPadding = CHART_PADDING + this.height * BOTTOM_PADDING_RATIO;
|
|
10677
10818
|
let availableHeight = this.height - 2 * verticalPadding;
|
|
10678
|
-
availableHeight -= this.title ?
|
|
10819
|
+
availableHeight -= this.title ? DEFAULT_CHART_FONT_SIZE * LINE_HEIGHT : 0;
|
|
10679
10820
|
return availableHeight;
|
|
10680
10821
|
}
|
|
10681
10822
|
}
|
|
@@ -12025,7 +12166,7 @@ const COUNTUNIQUEIFS = {
|
|
|
12025
12166
|
compute: function (range, ...args) {
|
|
12026
12167
|
let uniqueValues = new Set();
|
|
12027
12168
|
visitMatchingRanges(args, (i, j) => {
|
|
12028
|
-
const data = range[i][j];
|
|
12169
|
+
const data = range[i]?.[j];
|
|
12029
12170
|
if (isDataNonEmpty(data)) {
|
|
12030
12171
|
uniqueValues.add(data.value);
|
|
12031
12172
|
}
|
|
@@ -12655,7 +12796,7 @@ const SUMIF = {
|
|
|
12655
12796
|
}
|
|
12656
12797
|
let sum = 0;
|
|
12657
12798
|
visitMatchingRanges([criteriaRange, criterion], (i, j) => {
|
|
12658
|
-
const value = sumRange[i][j]
|
|
12799
|
+
const value = sumRange[i]?.[j]?.value;
|
|
12659
12800
|
if (typeof value === "number") {
|
|
12660
12801
|
sum += value;
|
|
12661
12802
|
}
|
|
@@ -12680,7 +12821,7 @@ const SUMIFS = {
|
|
|
12680
12821
|
compute: function (sumRange, ...criters) {
|
|
12681
12822
|
let sum = 0;
|
|
12682
12823
|
visitMatchingRanges(criters, (i, j) => {
|
|
12683
|
-
const value = sumRange[i][j]
|
|
12824
|
+
const value = sumRange[i]?.[j]?.value;
|
|
12684
12825
|
if (typeof value === "number") {
|
|
12685
12826
|
sum += value;
|
|
12686
12827
|
}
|
|
@@ -13227,7 +13368,7 @@ const AVERAGEIF = {
|
|
|
13227
13368
|
let count = 0;
|
|
13228
13369
|
let sum = 0;
|
|
13229
13370
|
visitMatchingRanges([criteriaRange, criterion], (i, j) => {
|
|
13230
|
-
const value = _averageRange[i][j]
|
|
13371
|
+
const value = _averageRange[i]?.[j]?.value;
|
|
13231
13372
|
if (typeof value === "number") {
|
|
13232
13373
|
count += 1;
|
|
13233
13374
|
sum += value;
|
|
@@ -13256,7 +13397,7 @@ const AVERAGEIFS = {
|
|
|
13256
13397
|
let count = 0;
|
|
13257
13398
|
let sum = 0;
|
|
13258
13399
|
visitMatchingRanges(args, (i, j) => {
|
|
13259
|
-
const value = _averageRange[i][j]
|
|
13400
|
+
const value = _averageRange[i]?.[j]?.value;
|
|
13260
13401
|
if (typeof value === "number") {
|
|
13261
13402
|
count += 1;
|
|
13262
13403
|
sum += value;
|
|
@@ -13561,7 +13702,7 @@ const MAXIFS = {
|
|
|
13561
13702
|
compute: function (range, ...args) {
|
|
13562
13703
|
let result = -Infinity;
|
|
13563
13704
|
visitMatchingRanges(args, (i, j) => {
|
|
13564
|
-
const value = range[i][j]
|
|
13705
|
+
const value = range[i]?.[j]?.value;
|
|
13565
13706
|
if (typeof value === "number") {
|
|
13566
13707
|
result = result < value ? value : result;
|
|
13567
13708
|
}
|
|
@@ -13644,7 +13785,7 @@ const MINIFS = {
|
|
|
13644
13785
|
compute: function (range, ...args) {
|
|
13645
13786
|
let result = Infinity;
|
|
13646
13787
|
visitMatchingRanges(args, (i, j) => {
|
|
13647
|
-
const value = range[i][j]
|
|
13788
|
+
const value = range[i]?.[j]?.value;
|
|
13648
13789
|
if (typeof value === "number") {
|
|
13649
13790
|
result = result > value ? value : result;
|
|
13650
13791
|
}
|
|
@@ -22101,9 +22242,9 @@ const GAUGE_TEXT_COLOR_HIGH_CONTRAST = "#C8C8C8";
|
|
|
22101
22242
|
const GAUGE_INFLECTION_MARKER_COLOR = "#666666aa";
|
|
22102
22243
|
const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
|
|
22103
22244
|
const GAUGE_TITLE_SECTION_HEIGHT = 25;
|
|
22104
|
-
const GAUGE_TITLE_FONT_SIZE =
|
|
22105
|
-
const GAUGE_TITLE_PADDING_LEFT =
|
|
22106
|
-
const GAUGE_TITLE_PADDING_TOP =
|
|
22245
|
+
const GAUGE_TITLE_FONT_SIZE = DEFAULT_CHART_FONT_SIZE;
|
|
22246
|
+
const GAUGE_TITLE_PADDING_LEFT = DEFAULT_CHART_PADDING;
|
|
22247
|
+
const GAUGE_TITLE_PADDING_TOP = DEFAULT_CHART_PADDING;
|
|
22107
22248
|
function drawGaugeChart(canvas, runtime) {
|
|
22108
22249
|
const canvasBoundingRect = canvas.getBoundingClientRect();
|
|
22109
22250
|
canvas.width = canvasBoundingRect.width;
|
|
@@ -22178,7 +22319,8 @@ function drawInflectionValues(ctx, config) {
|
|
|
22178
22319
|
function drawTitle(ctx, config) {
|
|
22179
22320
|
ctx.save();
|
|
22180
22321
|
const title = config.title;
|
|
22181
|
-
ctx.font =
|
|
22322
|
+
ctx.font = getDefaultContextFont(title.fontSize, title.bold, title.italic);
|
|
22323
|
+
ctx.textBaseline = "middle";
|
|
22182
22324
|
ctx.fillStyle = title.color;
|
|
22183
22325
|
ctx.fillText(title.label, title.textPosition.x, title.textPosition.y);
|
|
22184
22326
|
ctx.restore();
|
|
@@ -22187,7 +22329,7 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
|
|
|
22187
22329
|
const maxValue = runtime.maxValue;
|
|
22188
22330
|
const minValue = runtime.minValue;
|
|
22189
22331
|
const gaugeValue = runtime.gaugeValue;
|
|
22190
|
-
const gaugeRect = getGaugeRect(boundingRect, runtime.title);
|
|
22332
|
+
const gaugeRect = getGaugeRect(boundingRect, runtime.title.text);
|
|
22191
22333
|
const gaugeArcWidth = gaugeRect.width / 6;
|
|
22192
22334
|
const gaugePercentage = gaugeValue
|
|
22193
22335
|
? (gaugeValue.value - minValue.value) / (maxValue.value - minValue.value)
|
|
@@ -22217,17 +22359,35 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
|
|
|
22217
22359
|
};
|
|
22218
22360
|
const textColor = getContrastedTextColor(runtime.background);
|
|
22219
22361
|
const inflectionValues = getInflectionValues(runtime, gaugeRect, textColor, ctx);
|
|
22362
|
+
let x = 0, titleWidth = 0, titleHeight = 0;
|
|
22363
|
+
if (runtime.title.text) {
|
|
22364
|
+
({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { ...runtime.title, fontSize: GAUGE_TITLE_FONT_SIZE }, "px"));
|
|
22365
|
+
}
|
|
22366
|
+
switch (runtime.title.align) {
|
|
22367
|
+
case "right":
|
|
22368
|
+
x = boundingRect.width - titleWidth - GAUGE_TITLE_PADDING_LEFT;
|
|
22369
|
+
break;
|
|
22370
|
+
case "center":
|
|
22371
|
+
x = (boundingRect.width - titleWidth) / 2;
|
|
22372
|
+
break;
|
|
22373
|
+
case "left":
|
|
22374
|
+
default:
|
|
22375
|
+
x = GAUGE_TITLE_PADDING_LEFT;
|
|
22376
|
+
break;
|
|
22377
|
+
}
|
|
22220
22378
|
return {
|
|
22221
22379
|
width: boundingRect.width,
|
|
22222
22380
|
height: boundingRect.height,
|
|
22223
22381
|
title: {
|
|
22224
|
-
label: runtime.title,
|
|
22382
|
+
label: runtime.title.text ?? "",
|
|
22225
22383
|
fontSize: GAUGE_TITLE_FONT_SIZE,
|
|
22226
22384
|
textPosition: {
|
|
22227
|
-
x
|
|
22228
|
-
y: GAUGE_TITLE_PADDING_TOP +
|
|
22385
|
+
x,
|
|
22386
|
+
y: GAUGE_TITLE_PADDING_TOP + titleHeight / 2,
|
|
22229
22387
|
},
|
|
22230
|
-
color: textColor,
|
|
22388
|
+
color: runtime.title.color ?? textColor,
|
|
22389
|
+
bold: runtime.title.bold,
|
|
22390
|
+
italic: runtime.title.italic,
|
|
22231
22391
|
},
|
|
22232
22392
|
backgroundColor: runtime.background,
|
|
22233
22393
|
gauge: {
|
|
@@ -22517,12 +22677,18 @@ function truncateLabel(label) {
|
|
|
22517
22677
|
* Get a default chart js configuration
|
|
22518
22678
|
*/
|
|
22519
22679
|
function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels }) {
|
|
22680
|
+
const chartTitle = chart.title.text ? chart.title : { ...chart.title, content: "" };
|
|
22520
22681
|
const options = {
|
|
22521
22682
|
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
22522
22683
|
responsive: true, // will resize when its container is resized
|
|
22523
22684
|
maintainAspectRatio: false, // doesn't maintain the aspect ration (width/height =2 by default) so the user has the choice of the exact layout
|
|
22524
22685
|
layout: {
|
|
22525
|
-
padding: {
|
|
22686
|
+
padding: {
|
|
22687
|
+
left: DEFAULT_CHART_PADDING,
|
|
22688
|
+
right: DEFAULT_CHART_PADDING,
|
|
22689
|
+
top: chartTitle.text ? DEFAULT_CHART_PADDING / 2 : DEFAULT_CHART_PADDING + 5,
|
|
22690
|
+
bottom: DEFAULT_CHART_PADDING,
|
|
22691
|
+
},
|
|
22526
22692
|
},
|
|
22527
22693
|
elements: {
|
|
22528
22694
|
line: {
|
|
@@ -22535,10 +22701,15 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
|
|
|
22535
22701
|
animation: false,
|
|
22536
22702
|
plugins: {
|
|
22537
22703
|
title: {
|
|
22538
|
-
display: !!
|
|
22539
|
-
text: _t(
|
|
22540
|
-
color: fontColor,
|
|
22541
|
-
|
|
22704
|
+
display: !!chartTitle.text,
|
|
22705
|
+
text: _t(chartTitle.text),
|
|
22706
|
+
color: chartTitle?.color ?? fontColor,
|
|
22707
|
+
align: chartTitle.align === "center" ? "center" : chartTitle.align === "right" ? "end" : "start",
|
|
22708
|
+
font: {
|
|
22709
|
+
size: DEFAULT_CHART_FONT_SIZE,
|
|
22710
|
+
weight: chartTitle.bold ? "bold" : "normal",
|
|
22711
|
+
style: chartTitle.italic ? "italic" : "normal",
|
|
22712
|
+
},
|
|
22542
22713
|
},
|
|
22543
22714
|
legend: {
|
|
22544
22715
|
// Disable default legend onClick (show/hide dataset), to allow us to set a global onClick on the chart container.
|
|
@@ -22673,9 +22844,10 @@ function chartToImage(runtime, figure, type) {
|
|
|
22673
22844
|
// we have to add the canvas to the DOM otherwise it won't be rendered
|
|
22674
22845
|
document.body.append(div);
|
|
22675
22846
|
if ("chartJsConfig" in runtime) {
|
|
22676
|
-
runtime.chartJsConfig
|
|
22847
|
+
const config = deepCopy(runtime.chartJsConfig);
|
|
22848
|
+
config.plugins = [backgroundColorChartJSPlugin];
|
|
22677
22849
|
// @ts-ignore
|
|
22678
|
-
const chart = new window.Chart(canvas,
|
|
22850
|
+
const chart = new window.Chart(canvas, config);
|
|
22679
22851
|
const imgContent = chart.toBase64Image();
|
|
22680
22852
|
chart.destroy();
|
|
22681
22853
|
div.remove();
|
|
@@ -22716,22 +22888,24 @@ class BarChart extends AbstractChart {
|
|
|
22716
22888
|
dataSets;
|
|
22717
22889
|
labelRange;
|
|
22718
22890
|
background;
|
|
22719
|
-
verticalAxisPosition;
|
|
22720
22891
|
legendPosition;
|
|
22721
22892
|
stacked;
|
|
22722
22893
|
aggregated;
|
|
22723
22894
|
type = "bar";
|
|
22724
22895
|
dataSetsHaveTitle;
|
|
22896
|
+
dataSetDesign;
|
|
22897
|
+
axesDesign;
|
|
22725
22898
|
constructor(definition, sheetId, getters) {
|
|
22726
22899
|
super(definition, sheetId, getters);
|
|
22727
22900
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
22728
|
-
this.labelRange =
|
|
22901
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
22729
22902
|
this.background = definition.background;
|
|
22730
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
22731
22903
|
this.legendPosition = definition.legendPosition;
|
|
22732
22904
|
this.stacked = definition.stacked;
|
|
22733
22905
|
this.aggregated = definition.aggregated;
|
|
22734
22906
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
22907
|
+
this.dataSetDesign = definition.dataSets;
|
|
22908
|
+
this.axesDesign = definition.axesDesign;
|
|
22735
22909
|
}
|
|
22736
22910
|
static transformDefinition(definition, executed) {
|
|
22737
22911
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -22742,21 +22916,28 @@ class BarChart extends AbstractChart {
|
|
|
22742
22916
|
static getDefinitionFromContextCreation(context) {
|
|
22743
22917
|
return {
|
|
22744
22918
|
background: context.background,
|
|
22745
|
-
dataSets: context.range
|
|
22919
|
+
dataSets: context.range ?? [],
|
|
22746
22920
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
22747
22921
|
stacked: context.stacked ?? false,
|
|
22748
22922
|
aggregated: context.aggregated ?? false,
|
|
22749
22923
|
legendPosition: context.legendPosition ?? "top",
|
|
22750
|
-
title: context.title || "",
|
|
22924
|
+
title: context.title || { text: "" },
|
|
22751
22925
|
type: "bar",
|
|
22752
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
22753
22926
|
labelRange: context.auxiliaryRange || undefined,
|
|
22927
|
+
axesDesign: context.axesDesign,
|
|
22754
22928
|
};
|
|
22755
22929
|
}
|
|
22756
22930
|
getContextCreation() {
|
|
22931
|
+
const range = [];
|
|
22932
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
22933
|
+
range.push({
|
|
22934
|
+
...this.dataSetDesign?.[i],
|
|
22935
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
22936
|
+
});
|
|
22937
|
+
}
|
|
22757
22938
|
return {
|
|
22758
22939
|
...this,
|
|
22759
|
-
range
|
|
22940
|
+
range,
|
|
22760
22941
|
auxiliaryRange: this.labelRange
|
|
22761
22942
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
22762
22943
|
: undefined,
|
|
@@ -22776,19 +22957,26 @@ class BarChart extends AbstractChart {
|
|
|
22776
22957
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
22777
22958
|
}
|
|
22778
22959
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
22960
|
+
const ranges = [];
|
|
22961
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
22962
|
+
ranges.push({
|
|
22963
|
+
...this.dataSetDesign?.[i],
|
|
22964
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
22965
|
+
});
|
|
22966
|
+
}
|
|
22779
22967
|
return {
|
|
22780
22968
|
type: "bar",
|
|
22781
22969
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
22782
22970
|
background: this.background,
|
|
22783
|
-
dataSets:
|
|
22971
|
+
dataSets: ranges,
|
|
22784
22972
|
legendPosition: this.legendPosition,
|
|
22785
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
22786
22973
|
labelRange: labelRange
|
|
22787
22974
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
22788
22975
|
: undefined,
|
|
22789
22976
|
title: this.title,
|
|
22790
22977
|
stacked: this.stacked,
|
|
22791
22978
|
aggregated: this.aggregated,
|
|
22979
|
+
axesDesign: this.axesDesign,
|
|
22792
22980
|
};
|
|
22793
22981
|
}
|
|
22794
22982
|
getDefinitionForExcel() {
|
|
@@ -22799,12 +22987,14 @@ class BarChart extends AbstractChart {
|
|
|
22799
22987
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
22800
22988
|
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
22801
22989
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
22990
|
+
const definition = this.getDefinition();
|
|
22802
22991
|
return {
|
|
22803
|
-
...
|
|
22992
|
+
...definition,
|
|
22804
22993
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
22805
22994
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
22806
22995
|
dataSets,
|
|
22807
22996
|
labelRange,
|
|
22997
|
+
verticalAxis: getDefinedAxis(definition),
|
|
22808
22998
|
};
|
|
22809
22999
|
}
|
|
22810
23000
|
updateRanges(applyChange) {
|
|
@@ -22838,30 +23028,51 @@ function getBarConfiguration(chart, labels, localeFormat) {
|
|
|
22838
23028
|
padding: 5,
|
|
22839
23029
|
color: fontColor,
|
|
22840
23030
|
},
|
|
23031
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
22841
23032
|
},
|
|
22842
|
-
|
|
22843
|
-
|
|
22844
|
-
|
|
22845
|
-
|
|
22846
|
-
|
|
22847
|
-
|
|
22848
|
-
|
|
22849
|
-
|
|
22850
|
-
|
|
22851
|
-
|
|
22852
|
-
|
|
22853
|
-
|
|
22854
|
-
|
|
22855
|
-
|
|
22856
|
-
},
|
|
23033
|
+
};
|
|
23034
|
+
const yAxis = {
|
|
23035
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
23036
|
+
ticks: {
|
|
23037
|
+
color: fontColor,
|
|
23038
|
+
callback: (value) => {
|
|
23039
|
+
value = Number(value);
|
|
23040
|
+
if (isNaN(value))
|
|
23041
|
+
return value;
|
|
23042
|
+
const { locale, format } = localeFormat;
|
|
23043
|
+
return formatValue(value, {
|
|
23044
|
+
locale,
|
|
23045
|
+
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23046
|
+
});
|
|
22857
23047
|
},
|
|
22858
23048
|
},
|
|
22859
23049
|
};
|
|
23050
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(chart.getDefinition());
|
|
23051
|
+
if (useLeftAxis) {
|
|
23052
|
+
config.options.scales.y = {
|
|
23053
|
+
...yAxis,
|
|
23054
|
+
position: "left",
|
|
23055
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
23056
|
+
};
|
|
23057
|
+
}
|
|
23058
|
+
if (useRightAxis) {
|
|
23059
|
+
config.options.scales.y1 = {
|
|
23060
|
+
...yAxis,
|
|
23061
|
+
position: "right",
|
|
23062
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
23063
|
+
};
|
|
23064
|
+
}
|
|
22860
23065
|
if (chart.stacked) {
|
|
22861
23066
|
// @ts-ignore chart.js type is broken
|
|
22862
23067
|
config.options.scales.x.stacked = true;
|
|
22863
|
-
|
|
22864
|
-
|
|
23068
|
+
if (useLeftAxis) {
|
|
23069
|
+
// @ts-ignore chart.js type is broken
|
|
23070
|
+
config.options.scales.y.stacked = true;
|
|
23071
|
+
}
|
|
23072
|
+
if (useRightAxis) {
|
|
23073
|
+
// @ts-ignore chart.js type is broken
|
|
23074
|
+
config.options.scales.y1.stacked = true;
|
|
23075
|
+
}
|
|
22865
23076
|
}
|
|
22866
23077
|
return config;
|
|
22867
23078
|
}
|
|
@@ -22881,8 +23092,9 @@ function createBarChartRuntime(chart, getters) {
|
|
|
22881
23092
|
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
|
|
22882
23093
|
const locale = getters.getLocale();
|
|
22883
23094
|
const config = getBarConfiguration(chart, labels, { format: dataSetFormat, locale });
|
|
22884
|
-
const colors = new
|
|
22885
|
-
|
|
23095
|
+
const colors = new ColorGenerator();
|
|
23096
|
+
const definition = chart.getDefinition();
|
|
23097
|
+
for (const { label, data } of dataSetsValues) {
|
|
22886
23098
|
const color = colors.next();
|
|
22887
23099
|
const dataset = {
|
|
22888
23100
|
label,
|
|
@@ -22892,29 +23104,43 @@ function createBarChartRuntime(chart, getters) {
|
|
|
22892
23104
|
};
|
|
22893
23105
|
config.data.datasets.push(dataset);
|
|
22894
23106
|
}
|
|
23107
|
+
for (const [index, dataset] of config.data.datasets.entries()) {
|
|
23108
|
+
if (definition.dataSets?.[index]?.backgroundColor) {
|
|
23109
|
+
const color = definition.dataSets[index].backgroundColor;
|
|
23110
|
+
dataset.backgroundColor = color;
|
|
23111
|
+
dataset.borderColor = color;
|
|
23112
|
+
}
|
|
23113
|
+
if (definition.dataSets?.[index]?.label) {
|
|
23114
|
+
const label = definition.dataSets[index].label;
|
|
23115
|
+
dataset.label = label;
|
|
23116
|
+
}
|
|
23117
|
+
if (definition.dataSets?.[index]?.yAxisId) {
|
|
23118
|
+
dataset["yAxisID"] = definition.dataSets[index].yAxisId;
|
|
23119
|
+
}
|
|
23120
|
+
}
|
|
22895
23121
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
22896
23122
|
}
|
|
22897
23123
|
|
|
22898
23124
|
class ComboChart extends AbstractChart {
|
|
22899
|
-
useBothYAxis;
|
|
22900
23125
|
dataSets;
|
|
22901
23126
|
labelRange;
|
|
22902
23127
|
background;
|
|
22903
|
-
verticalAxisPosition;
|
|
22904
23128
|
legendPosition;
|
|
22905
23129
|
aggregated;
|
|
22906
23130
|
dataSetsHaveTitle;
|
|
23131
|
+
dataSetDesign;
|
|
23132
|
+
axesDesign;
|
|
22907
23133
|
type = "combo";
|
|
22908
23134
|
constructor(definition, sheetId, getters) {
|
|
22909
23135
|
super(definition, sheetId, getters);
|
|
22910
23136
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
22911
|
-
this.labelRange =
|
|
23137
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
22912
23138
|
this.background = definition.background;
|
|
22913
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
22914
23139
|
this.legendPosition = definition.legendPosition;
|
|
22915
23140
|
this.aggregated = definition.aggregated;
|
|
22916
23141
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
22917
|
-
this.
|
|
23142
|
+
this.dataSetDesign = definition.dataSets;
|
|
23143
|
+
this.axesDesign = definition.axesDesign;
|
|
22918
23144
|
}
|
|
22919
23145
|
static transformDefinition(definition, executed) {
|
|
22920
23146
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -22923,9 +23149,16 @@ class ComboChart extends AbstractChart {
|
|
|
22923
23149
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
22924
23150
|
}
|
|
22925
23151
|
getContextCreation() {
|
|
23152
|
+
const range = [];
|
|
23153
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
23154
|
+
range.push({
|
|
23155
|
+
...this.dataSetDesign?.[i],
|
|
23156
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
23157
|
+
});
|
|
23158
|
+
}
|
|
22926
23159
|
return {
|
|
22927
23160
|
...this,
|
|
22928
|
-
range
|
|
23161
|
+
range,
|
|
22929
23162
|
auxiliaryRange: this.labelRange
|
|
22930
23163
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
22931
23164
|
: undefined,
|
|
@@ -22935,19 +23168,25 @@ class ComboChart extends AbstractChart {
|
|
|
22935
23168
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
22936
23169
|
}
|
|
22937
23170
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
23171
|
+
const ranges = [];
|
|
23172
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
23173
|
+
ranges.push({
|
|
23174
|
+
...this.dataSetDesign?.[i],
|
|
23175
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
23176
|
+
});
|
|
23177
|
+
}
|
|
22938
23178
|
return {
|
|
22939
23179
|
type: "combo",
|
|
22940
23180
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
22941
23181
|
background: this.background,
|
|
22942
|
-
dataSets:
|
|
23182
|
+
dataSets: ranges,
|
|
22943
23183
|
legendPosition: this.legendPosition,
|
|
22944
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
22945
23184
|
labelRange: labelRange
|
|
22946
23185
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
22947
23186
|
: undefined,
|
|
22948
23187
|
title: this.title,
|
|
22949
23188
|
aggregated: this.aggregated,
|
|
22950
|
-
|
|
23189
|
+
axesDesign: this.axesDesign,
|
|
22951
23190
|
};
|
|
22952
23191
|
}
|
|
22953
23192
|
getDefinitionForExcel() {
|
|
@@ -22959,12 +23198,14 @@ class ComboChart extends AbstractChart {
|
|
|
22959
23198
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
22960
23199
|
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
22961
23200
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
23201
|
+
const definition = this.getDefinition();
|
|
22962
23202
|
return {
|
|
22963
|
-
...
|
|
23203
|
+
...definition,
|
|
22964
23204
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
22965
23205
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
22966
23206
|
dataSets,
|
|
22967
23207
|
labelRange,
|
|
23208
|
+
verticalAxis: getDefinedAxis(definition),
|
|
22968
23209
|
};
|
|
22969
23210
|
}
|
|
22970
23211
|
updateRanges(applyChange) {
|
|
@@ -22982,11 +23223,10 @@ class ComboChart extends AbstractChart {
|
|
|
22982
23223
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
22983
23224
|
aggregated: context.aggregated,
|
|
22984
23225
|
legendPosition: context.legendPosition ?? "top",
|
|
22985
|
-
title: context.title || "",
|
|
22986
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
23226
|
+
title: context.title || { text: "" },
|
|
22987
23227
|
labelRange: context.auxiliaryRange || undefined,
|
|
22988
23228
|
type: "combo",
|
|
22989
|
-
|
|
23229
|
+
axesDesign: context.axesDesign,
|
|
22990
23230
|
};
|
|
22991
23231
|
}
|
|
22992
23232
|
copyForSheetId(sheetId) {
|
|
@@ -23001,7 +23241,10 @@ class ComboChart extends AbstractChart {
|
|
|
23001
23241
|
}
|
|
23002
23242
|
}
|
|
23003
23243
|
function createComboChartRuntime(chart, getters) {
|
|
23004
|
-
const
|
|
23244
|
+
const mainDataSetFormat = chart.dataSets.length
|
|
23245
|
+
? getChartDatasetFormat(getters, [chart.dataSets[0]])
|
|
23246
|
+
: undefined;
|
|
23247
|
+
const lineDataSetsFormat = getChartDatasetFormat(getters, chart.dataSets.slice(1));
|
|
23005
23248
|
const locale = getters.getLocale();
|
|
23006
23249
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
23007
23250
|
let labels = labelValues.formattedValues;
|
|
@@ -23015,11 +23258,12 @@ function createComboChartRuntime(chart, getters) {
|
|
|
23015
23258
|
if (chart.aggregated) {
|
|
23016
23259
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
23017
23260
|
}
|
|
23018
|
-
const localeFormat = { format:
|
|
23261
|
+
const localeFormat = { format: mainDataSetFormat, locale };
|
|
23019
23262
|
const fontColor = chartFontColor(chart.background);
|
|
23020
23263
|
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
|
|
23021
23264
|
const legend = {
|
|
23022
23265
|
labels: { color: fontColor },
|
|
23266
|
+
reverse: true,
|
|
23023
23267
|
};
|
|
23024
23268
|
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
|
|
23025
23269
|
legend.display = false;
|
|
@@ -23037,52 +23281,64 @@ function createComboChartRuntime(chart, getters) {
|
|
|
23037
23281
|
padding: 5,
|
|
23038
23282
|
color: fontColor,
|
|
23039
23283
|
},
|
|
23284
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
23040
23285
|
},
|
|
23041
23286
|
};
|
|
23042
|
-
const
|
|
23287
|
+
const formatCallback = (format) => {
|
|
23288
|
+
return (value) => {
|
|
23289
|
+
value = Number(value);
|
|
23290
|
+
if (isNaN(value))
|
|
23291
|
+
return value;
|
|
23292
|
+
const { locale } = localeFormat;
|
|
23293
|
+
return formatValue(value, {
|
|
23294
|
+
locale,
|
|
23295
|
+
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23296
|
+
});
|
|
23297
|
+
};
|
|
23298
|
+
};
|
|
23299
|
+
const leftVerticalAxis = {
|
|
23043
23300
|
beginAtZero: true, // the origin of the y axis is always zero
|
|
23044
23301
|
ticks: {
|
|
23045
23302
|
color: fontColor,
|
|
23046
|
-
callback: (
|
|
23047
|
-
value = Number(value);
|
|
23048
|
-
if (isNaN(value))
|
|
23049
|
-
return value;
|
|
23050
|
-
const { locale, format } = localeFormat;
|
|
23051
|
-
return formatValue(value, {
|
|
23052
|
-
locale,
|
|
23053
|
-
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23054
|
-
});
|
|
23055
|
-
},
|
|
23303
|
+
callback: formatCallback(mainDataSetFormat),
|
|
23056
23304
|
},
|
|
23057
23305
|
};
|
|
23058
|
-
|
|
23306
|
+
const rightVerticalAxis = {
|
|
23307
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
23308
|
+
ticks: {
|
|
23309
|
+
color: fontColor,
|
|
23310
|
+
callback: formatCallback(lineDataSetsFormat),
|
|
23311
|
+
},
|
|
23312
|
+
};
|
|
23313
|
+
const definition = chart.getDefinition();
|
|
23314
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(definition);
|
|
23315
|
+
if (useLeftAxis) {
|
|
23059
23316
|
config.options.scales.y = {
|
|
23060
|
-
...
|
|
23317
|
+
...leftVerticalAxis,
|
|
23061
23318
|
position: "left",
|
|
23319
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
23062
23320
|
};
|
|
23321
|
+
}
|
|
23322
|
+
if (useRightAxis) {
|
|
23063
23323
|
config.options.scales.y1 = {
|
|
23064
|
-
...
|
|
23324
|
+
...rightVerticalAxis,
|
|
23065
23325
|
position: "right",
|
|
23066
23326
|
grid: {
|
|
23067
23327
|
display: false,
|
|
23068
23328
|
},
|
|
23329
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
23069
23330
|
};
|
|
23070
23331
|
}
|
|
23071
|
-
|
|
23072
|
-
config.options.scales.y = {
|
|
23073
|
-
...verticalAxis,
|
|
23074
|
-
position: chart.verticalAxisPosition,
|
|
23075
|
-
};
|
|
23076
|
-
}
|
|
23077
|
-
const colors = new ChartColors();
|
|
23332
|
+
const colors = new ColorGenerator();
|
|
23078
23333
|
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
23334
|
+
const design = definition.dataSets[index];
|
|
23079
23335
|
const color = colors.next();
|
|
23080
23336
|
const dataset = {
|
|
23081
|
-
label,
|
|
23337
|
+
label: design?.label ?? label,
|
|
23082
23338
|
data,
|
|
23083
|
-
borderColor: color,
|
|
23084
|
-
backgroundColor: color,
|
|
23085
|
-
yAxisID:
|
|
23339
|
+
borderColor: design?.backgroundColor ?? color,
|
|
23340
|
+
backgroundColor: design.backgroundColor ?? color,
|
|
23341
|
+
yAxisID: design?.yAxisId ?? "y",
|
|
23086
23342
|
type: index === 0 ? "bar" : "line",
|
|
23087
23343
|
order: -index,
|
|
23088
23344
|
};
|
|
@@ -23163,7 +23419,7 @@ class GaugeChart extends AbstractChart {
|
|
|
23163
23419
|
type = "gauge";
|
|
23164
23420
|
constructor(definition, sheetId, getters) {
|
|
23165
23421
|
super(definition, sheetId, getters);
|
|
23166
|
-
this.dataRange =
|
|
23422
|
+
this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
|
|
23167
23423
|
this.sectionRule = definition.sectionRule;
|
|
23168
23424
|
this.background = definition.background;
|
|
23169
23425
|
}
|
|
@@ -23183,9 +23439,9 @@ class GaugeChart extends AbstractChart {
|
|
|
23183
23439
|
static getDefinitionFromContextCreation(context) {
|
|
23184
23440
|
return {
|
|
23185
23441
|
background: context.background,
|
|
23186
|
-
title: context.title || "",
|
|
23442
|
+
title: context.title || { text: "" },
|
|
23187
23443
|
type: "gauge",
|
|
23188
|
-
dataRange: context.range ? context.range[0] : undefined,
|
|
23444
|
+
dataRange: context.range ? context.range[0].dataRange : undefined,
|
|
23189
23445
|
sectionRule: {
|
|
23190
23446
|
colors: {
|
|
23191
23447
|
lowerColor: DEFAULT_GAUGE_LOWER_COLOR,
|
|
@@ -23236,7 +23492,7 @@ class GaugeChart extends AbstractChart {
|
|
|
23236
23492
|
return {
|
|
23237
23493
|
...this,
|
|
23238
23494
|
range: this.dataRange
|
|
23239
|
-
? [this.getters.getRangeString(this.dataRange, this.sheetId)]
|
|
23495
|
+
? [{ dataRange: this.getters.getRangeString(this.dataRange, this.sheetId) }]
|
|
23240
23496
|
: undefined,
|
|
23241
23497
|
};
|
|
23242
23498
|
}
|
|
@@ -23299,7 +23555,7 @@ function createGaugeChartRuntime(chart, getters) {
|
|
|
23299
23555
|
colors.push(chartColors.upperColor);
|
|
23300
23556
|
return {
|
|
23301
23557
|
background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
|
|
23302
|
-
title: chart.title,
|
|
23558
|
+
title: chart.title ?? { text: "" },
|
|
23303
23559
|
minValue: {
|
|
23304
23560
|
value: minValue,
|
|
23305
23561
|
label: formatValue(minValue, { locale, format }),
|
|
@@ -23557,28 +23813,49 @@ function getLineOrScatterConfiguration(chart, labels, options) {
|
|
|
23557
23813
|
padding: 5,
|
|
23558
23814
|
color: fontColor,
|
|
23559
23815
|
},
|
|
23816
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
23560
23817
|
},
|
|
23561
|
-
|
|
23562
|
-
|
|
23563
|
-
|
|
23564
|
-
|
|
23565
|
-
|
|
23566
|
-
|
|
23567
|
-
|
|
23568
|
-
|
|
23569
|
-
|
|
23570
|
-
|
|
23571
|
-
|
|
23572
|
-
|
|
23573
|
-
|
|
23574
|
-
|
|
23575
|
-
},
|
|
23818
|
+
};
|
|
23819
|
+
const yAxis = {
|
|
23820
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
23821
|
+
ticks: {
|
|
23822
|
+
color: fontColor,
|
|
23823
|
+
callback: (value) => {
|
|
23824
|
+
value = Number(value);
|
|
23825
|
+
if (isNaN(value))
|
|
23826
|
+
return value;
|
|
23827
|
+
const { locale, format } = options;
|
|
23828
|
+
return formatValue(value, {
|
|
23829
|
+
locale,
|
|
23830
|
+
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
23831
|
+
});
|
|
23576
23832
|
},
|
|
23577
23833
|
},
|
|
23578
23834
|
};
|
|
23579
|
-
|
|
23580
|
-
|
|
23581
|
-
config.options.scales.y
|
|
23835
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(chart.getDefinition());
|
|
23836
|
+
if (useLeftAxis) {
|
|
23837
|
+
config.options.scales.y = {
|
|
23838
|
+
...yAxis,
|
|
23839
|
+
position: "left",
|
|
23840
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
23841
|
+
};
|
|
23842
|
+
}
|
|
23843
|
+
if (useRightAxis) {
|
|
23844
|
+
config.options.scales.y1 = {
|
|
23845
|
+
...yAxis,
|
|
23846
|
+
position: "right",
|
|
23847
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
23848
|
+
};
|
|
23849
|
+
}
|
|
23850
|
+
if ("stacked" in chart && chart.stacked) {
|
|
23851
|
+
if (useLeftAxis) {
|
|
23852
|
+
// @ts-ignore chart.js type is broken
|
|
23853
|
+
config.options.scales.y.stacked = true;
|
|
23854
|
+
}
|
|
23855
|
+
if (useRightAxis) {
|
|
23856
|
+
// @ts-ignore chart.js type is broken
|
|
23857
|
+
config.options.scales.y1.stacked = true;
|
|
23858
|
+
}
|
|
23582
23859
|
}
|
|
23583
23860
|
return config;
|
|
23584
23861
|
}
|
|
@@ -23625,7 +23902,8 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
23625
23902
|
}
|
|
23626
23903
|
const stacked = "stacked" in chart ? chart.stacked : false;
|
|
23627
23904
|
const cumulative = "cumulative" in chart ? chart.cumulative : false;
|
|
23628
|
-
const colors = new
|
|
23905
|
+
const colors = new ColorGenerator();
|
|
23906
|
+
const definition = chart.getDefinition();
|
|
23629
23907
|
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
23630
23908
|
if (["linear", "time"].includes(axisType)) {
|
|
23631
23909
|
// Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
|
|
@@ -23658,6 +23936,22 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
23658
23936
|
};
|
|
23659
23937
|
config.data.datasets.push(dataset);
|
|
23660
23938
|
}
|
|
23939
|
+
for (const [index, dataset] of config.data.datasets.entries()) {
|
|
23940
|
+
if (definition.dataSets?.[index]?.backgroundColor) {
|
|
23941
|
+
const color = definition.dataSets[index].backgroundColor;
|
|
23942
|
+
dataset.backgroundColor = color;
|
|
23943
|
+
dataset.borderColor = color;
|
|
23944
|
+
//@ts-ignore
|
|
23945
|
+
dataset.pointBackgroundColor = color;
|
|
23946
|
+
}
|
|
23947
|
+
if (definition.dataSets?.[index]?.label) {
|
|
23948
|
+
const label = definition.dataSets[index].label;
|
|
23949
|
+
dataset.label = label;
|
|
23950
|
+
}
|
|
23951
|
+
if (definition.dataSets?.[index]?.yAxisId) {
|
|
23952
|
+
dataset["yAxisID"] = definition.dataSets[index].yAxisId;
|
|
23953
|
+
}
|
|
23954
|
+
}
|
|
23661
23955
|
return {
|
|
23662
23956
|
chartJsConfig: config,
|
|
23663
23957
|
background: chart.background || BACKGROUND_CHART_COLOR,
|
|
@@ -23672,7 +23966,6 @@ class LineChart extends AbstractChart {
|
|
|
23672
23966
|
dataSets;
|
|
23673
23967
|
labelRange;
|
|
23674
23968
|
background;
|
|
23675
|
-
verticalAxisPosition;
|
|
23676
23969
|
legendPosition;
|
|
23677
23970
|
labelsAsText;
|
|
23678
23971
|
stacked;
|
|
@@ -23680,18 +23973,21 @@ class LineChart extends AbstractChart {
|
|
|
23680
23973
|
type = "line";
|
|
23681
23974
|
dataSetsHaveTitle;
|
|
23682
23975
|
cumulative;
|
|
23976
|
+
dataSetDesign;
|
|
23977
|
+
axesDesign;
|
|
23683
23978
|
constructor(definition, sheetId, getters) {
|
|
23684
23979
|
super(definition, sheetId, getters);
|
|
23685
23980
|
this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
23686
|
-
this.labelRange =
|
|
23981
|
+
this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
|
|
23687
23982
|
this.background = definition.background;
|
|
23688
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
23689
23983
|
this.legendPosition = definition.legendPosition;
|
|
23690
23984
|
this.labelsAsText = definition.labelsAsText;
|
|
23691
23985
|
this.stacked = definition.stacked;
|
|
23692
23986
|
this.aggregated = definition.aggregated;
|
|
23693
23987
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
23694
23988
|
this.cumulative = definition.cumulative;
|
|
23989
|
+
this.dataSetDesign = definition.dataSets;
|
|
23990
|
+
this.axesDesign = definition.axesDesign;
|
|
23695
23991
|
}
|
|
23696
23992
|
static validateChartDefinition(validator, definition) {
|
|
23697
23993
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -23702,30 +23998,36 @@ class LineChart extends AbstractChart {
|
|
|
23702
23998
|
static getDefinitionFromContextCreation(context) {
|
|
23703
23999
|
return {
|
|
23704
24000
|
background: context.background,
|
|
23705
|
-
dataSets: context.range
|
|
24001
|
+
dataSets: context.range ?? [],
|
|
23706
24002
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
23707
24003
|
labelsAsText: context.labelsAsText ?? false,
|
|
23708
24004
|
legendPosition: context.legendPosition ?? "top",
|
|
23709
|
-
title: context.title || "",
|
|
24005
|
+
title: context.title || { text: "" },
|
|
23710
24006
|
type: "line",
|
|
23711
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
23712
24007
|
labelRange: context.auxiliaryRange || undefined,
|
|
23713
24008
|
stacked: context.stacked ?? false,
|
|
23714
24009
|
aggregated: context.aggregated ?? false,
|
|
23715
24010
|
cumulative: context.cumulative ?? false,
|
|
24011
|
+
axesDesign: context.axesDesign,
|
|
23716
24012
|
};
|
|
23717
24013
|
}
|
|
23718
24014
|
getDefinition() {
|
|
23719
24015
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
23720
24016
|
}
|
|
23721
24017
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
24018
|
+
const ranges = [];
|
|
24019
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
24020
|
+
ranges.push({
|
|
24021
|
+
...this.dataSetDesign?.[i],
|
|
24022
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
24023
|
+
});
|
|
24024
|
+
}
|
|
23722
24025
|
return {
|
|
23723
24026
|
type: "line",
|
|
23724
24027
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
23725
24028
|
background: this.background,
|
|
23726
|
-
dataSets:
|
|
24029
|
+
dataSets: ranges,
|
|
23727
24030
|
legendPosition: this.legendPosition,
|
|
23728
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
23729
24031
|
labelRange: labelRange
|
|
23730
24032
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
23731
24033
|
: undefined,
|
|
@@ -23734,12 +24036,20 @@ class LineChart extends AbstractChart {
|
|
|
23734
24036
|
stacked: this.stacked,
|
|
23735
24037
|
aggregated: this.aggregated,
|
|
23736
24038
|
cumulative: this.cumulative,
|
|
24039
|
+
axesDesign: this.axesDesign,
|
|
23737
24040
|
};
|
|
23738
24041
|
}
|
|
23739
24042
|
getContextCreation() {
|
|
24043
|
+
const range = [];
|
|
24044
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
24045
|
+
range.push({
|
|
24046
|
+
...this.dataSetDesign?.[i],
|
|
24047
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
24048
|
+
});
|
|
24049
|
+
}
|
|
23740
24050
|
return {
|
|
23741
24051
|
...this,
|
|
23742
|
-
range
|
|
24052
|
+
range,
|
|
23743
24053
|
auxiliaryRange: this.labelRange
|
|
23744
24054
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
23745
24055
|
: undefined,
|
|
@@ -23761,12 +24071,14 @@ class LineChart extends AbstractChart {
|
|
|
23761
24071
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
23762
24072
|
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
23763
24073
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
24074
|
+
const definition = this.getDefinition();
|
|
23764
24075
|
return {
|
|
23765
|
-
...
|
|
24076
|
+
...definition,
|
|
23766
24077
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
23767
24078
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
23768
24079
|
dataSets,
|
|
23769
24080
|
labelRange,
|
|
24081
|
+
verticalAxis: getDefinedAxis(definition),
|
|
23770
24082
|
};
|
|
23771
24083
|
}
|
|
23772
24084
|
copyForSheetId(sheetId) {
|
|
@@ -23796,7 +24108,7 @@ class PieChart extends AbstractChart {
|
|
|
23796
24108
|
constructor(definition, sheetId, getters) {
|
|
23797
24109
|
super(definition, sheetId, getters);
|
|
23798
24110
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
23799
|
-
this.labelRange =
|
|
24111
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
23800
24112
|
this.background = definition.background;
|
|
23801
24113
|
this.legendPosition = definition.legendPosition;
|
|
23802
24114
|
this.aggregated = definition.aggregated;
|
|
@@ -23811,10 +24123,10 @@ class PieChart extends AbstractChart {
|
|
|
23811
24123
|
static getDefinitionFromContextCreation(context) {
|
|
23812
24124
|
return {
|
|
23813
24125
|
background: context.background,
|
|
23814
|
-
dataSets: context.range
|
|
24126
|
+
dataSets: context.range ?? [],
|
|
23815
24127
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
23816
24128
|
legendPosition: context.legendPosition ?? "top",
|
|
23817
|
-
title: context.title || "",
|
|
24129
|
+
title: context.title || { text: "" },
|
|
23818
24130
|
type: "pie",
|
|
23819
24131
|
labelRange: context.auxiliaryRange || undefined,
|
|
23820
24132
|
aggregated: context.aggregated ?? false,
|
|
@@ -23826,7 +24138,9 @@ class PieChart extends AbstractChart {
|
|
|
23826
24138
|
getContextCreation() {
|
|
23827
24139
|
return {
|
|
23828
24140
|
...this,
|
|
23829
|
-
range: this.dataSets.map((ds) =>
|
|
24141
|
+
range: this.dataSets.map((ds) => ({
|
|
24142
|
+
dataRange: this.getters.getRangeString(ds.dataRange, this.sheetId),
|
|
24143
|
+
})),
|
|
23830
24144
|
auxiliaryRange: this.labelRange
|
|
23831
24145
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
23832
24146
|
: undefined,
|
|
@@ -23837,7 +24151,9 @@ class PieChart extends AbstractChart {
|
|
|
23837
24151
|
type: "pie",
|
|
23838
24152
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
23839
24153
|
background: this.background,
|
|
23840
|
-
dataSets: dataSets.map((ds) =>
|
|
24154
|
+
dataSets: dataSets.map((ds) => ({
|
|
24155
|
+
dataRange: this.getters.getRangeString(ds.dataRange, targetSheetId || this.sheetId),
|
|
24156
|
+
})),
|
|
23841
24157
|
legendPosition: this.legendPosition,
|
|
23842
24158
|
labelRange: labelRange
|
|
23843
24159
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
@@ -23868,7 +24184,6 @@ class PieChart extends AbstractChart {
|
|
|
23868
24184
|
...this.getDefinition(),
|
|
23869
24185
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
23870
24186
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
23871
|
-
verticalAxisPosition: "left", //TODO ExcelChartDefinition should be adapted, but can be done later
|
|
23872
24187
|
dataSets,
|
|
23873
24188
|
labelRange,
|
|
23874
24189
|
};
|
|
@@ -23969,9 +24284,8 @@ function createPieChartRuntime(chart, getters) {
|
|
|
23969
24284
|
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
|
|
23970
24285
|
const locale = getters.getLocale();
|
|
23971
24286
|
const config = getPieConfiguration(chart, labels, { format: dataSetFormat, locale });
|
|
23972
|
-
const
|
|
23973
|
-
for (
|
|
23974
|
-
const backgroundColor = getPieColors(colors, dataSetsValues);
|
|
24287
|
+
const backgroundColor = getPieColors(new ColorGenerator(), dataSetsValues);
|
|
24288
|
+
for (const { label, data } of dataSetsValues) {
|
|
23975
24289
|
const dataset = {
|
|
23976
24290
|
label,
|
|
23977
24291
|
data,
|
|
@@ -23987,22 +24301,24 @@ class ScatterChart extends AbstractChart {
|
|
|
23987
24301
|
dataSets;
|
|
23988
24302
|
labelRange;
|
|
23989
24303
|
background;
|
|
23990
|
-
verticalAxisPosition;
|
|
23991
24304
|
legendPosition;
|
|
23992
24305
|
labelsAsText;
|
|
23993
24306
|
aggregated;
|
|
23994
24307
|
type = "scatter";
|
|
23995
24308
|
dataSetsHaveTitle;
|
|
24309
|
+
dataSetDesign;
|
|
24310
|
+
axesDesign;
|
|
23996
24311
|
constructor(definition, sheetId, getters) {
|
|
23997
24312
|
super(definition, sheetId, getters);
|
|
23998
24313
|
this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
23999
|
-
this.labelRange =
|
|
24314
|
+
this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
|
|
24000
24315
|
this.background = definition.background;
|
|
24001
|
-
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
24002
24316
|
this.legendPosition = definition.legendPosition;
|
|
24003
24317
|
this.labelsAsText = definition.labelsAsText;
|
|
24004
24318
|
this.aggregated = definition.aggregated;
|
|
24005
24319
|
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
24320
|
+
this.dataSetDesign = definition.dataSets;
|
|
24321
|
+
this.axesDesign = definition.axesDesign;
|
|
24006
24322
|
}
|
|
24007
24323
|
static validateChartDefinition(validator, definition) {
|
|
24008
24324
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -24013,40 +24329,54 @@ class ScatterChart extends AbstractChart {
|
|
|
24013
24329
|
static getDefinitionFromContextCreation(context) {
|
|
24014
24330
|
return {
|
|
24015
24331
|
background: context.background,
|
|
24016
|
-
dataSets: context.range
|
|
24332
|
+
dataSets: context.range ?? [],
|
|
24017
24333
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
24018
24334
|
labelsAsText: context.labelsAsText ?? false,
|
|
24019
24335
|
legendPosition: context.legendPosition ?? "top",
|
|
24020
|
-
title: context.title || "",
|
|
24336
|
+
title: context.title || { text: "" },
|
|
24021
24337
|
type: "scatter",
|
|
24022
|
-
verticalAxisPosition: context.verticalAxisPosition ?? "left",
|
|
24023
24338
|
labelRange: context.auxiliaryRange || undefined,
|
|
24024
24339
|
aggregated: context.aggregated ?? false,
|
|
24340
|
+
axesDesign: context.axesDesign,
|
|
24025
24341
|
};
|
|
24026
24342
|
}
|
|
24027
24343
|
getDefinition() {
|
|
24028
24344
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
24029
24345
|
}
|
|
24030
24346
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
24347
|
+
const ranges = [];
|
|
24348
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
24349
|
+
ranges.push({
|
|
24350
|
+
...this.dataSetDesign?.[i],
|
|
24351
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
24352
|
+
});
|
|
24353
|
+
}
|
|
24031
24354
|
return {
|
|
24032
24355
|
type: "scatter",
|
|
24033
24356
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
24034
24357
|
background: this.background,
|
|
24035
|
-
dataSets:
|
|
24358
|
+
dataSets: ranges,
|
|
24036
24359
|
legendPosition: this.legendPosition,
|
|
24037
|
-
verticalAxisPosition: this.verticalAxisPosition,
|
|
24038
24360
|
labelRange: labelRange
|
|
24039
24361
|
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
24040
24362
|
: undefined,
|
|
24041
24363
|
title: this.title,
|
|
24042
24364
|
labelsAsText: this.labelsAsText,
|
|
24043
24365
|
aggregated: this.aggregated,
|
|
24366
|
+
axesDesign: this.axesDesign,
|
|
24044
24367
|
};
|
|
24045
24368
|
}
|
|
24046
24369
|
getContextCreation() {
|
|
24370
|
+
const range = [];
|
|
24371
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
24372
|
+
range.push({
|
|
24373
|
+
...this.dataSetDesign?.[i],
|
|
24374
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
24375
|
+
});
|
|
24376
|
+
}
|
|
24047
24377
|
return {
|
|
24048
24378
|
...this,
|
|
24049
|
-
range
|
|
24379
|
+
range,
|
|
24050
24380
|
auxiliaryRange: this.labelRange
|
|
24051
24381
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
24052
24382
|
: undefined,
|
|
@@ -24069,12 +24399,14 @@ class ScatterChart extends AbstractChart {
|
|
|
24069
24399
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
24070
24400
|
.filter((ds) => ds.range !== "");
|
|
24071
24401
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
24402
|
+
const definition = this.getDefinition();
|
|
24072
24403
|
return {
|
|
24073
|
-
...
|
|
24404
|
+
...definition,
|
|
24074
24405
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
24075
24406
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
24076
24407
|
dataSets,
|
|
24077
24408
|
labelRange,
|
|
24409
|
+
verticalAxis: getDefinedAxis(definition),
|
|
24078
24410
|
};
|
|
24079
24411
|
}
|
|
24080
24412
|
copyForSheetId(sheetId) {
|
|
@@ -24094,13 +24426,6 @@ function createScatterChartRuntime(chart, getters) {
|
|
|
24094
24426
|
// have less options than the line chart (it only works with linear labels)
|
|
24095
24427
|
chartJsConfig.type = "line";
|
|
24096
24428
|
const configOptions = chartJsConfig.options;
|
|
24097
|
-
configOptions.elements = {
|
|
24098
|
-
point: {
|
|
24099
|
-
radius: 3,
|
|
24100
|
-
hoverRadius: 3, // chartJS seems bugged, the point starts with the "hoverRadius" value
|
|
24101
|
-
hitRadius: 8,
|
|
24102
|
-
},
|
|
24103
|
-
};
|
|
24104
24429
|
const locale = getters.getLocale();
|
|
24105
24430
|
configOptions.plugins.tooltip.callbacks.title = () => "";
|
|
24106
24431
|
configOptions.plugins.tooltip.callbacks.label = (tooltipItem) => {
|
|
@@ -24137,10 +24462,12 @@ class WaterfallChart extends AbstractChart {
|
|
|
24137
24462
|
positiveValuesColor;
|
|
24138
24463
|
negativeValuesColor;
|
|
24139
24464
|
subTotalValuesColor;
|
|
24465
|
+
dataSetDesign;
|
|
24466
|
+
axesDesign;
|
|
24140
24467
|
constructor(definition, sheetId, getters) {
|
|
24141
24468
|
super(definition, sheetId, getters);
|
|
24142
24469
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
24143
|
-
this.labelRange =
|
|
24470
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
24144
24471
|
this.background = definition.background;
|
|
24145
24472
|
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
24146
24473
|
this.legendPosition = definition.legendPosition;
|
|
@@ -24152,6 +24479,8 @@ class WaterfallChart extends AbstractChart {
|
|
|
24152
24479
|
this.negativeValuesColor = definition.negativeValuesColor;
|
|
24153
24480
|
this.subTotalValuesColor = definition.subTotalValuesColor;
|
|
24154
24481
|
this.firstValueAsSubtotal = definition.firstValueAsSubtotal;
|
|
24482
|
+
this.dataSetDesign = definition.dataSets;
|
|
24483
|
+
this.axesDesign = definition.axesDesign;
|
|
24155
24484
|
}
|
|
24156
24485
|
static transformDefinition(definition, executed) {
|
|
24157
24486
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -24166,19 +24495,27 @@ class WaterfallChart extends AbstractChart {
|
|
|
24166
24495
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
24167
24496
|
aggregated: context.aggregated ?? false,
|
|
24168
24497
|
legendPosition: context.legendPosition ?? "top",
|
|
24169
|
-
title: context.title || "",
|
|
24498
|
+
title: context.title || { text: "" },
|
|
24170
24499
|
type: "waterfall",
|
|
24171
|
-
verticalAxisPosition:
|
|
24500
|
+
verticalAxisPosition: "left",
|
|
24172
24501
|
labelRange: context.auxiliaryRange || undefined,
|
|
24173
24502
|
showSubTotals: context.showSubTotals ?? false,
|
|
24174
24503
|
showConnectorLines: context.showConnectorLines ?? true,
|
|
24175
24504
|
firstValueAsSubtotal: context.firstValueAsSubtotal ?? false,
|
|
24505
|
+
axesDesign: context.axesDesign,
|
|
24176
24506
|
};
|
|
24177
24507
|
}
|
|
24178
24508
|
getContextCreation() {
|
|
24509
|
+
const range = [];
|
|
24510
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
24511
|
+
range.push({
|
|
24512
|
+
...this.dataSetDesign?.[i],
|
|
24513
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
24514
|
+
});
|
|
24515
|
+
}
|
|
24179
24516
|
return {
|
|
24180
24517
|
...this,
|
|
24181
|
-
range
|
|
24518
|
+
range,
|
|
24182
24519
|
auxiliaryRange: this.labelRange
|
|
24183
24520
|
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
24184
24521
|
: undefined,
|
|
@@ -24198,11 +24535,18 @@ class WaterfallChart extends AbstractChart {
|
|
|
24198
24535
|
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
24199
24536
|
}
|
|
24200
24537
|
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
24538
|
+
const ranges = [];
|
|
24539
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
24540
|
+
ranges.push({
|
|
24541
|
+
...this.dataSetDesign?.[i],
|
|
24542
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
24543
|
+
});
|
|
24544
|
+
}
|
|
24201
24545
|
return {
|
|
24202
24546
|
type: "waterfall",
|
|
24203
24547
|
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
24204
24548
|
background: this.background,
|
|
24205
|
-
dataSets:
|
|
24549
|
+
dataSets: ranges,
|
|
24206
24550
|
legendPosition: this.legendPosition,
|
|
24207
24551
|
verticalAxisPosition: this.verticalAxisPosition,
|
|
24208
24552
|
labelRange: labelRange
|
|
@@ -24216,6 +24560,7 @@ class WaterfallChart extends AbstractChart {
|
|
|
24216
24560
|
negativeValuesColor: this.negativeValuesColor,
|
|
24217
24561
|
subTotalValuesColor: this.subTotalValuesColor,
|
|
24218
24562
|
firstValueAsSubtotal: this.firstValueAsSubtotal,
|
|
24563
|
+
axesDesign: this.axesDesign,
|
|
24219
24564
|
};
|
|
24220
24565
|
}
|
|
24221
24566
|
getDefinitionForExcel() {
|
|
@@ -24275,6 +24620,7 @@ function getWaterfallConfiguration(chart, labels, dataSeriesLabels, localeFormat
|
|
|
24275
24620
|
grid: {
|
|
24276
24621
|
display: false,
|
|
24277
24622
|
},
|
|
24623
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
24278
24624
|
},
|
|
24279
24625
|
y: {
|
|
24280
24626
|
position: chart.verticalAxisPosition,
|
|
@@ -24295,6 +24641,7 @@ function getWaterfallConfiguration(chart, labels, dataSeriesLabels, localeFormat
|
|
|
24295
24641
|
return context.tick.value === 0 ? 2 : 1;
|
|
24296
24642
|
},
|
|
24297
24643
|
},
|
|
24644
|
+
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
24298
24645
|
},
|
|
24299
24646
|
};
|
|
24300
24647
|
config.options.plugins.tooltip = {
|
|
@@ -26354,13 +26701,14 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26354
26701
|
if (!singleColumn) {
|
|
26355
26702
|
dataSetZone = { ...zone, left: zone.left + 1 };
|
|
26356
26703
|
}
|
|
26357
|
-
const
|
|
26704
|
+
const dataRange = zoneToXc(dataSetZone);
|
|
26705
|
+
const dataSets = [{ dataRange, yAxisId: "y" }];
|
|
26358
26706
|
const sheetId = getters.getActiveSheetId();
|
|
26359
26707
|
const topLeftCell = getters.getCell({ sheetId, col: zone.left, row: zone.top });
|
|
26360
26708
|
if (getZoneArea(zone) === 1 && topLeftCell?.content) {
|
|
26361
26709
|
return {
|
|
26362
26710
|
type: "scorecard",
|
|
26363
|
-
title: "",
|
|
26711
|
+
title: { text: "" },
|
|
26364
26712
|
background: topLeftCell.style?.fillColor || undefined,
|
|
26365
26713
|
keyValue: zoneToXc(zone),
|
|
26366
26714
|
baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
|
|
@@ -26396,7 +26744,7 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26396
26744
|
const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
|
|
26397
26745
|
if (canChartParseLabels(labelRange, getters)) {
|
|
26398
26746
|
return {
|
|
26399
|
-
title,
|
|
26747
|
+
title: { text: title },
|
|
26400
26748
|
dataSets,
|
|
26401
26749
|
labelsAsText: false,
|
|
26402
26750
|
stacked: false,
|
|
@@ -26405,7 +26753,6 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26405
26753
|
labelRange: labelRangeXc,
|
|
26406
26754
|
type: "line",
|
|
26407
26755
|
dataSetsHaveTitle,
|
|
26408
|
-
verticalAxisPosition: "left",
|
|
26409
26756
|
legendPosition: newLegendPos,
|
|
26410
26757
|
};
|
|
26411
26758
|
}
|
|
@@ -26413,24 +26760,23 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
26413
26760
|
if (singleColumn &&
|
|
26414
26761
|
getData(getters, _dataSets[0]).every((e) => typeof e === "string" && !isEvaluationError(e))) {
|
|
26415
26762
|
return {
|
|
26416
|
-
title: "",
|
|
26417
|
-
dataSets,
|
|
26763
|
+
title: { text: "" },
|
|
26764
|
+
dataSets: [{ dataRange }],
|
|
26418
26765
|
aggregated: true,
|
|
26419
|
-
labelRange:
|
|
26766
|
+
labelRange: dataRange,
|
|
26420
26767
|
type: "pie",
|
|
26421
26768
|
legendPosition: "top",
|
|
26422
26769
|
dataSetsHaveTitle: false,
|
|
26423
26770
|
};
|
|
26424
26771
|
}
|
|
26425
26772
|
return {
|
|
26426
|
-
title,
|
|
26773
|
+
title: { text: title },
|
|
26427
26774
|
dataSets,
|
|
26428
26775
|
labelRange: labelRangeXc,
|
|
26429
26776
|
type: "bar",
|
|
26430
26777
|
stacked: false,
|
|
26431
26778
|
aggregated: false,
|
|
26432
26779
|
dataSetsHaveTitle,
|
|
26433
|
-
verticalAxisPosition: "left",
|
|
26434
26780
|
legendPosition: newLegendPos,
|
|
26435
26781
|
};
|
|
26436
26782
|
}
|
|
@@ -29471,6 +29817,41 @@ class OTRegistry extends Registry {
|
|
|
29471
29817
|
}
|
|
29472
29818
|
const otRegistry = new OTRegistry();
|
|
29473
29819
|
|
|
29820
|
+
css /* scss */ `
|
|
29821
|
+
.o-checkbox {
|
|
29822
|
+
display: flex;
|
|
29823
|
+
justify-items: center;
|
|
29824
|
+
input {
|
|
29825
|
+
margin-right: 5px;
|
|
29826
|
+
}
|
|
29827
|
+
}
|
|
29828
|
+
`;
|
|
29829
|
+
class Checkbox extends Component {
|
|
29830
|
+
static template = "o-spreadsheet.Checkbox";
|
|
29831
|
+
static props = {
|
|
29832
|
+
label: { type: String, optional: true },
|
|
29833
|
+
value: { type: Boolean, optional: true },
|
|
29834
|
+
className: { type: String, optional: true },
|
|
29835
|
+
name: { type: String, optional: true },
|
|
29836
|
+
title: { type: String, optional: true },
|
|
29837
|
+
disabled: { type: Boolean, optional: true },
|
|
29838
|
+
onChange: Function,
|
|
29839
|
+
};
|
|
29840
|
+
static defaultProps = { value: false };
|
|
29841
|
+
onChange(ev) {
|
|
29842
|
+
const value = ev.target.checked;
|
|
29843
|
+
this.props.onChange(value);
|
|
29844
|
+
}
|
|
29845
|
+
}
|
|
29846
|
+
|
|
29847
|
+
class Section extends Component {
|
|
29848
|
+
static template = "o_spreadsheet.Section";
|
|
29849
|
+
static props = {
|
|
29850
|
+
class: { type: String, optional: true },
|
|
29851
|
+
slots: Object,
|
|
29852
|
+
};
|
|
29853
|
+
}
|
|
29854
|
+
|
|
29474
29855
|
// The name is misleading and can be confused with the DOM focus.
|
|
29475
29856
|
class FocusStore {
|
|
29476
29857
|
mutators = ["focus", "unfocus"];
|
|
@@ -29495,6 +29876,7 @@ class FocusStore {
|
|
|
29495
29876
|
class SelectionInputStore extends SpreadsheetStore {
|
|
29496
29877
|
initialRanges;
|
|
29497
29878
|
inputHasSingleRange;
|
|
29879
|
+
colors;
|
|
29498
29880
|
mutators = [
|
|
29499
29881
|
"resetWithRanges",
|
|
29500
29882
|
"focusById",
|
|
@@ -29510,10 +29892,11 @@ class SelectionInputStore extends SpreadsheetStore {
|
|
|
29510
29892
|
inputSheetId;
|
|
29511
29893
|
focusStore = this.get(FocusStore);
|
|
29512
29894
|
highlightStore = this.get(HighlightStore);
|
|
29513
|
-
constructor(get, initialRanges = [], inputHasSingleRange = false) {
|
|
29895
|
+
constructor(get, initialRanges = [], inputHasSingleRange = false, colors = []) {
|
|
29514
29896
|
super(get);
|
|
29515
29897
|
this.initialRanges = initialRanges;
|
|
29516
29898
|
this.inputHasSingleRange = inputHasSingleRange;
|
|
29899
|
+
this.colors = colors;
|
|
29517
29900
|
if (inputHasSingleRange && initialRanges.length > 1) {
|
|
29518
29901
|
throw new Error("Input with a single range cannot be instantiated with several range references.");
|
|
29519
29902
|
}
|
|
@@ -29655,11 +30038,12 @@ class SelectionInputStore extends SpreadsheetStore {
|
|
|
29655
30038
|
* e.g. ["A1", "Sheet2!B3", "E12"]
|
|
29656
30039
|
*/
|
|
29657
30040
|
get selectionInputs() {
|
|
30041
|
+
const generator = new ColorGenerator(this.colors);
|
|
29658
30042
|
return this.ranges.map((input, index) => Object.assign({}, input, {
|
|
29659
30043
|
color: this.hasMainFocus &&
|
|
29660
30044
|
this.focusedRangeIndex !== null &&
|
|
29661
30045
|
this.getters.isRangeValid(input.xc)
|
|
29662
|
-
?
|
|
30046
|
+
? generator.next()
|
|
29663
30047
|
: null,
|
|
29664
30048
|
isFocused: this.hasMainFocus && this.focusedRangeIndex === index,
|
|
29665
30049
|
isValidRange: input.xc === "" || this.getters.isRangeValid(input.xc),
|
|
@@ -29736,10 +30120,14 @@ class SelectionInputStore extends SpreadsheetStore {
|
|
|
29736
30120
|
*/
|
|
29737
30121
|
insertNewRange(index, values) {
|
|
29738
30122
|
const currentMaxId = Math.max(0, ...this.ranges.map((range) => Number(range.id)));
|
|
30123
|
+
const colors = new ColorGenerator(this.colors);
|
|
30124
|
+
for (let i = 0; i < index; i++) {
|
|
30125
|
+
colors.next();
|
|
30126
|
+
}
|
|
29739
30127
|
this.ranges.splice(index, 0, ...values.map((xc, i) => ({
|
|
29740
30128
|
xc,
|
|
29741
30129
|
id: currentMaxId + i + 1,
|
|
29742
|
-
color: colors
|
|
30130
|
+
color: colors.next(),
|
|
29743
30131
|
})));
|
|
29744
30132
|
}
|
|
29745
30133
|
/**
|
|
@@ -29883,6 +30271,7 @@ class SelectionInput extends Component {
|
|
|
29883
30271
|
class: { type: String, optional: true },
|
|
29884
30272
|
onSelectionChanged: { type: Function, optional: true },
|
|
29885
30273
|
onSelectionConfirmed: { type: Function, optional: true },
|
|
30274
|
+
colors: { type: Array, optional: true, default: [] },
|
|
29886
30275
|
};
|
|
29887
30276
|
state = useState({
|
|
29888
30277
|
isMissing: false,
|
|
@@ -29907,7 +30296,7 @@ class SelectionInput extends Component {
|
|
|
29907
30296
|
}
|
|
29908
30297
|
setup() {
|
|
29909
30298
|
useEffect(() => this.focusedInput.el?.focus(), () => [this.focusedInput.el]);
|
|
29910
|
-
this.store = useLocalStore(SelectionInputStore, this.props.ranges, this.props.hasSingleRange || false);
|
|
30299
|
+
this.store = useLocalStore(SelectionInputStore, this.props.ranges, this.props.hasSingleRange || false, this.props.colors);
|
|
29911
30300
|
onWillUpdateProps((nextProps) => {
|
|
29912
30301
|
if (nextProps.ranges.join() !== this.store.selectionInputValues.join()) {
|
|
29913
30302
|
this.triggerChange();
|
|
@@ -29982,6 +30371,26 @@ class SelectionInput extends Component {
|
|
|
29982
30371
|
}
|
|
29983
30372
|
}
|
|
29984
30373
|
|
|
30374
|
+
class ChartDataSeries extends Component {
|
|
30375
|
+
static template = "o-spreadsheet.ChartDataSeries";
|
|
30376
|
+
static components = { SelectionInput, Section };
|
|
30377
|
+
static props = {
|
|
30378
|
+
ranges: Array,
|
|
30379
|
+
hasSingleRange: { type: Boolean, optional: true },
|
|
30380
|
+
onSelectionChanged: Function,
|
|
30381
|
+
onSelectionConfirmed: Function,
|
|
30382
|
+
};
|
|
30383
|
+
get ranges() {
|
|
30384
|
+
return this.props.ranges.map((r) => r.dataRange);
|
|
30385
|
+
}
|
|
30386
|
+
get colors() {
|
|
30387
|
+
return this.props.ranges.map((r) => r.backgroundColor);
|
|
30388
|
+
}
|
|
30389
|
+
get title() {
|
|
30390
|
+
return this.props.hasSingleRange ? _t("Data range") : _t("Data series");
|
|
30391
|
+
}
|
|
30392
|
+
}
|
|
30393
|
+
|
|
29985
30394
|
css /* scss */ `
|
|
29986
30395
|
.o-validation-error,
|
|
29987
30396
|
.o-validation-warning {
|
|
@@ -30008,55 +30417,6 @@ class ValidationMessages extends Component {
|
|
|
30008
30417
|
}
|
|
30009
30418
|
}
|
|
30010
30419
|
|
|
30011
|
-
css /* scss */ `
|
|
30012
|
-
.o-checkbox {
|
|
30013
|
-
display: flex;
|
|
30014
|
-
justify-items: center;
|
|
30015
|
-
input {
|
|
30016
|
-
margin-right: 5px;
|
|
30017
|
-
}
|
|
30018
|
-
}
|
|
30019
|
-
`;
|
|
30020
|
-
class Checkbox extends Component {
|
|
30021
|
-
static template = "o-spreadsheet.Checkbox";
|
|
30022
|
-
static props = {
|
|
30023
|
-
label: { type: String, optional: true },
|
|
30024
|
-
value: { type: Boolean, optional: true },
|
|
30025
|
-
className: { type: String, optional: true },
|
|
30026
|
-
name: { type: String, optional: true },
|
|
30027
|
-
title: { type: String, optional: true },
|
|
30028
|
-
disabled: { type: Boolean, optional: true },
|
|
30029
|
-
onChange: Function,
|
|
30030
|
-
};
|
|
30031
|
-
static defaultProps = { value: false };
|
|
30032
|
-
onChange(ev) {
|
|
30033
|
-
const value = ev.target.checked;
|
|
30034
|
-
this.props.onChange(value);
|
|
30035
|
-
}
|
|
30036
|
-
}
|
|
30037
|
-
|
|
30038
|
-
class Section extends Component {
|
|
30039
|
-
static template = "o_spreadsheet.Section";
|
|
30040
|
-
static props = {
|
|
30041
|
-
class: { type: String, optional: true },
|
|
30042
|
-
slots: Object,
|
|
30043
|
-
};
|
|
30044
|
-
}
|
|
30045
|
-
|
|
30046
|
-
class ChartDataSeries extends Component {
|
|
30047
|
-
static template = "o-spreadsheet.ChartDataSeries";
|
|
30048
|
-
static components = { SelectionInput, Section };
|
|
30049
|
-
static props = {
|
|
30050
|
-
ranges: Array,
|
|
30051
|
-
hasSingleRange: { type: Boolean, optional: true },
|
|
30052
|
-
onSelectionChanged: Function,
|
|
30053
|
-
onSelectionConfirmed: Function,
|
|
30054
|
-
};
|
|
30055
|
-
get title() {
|
|
30056
|
-
return this.props.hasSingleRange ? _t("Data range") : _t("Data series");
|
|
30057
|
-
}
|
|
30058
|
-
}
|
|
30059
|
-
|
|
30060
30420
|
class ChartErrorSection extends Component {
|
|
30061
30421
|
static template = "o-spreadsheet.ChartErrorSection";
|
|
30062
30422
|
static components = { Section, ValidationMessages };
|
|
@@ -30085,8 +30445,6 @@ class ChartLabelRange extends Component {
|
|
|
30085
30445
|
class GenericChartConfigPanel extends Component {
|
|
30086
30446
|
static template = "o-spreadsheet-GenericChartConfigPanel";
|
|
30087
30447
|
static components = {
|
|
30088
|
-
SelectionInput,
|
|
30089
|
-
ValidationMessages,
|
|
30090
30448
|
ChartDataSeries,
|
|
30091
30449
|
ChartLabelRange,
|
|
30092
30450
|
Section,
|
|
@@ -30145,7 +30503,10 @@ class GenericChartConfigPanel extends Component {
|
|
|
30145
30503
|
* button "confirm" is clicked
|
|
30146
30504
|
*/
|
|
30147
30505
|
onDataSeriesRangesChanged(ranges) {
|
|
30148
|
-
this.dataSeriesRanges = ranges
|
|
30506
|
+
this.dataSeriesRanges = ranges.map((dataRange, i) => ({
|
|
30507
|
+
...this.dataSeriesRanges?.[i],
|
|
30508
|
+
dataRange,
|
|
30509
|
+
}));
|
|
30149
30510
|
this.state.datasetDispatchResult = this.props.canUpdateChart(this.props.figureId, {
|
|
30150
30511
|
dataSets: this.dataSeriesRanges,
|
|
30151
30512
|
});
|
|
@@ -30188,7 +30549,7 @@ class GenericChartConfigPanel extends Component {
|
|
|
30188
30549
|
}
|
|
30189
30550
|
const getters = this.env.model.getters;
|
|
30190
30551
|
const sheetId = getters.getActiveSheetId();
|
|
30191
|
-
const labelRange =
|
|
30552
|
+
const labelRange = createValidRange(getters, sheetId, this.labelRange);
|
|
30192
30553
|
const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
|
|
30193
30554
|
if (dataSets.length) {
|
|
30194
30555
|
return dataSets[0].dataRange.zone.top + 1;
|
|
@@ -30217,15 +30578,102 @@ class BarConfigPanel extends GenericChartConfigPanel {
|
|
|
30217
30578
|
}
|
|
30218
30579
|
}
|
|
30219
30580
|
|
|
30581
|
+
const ANGLE_DOWN = /*xml*/ `
|
|
30582
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 224 256">
|
|
30583
|
+
<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)"/>
|
|
30584
|
+
</svg>
|
|
30585
|
+
`;
|
|
30586
|
+
const BACKGROUND_COLOR = "#fdfdfd";
|
|
30587
|
+
const BORDER_COLOR = "#8b8b8b";
|
|
30588
|
+
css /* scss */ `
|
|
30589
|
+
.o_side_panel_collapsible_title {
|
|
30590
|
+
font-size: 16px;
|
|
30591
|
+
font-weight: bold;
|
|
30592
|
+
cursor: pointer;
|
|
30593
|
+
padding: 6px 0px 6px 6px !important;
|
|
30594
|
+
|
|
30595
|
+
.collapsor:before {
|
|
30596
|
+
transform: rotate(-90deg);
|
|
30597
|
+
content: url("data:image/svg+xml,${encodeURIComponent(ANGLE_DOWN)}");
|
|
30598
|
+
width: 12px;
|
|
30599
|
+
display: inline-block;
|
|
30600
|
+
margin: 0 5px 0px 2px;
|
|
30601
|
+
height: 22px;
|
|
30602
|
+
transform-origin: 7px 10px;
|
|
30603
|
+
transition: transform 0.2s ease-in-out;
|
|
30604
|
+
}
|
|
30605
|
+
.collapsor:not(.collapsed):before {
|
|
30606
|
+
transform: rotate(0);
|
|
30607
|
+
}
|
|
30608
|
+
|
|
30609
|
+
.collapsor:not(.collapsed) {
|
|
30610
|
+
background-color: ${BACKGROUND_COLOR};
|
|
30611
|
+
border: solid ${BORDER_COLOR} 1px;
|
|
30612
|
+
margin: -3px 1px -6px -5px;
|
|
30613
|
+
border-radius: 5px 5px 0px 0px;
|
|
30614
|
+
border-bottom: 0px;
|
|
30615
|
+
transition-delay: 0s;
|
|
30616
|
+
}
|
|
30617
|
+
|
|
30618
|
+
.collapsor {
|
|
30619
|
+
width: 100%;
|
|
30620
|
+
margin: -2px 2px -5px -4px;
|
|
30621
|
+
padding: 2px 0 6px 4px;
|
|
30622
|
+
background-color: transparent;
|
|
30623
|
+
border: solid ${BORDER_COLOR} 0px;
|
|
30624
|
+
transition-delay: 0.35s;
|
|
30625
|
+
transition-property: all;
|
|
30626
|
+
}
|
|
30627
|
+
|
|
30628
|
+
.collapsor.collapsed {
|
|
30629
|
+
}
|
|
30630
|
+
}
|
|
30631
|
+
|
|
30632
|
+
.collapsible_section {
|
|
30633
|
+
background-color: #fff;
|
|
30634
|
+
border: solid ${BORDER_COLOR} 1px;
|
|
30635
|
+
border-top: 0;
|
|
30636
|
+
border-radius: 0 0 5px 5px;
|
|
30637
|
+
margin: 0px 1px 0px 1px;
|
|
30638
|
+
|
|
30639
|
+
&.collapsing,
|
|
30640
|
+
&.show {
|
|
30641
|
+
background-color: ${BACKGROUND_COLOR};
|
|
30642
|
+
}
|
|
30643
|
+
|
|
30644
|
+
&.collapsing {
|
|
30645
|
+
transition: height 0.35s, background-color 0.35s !important;
|
|
30646
|
+
}
|
|
30647
|
+
}
|
|
30648
|
+
`;
|
|
30649
|
+
let CURRENT_COLLAPSIBLE_ID = 0;
|
|
30650
|
+
class SidePanelCollapsible extends Component {
|
|
30651
|
+
static template = "o-spreadsheet-SidePanelCollapsible";
|
|
30652
|
+
static props = {
|
|
30653
|
+
slots: Object,
|
|
30654
|
+
collapsedAtInit: { type: Boolean, optional: true },
|
|
30655
|
+
class: { type: String, optional: true },
|
|
30656
|
+
};
|
|
30657
|
+
currentId = (CURRENT_COLLAPSIBLE_ID++).toString();
|
|
30658
|
+
}
|
|
30659
|
+
|
|
30660
|
+
/**
|
|
30661
|
+
* Start listening to pointer events and apply the given callbacks.
|
|
30662
|
+
*
|
|
30663
|
+
* @returns A function to remove the listeners.
|
|
30664
|
+
*/
|
|
30220
30665
|
function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
|
|
30221
|
-
const
|
|
30222
|
-
onMouseUp(ev);
|
|
30666
|
+
const removeListeners = () => {
|
|
30223
30667
|
window.removeEventListener("pointerdown", onMouseDown);
|
|
30224
30668
|
window.removeEventListener("pointerup", _onMouseUp);
|
|
30225
30669
|
window.removeEventListener("dragstart", _onDragStart);
|
|
30226
30670
|
window.removeEventListener("pointermove", onMouseMove);
|
|
30227
30671
|
window.removeEventListener("wheel", onMouseMove);
|
|
30228
30672
|
};
|
|
30673
|
+
const _onMouseUp = (ev) => {
|
|
30674
|
+
onMouseUp(ev);
|
|
30675
|
+
removeListeners();
|
|
30676
|
+
};
|
|
30229
30677
|
function _onDragStart(ev) {
|
|
30230
30678
|
ev.preventDefault();
|
|
30231
30679
|
}
|
|
@@ -30237,6 +30685,7 @@ function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
|
|
|
30237
30685
|
// preventDefault() is not allowed in passive event handler.
|
|
30238
30686
|
// https://chromestatus.com/feature/6662647093133312
|
|
30239
30687
|
window.addEventListener("wheel", onMouseMove, { passive: false });
|
|
30688
|
+
return removeListeners;
|
|
30240
30689
|
}
|
|
30241
30690
|
/**
|
|
30242
30691
|
* Function to be used during a pointerdown event, this function allows to
|
|
@@ -30798,63 +31247,325 @@ class RoundColorPicker extends Component {
|
|
|
30798
31247
|
}
|
|
30799
31248
|
}
|
|
30800
31249
|
|
|
31250
|
+
css /* scss */ `
|
|
31251
|
+
.o-chart-title-designer {
|
|
31252
|
+
> span {
|
|
31253
|
+
height: 30px;
|
|
31254
|
+
}
|
|
31255
|
+
|
|
31256
|
+
.o-menu-item-button.active {
|
|
31257
|
+
background-color: #e6f4ea;
|
|
31258
|
+
color: #188038;
|
|
31259
|
+
}
|
|
31260
|
+
|
|
31261
|
+
.o-dropdown-content {
|
|
31262
|
+
overflow-y: auto;
|
|
31263
|
+
overflow-x: hidden;
|
|
31264
|
+
padding: 2px;
|
|
31265
|
+
z-index: 100;
|
|
31266
|
+
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
|
|
31267
|
+
|
|
31268
|
+
.o-dropdown-line {
|
|
31269
|
+
> span {
|
|
31270
|
+
padding: 4px;
|
|
31271
|
+
}
|
|
31272
|
+
}
|
|
31273
|
+
}
|
|
31274
|
+
}
|
|
31275
|
+
`;
|
|
30801
31276
|
class ChartTitle extends Component {
|
|
30802
31277
|
static template = "o-spreadsheet.ChartTitle";
|
|
30803
|
-
static components = { Section };
|
|
30804
|
-
static props = {
|
|
31278
|
+
static components = { Section, ColorPickerWidget };
|
|
31279
|
+
static props = {
|
|
31280
|
+
title: String,
|
|
31281
|
+
updateTitle: Function,
|
|
31282
|
+
name: { type: String, optional: true },
|
|
31283
|
+
toggleItalic: { type: Function, optional: true },
|
|
31284
|
+
toggleBold: { type: Function, optional: true },
|
|
31285
|
+
updateAlignment: { type: Function, optional: true },
|
|
31286
|
+
updateColor: { type: Function, optional: true },
|
|
31287
|
+
style: { type: Object, optional: true },
|
|
31288
|
+
};
|
|
31289
|
+
openedEl = null;
|
|
31290
|
+
setup() {
|
|
31291
|
+
useExternalListener(window, "click", this.onExternalClick);
|
|
31292
|
+
}
|
|
31293
|
+
state = useState({
|
|
31294
|
+
activeTool: "",
|
|
31295
|
+
});
|
|
30805
31296
|
updateTitle(ev) {
|
|
30806
|
-
this.props.
|
|
31297
|
+
this.props.updateTitle(ev.target.value);
|
|
31298
|
+
}
|
|
31299
|
+
toggleDropdownTool(tool, ev) {
|
|
31300
|
+
const isOpen = this.state.activeTool === tool;
|
|
31301
|
+
this.closeMenus();
|
|
31302
|
+
this.state.activeTool = isOpen ? "" : tool;
|
|
31303
|
+
this.openedEl = isOpen ? null : ev.target;
|
|
31304
|
+
}
|
|
31305
|
+
/**
|
|
31306
|
+
* TODO: This is clearly not a goot way to handle external click, but
|
|
31307
|
+
* we currently have no other way to do it ... Should be done in
|
|
31308
|
+
* another task to handle the fact we want only one menu opened at a
|
|
31309
|
+
* time with something like a menuStore ?
|
|
31310
|
+
*/
|
|
31311
|
+
onExternalClick(ev) {
|
|
31312
|
+
if (this.openedEl === ev.target) {
|
|
31313
|
+
return;
|
|
31314
|
+
}
|
|
31315
|
+
this.closeMenus();
|
|
31316
|
+
}
|
|
31317
|
+
onColorPicked(color) {
|
|
31318
|
+
this.props.updateColor?.(color);
|
|
31319
|
+
this.closeMenus();
|
|
31320
|
+
}
|
|
31321
|
+
updateAlignment(aligment) {
|
|
31322
|
+
this.props.updateAlignment?.(aligment);
|
|
31323
|
+
this.closeMenus();
|
|
31324
|
+
}
|
|
31325
|
+
closeMenus() {
|
|
31326
|
+
this.state.activeTool = "";
|
|
31327
|
+
this.openedEl = null;
|
|
30807
31328
|
}
|
|
30808
31329
|
}
|
|
30809
31330
|
|
|
30810
|
-
class
|
|
30811
|
-
static template = "o-spreadsheet-
|
|
30812
|
-
static components = {
|
|
31331
|
+
class AxisDesignEditor extends Component {
|
|
31332
|
+
static template = "o-spreadsheet-AxisDesignEditor";
|
|
31333
|
+
static components = {
|
|
31334
|
+
Section,
|
|
31335
|
+
ChartTitle,
|
|
31336
|
+
};
|
|
31337
|
+
state = useState({ currentAxis: "x" });
|
|
31338
|
+
get axisTitleStyle() {
|
|
31339
|
+
const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
|
|
31340
|
+
return {
|
|
31341
|
+
color: "",
|
|
31342
|
+
align: "center",
|
|
31343
|
+
...axisDesign.title,
|
|
31344
|
+
};
|
|
31345
|
+
}
|
|
31346
|
+
updateAxisTitleColor(color) {
|
|
31347
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31348
|
+
axesDesign[this.state.currentAxis] = {
|
|
31349
|
+
...axesDesign[this.state.currentAxis],
|
|
31350
|
+
title: {
|
|
31351
|
+
...(axesDesign[this.state.currentAxis]?.title ?? {}),
|
|
31352
|
+
color,
|
|
31353
|
+
},
|
|
31354
|
+
};
|
|
31355
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31356
|
+
}
|
|
31357
|
+
toggleBoldAxisTitle() {
|
|
31358
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31359
|
+
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
31360
|
+
axesDesign[this.state.currentAxis] = {
|
|
31361
|
+
...axesDesign[this.state.currentAxis],
|
|
31362
|
+
title: {
|
|
31363
|
+
...title,
|
|
31364
|
+
bold: !title?.bold,
|
|
31365
|
+
},
|
|
31366
|
+
};
|
|
31367
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31368
|
+
}
|
|
31369
|
+
toggleItalicAxisTitle() {
|
|
31370
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31371
|
+
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
31372
|
+
axesDesign[this.state.currentAxis] = {
|
|
31373
|
+
...axesDesign[this.state.currentAxis],
|
|
31374
|
+
title: {
|
|
31375
|
+
...title,
|
|
31376
|
+
italic: !title?.italic,
|
|
31377
|
+
},
|
|
31378
|
+
};
|
|
31379
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31380
|
+
}
|
|
31381
|
+
updateAxisTitleAlignment(align) {
|
|
31382
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31383
|
+
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
31384
|
+
axesDesign[this.state.currentAxis] = {
|
|
31385
|
+
...axesDesign[this.state.currentAxis],
|
|
31386
|
+
title: {
|
|
31387
|
+
...title,
|
|
31388
|
+
align,
|
|
31389
|
+
},
|
|
31390
|
+
};
|
|
31391
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31392
|
+
}
|
|
31393
|
+
updateAxisEditor(ev) {
|
|
31394
|
+
const axis = ev.target.value;
|
|
31395
|
+
this.state.currentAxis = axis;
|
|
31396
|
+
}
|
|
31397
|
+
getAxisTitle() {
|
|
31398
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31399
|
+
return axesDesign[this.state.currentAxis]?.title.text || "";
|
|
31400
|
+
}
|
|
31401
|
+
updateAxisTitle(text) {
|
|
31402
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
31403
|
+
axesDesign[this.state.currentAxis] = {
|
|
31404
|
+
...axesDesign[this.state.currentAxis],
|
|
31405
|
+
title: {
|
|
31406
|
+
...axesDesign?.[this.state.currentAxis]?.title,
|
|
31407
|
+
text,
|
|
31408
|
+
},
|
|
31409
|
+
};
|
|
31410
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
31411
|
+
}
|
|
31412
|
+
}
|
|
31413
|
+
|
|
31414
|
+
class GeneralDesignEditor extends Component {
|
|
31415
|
+
static template = "o-spreadsheet-GeneralDesignEditor";
|
|
31416
|
+
static components = {
|
|
31417
|
+
RoundColorPicker,
|
|
31418
|
+
ChartTitle,
|
|
31419
|
+
Section,
|
|
31420
|
+
SidePanelCollapsible,
|
|
31421
|
+
};
|
|
30813
31422
|
static props = {
|
|
30814
31423
|
figureId: String,
|
|
30815
31424
|
definition: Object,
|
|
30816
31425
|
updateChart: Function,
|
|
30817
|
-
|
|
31426
|
+
slots: { type: Object, optional: true },
|
|
30818
31427
|
};
|
|
31428
|
+
state;
|
|
31429
|
+
setup() {
|
|
31430
|
+
this.state = useState({
|
|
31431
|
+
activeTool: "",
|
|
31432
|
+
});
|
|
31433
|
+
}
|
|
30819
31434
|
get title() {
|
|
30820
|
-
return
|
|
31435
|
+
return this.props.definition.title;
|
|
31436
|
+
}
|
|
31437
|
+
toggleDropdownTool(tool, ev) {
|
|
31438
|
+
const isOpen = this.state.activeTool === tool;
|
|
31439
|
+
this.state.activeTool = isOpen ? "" : tool;
|
|
30821
31440
|
}
|
|
30822
31441
|
updateBackgroundColor(color) {
|
|
30823
31442
|
this.props.updateChart(this.props.figureId, {
|
|
30824
31443
|
background: color,
|
|
30825
31444
|
});
|
|
30826
31445
|
}
|
|
30827
|
-
updateTitle(
|
|
31446
|
+
updateTitle(newTitle) {
|
|
31447
|
+
const title = { ...this.title, text: newTitle };
|
|
30828
31448
|
this.props.updateChart(this.props.figureId, { title });
|
|
30829
31449
|
}
|
|
30830
|
-
|
|
30831
|
-
|
|
30832
|
-
|
|
30833
|
-
|
|
31450
|
+
get titleStyle() {
|
|
31451
|
+
return {
|
|
31452
|
+
align: "left",
|
|
31453
|
+
...this.title,
|
|
31454
|
+
};
|
|
30834
31455
|
}
|
|
30835
|
-
|
|
30836
|
-
|
|
31456
|
+
updateChartTitleColor(color) {
|
|
31457
|
+
const title = { ...this.title, color };
|
|
31458
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31459
|
+
this.state.activeTool = "";
|
|
31460
|
+
}
|
|
31461
|
+
toggleBoldChartTitle() {
|
|
31462
|
+
let title = this.title;
|
|
31463
|
+
title = { ...title, bold: !title.bold };
|
|
31464
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31465
|
+
}
|
|
31466
|
+
toggleItalicChartTitle() {
|
|
31467
|
+
let title = this.title;
|
|
31468
|
+
title = { ...title, italic: !title.italic };
|
|
31469
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31470
|
+
}
|
|
31471
|
+
updateChartTitleAlignment(align) {
|
|
31472
|
+
const title = { ...this.title, align };
|
|
31473
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
31474
|
+
this.state.activeTool = "";
|
|
30837
31475
|
}
|
|
30838
31476
|
}
|
|
30839
31477
|
|
|
30840
|
-
class
|
|
30841
|
-
static template = "o-spreadsheet-
|
|
30842
|
-
|
|
30843
|
-
|
|
30844
|
-
|
|
30845
|
-
|
|
30846
|
-
|
|
30847
|
-
|
|
31478
|
+
class ChartWithAxisDesignPanel extends Component {
|
|
31479
|
+
static template = "o-spreadsheet-ChartWithAxisDesignPanel";
|
|
31480
|
+
static components = {
|
|
31481
|
+
GeneralDesignEditor,
|
|
31482
|
+
SidePanelCollapsible,
|
|
31483
|
+
Section,
|
|
31484
|
+
AxisDesignEditor,
|
|
31485
|
+
RoundColorPicker,
|
|
31486
|
+
};
|
|
31487
|
+
state = useState({ index: 0 });
|
|
31488
|
+
get axesList() {
|
|
31489
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
|
|
31490
|
+
let axes = [{ id: "x", name: _t("Horizontal axis") }];
|
|
31491
|
+
if (useLeftAxis) {
|
|
31492
|
+
axes.push({ id: "y", name: _t("Vertical (left) axis") });
|
|
31493
|
+
}
|
|
31494
|
+
if (useRightAxis) {
|
|
31495
|
+
axes.push({ id: "y1", name: _t("Vertical (right) axis") });
|
|
31496
|
+
}
|
|
31497
|
+
return axes;
|
|
30848
31498
|
}
|
|
30849
|
-
|
|
31499
|
+
updateLegendPosition(ev) {
|
|
30850
31500
|
this.props.updateChart(this.props.figureId, {
|
|
30851
|
-
|
|
31501
|
+
legendPosition: ev.target.value,
|
|
30852
31502
|
});
|
|
30853
31503
|
}
|
|
30854
|
-
|
|
30855
|
-
|
|
30856
|
-
|
|
30857
|
-
|
|
31504
|
+
getDataSeries() {
|
|
31505
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.figureId);
|
|
31506
|
+
if (!runtime || !("chartJsConfig" in runtime)) {
|
|
31507
|
+
return [];
|
|
31508
|
+
}
|
|
31509
|
+
return runtime.chartJsConfig.data.datasets.map((d) => d.label);
|
|
31510
|
+
}
|
|
31511
|
+
updateSerieEditor(ev) {
|
|
31512
|
+
const chartId = this.props.figureId;
|
|
31513
|
+
const selectedIndex = ev.target.selectedIndex;
|
|
31514
|
+
const runtime = this.env.model.getters.getChartRuntime(chartId);
|
|
31515
|
+
if (!runtime) {
|
|
31516
|
+
return;
|
|
31517
|
+
}
|
|
31518
|
+
this.state.index = selectedIndex;
|
|
31519
|
+
}
|
|
31520
|
+
updateDataSeriesColor(color) {
|
|
31521
|
+
const dataSets = this.props.definition.dataSets;
|
|
31522
|
+
if (!dataSets?.[this.state.index])
|
|
31523
|
+
return;
|
|
31524
|
+
dataSets[this.state.index] = {
|
|
31525
|
+
...dataSets[this.state.index],
|
|
31526
|
+
backgroundColor: color,
|
|
31527
|
+
};
|
|
31528
|
+
this.props.updateChart(this.props.figureId, { dataSets });
|
|
31529
|
+
}
|
|
31530
|
+
getDataSerieColor() {
|
|
31531
|
+
const dataSets = this.props.definition.dataSets;
|
|
31532
|
+
if (!dataSets?.[this.state.index])
|
|
31533
|
+
return "";
|
|
31534
|
+
const color = dataSets[this.state.index].backgroundColor;
|
|
31535
|
+
return color ? toHex(color) : getNthColor(this.state.index);
|
|
31536
|
+
}
|
|
31537
|
+
updateDataSeriesAxis(ev) {
|
|
31538
|
+
const axis = ev.target.value;
|
|
31539
|
+
const dataSets = this.props.definition.dataSets;
|
|
31540
|
+
if (!dataSets?.[this.state.index])
|
|
31541
|
+
return;
|
|
31542
|
+
dataSets[this.state.index] = {
|
|
31543
|
+
...dataSets[this.state.index],
|
|
31544
|
+
yAxisId: axis === "left" ? "y" : "y1",
|
|
31545
|
+
};
|
|
31546
|
+
this.props.updateChart(this.props.figureId, { dataSets });
|
|
31547
|
+
}
|
|
31548
|
+
getDataSerieAxis() {
|
|
31549
|
+
const dataSets = this.props.definition.dataSets;
|
|
31550
|
+
if (!dataSets?.[this.state.index])
|
|
31551
|
+
return "left";
|
|
31552
|
+
return dataSets[this.state.index].yAxisId === "y1" ? "right" : "left";
|
|
31553
|
+
}
|
|
31554
|
+
updateDataSeriesLabel(ev) {
|
|
31555
|
+
const label = ev.target.value;
|
|
31556
|
+
const dataSets = this.props.definition.dataSets;
|
|
31557
|
+
if (!dataSets?.[this.state.index])
|
|
31558
|
+
return;
|
|
31559
|
+
dataSets[this.state.index] = {
|
|
31560
|
+
...dataSets[this.state.index],
|
|
31561
|
+
label,
|
|
31562
|
+
};
|
|
31563
|
+
this.props.updateChart(this.props.figureId, { dataSets });
|
|
31564
|
+
}
|
|
31565
|
+
getDataSerieLabel() {
|
|
31566
|
+
const dataSets = this.props.definition.dataSets;
|
|
31567
|
+
return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
|
|
31568
|
+
}
|
|
30858
31569
|
}
|
|
30859
31570
|
|
|
30860
31571
|
class GaugeChartConfigPanel extends Component {
|
|
@@ -30889,7 +31600,7 @@ class GaugeChartConfigPanel extends Component {
|
|
|
30889
31600
|
});
|
|
30890
31601
|
}
|
|
30891
31602
|
getDataRange() {
|
|
30892
|
-
return this.dataRange || "";
|
|
31603
|
+
return { dataRange: this.dataRange || "" };
|
|
30893
31604
|
}
|
|
30894
31605
|
}
|
|
30895
31606
|
|
|
@@ -30931,24 +31642,24 @@ css /* scss */ `
|
|
|
30931
31642
|
class GaugeChartDesignPanel extends Component {
|
|
30932
31643
|
static template = "o-spreadsheet-GaugeChartDesignPanel";
|
|
30933
31644
|
static components = {
|
|
30934
|
-
|
|
30935
|
-
RoundColorPicker,
|
|
30936
|
-
ChartTitle,
|
|
31645
|
+
SidePanelCollapsible,
|
|
30937
31646
|
Section,
|
|
31647
|
+
RoundColorPicker,
|
|
31648
|
+
GeneralDesignEditor,
|
|
31649
|
+
ChartErrorSection,
|
|
30938
31650
|
};
|
|
30939
31651
|
static props = {
|
|
30940
31652
|
figureId: String,
|
|
30941
31653
|
definition: Object,
|
|
30942
31654
|
updateChart: Function,
|
|
30943
|
-
canUpdateChart: Function,
|
|
31655
|
+
canUpdateChart: { type: Function, optional: true },
|
|
30944
31656
|
};
|
|
30945
|
-
state
|
|
30946
|
-
|
|
30947
|
-
|
|
30948
|
-
|
|
30949
|
-
|
|
30950
|
-
|
|
30951
|
-
return _t(this.props.definition.title);
|
|
31657
|
+
state;
|
|
31658
|
+
setup() {
|
|
31659
|
+
this.state = useState({
|
|
31660
|
+
sectionRuleDispatchResult: undefined,
|
|
31661
|
+
sectionRule: deepCopy(this.props.definition.sectionRule),
|
|
31662
|
+
});
|
|
30952
31663
|
}
|
|
30953
31664
|
get designErrorMessages() {
|
|
30954
31665
|
const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
|
|
@@ -30959,8 +31670,8 @@ class GaugeChartDesignPanel extends Component {
|
|
|
30959
31670
|
background: color,
|
|
30960
31671
|
});
|
|
30961
31672
|
}
|
|
30962
|
-
updateTitle(
|
|
30963
|
-
this.props.updateChart(this.props.figureId, { title });
|
|
31673
|
+
updateTitle(content) {
|
|
31674
|
+
this.props.updateChart(this.props.figureId, { title: { text: content } });
|
|
30964
31675
|
}
|
|
30965
31676
|
isRangeMinInvalid() {
|
|
30966
31677
|
return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
|
|
@@ -31055,8 +31766,23 @@ class LineConfigPanel extends GenericChartConfigPanel {
|
|
|
31055
31766
|
}
|
|
31056
31767
|
}
|
|
31057
31768
|
|
|
31058
|
-
class
|
|
31059
|
-
static template = "o-spreadsheet-
|
|
31769
|
+
class PieChartDesignPanel extends Component {
|
|
31770
|
+
static template = "o-spreadsheet-PieChartDesignPanel";
|
|
31771
|
+
static components = {
|
|
31772
|
+
GeneralDesignEditor,
|
|
31773
|
+
Section,
|
|
31774
|
+
};
|
|
31775
|
+
static props = {
|
|
31776
|
+
figureId: String,
|
|
31777
|
+
definition: Object,
|
|
31778
|
+
updateChart: Function,
|
|
31779
|
+
canUpdateChart: { type: Function, optional: true },
|
|
31780
|
+
};
|
|
31781
|
+
updateLegendPosition(ev) {
|
|
31782
|
+
this.props.updateChart(this.props.figureId, {
|
|
31783
|
+
legendPosition: ev.target.value,
|
|
31784
|
+
});
|
|
31785
|
+
}
|
|
31060
31786
|
}
|
|
31061
31787
|
|
|
31062
31788
|
class ScatterConfigPanel extends GenericChartConfigPanel {
|
|
@@ -31150,16 +31876,19 @@ class ScorecardChartConfigPanel extends Component {
|
|
|
31150
31876
|
|
|
31151
31877
|
class ScorecardChartDesignPanel extends Component {
|
|
31152
31878
|
static template = "o-spreadsheet-ScorecardChartDesignPanel";
|
|
31153
|
-
static components = {
|
|
31879
|
+
static components = {
|
|
31880
|
+
GeneralDesignEditor,
|
|
31881
|
+
RoundColorPicker,
|
|
31882
|
+
SidePanelCollapsible,
|
|
31883
|
+
Section,
|
|
31884
|
+
Checkbox,
|
|
31885
|
+
};
|
|
31154
31886
|
static props = {
|
|
31155
31887
|
figureId: String,
|
|
31156
31888
|
definition: Object,
|
|
31157
31889
|
updateChart: Function,
|
|
31158
|
-
canUpdateChart: Function,
|
|
31890
|
+
canUpdateChart: { type: Function, optional: true },
|
|
31159
31891
|
};
|
|
31160
|
-
get title() {
|
|
31161
|
-
return _t(this.props.definition.title);
|
|
31162
|
-
}
|
|
31163
31892
|
get colorsSectionTitle() {
|
|
31164
31893
|
return this.props.definition.baselineMode === "progress"
|
|
31165
31894
|
? _t("Progress bar colors")
|
|
@@ -31168,8 +31897,8 @@ class ScorecardChartDesignPanel extends Component {
|
|
|
31168
31897
|
get humanizeNumbersLabel() {
|
|
31169
31898
|
return _t("Humanize numbers");
|
|
31170
31899
|
}
|
|
31171
|
-
updateTitle(
|
|
31172
|
-
this.props.updateChart(this.props.figureId, { title });
|
|
31900
|
+
updateTitle(content) {
|
|
31901
|
+
this.props.updateChart(this.props.figureId, { title: { text: content } });
|
|
31173
31902
|
}
|
|
31174
31903
|
updateHumanizeNumbers(humanize) {
|
|
31175
31904
|
this.props.updateChart(this.props.figureId, { humanize });
|
|
@@ -31198,14 +31927,22 @@ class ScorecardChartDesignPanel extends Component {
|
|
|
31198
31927
|
}
|
|
31199
31928
|
}
|
|
31200
31929
|
|
|
31201
|
-
class WaterfallChartDesignPanel extends
|
|
31930
|
+
class WaterfallChartDesignPanel extends Component {
|
|
31202
31931
|
static template = "o-spreadsheet-WaterfallChartDesignPanel";
|
|
31203
|
-
static components = {
|
|
31204
|
-
|
|
31205
|
-
|
|
31206
|
-
|
|
31207
|
-
|
|
31208
|
-
|
|
31932
|
+
static components = {
|
|
31933
|
+
GeneralDesignEditor,
|
|
31934
|
+
Checkbox,
|
|
31935
|
+
SidePanelCollapsible,
|
|
31936
|
+
Section,
|
|
31937
|
+
RoundColorPicker,
|
|
31938
|
+
AxisDesignEditor,
|
|
31939
|
+
};
|
|
31940
|
+
static props = {
|
|
31941
|
+
figureId: String,
|
|
31942
|
+
definition: Object,
|
|
31943
|
+
updateChart: Function,
|
|
31944
|
+
canUpdateChart: { type: Function, optional: true },
|
|
31945
|
+
};
|
|
31209
31946
|
onUpdateShowSubTotals(showSubTotals) {
|
|
31210
31947
|
this.props.updateChart(this.props.figureId, { showSubTotals });
|
|
31211
31948
|
}
|
|
@@ -31218,11 +31955,11 @@ class WaterfallChartDesignPanel extends GenericChartDesignPanel {
|
|
|
31218
31955
|
updateColor(colorName, color) {
|
|
31219
31956
|
this.props.updateChart(this.props.figureId, { [colorName]: color });
|
|
31220
31957
|
}
|
|
31221
|
-
|
|
31222
|
-
|
|
31223
|
-
|
|
31224
|
-
|
|
31225
|
-
|
|
31958
|
+
get axesList() {
|
|
31959
|
+
return [
|
|
31960
|
+
{ id: "x", name: _t("Horizontal axis") },
|
|
31961
|
+
{ id: "y", name: _t("Vertical axis") },
|
|
31962
|
+
];
|
|
31226
31963
|
}
|
|
31227
31964
|
get positiveValuesColor() {
|
|
31228
31965
|
return (this.props.definition.positiveValuesColor ||
|
|
@@ -31236,29 +31973,39 @@ class WaterfallChartDesignPanel extends GenericChartDesignPanel {
|
|
|
31236
31973
|
return (this.props.definition.subTotalValuesColor ||
|
|
31237
31974
|
CHART_WATERFALL_SUBTOTAL_COLOR);
|
|
31238
31975
|
}
|
|
31976
|
+
updateLegendPosition(ev) {
|
|
31977
|
+
this.props.updateChart(this.props.figureId, {
|
|
31978
|
+
legendPosition: ev.target.value,
|
|
31979
|
+
});
|
|
31980
|
+
}
|
|
31981
|
+
updateVerticalAxisPosition(ev) {
|
|
31982
|
+
this.props.updateChart(this.props.figureId, {
|
|
31983
|
+
verticalAxisPosition: ev.target.value,
|
|
31984
|
+
});
|
|
31985
|
+
}
|
|
31239
31986
|
}
|
|
31240
31987
|
|
|
31241
31988
|
const chartSidePanelComponentRegistry = new Registry();
|
|
31242
31989
|
chartSidePanelComponentRegistry
|
|
31243
31990
|
.add("line", {
|
|
31244
31991
|
configuration: LineConfigPanel,
|
|
31245
|
-
design:
|
|
31992
|
+
design: ChartWithAxisDesignPanel,
|
|
31246
31993
|
})
|
|
31247
31994
|
.add("scatter", {
|
|
31248
31995
|
configuration: ScatterConfigPanel,
|
|
31249
|
-
design:
|
|
31996
|
+
design: ChartWithAxisDesignPanel,
|
|
31250
31997
|
})
|
|
31251
31998
|
.add("bar", {
|
|
31252
31999
|
configuration: BarConfigPanel,
|
|
31253
|
-
design:
|
|
32000
|
+
design: ChartWithAxisDesignPanel,
|
|
31254
32001
|
})
|
|
31255
32002
|
.add("combo", {
|
|
31256
|
-
configuration:
|
|
31257
|
-
design:
|
|
32003
|
+
configuration: GenericChartConfigPanel,
|
|
32004
|
+
design: ChartWithAxisDesignPanel,
|
|
31258
32005
|
})
|
|
31259
32006
|
.add("pie", {
|
|
31260
32007
|
configuration: GenericChartConfigPanel,
|
|
31261
|
-
design:
|
|
32008
|
+
design: PieChartDesignPanel,
|
|
31262
32009
|
})
|
|
31263
32010
|
.add("gauge", {
|
|
31264
32011
|
configuration: GaugeChartConfigPanel,
|
|
@@ -31544,6 +32291,7 @@ function useDragAndDropListItems() {
|
|
|
31544
32291
|
state.itemsStyle = {};
|
|
31545
32292
|
document.body.style.cursor = previousCursor;
|
|
31546
32293
|
args.onCancel?.();
|
|
32294
|
+
cleanUp();
|
|
31547
32295
|
};
|
|
31548
32296
|
const onDragEnd = (itemId, indexAtEnd) => {
|
|
31549
32297
|
state.draggedItemId = undefined;
|
|
@@ -31564,7 +32312,8 @@ function useDragAndDropListItems() {
|
|
|
31564
32312
|
onDragEnd,
|
|
31565
32313
|
onCancel: state.cancel,
|
|
31566
32314
|
});
|
|
31567
|
-
startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
|
|
32315
|
+
const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
|
|
32316
|
+
cleanupFns.push(stopListening);
|
|
31568
32317
|
const onScroll = dndHelper.onScroll.bind(dndHelper);
|
|
31569
32318
|
args.containerEl.addEventListener("scroll", onScroll);
|
|
31570
32319
|
cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
|
|
@@ -31641,7 +32390,7 @@ class DOMDndHelper {
|
|
|
31641
32390
|
this.moveDraggedItemToPosition(this.currentMousePosition + this.scrollOffset);
|
|
31642
32391
|
}
|
|
31643
32392
|
onMouseMove(ev) {
|
|
31644
|
-
if (ev.button
|
|
32393
|
+
if (ev.button > 1) {
|
|
31645
32394
|
this.onCancel();
|
|
31646
32395
|
return;
|
|
31647
32396
|
}
|
|
@@ -34384,7 +35133,7 @@ class SpreadsheetPivotTable {
|
|
|
34384
35133
|
* This function converts a list of data entry into a spreadsheet pivot table.
|
|
34385
35134
|
*/
|
|
34386
35135
|
function dataEntriesToSpreadsheetPivotTable(dataEntries, definition) {
|
|
34387
|
-
const columnsTree =
|
|
35136
|
+
const columnsTree = dataEntriesToColumnsTree(dataEntries, definition.columns, 0);
|
|
34388
35137
|
computeWidthOfColumnsNodes(columnsTree, definition.measures.length);
|
|
34389
35138
|
const cols = columnsTreeToColumns(columnsTree, definition);
|
|
34390
35139
|
const rows = dataEntriesToRows(dataEntries, 0, definition.rows, [], []);
|
|
@@ -34435,7 +35184,7 @@ function dataEntriesToRows(dataEntries, index, rows, fields, values) {
|
|
|
34435
35184
|
/**
|
|
34436
35185
|
* Create the columns tree from data entries.
|
|
34437
35186
|
*/
|
|
34438
|
-
function
|
|
35187
|
+
function dataEntriesToColumnsTree(dataEntries, columns, index) {
|
|
34439
35188
|
if (index >= columns.length) {
|
|
34440
35189
|
return [];
|
|
34441
35190
|
}
|
|
@@ -34447,7 +35196,7 @@ function dateEntriesToColumnsTree(dataEntries, columns, index) {
|
|
|
34447
35196
|
return {
|
|
34448
35197
|
value,
|
|
34449
35198
|
field: colName,
|
|
34450
|
-
children:
|
|
35199
|
+
children: dataEntriesToColumnsTree(groups[value] || [], columns, index + 1),
|
|
34451
35200
|
width: 0,
|
|
34452
35201
|
};
|
|
34453
35202
|
});
|
|
@@ -34954,7 +35703,12 @@ class SpreadsheetPivot {
|
|
|
34954
35703
|
if (!field) {
|
|
34955
35704
|
throw new Error(`Field ${this.fieldKeys[index]} does not exist`);
|
|
34956
35705
|
}
|
|
34957
|
-
|
|
35706
|
+
if (cell.value === "") {
|
|
35707
|
+
entry[field.name] = { value: null, type: CellValueType.empty };
|
|
35708
|
+
}
|
|
35709
|
+
else {
|
|
35710
|
+
entry[field.name] = cell;
|
|
35711
|
+
}
|
|
34958
35712
|
}
|
|
34959
35713
|
entry["__count"] = { value: 1, type: CellValueType.number };
|
|
34960
35714
|
dataEntries.push(entry);
|
|
@@ -34997,7 +35751,14 @@ pivotRegistry.add("SPREADSHEET", {
|
|
|
34997
35751
|
|
|
34998
35752
|
class PivotSidePanelStore extends SpreadsheetStore {
|
|
34999
35753
|
pivotId;
|
|
35000
|
-
mutators = [
|
|
35754
|
+
mutators = [
|
|
35755
|
+
"reset",
|
|
35756
|
+
"deferUpdates",
|
|
35757
|
+
"applyUpdate",
|
|
35758
|
+
"discardPendingUpdate",
|
|
35759
|
+
"renamePivot",
|
|
35760
|
+
"update",
|
|
35761
|
+
];
|
|
35001
35762
|
updatesAreDeferred = true;
|
|
35002
35763
|
draft = null;
|
|
35003
35764
|
constructor(get, pivotId) {
|
|
@@ -36710,14 +37471,15 @@ class FigureComponent extends Component {
|
|
|
36710
37471
|
}
|
|
36711
37472
|
onKeyDown(ev) {
|
|
36712
37473
|
const figure = this.props.figure;
|
|
36713
|
-
|
|
37474
|
+
const keyDownShortcut = keyboardEventToShortcutString(ev);
|
|
37475
|
+
switch (keyDownShortcut) {
|
|
36714
37476
|
case "Delete":
|
|
37477
|
+
case "Backspace":
|
|
36715
37478
|
this.env.model.dispatch("DELETE_FIGURE", {
|
|
36716
37479
|
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
36717
37480
|
id: figure.id,
|
|
36718
37481
|
});
|
|
36719
37482
|
this.props.onFigureDeleted();
|
|
36720
|
-
ev.stopPropagation();
|
|
36721
37483
|
ev.preventDefault();
|
|
36722
37484
|
ev.stopPropagation();
|
|
36723
37485
|
break;
|
|
@@ -36738,7 +37500,22 @@ class FigureComponent extends Component {
|
|
|
36738
37500
|
x: figure.x + delta[0],
|
|
36739
37501
|
y: figure.y + delta[1],
|
|
36740
37502
|
});
|
|
37503
|
+
ev.preventDefault();
|
|
37504
|
+
ev.stopPropagation();
|
|
37505
|
+
break;
|
|
37506
|
+
case "Ctrl+A":
|
|
37507
|
+
// Maybe in the future we will implement a way to select all figures
|
|
37508
|
+
ev.preventDefault();
|
|
36741
37509
|
ev.stopPropagation();
|
|
37510
|
+
break;
|
|
37511
|
+
case "Ctrl+Y":
|
|
37512
|
+
case "Ctrl+Z":
|
|
37513
|
+
if (keyDownShortcut === "Ctrl+Y") {
|
|
37514
|
+
this.env.model.dispatch("REQUEST_REDO");
|
|
37515
|
+
}
|
|
37516
|
+
else if (keyDownShortcut === "Ctrl+Z") {
|
|
37517
|
+
this.env.model.dispatch("REQUEST_UNDO");
|
|
37518
|
+
}
|
|
36742
37519
|
ev.preventDefault();
|
|
36743
37520
|
ev.stopPropagation();
|
|
36744
37521
|
break;
|
|
@@ -38018,9 +38795,7 @@ class FilterIcon extends Component {
|
|
|
38018
38795
|
|
|
38019
38796
|
class FilterIconsOverlay extends Component {
|
|
38020
38797
|
static template = "o-spreadsheet-FilterIconsOverlay";
|
|
38021
|
-
static props = {
|
|
38022
|
-
onMouseDown: Function,
|
|
38023
|
-
};
|
|
38798
|
+
static props = {};
|
|
38024
38799
|
static components = {
|
|
38025
38800
|
GridCellIcon,
|
|
38026
38801
|
FilterIcon,
|
|
@@ -38260,6 +39035,7 @@ class GridOverlay extends Component {
|
|
|
38260
39035
|
};
|
|
38261
39036
|
gridOverlay = useRef("gridOverlay");
|
|
38262
39037
|
gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
|
|
39038
|
+
cellPopovers;
|
|
38263
39039
|
setup() {
|
|
38264
39040
|
useCellHovered(this.env, this.gridOverlay, this.props.onCellHovered);
|
|
38265
39041
|
const resizeObserver = new ResizeObserver(() => {
|
|
@@ -38281,6 +39057,7 @@ class GridOverlay extends Component {
|
|
|
38281
39057
|
const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
|
|
38282
39058
|
return scrollY > 0;
|
|
38283
39059
|
});
|
|
39060
|
+
this.cellPopovers = useStore(CellPopoverStore);
|
|
38284
39061
|
}
|
|
38285
39062
|
get gridOverlayEl() {
|
|
38286
39063
|
if (!this.gridOverlay.el) {
|
|
@@ -38294,16 +39071,18 @@ class GridOverlay extends Component {
|
|
|
38294
39071
|
get isPaintingFormat() {
|
|
38295
39072
|
return this.env.model.getters.isPaintingFormat();
|
|
38296
39073
|
}
|
|
38297
|
-
onMouseDown(ev
|
|
39074
|
+
onMouseDown(ev) {
|
|
38298
39075
|
if (ev.button > 0) {
|
|
38299
39076
|
// not main button, probably a context menu
|
|
38300
39077
|
return;
|
|
38301
39078
|
}
|
|
39079
|
+
if (ev.target === this.gridOverlay.el && this.cellPopovers.isOpen) {
|
|
39080
|
+
this.cellPopovers.close();
|
|
39081
|
+
}
|
|
38302
39082
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
38303
39083
|
this.props.onCellClicked(col, row, {
|
|
38304
39084
|
expandZone: ev.shiftKey,
|
|
38305
39085
|
addZone: isCtrlKey(ev),
|
|
38306
|
-
closePopover: modifiers?.closePopover ?? true,
|
|
38307
39086
|
});
|
|
38308
39087
|
}
|
|
38309
39088
|
onDoubleClick(ev) {
|
|
@@ -40447,9 +41226,6 @@ class Grid extends Component {
|
|
|
40447
41226
|
// Zone selection with mouse
|
|
40448
41227
|
// ---------------------------------------------------------------------------
|
|
40449
41228
|
onCellClicked(col, row, modifiers) {
|
|
40450
|
-
if (modifiers.closePopover && this.cellPopovers.isOpen) {
|
|
40451
|
-
this.cellPopovers.close();
|
|
40452
|
-
}
|
|
40453
41229
|
if (this.composerStore.editionMode === "editing") {
|
|
40454
41230
|
this.composerStore.stopEdition();
|
|
40455
41231
|
}
|
|
@@ -42322,11 +43098,20 @@ function isImageData(data) {
|
|
|
42322
43098
|
return "imageSrc" in data;
|
|
42323
43099
|
}
|
|
42324
43100
|
function convertChartData(chartData) {
|
|
42325
|
-
const dataSetsHaveTitle = chartData.dataSets
|
|
43101
|
+
const dataSetsHaveTitle = chartData.dataSets.some((ds) => "reference" in (ds.label ?? {}));
|
|
42326
43102
|
const labelRange = chartData.labelRange
|
|
42327
43103
|
? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
|
|
42328
43104
|
: undefined;
|
|
42329
|
-
|
|
43105
|
+
const dataSets = chartData.dataSets.map((data) => {
|
|
43106
|
+
let label = undefined;
|
|
43107
|
+
if (data.label && "text" in data.label) {
|
|
43108
|
+
label = data.label.text;
|
|
43109
|
+
}
|
|
43110
|
+
return {
|
|
43111
|
+
dataRange: convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle),
|
|
43112
|
+
label,
|
|
43113
|
+
};
|
|
43114
|
+
});
|
|
42330
43115
|
// For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
|
|
42331
43116
|
if (chartData.type === "pie") {
|
|
42332
43117
|
dataSets.reverse();
|
|
@@ -42335,10 +43120,9 @@ function convertChartData(chartData) {
|
|
|
42335
43120
|
dataSets,
|
|
42336
43121
|
dataSetsHaveTitle,
|
|
42337
43122
|
labelRange,
|
|
42338
|
-
title: chartData.title
|
|
43123
|
+
title: chartData.title ?? { text: "" },
|
|
42339
43124
|
type: chartData.type,
|
|
42340
43125
|
background: convertColor({ rgb: chartData.backgroundColor }) || "#FFFFFF",
|
|
42341
|
-
verticalAxisPosition: chartData.verticalAxisPosition,
|
|
42342
43126
|
legendPosition: chartData.legendPosition,
|
|
42343
43127
|
stacked: chartData.stacked || false,
|
|
42344
43128
|
aggregated: false,
|
|
@@ -43453,25 +44237,20 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43453
44237
|
return this.extractComboChart(rootChartElement);
|
|
43454
44238
|
}
|
|
43455
44239
|
// Title can be separated into multiple xml elements (for styling and such), we only import the text
|
|
43456
|
-
const chartTitle = this.mapOnElements({ parent: rootChartElement, query: "c:title a:t" }, (textElement) => {
|
|
44240
|
+
const chartTitle = this.mapOnElements({ parent: rootChartElement, query: "c:chart > c:title a:t" }, (textElement) => {
|
|
43457
44241
|
return textElement.textContent || "";
|
|
43458
44242
|
}).join("");
|
|
43459
44243
|
const barChartGrouping = this.extractChildAttr(rootChartElement, "c:grouping", "val", {
|
|
43460
44244
|
default: "clustered",
|
|
43461
44245
|
}).asString();
|
|
43462
44246
|
return {
|
|
43463
|
-
title: chartTitle,
|
|
44247
|
+
title: { text: chartTitle },
|
|
43464
44248
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
43465
|
-
dataSets: this.extractChartDatasets(this.
|
|
44249
|
+
dataSets: this.extractChartDatasets(this.querySelectorAll(rootChartElement, `c:${chartType}`), chartType),
|
|
43466
44250
|
labelRange: this.extractChildTextContent(rootChartElement, `c:ser ${chartType === "scatterChart" ? "c:numRef" : "c:cat"} c:f`),
|
|
43467
44251
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
43468
44252
|
default: "ffffff",
|
|
43469
44253
|
}).asString(),
|
|
43470
|
-
verticalAxisPosition: this.extractChildAttr(rootChartElement, "c:valAx > c:axPos", "val", {
|
|
43471
|
-
default: "l",
|
|
43472
|
-
}).asString() === "r"
|
|
43473
|
-
? "right"
|
|
43474
|
-
: "left",
|
|
43475
44254
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
|
|
43476
44255
|
default: "b",
|
|
43477
44256
|
}).asString()],
|
|
@@ -43489,21 +44268,16 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43489
44268
|
default: "clustered",
|
|
43490
44269
|
}).asString();
|
|
43491
44270
|
return {
|
|
43492
|
-
title: chartTitle,
|
|
44271
|
+
title: { text: chartTitle },
|
|
43493
44272
|
type: "combo",
|
|
43494
44273
|
dataSets: [
|
|
43495
|
-
...this.extractChartDatasets(this.
|
|
43496
|
-
...this.extractChartDatasets(this.
|
|
44274
|
+
...this.extractChartDatasets(this.querySelectorAll(chartElement, `c:barChart`), "comboChart"),
|
|
44275
|
+
...this.extractChartDatasets(this.querySelectorAll(chartElement, `c:lineChart`), "comboChart"),
|
|
43497
44276
|
],
|
|
43498
44277
|
labelRange: this.extractChildTextContent(chartElement, "c:ser c:cat c:f"),
|
|
43499
44278
|
backgroundColor: this.extractChildAttr(chartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
43500
44279
|
default: "ffffff",
|
|
43501
44280
|
}).asString(),
|
|
43502
|
-
verticalAxisPosition: this.extractChildAttr(chartElement, "c:valAx > c:axPos", "val", {
|
|
43503
|
-
default: "l",
|
|
43504
|
-
}).asString() === "r"
|
|
43505
|
-
? "right"
|
|
43506
|
-
: "left",
|
|
43507
44281
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
|
|
43508
44282
|
default: "b",
|
|
43509
44283
|
}).asString()],
|
|
@@ -43511,21 +44285,49 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43511
44285
|
fontColor: "000000",
|
|
43512
44286
|
};
|
|
43513
44287
|
}
|
|
43514
|
-
extractChartDatasets(
|
|
43515
|
-
|
|
43516
|
-
|
|
43517
|
-
|
|
43518
|
-
|
|
43519
|
-
|
|
43520
|
-
|
|
43521
|
-
|
|
43522
|
-
|
|
43523
|
-
|
|
44288
|
+
extractChartDatasets(chartElements, chartType) {
|
|
44289
|
+
return Array.from(chartElements)
|
|
44290
|
+
.map((element) => {
|
|
44291
|
+
if (chartType === "scatterChart") {
|
|
44292
|
+
return this.extractScatterChartDatasets(element);
|
|
44293
|
+
}
|
|
44294
|
+
return this.mapOnElements({ parent: element, query: "c:ser" }, (chartDataElement) => {
|
|
44295
|
+
let label = {};
|
|
44296
|
+
const reference = this.extractChildTextContent(chartDataElement, "c:tx c:f");
|
|
44297
|
+
if (reference) {
|
|
44298
|
+
label = { reference };
|
|
44299
|
+
}
|
|
44300
|
+
else {
|
|
44301
|
+
const text = this.extractChildTextContent(chartDataElement, "c:tx c:v");
|
|
44302
|
+
if (text) {
|
|
44303
|
+
label = { text };
|
|
44304
|
+
}
|
|
44305
|
+
}
|
|
44306
|
+
return {
|
|
44307
|
+
label,
|
|
44308
|
+
range: this.extractChildTextContent(chartDataElement, "c:val c:f", {
|
|
44309
|
+
required: true,
|
|
44310
|
+
}),
|
|
44311
|
+
};
|
|
44312
|
+
});
|
|
44313
|
+
})
|
|
44314
|
+
.flat();
|
|
43524
44315
|
}
|
|
43525
44316
|
extractScatterChartDatasets(chartElement) {
|
|
43526
44317
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
44318
|
+
let label = {};
|
|
44319
|
+
const reference = this.extractChildTextContent(chartDataElement, "c:tx c:f");
|
|
44320
|
+
if (reference) {
|
|
44321
|
+
label = { reference };
|
|
44322
|
+
}
|
|
44323
|
+
else {
|
|
44324
|
+
const text = this.extractChildTextContent(chartDataElement, "c:tx c:v");
|
|
44325
|
+
if (text) {
|
|
44326
|
+
label = { text };
|
|
44327
|
+
}
|
|
44328
|
+
}
|
|
43527
44329
|
return {
|
|
43528
|
-
label
|
|
44330
|
+
label,
|
|
43529
44331
|
range: this.extractChildTextContent(chartDataElement, "c:yVal c:f", { required: true }),
|
|
43530
44332
|
};
|
|
43531
44333
|
});
|
|
@@ -44257,7 +45059,7 @@ function getRelationFile(file, xmls) {
|
|
|
44257
45059
|
return relsFile;
|
|
44258
45060
|
}
|
|
44259
45061
|
|
|
44260
|
-
const EXCEL_IMPORT_VERSION =
|
|
45062
|
+
const EXCEL_IMPORT_VERSION = 16;
|
|
44261
45063
|
class XlsxReader {
|
|
44262
45064
|
warningManager;
|
|
44263
45065
|
xmls;
|
|
@@ -44735,6 +45537,30 @@ const MIGRATIONS = [
|
|
|
44735
45537
|
return data;
|
|
44736
45538
|
},
|
|
44737
45539
|
},
|
|
45540
|
+
{
|
|
45541
|
+
description: "transform chart data structure (2)",
|
|
45542
|
+
from: 16,
|
|
45543
|
+
to: 17,
|
|
45544
|
+
applyMigration(data) {
|
|
45545
|
+
for (const sheet of data.sheets || []) {
|
|
45546
|
+
for (const f in sheet.figures || []) {
|
|
45547
|
+
const figure = sheet.figures[f];
|
|
45548
|
+
if ("title" in figure.data && typeof figure.data.title === "string") {
|
|
45549
|
+
figure.data.title = { text: figure.data.title };
|
|
45550
|
+
}
|
|
45551
|
+
const figureType = figure.data.type;
|
|
45552
|
+
if (!["line", "bar", "pie", "scatter", "waterfall", "combo"].includes(figureType)) {
|
|
45553
|
+
continue;
|
|
45554
|
+
}
|
|
45555
|
+
const { dataSets, ...newData } = sheet.figures[f].data;
|
|
45556
|
+
const newDataSets = dataSets.map((dataRange) => ({ dataRange }));
|
|
45557
|
+
newData.dataSets = newDataSets;
|
|
45558
|
+
sheet.figures[f].data = newData;
|
|
45559
|
+
}
|
|
45560
|
+
}
|
|
45561
|
+
return data;
|
|
45562
|
+
},
|
|
45563
|
+
},
|
|
44738
45564
|
];
|
|
44739
45565
|
/**
|
|
44740
45566
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -48346,6 +49172,9 @@ class RangeAdapter {
|
|
|
48346
49172
|
if (range.invalidXc) {
|
|
48347
49173
|
return range.invalidXc;
|
|
48348
49174
|
}
|
|
49175
|
+
if (!this.getters.tryGetSheet(range.sheetId)) {
|
|
49176
|
+
return CellErrorType.InvalidReference;
|
|
49177
|
+
}
|
|
48349
49178
|
if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
|
|
48350
49179
|
return CellErrorType.InvalidReference;
|
|
48351
49180
|
}
|
|
@@ -51764,7 +52593,6 @@ class PositionSet {
|
|
|
51764
52593
|
*
|
|
51765
52594
|
*/
|
|
51766
52595
|
class SpreadingRelation {
|
|
51767
|
-
createEmptyPositionSet;
|
|
51768
52596
|
/**
|
|
51769
52597
|
* Internal structure:
|
|
51770
52598
|
* For something like
|
|
@@ -51795,9 +52623,6 @@ class SpreadingRelation {
|
|
|
51795
52623
|
*/
|
|
51796
52624
|
resultsToArrayFormulas = new PositionMap();
|
|
51797
52625
|
arrayFormulasToResults = new PositionMap();
|
|
51798
|
-
constructor(createEmptyPositionSet) {
|
|
51799
|
-
this.createEmptyPositionSet = createEmptyPositionSet;
|
|
51800
|
-
}
|
|
51801
52626
|
getFormulaPositionsSpreadingOn(resultPosition) {
|
|
51802
52627
|
return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
|
|
51803
52628
|
}
|
|
@@ -51816,13 +52641,13 @@ class SpreadingRelation {
|
|
|
51816
52641
|
*/
|
|
51817
52642
|
addRelation({ arrayFormulaPosition, resultPosition, }) {
|
|
51818
52643
|
if (!this.resultsToArrayFormulas.has(resultPosition)) {
|
|
51819
|
-
this.resultsToArrayFormulas.set(resultPosition,
|
|
52644
|
+
this.resultsToArrayFormulas.set(resultPosition, []);
|
|
51820
52645
|
}
|
|
51821
|
-
this.resultsToArrayFormulas.get(resultPosition)?.
|
|
52646
|
+
this.resultsToArrayFormulas.get(resultPosition)?.push(arrayFormulaPosition);
|
|
51822
52647
|
if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
|
|
51823
|
-
this.arrayFormulasToResults.set(arrayFormulaPosition,
|
|
52648
|
+
this.arrayFormulasToResults.set(arrayFormulaPosition, []);
|
|
51824
52649
|
}
|
|
51825
|
-
this.arrayFormulasToResults.get(arrayFormulaPosition)?.
|
|
52650
|
+
this.arrayFormulasToResults.get(arrayFormulaPosition)?.push(resultPosition);
|
|
51826
52651
|
}
|
|
51827
52652
|
hasArrayFormulaResult(position) {
|
|
51828
52653
|
return this.resultsToArrayFormulas.has(position);
|
|
@@ -51843,7 +52668,7 @@ class Evaluator {
|
|
|
51843
52668
|
evaluatedCells = new PositionMap();
|
|
51844
52669
|
formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
|
|
51845
52670
|
blockedArrayFormulas = new PositionSet({});
|
|
51846
|
-
spreadingRelations = new SpreadingRelation(
|
|
52671
|
+
spreadingRelations = new SpreadingRelation();
|
|
51847
52672
|
constructor(context, getters) {
|
|
51848
52673
|
this.context = context;
|
|
51849
52674
|
this.getters = getters;
|
|
@@ -51937,7 +52762,7 @@ class Evaluator {
|
|
|
51937
52762
|
}
|
|
51938
52763
|
buildDependencyGraph() {
|
|
51939
52764
|
this.blockedArrayFormulas = this.createEmptyPositionSet();
|
|
51940
|
-
this.spreadingRelations = new SpreadingRelation(
|
|
52765
|
+
this.spreadingRelations = new SpreadingRelation();
|
|
51941
52766
|
this.formulaDependencies = lazy(() => {
|
|
51942
52767
|
const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
|
|
51943
52768
|
.filter((range) => !range.invalidSheetName && !range.invalidXc)
|
|
@@ -52069,6 +52894,7 @@ class Evaluator {
|
|
|
52069
52894
|
const nbColumns = formulaReturn.length;
|
|
52070
52895
|
const nbRows = formulaReturn[0].length;
|
|
52071
52896
|
forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
|
|
52897
|
+
this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
|
|
52072
52898
|
forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
|
|
52073
52899
|
forEachSpreadPositionInMatrix(nbColumns, nbRows,
|
|
52074
52900
|
// thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
|
|
@@ -52091,6 +52917,18 @@ class Evaluator {
|
|
|
52091
52917
|
}
|
|
52092
52918
|
throw new SplillBlockedError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
|
|
52093
52919
|
}
|
|
52920
|
+
assertNoMergedCellsInSpreadZone({ sheetId, col, row }, matrixResult) {
|
|
52921
|
+
const mergedCells = this.getters.getMergesInZone(sheetId, {
|
|
52922
|
+
top: row,
|
|
52923
|
+
bottom: row + matrixResult.length,
|
|
52924
|
+
left: col,
|
|
52925
|
+
right: col + matrixResult[0].length,
|
|
52926
|
+
});
|
|
52927
|
+
if (mergedCells.length === 0) {
|
|
52928
|
+
return;
|
|
52929
|
+
}
|
|
52930
|
+
throw new SplillBlockedError(_t("Merged cells found in the spill zone. Please unmerge cells before using array formulas."));
|
|
52931
|
+
}
|
|
52094
52932
|
updateSpreadRelation({ sheetId, col, row, }) {
|
|
52095
52933
|
const arrayFormulaPosition = { sheetId, col, row };
|
|
52096
52934
|
return (i, j) => {
|
|
@@ -52328,10 +53166,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
52328
53166
|
this.evaluator.updateDependencies(cmd);
|
|
52329
53167
|
}
|
|
52330
53168
|
break;
|
|
52331
|
-
case "DUPLICATE_SHEET":
|
|
52332
|
-
case "CREATE_SHEET":
|
|
52333
|
-
this.shouldRebuildDependenciesGraph = true;
|
|
52334
|
-
break;
|
|
52335
53169
|
case "EVALUATE_CELLS":
|
|
52336
53170
|
this.evaluator.evaluateAllCells();
|
|
52337
53171
|
break;
|
|
@@ -52432,16 +53266,22 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
52432
53266
|
let newContent = undefined;
|
|
52433
53267
|
let newFormat = undefined;
|
|
52434
53268
|
let isExported = true;
|
|
53269
|
+
const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
|
|
52435
53270
|
const formulaCell = this.getCorrespondingFormulaCell(position);
|
|
52436
53271
|
if (formulaCell) {
|
|
52437
53272
|
isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
|
|
52438
53273
|
isFormula = isExported;
|
|
52439
53274
|
if (!isExported) {
|
|
52440
|
-
|
|
52441
|
-
|
|
53275
|
+
// If the cell contains a non-exported formula and that is evaluates to
|
|
53276
|
+
// nothing* ,we don't export it.
|
|
53277
|
+
// * non-falsy value are relevant and so are 0 and FALSE, which only leaves
|
|
53278
|
+
// the empty string.
|
|
53279
|
+
if (value !== "") {
|
|
53280
|
+
newContent = (value ?? "").toString();
|
|
53281
|
+
newFormat = evaluatedCell.format;
|
|
53282
|
+
}
|
|
52442
53283
|
}
|
|
52443
53284
|
}
|
|
52444
|
-
const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
|
|
52445
53285
|
const exportedCellData = exportedSheetData.cells[xc] || {};
|
|
52446
53286
|
const format = newFormat
|
|
52447
53287
|
? getItemId(newFormat, data.formats)
|
|
@@ -57064,7 +57904,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57064
57904
|
paintFormatStatus = "inactive";
|
|
57065
57905
|
originSheetId;
|
|
57066
57906
|
copiedData;
|
|
57067
|
-
_isCutOperation;
|
|
57907
|
+
_isCutOperation = false;
|
|
57068
57908
|
// ---------------------------------------------------------------------------
|
|
57069
57909
|
// Command Handling
|
|
57070
57910
|
// ---------------------------------------------------------------------------
|
|
@@ -57076,14 +57916,17 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57076
57916
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
57077
57917
|
const copiedData = this.convertOSClipboardData(cmd.text);
|
|
57078
57918
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57079
|
-
return this.isPasteAllowed(cmd.target, copiedData, { pasteOption });
|
|
57919
|
+
return this.isPasteAllowed(cmd.target, copiedData, { pasteOption, isCutOperation: false });
|
|
57080
57920
|
}
|
|
57081
57921
|
case "PASTE": {
|
|
57082
57922
|
if (!this.copiedData) {
|
|
57083
57923
|
return "EmptyClipboard" /* CommandResult.EmptyClipboard */;
|
|
57084
57924
|
}
|
|
57085
57925
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57086
|
-
return this.isPasteAllowed(cmd.target, this.copiedData, {
|
|
57926
|
+
return this.isPasteAllowed(cmd.target, this.copiedData, {
|
|
57927
|
+
pasteOption: pasteOption,
|
|
57928
|
+
isCutOperation: this._isCutOperation,
|
|
57929
|
+
});
|
|
57087
57930
|
}
|
|
57088
57931
|
case "COPY_PASTE_CELLS_ABOVE": {
|
|
57089
57932
|
const zones = this.getters.getSelectedZones();
|
|
@@ -57101,13 +57944,13 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57101
57944
|
}
|
|
57102
57945
|
case "INSERT_CELL": {
|
|
57103
57946
|
const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57104
|
-
const copiedData = this.copy(
|
|
57105
|
-
return this.isPasteAllowed(paste, copiedData, {});
|
|
57947
|
+
const copiedData = this.copy(cut);
|
|
57948
|
+
return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
|
|
57106
57949
|
}
|
|
57107
57950
|
case "DELETE_CELL": {
|
|
57108
57951
|
const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57109
|
-
const copiedData = this.copy(
|
|
57110
|
-
return this.isPasteAllowed(paste, copiedData, {});
|
|
57952
|
+
const copiedData = this.copy(cut);
|
|
57953
|
+
return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
|
|
57111
57954
|
}
|
|
57112
57955
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
57113
57956
|
if (this.paintFormatStatus !== "inactive") {
|
|
@@ -57125,23 +57968,27 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57125
57968
|
const zones = this.getters.getSelectedZones();
|
|
57126
57969
|
this.status = "visible";
|
|
57127
57970
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57128
|
-
this.copiedData = this.copy(
|
|
57971
|
+
this.copiedData = this.copy(zones);
|
|
57972
|
+
this._isCutOperation = cmd.type === "CUT";
|
|
57129
57973
|
break;
|
|
57130
57974
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
57975
|
+
this._isCutOperation = false;
|
|
57131
57976
|
this.copiedData = this.convertOSClipboardData(cmd.text);
|
|
57132
57977
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57133
|
-
this.paste(cmd.target, {
|
|
57978
|
+
this.paste(cmd.target, this.copiedData, {
|
|
57134
57979
|
pasteOption,
|
|
57135
57980
|
selectTarget: true,
|
|
57981
|
+
isCutOperation: false,
|
|
57136
57982
|
});
|
|
57137
57983
|
this.status = "invisible";
|
|
57138
57984
|
break;
|
|
57139
57985
|
}
|
|
57140
57986
|
case "PASTE": {
|
|
57141
57987
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57142
|
-
this.paste(cmd.target, {
|
|
57988
|
+
this.paste(cmd.target, this.copiedData, {
|
|
57143
57989
|
pasteOption,
|
|
57144
57990
|
selectTarget: true,
|
|
57991
|
+
isCutOperation: this._isCutOperation,
|
|
57145
57992
|
});
|
|
57146
57993
|
if (this.paintFormatStatus === "oneOff") {
|
|
57147
57994
|
this.paintFormatStatus = "inactive";
|
|
@@ -57162,9 +58009,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57162
58009
|
top: multipleRowsInSelection ? zone.top : zone.top - 1,
|
|
57163
58010
|
};
|
|
57164
58011
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57165
|
-
|
|
57166
|
-
this.paste([zone], {
|
|
57167
|
-
|
|
58012
|
+
const copiedData = this.copy([copyTarget]);
|
|
58013
|
+
this.paste([zone], copiedData, {
|
|
58014
|
+
isCutOperation: false,
|
|
57168
58015
|
selectTarget: true,
|
|
57169
58016
|
});
|
|
57170
58017
|
}
|
|
@@ -57179,9 +58026,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57179
58026
|
left: multipleColsInSelection ? zone.left : zone.left - 1,
|
|
57180
58027
|
};
|
|
57181
58028
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57182
|
-
|
|
57183
|
-
this.paste([zone], {
|
|
57184
|
-
|
|
58029
|
+
const copiedData = this.copy([copyTarget]);
|
|
58030
|
+
this.paste([zone], copiedData, {
|
|
58031
|
+
isCutOperation: false,
|
|
57185
58032
|
selectTarget: true,
|
|
57186
58033
|
});
|
|
57187
58034
|
}
|
|
@@ -57197,14 +58044,14 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57197
58044
|
}
|
|
57198
58045
|
break;
|
|
57199
58046
|
}
|
|
57200
|
-
|
|
57201
|
-
this.paste(paste, {});
|
|
58047
|
+
const copiedData = this.copy(cut);
|
|
58048
|
+
this.paste(paste, copiedData, { isCutOperation: true });
|
|
57202
58049
|
break;
|
|
57203
58050
|
}
|
|
57204
58051
|
case "INSERT_CELL": {
|
|
57205
58052
|
const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57206
|
-
|
|
57207
|
-
this.paste(paste, {});
|
|
58053
|
+
const copiedData = this.copy(cut);
|
|
58054
|
+
this.paste(paste, copiedData, { isCutOperation: true });
|
|
57208
58055
|
break;
|
|
57209
58056
|
}
|
|
57210
58057
|
case "ADD_COLUMNS_ROWS": {
|
|
@@ -57236,7 +58083,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57236
58083
|
break;
|
|
57237
58084
|
}
|
|
57238
58085
|
case "REPEAT_PASTE": {
|
|
57239
|
-
this.paste(cmd.target, {
|
|
58086
|
+
this.paste(cmd.target, this.copiedData, {
|
|
58087
|
+
isCutOperation: false,
|
|
57240
58088
|
pasteOption: cmd.pasteOption,
|
|
57241
58089
|
selectTarget: true,
|
|
57242
58090
|
});
|
|
@@ -57244,7 +58092,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57244
58092
|
}
|
|
57245
58093
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
57246
58094
|
const zones = this.getters.getSelectedZones();
|
|
57247
|
-
this.copiedData = this.copy(
|
|
58095
|
+
this.copiedData = this.copy(zones);
|
|
57248
58096
|
this.status = "visible";
|
|
57249
58097
|
if (cmd.persistent) {
|
|
57250
58098
|
this.paintFormatStatus = "persistent";
|
|
@@ -57275,7 +58123,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57275
58123
|
}
|
|
57276
58124
|
}
|
|
57277
58125
|
convertOSClipboardData(clipboardData) {
|
|
57278
|
-
this._isCutOperation = false;
|
|
57279
58126
|
const handlers = clipboardHandlersRegistries.figureHandlers
|
|
57280
58127
|
.getAll()
|
|
57281
58128
|
.map((handler) => new handler(this.getters, this.dispatch));
|
|
@@ -57313,7 +58160,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57313
58160
|
for (const handler of this.selectClipboardHandlers(copiedData)) {
|
|
57314
58161
|
const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
|
|
57315
58162
|
...options,
|
|
57316
|
-
isCutOperation: this.isCutOperation(),
|
|
57317
58163
|
});
|
|
57318
58164
|
if (result !== "Success" /* CommandResult.Success */) {
|
|
57319
58165
|
return result;
|
|
@@ -57336,9 +58182,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57336
58182
|
}
|
|
57337
58183
|
return false;
|
|
57338
58184
|
}
|
|
57339
|
-
copy(
|
|
58185
|
+
copy(zones) {
|
|
57340
58186
|
let copiedData = {};
|
|
57341
|
-
this._isCutOperation = operation === "CUT";
|
|
57342
58187
|
const clipboardData = this.getClipboardData(zones);
|
|
57343
58188
|
for (const handler of this.selectClipboardHandlers(clipboardData)) {
|
|
57344
58189
|
const data = handler.copy(clipboardData);
|
|
@@ -57346,8 +58191,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57346
58191
|
}
|
|
57347
58192
|
return copiedData;
|
|
57348
58193
|
}
|
|
57349
|
-
paste(zones, options) {
|
|
57350
|
-
if (!
|
|
58194
|
+
paste(zones, copiedData, options) {
|
|
58195
|
+
if (!copiedData) {
|
|
57351
58196
|
return;
|
|
57352
58197
|
}
|
|
57353
58198
|
let zone = undefined;
|
|
@@ -57355,12 +58200,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57355
58200
|
let target = {
|
|
57356
58201
|
zones,
|
|
57357
58202
|
};
|
|
57358
|
-
const handlers = this.selectClipboardHandlers(
|
|
58203
|
+
const handlers = this.selectClipboardHandlers(copiedData);
|
|
57359
58204
|
for (const handler of handlers) {
|
|
57360
|
-
const currentTarget = handler.getPasteTarget(zones,
|
|
57361
|
-
...options,
|
|
57362
|
-
isCutOperation: this.isCutOperation(),
|
|
57363
|
-
});
|
|
58205
|
+
const currentTarget = handler.getPasteTarget(zones, copiedData, options);
|
|
57364
58206
|
if (currentTarget.figureId) {
|
|
57365
58207
|
target.figureId = currentTarget.figureId;
|
|
57366
58208
|
}
|
|
@@ -57376,7 +58218,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57376
58218
|
if (zone !== undefined) {
|
|
57377
58219
|
this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
|
|
57378
58220
|
}
|
|
57379
|
-
handlers.forEach((handler) => handler.paste(target,
|
|
58221
|
+
handlers.forEach((handler) => handler.paste(target, copiedData, options));
|
|
57380
58222
|
if (!options?.selectTarget) {
|
|
57381
58223
|
return;
|
|
57382
58224
|
}
|
|
@@ -59762,6 +60604,7 @@ class BottomBarSheet extends Component {
|
|
|
59762
60604
|
sheetDivRef = useRef("sheetDiv");
|
|
59763
60605
|
sheetNameRef = useRef("sheetNameSpan");
|
|
59764
60606
|
editionState = "initializing";
|
|
60607
|
+
DOMFocusableElementStore;
|
|
59765
60608
|
setup() {
|
|
59766
60609
|
onMounted(() => {
|
|
59767
60610
|
if (this.isSheetActive) {
|
|
@@ -59774,6 +60617,7 @@ class BottomBarSheet extends Component {
|
|
|
59774
60617
|
this.focusInputAndSelectContent();
|
|
59775
60618
|
}
|
|
59776
60619
|
});
|
|
60620
|
+
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
|
|
59777
60621
|
}
|
|
59778
60622
|
focusInputAndSelectContent() {
|
|
59779
60623
|
if (!this.state.isEditing || !this.sheetNameRef.el)
|
|
@@ -59815,9 +60659,11 @@ class BottomBarSheet extends Component {
|
|
|
59815
60659
|
if (ev.key === "Enter") {
|
|
59816
60660
|
ev.preventDefault();
|
|
59817
60661
|
this.stopEdition();
|
|
60662
|
+
this.DOMFocusableElementStore.focus();
|
|
59818
60663
|
}
|
|
59819
60664
|
if (ev.key === "Escape") {
|
|
59820
60665
|
this.cancelEdition();
|
|
60666
|
+
this.DOMFocusableElementStore.focus();
|
|
59821
60667
|
}
|
|
59822
60668
|
}
|
|
59823
60669
|
onClickSheetName(ev) {
|
|
@@ -61866,6 +62712,9 @@ class Spreadsheet extends Component {
|
|
|
61866
62712
|
static template = "o-spreadsheet-Spreadsheet";
|
|
61867
62713
|
static props = {
|
|
61868
62714
|
model: Object,
|
|
62715
|
+
notifyUser: { type: Function, optional: true },
|
|
62716
|
+
raiseError: { type: Function, optional: true },
|
|
62717
|
+
askConfirmation: { type: Function, optional: true },
|
|
61869
62718
|
};
|
|
61870
62719
|
static components = {
|
|
61871
62720
|
TopBar,
|
|
@@ -61912,7 +62761,11 @@ class Spreadsheet extends Component {
|
|
|
61912
62761
|
toggleSidePanel: this.sidePanel.toggle.bind(this.sidePanel),
|
|
61913
62762
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
61914
62763
|
startCellEdition: (content) => this.composerFocusStore.focusGridComposerCell(content),
|
|
62764
|
+
notifyUser: (notification) => this.notificationStore.notifyUser(notification),
|
|
62765
|
+
askConfirmation: (text, confirm, cancel) => this.notificationStore.askConfirmation(text, confirm, cancel),
|
|
62766
|
+
raiseError: (text, cb) => this.notificationStore.raiseError(text, cb),
|
|
61915
62767
|
});
|
|
62768
|
+
this.notificationStore.updateNotificationCallbacks({ ...this.props });
|
|
61916
62769
|
useEffect(() => {
|
|
61917
62770
|
/**
|
|
61918
62771
|
* Only refocus the grid if the active element is not a child of the spreadsheet
|
|
@@ -61935,6 +62788,11 @@ class Spreadsheet extends Component {
|
|
|
61935
62788
|
if (nextProps.model !== this.props.model) {
|
|
61936
62789
|
throw new Error("Changing the props model is not supported at the moment.");
|
|
61937
62790
|
}
|
|
62791
|
+
if (nextProps.notifyUser !== this.props.notifyUser ||
|
|
62792
|
+
nextProps.askConfirmation !== this.props.askConfirmation ||
|
|
62793
|
+
nextProps.raiseError !== this.props.raiseError) {
|
|
62794
|
+
this.notificationStore.updateNotificationCallbacks({ ...nextProps });
|
|
62795
|
+
}
|
|
61938
62796
|
});
|
|
61939
62797
|
const render = batched(this.render.bind(this, true));
|
|
61940
62798
|
onMounted(() => {
|
|
@@ -61952,7 +62810,7 @@ class Spreadsheet extends Component {
|
|
|
61952
62810
|
bindModelEvents() {
|
|
61953
62811
|
this.model.on("update", this, () => this.render(true));
|
|
61954
62812
|
this.model.on("notify-ui", this, (notification) => this.notificationStore.notifyUser(notification));
|
|
61955
|
-
this.model.on("raise-error-ui", this, ({ text }) => this.
|
|
62813
|
+
this.model.on("raise-error-ui", this, ({ text }) => this.notificationStore.raiseError(text));
|
|
61956
62814
|
}
|
|
61957
62815
|
unbindModelEvents() {
|
|
61958
62816
|
this.model.off("update", this);
|
|
@@ -63507,10 +64365,13 @@ function createChart(chart, chartSheetIndex, data) {
|
|
|
63507
64365
|
});
|
|
63508
64366
|
// <manualLayout/> to manually position the chart in the figure container
|
|
63509
64367
|
let title = escapeXml ``;
|
|
63510
|
-
if (chart.data.title) {
|
|
64368
|
+
if (chart.data.title?.text) {
|
|
64369
|
+
const color = chart.data.title.color
|
|
64370
|
+
? toXlsxHexColor(chart.data.title.color)
|
|
64371
|
+
: chart.data.fontColor;
|
|
63511
64372
|
title = escapeXml /*xml*/ `
|
|
63512
64373
|
<c:title>
|
|
63513
|
-
${insertText(chart.data.title, chart.data.
|
|
64374
|
+
${insertText(chart.data.title.text, color, DEFAULT_CHART_FONT_SIZE, chart.data.title)}
|
|
63514
64375
|
<c:overlay val="0" />
|
|
63515
64376
|
</c:title>
|
|
63516
64377
|
`;
|
|
@@ -63598,7 +64459,7 @@ function lineAttributes(params) {
|
|
|
63598
64459
|
</a:ln>
|
|
63599
64460
|
`;
|
|
63600
64461
|
}
|
|
63601
|
-
function insertText(text, fontColor = "000000", fontsize =
|
|
64462
|
+
function insertText(text, fontColor = "000000", fontsize = DEFAULT_CHART_FONT_SIZE, style = {}) {
|
|
63602
64463
|
return escapeXml /*xml*/ `
|
|
63603
64464
|
<c:tx>
|
|
63604
64465
|
<c:rich>
|
|
@@ -63606,13 +64467,13 @@ function insertText(text, fontColor = "000000", fontsize = 22) {
|
|
|
63606
64467
|
<a:lstStyle />
|
|
63607
64468
|
<a:p>
|
|
63608
64469
|
<a:pPr lvl="0">
|
|
63609
|
-
<a:defRPr b="0">
|
|
64470
|
+
<a:defRPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}">
|
|
63610
64471
|
${solidFill(fontColor)}
|
|
63611
64472
|
<a:latin typeface="+mn-lt"/>
|
|
63612
64473
|
</a:defRPr>
|
|
63613
64474
|
</a:pPr>
|
|
63614
64475
|
<a:r> <!-- Runs -->
|
|
63615
|
-
<a:rPr sz="${fontsize * 100}"/>
|
|
64476
|
+
<a:rPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}" sz="${fontsize * 100}"/>
|
|
63616
64477
|
<a:t>${text}</a:t>
|
|
63617
64478
|
</a:r>
|
|
63618
64479
|
</a:p>
|
|
@@ -63641,6 +64502,24 @@ function insertTextProperties(fontsize = 12, fontColor = "000000", bold = false,
|
|
|
63641
64502
|
</c:txPr>
|
|
63642
64503
|
`;
|
|
63643
64504
|
}
|
|
64505
|
+
function extractDataSetLabel(label) {
|
|
64506
|
+
if (!label) {
|
|
64507
|
+
return escapeXml /*xml*/ ``;
|
|
64508
|
+
}
|
|
64509
|
+
if ("text" in label && label.text) {
|
|
64510
|
+
return escapeXml /*xml*/ `
|
|
64511
|
+
<c:tx><c:v>${label.text}</c:v></c:tx>
|
|
64512
|
+
`;
|
|
64513
|
+
}
|
|
64514
|
+
if ("reference" in label && label.reference) {
|
|
64515
|
+
return escapeXml /*xml*/ `
|
|
64516
|
+
<c:tx>
|
|
64517
|
+
${stringRef(label.reference)}
|
|
64518
|
+
</c:tx>
|
|
64519
|
+
`;
|
|
64520
|
+
}
|
|
64521
|
+
return escapeXml /*xml*/ ``;
|
|
64522
|
+
}
|
|
63644
64523
|
function addBarChart(chart) {
|
|
63645
64524
|
// gapWitdh and overlap that define the space between clusters (in %) and the overlap between datasets (from -100: completely scattered to 100, completely overlapped)
|
|
63646
64525
|
// see gapWidth : https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_gapWidth_topic_ID0EFVEQB.html#topic_ID0EFVEQB
|
|
@@ -63648,46 +64527,72 @@ function addBarChart(chart) {
|
|
|
63648
64527
|
//
|
|
63649
64528
|
// overlap and gapWitdh seems to be by default at -20 and 20 in chart.js.
|
|
63650
64529
|
// See https://www.chartjs.org/docs/latest/charts/bar.html and https://www.chartjs.org/docs/latest/charts/bar.html#barpercentage-vs-categorypercentage
|
|
63651
|
-
const
|
|
63652
|
-
const
|
|
64530
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64531
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64532
|
+
const leftDataSetsNodes = [];
|
|
64533
|
+
const rightDataSetsNodes = [];
|
|
63653
64534
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
63654
64535
|
const color = toXlsxHexColor(colors.next());
|
|
63655
64536
|
const dataShapeProperty = shapeProperty({
|
|
63656
64537
|
backgroundColor: color,
|
|
63657
64538
|
line: { color },
|
|
63658
64539
|
});
|
|
63659
|
-
|
|
64540
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63660
64541
|
<c:ser>
|
|
63661
64542
|
<c:idx val="${dsIndex}"/>
|
|
63662
64543
|
<c:order val="${dsIndex}"/>
|
|
63663
|
-
${
|
|
64544
|
+
${extractDataSetLabel(dataset.label)}
|
|
63664
64545
|
${dataShapeProperty}
|
|
63665
64546
|
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63666
64547
|
<c:val> <!-- x-coordinate values -->
|
|
63667
64548
|
${numberRef(dataset.range)}
|
|
63668
64549
|
</c:val>
|
|
63669
64550
|
</c:ser>
|
|
63670
|
-
|
|
64551
|
+
`;
|
|
64552
|
+
if (dataset.rightYAxis) {
|
|
64553
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64554
|
+
}
|
|
64555
|
+
else {
|
|
64556
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64557
|
+
}
|
|
63671
64558
|
}
|
|
63672
|
-
// Excel does not support this feature
|
|
63673
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63674
64559
|
const grouping = chart.stacked ? "stacked" : "clustered";
|
|
63675
64560
|
const overlap = chart.stacked ? 100 : -20;
|
|
63676
64561
|
return escapeXml /*xml*/ `
|
|
63677
|
-
|
|
63678
|
-
|
|
63679
|
-
|
|
63680
|
-
|
|
63681
|
-
|
|
63682
|
-
|
|
63683
|
-
|
|
63684
|
-
|
|
63685
|
-
|
|
63686
|
-
|
|
63687
|
-
|
|
63688
|
-
|
|
63689
|
-
|
|
63690
|
-
|
|
64562
|
+
${leftDataSetsNodes.length
|
|
64563
|
+
? escapeXml /*xml*/ `
|
|
64564
|
+
<c:barChart>
|
|
64565
|
+
<c:barDir val="col"/>
|
|
64566
|
+
<c:grouping val="${grouping}"/>
|
|
64567
|
+
<c:overlap val="${overlap}"/>
|
|
64568
|
+
<c:gapWidth val="70"/>
|
|
64569
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64570
|
+
<c:varyColors val="0"/>
|
|
64571
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64572
|
+
<c:axId val="${catAxId}" />
|
|
64573
|
+
<c:axId val="${valAxId}" />
|
|
64574
|
+
</c:barChart>
|
|
64575
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64576
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64577
|
+
`
|
|
64578
|
+
: ""}
|
|
64579
|
+
${rightDataSetsNodes.length
|
|
64580
|
+
? escapeXml /*xml*/ `
|
|
64581
|
+
<c:barChart>
|
|
64582
|
+
<c:barDir val="col"/>
|
|
64583
|
+
<c:grouping val="${grouping}"/>
|
|
64584
|
+
<c:overlap val="${overlap}"/>
|
|
64585
|
+
<c:gapWidth val="70"/>
|
|
64586
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64587
|
+
<c:varyColors val="0"/>
|
|
64588
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64589
|
+
<c:axId val="${catAxId + 1}" />
|
|
64590
|
+
<c:axId val="${valAxId + 1}" />
|
|
64591
|
+
</c:barChart>
|
|
64592
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64593
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64594
|
+
`
|
|
64595
|
+
: ""}`;
|
|
63691
64596
|
}
|
|
63692
64597
|
function addComboChart(chart) {
|
|
63693
64598
|
// gapWitdh and overlap that define the space between clusters (in %) and the overlap between datasets (from -100: completely scattered to 100, completely overlapped)
|
|
@@ -63696,28 +64601,38 @@ function addComboChart(chart) {
|
|
|
63696
64601
|
//
|
|
63697
64602
|
// overlap and gapWitdh seems to be by default at -20 and 20 in chart.js.
|
|
63698
64603
|
// See https://www.chartjs.org/docs/latest/charts/bar.html and https://www.chartjs.org/docs/latest/charts/bar.html#barpercentage-vs-categorypercentage
|
|
63699
|
-
const
|
|
63700
|
-
const
|
|
63701
|
-
|
|
64604
|
+
const dataSets = chart.dataSets;
|
|
64605
|
+
const dataSetsColors = dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64606
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64607
|
+
let dataSet = dataSets[0];
|
|
64608
|
+
const firstColor = toXlsxHexColor(colors.next());
|
|
64609
|
+
const useRightAxisForBarSerie = dataSet.rightYAxis ?? false;
|
|
64610
|
+
const barDataSetNode = escapeXml /*xml*/ `
|
|
64611
|
+
<c:ser>
|
|
64612
|
+
<c:idx val="0"/>
|
|
64613
|
+
<c:order val="0"/>
|
|
64614
|
+
${extractDataSetLabel(dataSet.label)}
|
|
64615
|
+
${shapeProperty({
|
|
64616
|
+
backgroundColor: firstColor,
|
|
64617
|
+
line: { color: firstColor },
|
|
64618
|
+
})}
|
|
64619
|
+
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
64620
|
+
<!-- x-coordinate values -->
|
|
64621
|
+
<c:val>
|
|
64622
|
+
${numberRef(dataSet.range)}
|
|
64623
|
+
</c:val>
|
|
64624
|
+
</c:ser>
|
|
64625
|
+
`;
|
|
64626
|
+
const leftDataSetsNodes = [];
|
|
64627
|
+
const rightDataSetsNodes = [];
|
|
64628
|
+
for (let dsIndex = 1; dsIndex < dataSets.length; dsIndex++) {
|
|
64629
|
+
dataSet = dataSets[dsIndex];
|
|
63702
64630
|
const color = toXlsxHexColor(colors.next());
|
|
63703
64631
|
const dataShapeProperty = shapeProperty({
|
|
63704
64632
|
backgroundColor: color,
|
|
63705
64633
|
line: { color },
|
|
63706
64634
|
});
|
|
63707
|
-
|
|
63708
|
-
? escapeXml /*xml*/ `
|
|
63709
|
-
<c:ser>
|
|
63710
|
-
<c:idx val="${dsIndex}"/>
|
|
63711
|
-
<c:order val="${dsIndex}"/>
|
|
63712
|
-
${dataset.label ? escapeXml /*xml*/ `<c:tx>${stringRef(dataset.label)}</c:tx>` : ""}
|
|
63713
|
-
${dataShapeProperty}
|
|
63714
|
-
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63715
|
-
<c:val> <!-- x-coordinate values -->
|
|
63716
|
-
${numberRef(dataset.range)}
|
|
63717
|
-
</c:val>
|
|
63718
|
-
</c:ser>
|
|
63719
|
-
`
|
|
63720
|
-
: escapeXml /*xml*/ `
|
|
64635
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63721
64636
|
<c:ser>
|
|
63722
64637
|
<c:idx val="${dsIndex}"/>
|
|
63723
64638
|
<c:order val="${dsIndex}"/>
|
|
@@ -63725,18 +64640,24 @@ function addComboChart(chart) {
|
|
|
63725
64640
|
<c:marker>
|
|
63726
64641
|
<c:symbol val="circle" />
|
|
63727
64642
|
<c:size val="5"/>
|
|
64643
|
+
${dataShapeProperty}
|
|
63728
64644
|
</c:marker>
|
|
63729
|
-
${
|
|
64645
|
+
${extractDataSetLabel(dataSet.label)}
|
|
63730
64646
|
${dataShapeProperty}
|
|
63731
|
-
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
63732
|
-
|
|
63733
|
-
|
|
64647
|
+
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
64648
|
+
<!-- x-coordinate values -->
|
|
64649
|
+
<c:val>
|
|
64650
|
+
${numberRef(dataSet.range)}
|
|
63734
64651
|
</c:val>
|
|
63735
64652
|
</c:ser>
|
|
63736
|
-
|
|
64653
|
+
`;
|
|
64654
|
+
if (dataSet.rightYAxis) {
|
|
64655
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64656
|
+
}
|
|
64657
|
+
else {
|
|
64658
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64659
|
+
}
|
|
63737
64660
|
}
|
|
63738
|
-
// Excel does not support this feature
|
|
63739
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63740
64661
|
const overlap = chart.stacked ? 100 : -20;
|
|
63741
64662
|
return escapeXml /*xml*/ `
|
|
63742
64663
|
<c:barChart>
|
|
@@ -63746,34 +64667,63 @@ function addComboChart(chart) {
|
|
|
63746
64667
|
<c:gapWidth val="70"/>
|
|
63747
64668
|
<!-- each data marker in the series does not have a different color -->
|
|
63748
64669
|
<c:varyColors val="0"/>
|
|
63749
|
-
${
|
|
63750
|
-
<c:axId val="${catAxId}" />
|
|
63751
|
-
<c:axId val="${valAxId}" />
|
|
64670
|
+
${barDataSetNode}
|
|
64671
|
+
<c:axId val="${catAxId + (useRightAxisForBarSerie ? 1 : 0)}" />
|
|
64672
|
+
<c:axId val="${valAxId + (useRightAxisForBarSerie ? 1 : 0)}" />
|
|
63752
64673
|
</c:barChart>
|
|
63753
|
-
|
|
63754
|
-
|
|
63755
|
-
|
|
63756
|
-
|
|
63757
|
-
|
|
63758
|
-
|
|
63759
|
-
|
|
63760
|
-
|
|
63761
|
-
|
|
63762
|
-
|
|
64674
|
+
${leftDataSetsNodes.length
|
|
64675
|
+
? escapeXml /*xml*/ `
|
|
64676
|
+
<c:lineChart>
|
|
64677
|
+
<c:grouping val="standard"/>
|
|
64678
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64679
|
+
<c:varyColors val="0"/>
|
|
64680
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64681
|
+
<c:axId val="${catAxId}" />
|
|
64682
|
+
<c:axId val="${valAxId}" />
|
|
64683
|
+
</c:lineChart>
|
|
64684
|
+
`
|
|
64685
|
+
: ""}
|
|
64686
|
+
${rightDataSetsNodes.length
|
|
64687
|
+
? escapeXml /*xml*/ `
|
|
64688
|
+
<c:lineChart>
|
|
64689
|
+
<c:grouping val="standard"/>
|
|
64690
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64691
|
+
<c:varyColors val="0"/>
|
|
64692
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64693
|
+
<c:axId val="${catAxId + 1}" />
|
|
64694
|
+
<c:axId val="${valAxId + 1}" />
|
|
64695
|
+
</c:lineChart>
|
|
64696
|
+
`
|
|
64697
|
+
: ""}
|
|
64698
|
+
${!useRightAxisForBarSerie || leftDataSetsNodes.length
|
|
64699
|
+
? escapeXml /*xml*/ `
|
|
64700
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64701
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64702
|
+
`
|
|
64703
|
+
: ""}
|
|
64704
|
+
${useRightAxisForBarSerie || rightDataSetsNodes.length
|
|
64705
|
+
? escapeXml /*xml*/ `
|
|
64706
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length || !useRightAxisForBarSerie ? 1 : 0)}
|
|
64707
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64708
|
+
`
|
|
64709
|
+
: ""}
|
|
63763
64710
|
`;
|
|
63764
64711
|
}
|
|
63765
64712
|
function addLineChart(chart) {
|
|
63766
|
-
const
|
|
63767
|
-
const
|
|
64713
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64714
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64715
|
+
const leftDataSetsNodes = [];
|
|
64716
|
+
const rightDataSetsNodes = [];
|
|
63768
64717
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
64718
|
+
const color = toXlsxHexColor(colors.next());
|
|
63769
64719
|
const dataShapeProperty = shapeProperty({
|
|
63770
64720
|
line: {
|
|
63771
64721
|
width: 2.5,
|
|
63772
64722
|
style: "solid",
|
|
63773
|
-
color
|
|
64723
|
+
color,
|
|
63774
64724
|
},
|
|
63775
64725
|
});
|
|
63776
|
-
|
|
64726
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63777
64727
|
<c:ser>
|
|
63778
64728
|
<c:idx val="${dsIndex}"/>
|
|
63779
64729
|
<c:order val="${dsIndex}"/>
|
|
@@ -63781,37 +64731,63 @@ function addLineChart(chart) {
|
|
|
63781
64731
|
<c:marker>
|
|
63782
64732
|
<c:symbol val="circle" />
|
|
63783
64733
|
<c:size val="5"/>
|
|
64734
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
63784
64735
|
</c:marker>
|
|
63785
|
-
${
|
|
64736
|
+
${extractDataSetLabel(dataset.label)}
|
|
63786
64737
|
${dataShapeProperty}
|
|
63787
64738
|
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63788
64739
|
<c:val> <!-- x-coordinate values -->
|
|
63789
64740
|
${numberRef(dataset.range)}
|
|
63790
64741
|
</c:val>
|
|
63791
64742
|
</c:ser>
|
|
63792
|
-
|
|
64743
|
+
`;
|
|
64744
|
+
if (dataset.rightYAxis) {
|
|
64745
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64746
|
+
}
|
|
64747
|
+
else {
|
|
64748
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64749
|
+
}
|
|
63793
64750
|
}
|
|
63794
|
-
// Excel does not support this feature
|
|
63795
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63796
64751
|
const grouping = chart.stacked ? "stacked" : "standard";
|
|
63797
64752
|
return escapeXml /*xml*/ `
|
|
63798
|
-
|
|
63799
|
-
|
|
63800
|
-
|
|
63801
|
-
|
|
63802
|
-
|
|
63803
|
-
|
|
63804
|
-
|
|
63805
|
-
|
|
63806
|
-
|
|
63807
|
-
|
|
64753
|
+
${leftDataSetsNodes.length
|
|
64754
|
+
? escapeXml /*xml*/ `
|
|
64755
|
+
<c:lineChart>
|
|
64756
|
+
<c:grouping val="${grouping}"/>
|
|
64757
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64758
|
+
<c:varyColors val="0"/>
|
|
64759
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64760
|
+
<c:axId val="${catAxId}" />
|
|
64761
|
+
<c:axId val="${valAxId}" />
|
|
64762
|
+
</c:lineChart>
|
|
64763
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64764
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64765
|
+
`
|
|
64766
|
+
: ""}
|
|
64767
|
+
${rightDataSetsNodes.length
|
|
64768
|
+
? escapeXml /*xml*/ `
|
|
64769
|
+
<c:lineChart>
|
|
64770
|
+
<c:grouping val="${grouping}"/>
|
|
64771
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64772
|
+
<c:varyColors val="0"/>
|
|
64773
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64774
|
+
<c:axId val="${catAxId + 1}" />
|
|
64775
|
+
<c:axId val="${valAxId + 1}" />
|
|
64776
|
+
</c:lineChart>
|
|
64777
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64778
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64779
|
+
`
|
|
64780
|
+
: ""}
|
|
63808
64781
|
`;
|
|
63809
64782
|
}
|
|
63810
64783
|
function addScatterChart(chart) {
|
|
63811
|
-
const
|
|
63812
|
-
const
|
|
64784
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64785
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64786
|
+
const leftDataSetsNodes = [];
|
|
64787
|
+
const rightDataSetsNodes = [];
|
|
63813
64788
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
63814
|
-
|
|
64789
|
+
const color = toXlsxHexColor(colors.next());
|
|
64790
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63815
64791
|
<c:ser>
|
|
63816
64792
|
<c:idx val="${dsIndex}"/>
|
|
63817
64793
|
<c:order val="${dsIndex}"/>
|
|
@@ -63826,8 +64802,9 @@ function addScatterChart(chart) {
|
|
|
63826
64802
|
<c:marker>
|
|
63827
64803
|
<c:symbol val="circle" />
|
|
63828
64804
|
<c:size val="5"/>
|
|
63829
|
-
${shapeProperty({ backgroundColor:
|
|
64805
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
63830
64806
|
</c:marker>
|
|
64807
|
+
${extractDataSetLabel(dataset.label)}
|
|
63831
64808
|
${chart.labelRange
|
|
63832
64809
|
? escapeXml /*xml*/ `<c:xVal> <!-- x-coordinate values -->
|
|
63833
64810
|
${numberRef(chart.labelRange)}
|
|
@@ -63837,24 +64814,46 @@ function addScatterChart(chart) {
|
|
|
63837
64814
|
${numberRef(dataset.range)}
|
|
63838
64815
|
</c:yVal>
|
|
63839
64816
|
</c:ser>
|
|
63840
|
-
|
|
64817
|
+
`;
|
|
64818
|
+
if (dataset.rightYAxis) {
|
|
64819
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64820
|
+
}
|
|
64821
|
+
else {
|
|
64822
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64823
|
+
}
|
|
63841
64824
|
}
|
|
63842
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63843
64825
|
return escapeXml /*xml*/ `
|
|
63844
|
-
|
|
63845
|
-
|
|
63846
|
-
<c:
|
|
63847
|
-
|
|
63848
|
-
|
|
63849
|
-
|
|
63850
|
-
|
|
63851
|
-
|
|
63852
|
-
|
|
63853
|
-
|
|
63854
|
-
|
|
64826
|
+
${leftDataSetsNodes.length
|
|
64827
|
+
? escapeXml /*xml*/ `
|
|
64828
|
+
<c:scatterChart>
|
|
64829
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64830
|
+
<c:varyColors val="0"/>
|
|
64831
|
+
<c:scatterStyle val="lineMarker"/>
|
|
64832
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64833
|
+
<c:axId val="${catAxId}" />
|
|
64834
|
+
<c:axId val="${valAxId}" />
|
|
64835
|
+
</c:scatterChart>
|
|
64836
|
+
${addAx("b", "c:valAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64837
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64838
|
+
`
|
|
64839
|
+
: ""}
|
|
64840
|
+
${rightDataSetsNodes.length
|
|
64841
|
+
? escapeXml /*xml*/ `
|
|
64842
|
+
<c:scatterChart>
|
|
64843
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64844
|
+
<c:varyColors val="0"/>
|
|
64845
|
+
<c:scatterStyle val="lineMarker"/>
|
|
64846
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64847
|
+
<c:axId val="${catAxId + 1}" />
|
|
64848
|
+
<c:axId val="${valAxId + 1}" />
|
|
64849
|
+
</c:scatterChart>
|
|
64850
|
+
${addAx("b", "c:valAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64851
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64852
|
+
`
|
|
64853
|
+
: ""}`;
|
|
63855
64854
|
}
|
|
63856
64855
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
63857
|
-
const colors = new
|
|
64856
|
+
const colors = new ColorGenerator();
|
|
63858
64857
|
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
63859
64858
|
const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
|
|
63860
64859
|
const dataSetsNodes = [];
|
|
@@ -63878,7 +64877,7 @@ function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSiz
|
|
|
63878
64877
|
<c:ser>
|
|
63879
64878
|
<c:idx val="${dsIndex}"/>
|
|
63880
64879
|
<c:order val="${dsIndex}"/>
|
|
63881
|
-
${
|
|
64880
|
+
${extractDataSetLabel(dataset.label)}
|
|
63882
64881
|
${joinXmlNodes(dataPoints)}
|
|
63883
64882
|
${insertDataLabels({ showLeaderLines: true })}
|
|
63884
64883
|
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
@@ -63910,14 +64909,16 @@ function insertDataLabels({ showLeaderLines } = { showLeaderLines: false }) {
|
|
|
63910
64909
|
</dLbls>
|
|
63911
64910
|
`;
|
|
63912
64911
|
}
|
|
63913
|
-
function addAx(position, axisName, axId, crossAxId,
|
|
64912
|
+
function addAx(position, axisName, axId, crossAxId, title, defaultFontColor, deleteAxis = 0) {
|
|
63914
64913
|
// Each Axis present inside a graph needs to be identified by an unsigned integer in order to be referenced by its crossAxis.
|
|
63915
64914
|
// I.e. x-axis, will reference y-axis and vice-versa.
|
|
64915
|
+
const color = title?.color ? toXlsxHexColor(title.color) : defaultFontColor;
|
|
63916
64916
|
return escapeXml /*xml*/ `
|
|
63917
64917
|
<${axisName}>
|
|
63918
64918
|
<c:axId val="${axId}"/>
|
|
63919
64919
|
<c:crossAx val="${crossAxId}"/> <!-- reference to the other axe of the chart -->
|
|
63920
|
-
<c:
|
|
64920
|
+
<c:crosses val="${position === "b" || position === "l" ? "min" : "max"}"/>
|
|
64921
|
+
<c:delete val="${deleteAxis}"/> <!-- by default, axis are not displayed -->
|
|
63921
64922
|
<c:scaling>
|
|
63922
64923
|
<c:orientation val="minMax" />
|
|
63923
64924
|
</c:scaling>
|
|
@@ -63927,9 +64928,9 @@ function addAx(position, axisName, axId, crossAxId, { fontColor }) {
|
|
|
63927
64928
|
<c:minorTickMark val="none" />
|
|
63928
64929
|
<c:numFmt formatCode="General" sourceLinked="1" />
|
|
63929
64930
|
<c:title>
|
|
63930
|
-
${insertText("")}
|
|
64931
|
+
${insertText(title?.text ?? "", color, 10, title)}
|
|
63931
64932
|
</c:title>
|
|
63932
|
-
${insertTextProperties(10,
|
|
64933
|
+
${insertTextProperties(10, defaultFontColor)}
|
|
63933
64934
|
</${axisName}>
|
|
63934
64935
|
<!-- <tickLblPos/> omitted -->
|
|
63935
64936
|
`;
|
|
@@ -64810,7 +65811,11 @@ function addRows(construct, data, sheet) {
|
|
|
64810
65811
|
let cellNode = escapeXml ``;
|
|
64811
65812
|
// Either formula or static value inside the cell
|
|
64812
65813
|
if (cell.isFormula) {
|
|
64813
|
-
|
|
65814
|
+
const res = addFormula(cell);
|
|
65815
|
+
if (!res) {
|
|
65816
|
+
continue;
|
|
65817
|
+
}
|
|
65818
|
+
({ attrs: additionalAttrs, node: cellNode } = res);
|
|
64814
65819
|
}
|
|
64815
65820
|
else if (cell.content && isMarkdownLink(cell.content)) {
|
|
64816
65821
|
const { label } = parseMarkdownLink(cell.content);
|
|
@@ -65816,13 +66821,14 @@ const helpers = {
|
|
|
65816
66821
|
UuidGenerator,
|
|
65817
66822
|
formatValue,
|
|
65818
66823
|
createCurrencyFormat,
|
|
66824
|
+
ColorGenerator,
|
|
65819
66825
|
computeTextWidth,
|
|
65820
66826
|
createEmptyWorkbookData,
|
|
65821
66827
|
createEmptySheet,
|
|
65822
66828
|
createEmptyExcelSheet,
|
|
65823
66829
|
getDefaultChartJsRuntime,
|
|
65824
66830
|
chartFontColor,
|
|
65825
|
-
|
|
66831
|
+
getChartAxisTitleRuntime,
|
|
65826
66832
|
getFillingMode,
|
|
65827
66833
|
rgbaToHex,
|
|
65828
66834
|
colorToRGBA,
|
|
@@ -65879,9 +66885,10 @@ const components = {
|
|
|
65879
66885
|
GridOverlay,
|
|
65880
66886
|
ScorecardChart,
|
|
65881
66887
|
LineConfigPanel,
|
|
65882
|
-
GenericChartDesignPanel,
|
|
65883
66888
|
BarConfigPanel,
|
|
66889
|
+
PieChartDesignPanel,
|
|
65884
66890
|
GenericChartConfigPanel,
|
|
66891
|
+
ChartWithAxisDesignPanel,
|
|
65885
66892
|
GaugeChartConfigPanel,
|
|
65886
66893
|
GaugeChartDesignPanel,
|
|
65887
66894
|
ScorecardChartConfigPanel,
|
|
@@ -65937,6 +66944,6 @@ const constants = {
|
|
|
65937
66944
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
65938
66945
|
|
|
65939
66946
|
|
|
65940
|
-
__info__.version = "17.3.
|
|
65941
|
-
__info__.date = "2024-
|
|
65942
|
-
__info__.hash = "
|
|
66947
|
+
__info__.version = "17.3.1";
|
|
66948
|
+
__info__.date = "2024-06-03T15:28:03.284Z";
|
|
66949
|
+
__info__.hash = "605d098";
|