@odoo/o-spreadsheet 17.3.0-alpha.9 → 17.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +1600 -603
- package/dist/o-spreadsheet.d.ts +425 -199
- package/dist/o-spreadsheet.esm.js +1600 -603
- package/dist/o-spreadsheet.iife.js +1600 -603
- package/dist/o-spreadsheet.iife.min.js +550 -392
- package/dist/o_spreadsheet.xml +479 -381
- package/package.json +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.0
|
|
7
|
-
* @date 2024-05-
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.3.0
|
|
7
|
+
* @date 2024-05-31T14:21:26.547Z
|
|
8
|
+
* @hash 271202e
|
|
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);
|
|
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);
|
|
@@ -36710,14 +37464,15 @@ class FigureComponent extends Component {
|
|
|
36710
37464
|
}
|
|
36711
37465
|
onKeyDown(ev) {
|
|
36712
37466
|
const figure = this.props.figure;
|
|
36713
|
-
|
|
37467
|
+
const keyDownShortcut = keyboardEventToShortcutString(ev);
|
|
37468
|
+
switch (keyDownShortcut) {
|
|
36714
37469
|
case "Delete":
|
|
37470
|
+
case "Backspace":
|
|
36715
37471
|
this.env.model.dispatch("DELETE_FIGURE", {
|
|
36716
37472
|
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
36717
37473
|
id: figure.id,
|
|
36718
37474
|
});
|
|
36719
37475
|
this.props.onFigureDeleted();
|
|
36720
|
-
ev.stopPropagation();
|
|
36721
37476
|
ev.preventDefault();
|
|
36722
37477
|
ev.stopPropagation();
|
|
36723
37478
|
break;
|
|
@@ -36738,7 +37493,22 @@ class FigureComponent extends Component {
|
|
|
36738
37493
|
x: figure.x + delta[0],
|
|
36739
37494
|
y: figure.y + delta[1],
|
|
36740
37495
|
});
|
|
37496
|
+
ev.preventDefault();
|
|
37497
|
+
ev.stopPropagation();
|
|
37498
|
+
break;
|
|
37499
|
+
case "Ctrl+A":
|
|
37500
|
+
// Maybe in the future we will implement a way to select all figures
|
|
37501
|
+
ev.preventDefault();
|
|
36741
37502
|
ev.stopPropagation();
|
|
37503
|
+
break;
|
|
37504
|
+
case "Ctrl+Y":
|
|
37505
|
+
case "Ctrl+Z":
|
|
37506
|
+
if (keyDownShortcut === "Ctrl+Y") {
|
|
37507
|
+
this.env.model.dispatch("REQUEST_REDO");
|
|
37508
|
+
}
|
|
37509
|
+
else if (keyDownShortcut === "Ctrl+Z") {
|
|
37510
|
+
this.env.model.dispatch("REQUEST_UNDO");
|
|
37511
|
+
}
|
|
36742
37512
|
ev.preventDefault();
|
|
36743
37513
|
ev.stopPropagation();
|
|
36744
37514
|
break;
|
|
@@ -38018,9 +38788,6 @@ class FilterIcon extends Component {
|
|
|
38018
38788
|
|
|
38019
38789
|
class FilterIconsOverlay extends Component {
|
|
38020
38790
|
static template = "o-spreadsheet-FilterIconsOverlay";
|
|
38021
|
-
static props = {
|
|
38022
|
-
onMouseDown: Function,
|
|
38023
|
-
};
|
|
38024
38791
|
static components = {
|
|
38025
38792
|
GridCellIcon,
|
|
38026
38793
|
FilterIcon,
|
|
@@ -38260,6 +39027,7 @@ class GridOverlay extends Component {
|
|
|
38260
39027
|
};
|
|
38261
39028
|
gridOverlay = useRef("gridOverlay");
|
|
38262
39029
|
gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
|
|
39030
|
+
cellPopovers;
|
|
38263
39031
|
setup() {
|
|
38264
39032
|
useCellHovered(this.env, this.gridOverlay, this.props.onCellHovered);
|
|
38265
39033
|
const resizeObserver = new ResizeObserver(() => {
|
|
@@ -38281,6 +39049,7 @@ class GridOverlay extends Component {
|
|
|
38281
39049
|
const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
|
|
38282
39050
|
return scrollY > 0;
|
|
38283
39051
|
});
|
|
39052
|
+
this.cellPopovers = useStore(CellPopoverStore);
|
|
38284
39053
|
}
|
|
38285
39054
|
get gridOverlayEl() {
|
|
38286
39055
|
if (!this.gridOverlay.el) {
|
|
@@ -38294,16 +39063,18 @@ class GridOverlay extends Component {
|
|
|
38294
39063
|
get isPaintingFormat() {
|
|
38295
39064
|
return this.env.model.getters.isPaintingFormat();
|
|
38296
39065
|
}
|
|
38297
|
-
onMouseDown(ev
|
|
39066
|
+
onMouseDown(ev) {
|
|
38298
39067
|
if (ev.button > 0) {
|
|
38299
39068
|
// not main button, probably a context menu
|
|
38300
39069
|
return;
|
|
38301
39070
|
}
|
|
39071
|
+
if (ev.target === this.gridOverlay.el && this.cellPopovers.isOpen) {
|
|
39072
|
+
this.cellPopovers.close();
|
|
39073
|
+
}
|
|
38302
39074
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
38303
39075
|
this.props.onCellClicked(col, row, {
|
|
38304
39076
|
expandZone: ev.shiftKey,
|
|
38305
39077
|
addZone: isCtrlKey(ev),
|
|
38306
|
-
closePopover: modifiers?.closePopover ?? true,
|
|
38307
39078
|
});
|
|
38308
39079
|
}
|
|
38309
39080
|
onDoubleClick(ev) {
|
|
@@ -40447,9 +41218,6 @@ class Grid extends Component {
|
|
|
40447
41218
|
// Zone selection with mouse
|
|
40448
41219
|
// ---------------------------------------------------------------------------
|
|
40449
41220
|
onCellClicked(col, row, modifiers) {
|
|
40450
|
-
if (modifiers.closePopover && this.cellPopovers.isOpen) {
|
|
40451
|
-
this.cellPopovers.close();
|
|
40452
|
-
}
|
|
40453
41221
|
if (this.composerStore.editionMode === "editing") {
|
|
40454
41222
|
this.composerStore.stopEdition();
|
|
40455
41223
|
}
|
|
@@ -42322,11 +43090,20 @@ function isImageData(data) {
|
|
|
42322
43090
|
return "imageSrc" in data;
|
|
42323
43091
|
}
|
|
42324
43092
|
function convertChartData(chartData) {
|
|
42325
|
-
const dataSetsHaveTitle = chartData.dataSets
|
|
43093
|
+
const dataSetsHaveTitle = chartData.dataSets.some((ds) => "reference" in (ds.label ?? {}));
|
|
42326
43094
|
const labelRange = chartData.labelRange
|
|
42327
43095
|
? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
|
|
42328
43096
|
: undefined;
|
|
42329
|
-
|
|
43097
|
+
const dataSets = chartData.dataSets.map((data) => {
|
|
43098
|
+
let label = undefined;
|
|
43099
|
+
if (data.label && "text" in data.label) {
|
|
43100
|
+
label = data.label.text;
|
|
43101
|
+
}
|
|
43102
|
+
return {
|
|
43103
|
+
dataRange: convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle),
|
|
43104
|
+
label,
|
|
43105
|
+
};
|
|
43106
|
+
});
|
|
42330
43107
|
// For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
|
|
42331
43108
|
if (chartData.type === "pie") {
|
|
42332
43109
|
dataSets.reverse();
|
|
@@ -42335,10 +43112,9 @@ function convertChartData(chartData) {
|
|
|
42335
43112
|
dataSets,
|
|
42336
43113
|
dataSetsHaveTitle,
|
|
42337
43114
|
labelRange,
|
|
42338
|
-
title: chartData.title
|
|
43115
|
+
title: chartData.title ?? { text: "" },
|
|
42339
43116
|
type: chartData.type,
|
|
42340
43117
|
background: convertColor({ rgb: chartData.backgroundColor }) || "#FFFFFF",
|
|
42341
|
-
verticalAxisPosition: chartData.verticalAxisPosition,
|
|
42342
43118
|
legendPosition: chartData.legendPosition,
|
|
42343
43119
|
stacked: chartData.stacked || false,
|
|
42344
43120
|
aggregated: false,
|
|
@@ -43453,25 +44229,20 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43453
44229
|
return this.extractComboChart(rootChartElement);
|
|
43454
44230
|
}
|
|
43455
44231
|
// 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) => {
|
|
44232
|
+
const chartTitle = this.mapOnElements({ parent: rootChartElement, query: "c:chart > c:title a:t" }, (textElement) => {
|
|
43457
44233
|
return textElement.textContent || "";
|
|
43458
44234
|
}).join("");
|
|
43459
44235
|
const barChartGrouping = this.extractChildAttr(rootChartElement, "c:grouping", "val", {
|
|
43460
44236
|
default: "clustered",
|
|
43461
44237
|
}).asString();
|
|
43462
44238
|
return {
|
|
43463
|
-
title: chartTitle,
|
|
44239
|
+
title: { text: chartTitle },
|
|
43464
44240
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
43465
|
-
dataSets: this.extractChartDatasets(this.
|
|
44241
|
+
dataSets: this.extractChartDatasets(this.querySelectorAll(rootChartElement, `c:${chartType}`), chartType),
|
|
43466
44242
|
labelRange: this.extractChildTextContent(rootChartElement, `c:ser ${chartType === "scatterChart" ? "c:numRef" : "c:cat"} c:f`),
|
|
43467
44243
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
43468
44244
|
default: "ffffff",
|
|
43469
44245
|
}).asString(),
|
|
43470
|
-
verticalAxisPosition: this.extractChildAttr(rootChartElement, "c:valAx > c:axPos", "val", {
|
|
43471
|
-
default: "l",
|
|
43472
|
-
}).asString() === "r"
|
|
43473
|
-
? "right"
|
|
43474
|
-
: "left",
|
|
43475
44246
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
|
|
43476
44247
|
default: "b",
|
|
43477
44248
|
}).asString()],
|
|
@@ -43489,21 +44260,16 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43489
44260
|
default: "clustered",
|
|
43490
44261
|
}).asString();
|
|
43491
44262
|
return {
|
|
43492
|
-
title: chartTitle,
|
|
44263
|
+
title: { text: chartTitle },
|
|
43493
44264
|
type: "combo",
|
|
43494
44265
|
dataSets: [
|
|
43495
|
-
...this.extractChartDatasets(this.
|
|
43496
|
-
...this.extractChartDatasets(this.
|
|
44266
|
+
...this.extractChartDatasets(this.querySelectorAll(chartElement, `c:barChart`), "comboChart"),
|
|
44267
|
+
...this.extractChartDatasets(this.querySelectorAll(chartElement, `c:lineChart`), "comboChart"),
|
|
43497
44268
|
],
|
|
43498
44269
|
labelRange: this.extractChildTextContent(chartElement, "c:ser c:cat c:f"),
|
|
43499
44270
|
backgroundColor: this.extractChildAttr(chartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
43500
44271
|
default: "ffffff",
|
|
43501
44272
|
}).asString(),
|
|
43502
|
-
verticalAxisPosition: this.extractChildAttr(chartElement, "c:valAx > c:axPos", "val", {
|
|
43503
|
-
default: "l",
|
|
43504
|
-
}).asString() === "r"
|
|
43505
|
-
? "right"
|
|
43506
|
-
: "left",
|
|
43507
44273
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
|
|
43508
44274
|
default: "b",
|
|
43509
44275
|
}).asString()],
|
|
@@ -43511,21 +44277,49 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
43511
44277
|
fontColor: "000000",
|
|
43512
44278
|
};
|
|
43513
44279
|
}
|
|
43514
|
-
extractChartDatasets(
|
|
43515
|
-
|
|
43516
|
-
|
|
43517
|
-
|
|
43518
|
-
|
|
43519
|
-
|
|
43520
|
-
|
|
43521
|
-
|
|
43522
|
-
|
|
43523
|
-
|
|
44280
|
+
extractChartDatasets(chartElements, chartType) {
|
|
44281
|
+
return Array.from(chartElements)
|
|
44282
|
+
.map((element) => {
|
|
44283
|
+
if (chartType === "scatterChart") {
|
|
44284
|
+
return this.extractScatterChartDatasets(element);
|
|
44285
|
+
}
|
|
44286
|
+
return this.mapOnElements({ parent: element, query: "c:ser" }, (chartDataElement) => {
|
|
44287
|
+
let label = {};
|
|
44288
|
+
const reference = this.extractChildTextContent(chartDataElement, "c:tx c:f");
|
|
44289
|
+
if (reference) {
|
|
44290
|
+
label = { reference };
|
|
44291
|
+
}
|
|
44292
|
+
else {
|
|
44293
|
+
const text = this.extractChildTextContent(chartDataElement, "c:tx c:v");
|
|
44294
|
+
if (text) {
|
|
44295
|
+
label = { text };
|
|
44296
|
+
}
|
|
44297
|
+
}
|
|
44298
|
+
return {
|
|
44299
|
+
label,
|
|
44300
|
+
range: this.extractChildTextContent(chartDataElement, "c:val c:f", {
|
|
44301
|
+
required: true,
|
|
44302
|
+
}),
|
|
44303
|
+
};
|
|
44304
|
+
});
|
|
44305
|
+
})
|
|
44306
|
+
.flat();
|
|
43524
44307
|
}
|
|
43525
44308
|
extractScatterChartDatasets(chartElement) {
|
|
43526
44309
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
44310
|
+
let label = {};
|
|
44311
|
+
const reference = this.extractChildTextContent(chartDataElement, "c:tx c:f");
|
|
44312
|
+
if (reference) {
|
|
44313
|
+
label = { reference };
|
|
44314
|
+
}
|
|
44315
|
+
else {
|
|
44316
|
+
const text = this.extractChildTextContent(chartDataElement, "c:tx c:v");
|
|
44317
|
+
if (text) {
|
|
44318
|
+
label = { text };
|
|
44319
|
+
}
|
|
44320
|
+
}
|
|
43527
44321
|
return {
|
|
43528
|
-
label
|
|
44322
|
+
label,
|
|
43529
44323
|
range: this.extractChildTextContent(chartDataElement, "c:yVal c:f", { required: true }),
|
|
43530
44324
|
};
|
|
43531
44325
|
});
|
|
@@ -44257,7 +45051,7 @@ function getRelationFile(file, xmls) {
|
|
|
44257
45051
|
return relsFile;
|
|
44258
45052
|
}
|
|
44259
45053
|
|
|
44260
|
-
const EXCEL_IMPORT_VERSION =
|
|
45054
|
+
const EXCEL_IMPORT_VERSION = 16;
|
|
44261
45055
|
class XlsxReader {
|
|
44262
45056
|
warningManager;
|
|
44263
45057
|
xmls;
|
|
@@ -44735,6 +45529,30 @@ const MIGRATIONS = [
|
|
|
44735
45529
|
return data;
|
|
44736
45530
|
},
|
|
44737
45531
|
},
|
|
45532
|
+
{
|
|
45533
|
+
description: "transform chart data structure (2)",
|
|
45534
|
+
from: 16,
|
|
45535
|
+
to: 17,
|
|
45536
|
+
applyMigration(data) {
|
|
45537
|
+
for (const sheet of data.sheets || []) {
|
|
45538
|
+
for (const f in sheet.figures || []) {
|
|
45539
|
+
const figure = sheet.figures[f];
|
|
45540
|
+
if ("title" in figure.data && typeof figure.data.title === "string") {
|
|
45541
|
+
figure.data.title = { text: figure.data.title };
|
|
45542
|
+
}
|
|
45543
|
+
const figureType = figure.data.type;
|
|
45544
|
+
if (!["line", "bar", "pie", "scatter", "waterfall", "combo"].includes(figureType)) {
|
|
45545
|
+
continue;
|
|
45546
|
+
}
|
|
45547
|
+
const { dataSets, ...newData } = sheet.figures[f].data;
|
|
45548
|
+
const newDataSets = dataSets.map((dataRange) => ({ dataRange }));
|
|
45549
|
+
newData.dataSets = newDataSets;
|
|
45550
|
+
sheet.figures[f].data = newData;
|
|
45551
|
+
}
|
|
45552
|
+
}
|
|
45553
|
+
return data;
|
|
45554
|
+
},
|
|
45555
|
+
},
|
|
44738
45556
|
];
|
|
44739
45557
|
/**
|
|
44740
45558
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -48346,6 +49164,9 @@ class RangeAdapter {
|
|
|
48346
49164
|
if (range.invalidXc) {
|
|
48347
49165
|
return range.invalidXc;
|
|
48348
49166
|
}
|
|
49167
|
+
if (!this.getters.tryGetSheet(range.sheetId)) {
|
|
49168
|
+
return CellErrorType.InvalidReference;
|
|
49169
|
+
}
|
|
48349
49170
|
if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
|
|
48350
49171
|
return CellErrorType.InvalidReference;
|
|
48351
49172
|
}
|
|
@@ -51764,7 +52585,6 @@ class PositionSet {
|
|
|
51764
52585
|
*
|
|
51765
52586
|
*/
|
|
51766
52587
|
class SpreadingRelation {
|
|
51767
|
-
createEmptyPositionSet;
|
|
51768
52588
|
/**
|
|
51769
52589
|
* Internal structure:
|
|
51770
52590
|
* For something like
|
|
@@ -51795,9 +52615,6 @@ class SpreadingRelation {
|
|
|
51795
52615
|
*/
|
|
51796
52616
|
resultsToArrayFormulas = new PositionMap();
|
|
51797
52617
|
arrayFormulasToResults = new PositionMap();
|
|
51798
|
-
constructor(createEmptyPositionSet) {
|
|
51799
|
-
this.createEmptyPositionSet = createEmptyPositionSet;
|
|
51800
|
-
}
|
|
51801
52618
|
getFormulaPositionsSpreadingOn(resultPosition) {
|
|
51802
52619
|
return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
|
|
51803
52620
|
}
|
|
@@ -51816,13 +52633,13 @@ class SpreadingRelation {
|
|
|
51816
52633
|
*/
|
|
51817
52634
|
addRelation({ arrayFormulaPosition, resultPosition, }) {
|
|
51818
52635
|
if (!this.resultsToArrayFormulas.has(resultPosition)) {
|
|
51819
|
-
this.resultsToArrayFormulas.set(resultPosition,
|
|
52636
|
+
this.resultsToArrayFormulas.set(resultPosition, []);
|
|
51820
52637
|
}
|
|
51821
|
-
this.resultsToArrayFormulas.get(resultPosition)?.
|
|
52638
|
+
this.resultsToArrayFormulas.get(resultPosition)?.push(arrayFormulaPosition);
|
|
51822
52639
|
if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
|
|
51823
|
-
this.arrayFormulasToResults.set(arrayFormulaPosition,
|
|
52640
|
+
this.arrayFormulasToResults.set(arrayFormulaPosition, []);
|
|
51824
52641
|
}
|
|
51825
|
-
this.arrayFormulasToResults.get(arrayFormulaPosition)?.
|
|
52642
|
+
this.arrayFormulasToResults.get(arrayFormulaPosition)?.push(resultPosition);
|
|
51826
52643
|
}
|
|
51827
52644
|
hasArrayFormulaResult(position) {
|
|
51828
52645
|
return this.resultsToArrayFormulas.has(position);
|
|
@@ -51843,7 +52660,7 @@ class Evaluator {
|
|
|
51843
52660
|
evaluatedCells = new PositionMap();
|
|
51844
52661
|
formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
|
|
51845
52662
|
blockedArrayFormulas = new PositionSet({});
|
|
51846
|
-
spreadingRelations = new SpreadingRelation(
|
|
52663
|
+
spreadingRelations = new SpreadingRelation();
|
|
51847
52664
|
constructor(context, getters) {
|
|
51848
52665
|
this.context = context;
|
|
51849
52666
|
this.getters = getters;
|
|
@@ -51937,7 +52754,7 @@ class Evaluator {
|
|
|
51937
52754
|
}
|
|
51938
52755
|
buildDependencyGraph() {
|
|
51939
52756
|
this.blockedArrayFormulas = this.createEmptyPositionSet();
|
|
51940
|
-
this.spreadingRelations = new SpreadingRelation(
|
|
52757
|
+
this.spreadingRelations = new SpreadingRelation();
|
|
51941
52758
|
this.formulaDependencies = lazy(() => {
|
|
51942
52759
|
const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
|
|
51943
52760
|
.filter((range) => !range.invalidSheetName && !range.invalidXc)
|
|
@@ -52069,6 +52886,7 @@ class Evaluator {
|
|
|
52069
52886
|
const nbColumns = formulaReturn.length;
|
|
52070
52887
|
const nbRows = formulaReturn[0].length;
|
|
52071
52888
|
forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
|
|
52889
|
+
this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
|
|
52072
52890
|
forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
|
|
52073
52891
|
forEachSpreadPositionInMatrix(nbColumns, nbRows,
|
|
52074
52892
|
// thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
|
|
@@ -52091,6 +52909,18 @@ class Evaluator {
|
|
|
52091
52909
|
}
|
|
52092
52910
|
throw new SplillBlockedError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
|
|
52093
52911
|
}
|
|
52912
|
+
assertNoMergedCellsInSpreadZone({ sheetId, col, row }, matrixResult) {
|
|
52913
|
+
const mergedCells = this.getters.getMergesInZone(sheetId, {
|
|
52914
|
+
top: row,
|
|
52915
|
+
bottom: row + matrixResult.length,
|
|
52916
|
+
left: col,
|
|
52917
|
+
right: col + matrixResult[0].length,
|
|
52918
|
+
});
|
|
52919
|
+
if (mergedCells.length === 0) {
|
|
52920
|
+
return;
|
|
52921
|
+
}
|
|
52922
|
+
throw new SplillBlockedError(_t("Merged cells found in the spill zone. Please unmerge cells before using array formulas."));
|
|
52923
|
+
}
|
|
52094
52924
|
updateSpreadRelation({ sheetId, col, row, }) {
|
|
52095
52925
|
const arrayFormulaPosition = { sheetId, col, row };
|
|
52096
52926
|
return (i, j) => {
|
|
@@ -52328,10 +53158,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
52328
53158
|
this.evaluator.updateDependencies(cmd);
|
|
52329
53159
|
}
|
|
52330
53160
|
break;
|
|
52331
|
-
case "DUPLICATE_SHEET":
|
|
52332
|
-
case "CREATE_SHEET":
|
|
52333
|
-
this.shouldRebuildDependenciesGraph = true;
|
|
52334
|
-
break;
|
|
52335
53161
|
case "EVALUATE_CELLS":
|
|
52336
53162
|
this.evaluator.evaluateAllCells();
|
|
52337
53163
|
break;
|
|
@@ -52432,16 +53258,22 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
52432
53258
|
let newContent = undefined;
|
|
52433
53259
|
let newFormat = undefined;
|
|
52434
53260
|
let isExported = true;
|
|
53261
|
+
const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
|
|
52435
53262
|
const formulaCell = this.getCorrespondingFormulaCell(position);
|
|
52436
53263
|
if (formulaCell) {
|
|
52437
53264
|
isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
|
|
52438
53265
|
isFormula = isExported;
|
|
52439
53266
|
if (!isExported) {
|
|
52440
|
-
|
|
52441
|
-
|
|
53267
|
+
// If the cell contains a non-exported formula and that is evaluates to
|
|
53268
|
+
// nothing* ,we don't export it.
|
|
53269
|
+
// * non-falsy value are relevant and so are 0 and FALSE, which only leaves
|
|
53270
|
+
// the empty string.
|
|
53271
|
+
if (value !== "") {
|
|
53272
|
+
newContent = (value ?? "").toString();
|
|
53273
|
+
newFormat = evaluatedCell.format;
|
|
53274
|
+
}
|
|
52442
53275
|
}
|
|
52443
53276
|
}
|
|
52444
|
-
const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
|
|
52445
53277
|
const exportedCellData = exportedSheetData.cells[xc] || {};
|
|
52446
53278
|
const format = newFormat
|
|
52447
53279
|
? getItemId(newFormat, data.formats)
|
|
@@ -57064,7 +57896,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57064
57896
|
paintFormatStatus = "inactive";
|
|
57065
57897
|
originSheetId;
|
|
57066
57898
|
copiedData;
|
|
57067
|
-
_isCutOperation;
|
|
57899
|
+
_isCutOperation = false;
|
|
57068
57900
|
// ---------------------------------------------------------------------------
|
|
57069
57901
|
// Command Handling
|
|
57070
57902
|
// ---------------------------------------------------------------------------
|
|
@@ -57076,14 +57908,17 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57076
57908
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
57077
57909
|
const copiedData = this.convertOSClipboardData(cmd.text);
|
|
57078
57910
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57079
|
-
return this.isPasteAllowed(cmd.target, copiedData, { pasteOption });
|
|
57911
|
+
return this.isPasteAllowed(cmd.target, copiedData, { pasteOption, isCutOperation: false });
|
|
57080
57912
|
}
|
|
57081
57913
|
case "PASTE": {
|
|
57082
57914
|
if (!this.copiedData) {
|
|
57083
57915
|
return "EmptyClipboard" /* CommandResult.EmptyClipboard */;
|
|
57084
57916
|
}
|
|
57085
57917
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57086
|
-
return this.isPasteAllowed(cmd.target, this.copiedData, {
|
|
57918
|
+
return this.isPasteAllowed(cmd.target, this.copiedData, {
|
|
57919
|
+
pasteOption: pasteOption,
|
|
57920
|
+
isCutOperation: this._isCutOperation,
|
|
57921
|
+
});
|
|
57087
57922
|
}
|
|
57088
57923
|
case "COPY_PASTE_CELLS_ABOVE": {
|
|
57089
57924
|
const zones = this.getters.getSelectedZones();
|
|
@@ -57101,13 +57936,13 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57101
57936
|
}
|
|
57102
57937
|
case "INSERT_CELL": {
|
|
57103
57938
|
const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57104
|
-
const copiedData = this.copy(
|
|
57105
|
-
return this.isPasteAllowed(paste, copiedData, {});
|
|
57939
|
+
const copiedData = this.copy(cut);
|
|
57940
|
+
return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
|
|
57106
57941
|
}
|
|
57107
57942
|
case "DELETE_CELL": {
|
|
57108
57943
|
const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57109
|
-
const copiedData = this.copy(
|
|
57110
|
-
return this.isPasteAllowed(paste, copiedData, {});
|
|
57944
|
+
const copiedData = this.copy(cut);
|
|
57945
|
+
return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
|
|
57111
57946
|
}
|
|
57112
57947
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
57113
57948
|
if (this.paintFormatStatus !== "inactive") {
|
|
@@ -57125,23 +57960,27 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57125
57960
|
const zones = this.getters.getSelectedZones();
|
|
57126
57961
|
this.status = "visible";
|
|
57127
57962
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57128
|
-
this.copiedData = this.copy(
|
|
57963
|
+
this.copiedData = this.copy(zones);
|
|
57964
|
+
this._isCutOperation = cmd.type === "CUT";
|
|
57129
57965
|
break;
|
|
57130
57966
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
57967
|
+
this._isCutOperation = false;
|
|
57131
57968
|
this.copiedData = this.convertOSClipboardData(cmd.text);
|
|
57132
57969
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57133
|
-
this.paste(cmd.target, {
|
|
57970
|
+
this.paste(cmd.target, this.copiedData, {
|
|
57134
57971
|
pasteOption,
|
|
57135
57972
|
selectTarget: true,
|
|
57973
|
+
isCutOperation: false,
|
|
57136
57974
|
});
|
|
57137
57975
|
this.status = "invisible";
|
|
57138
57976
|
break;
|
|
57139
57977
|
}
|
|
57140
57978
|
case "PASTE": {
|
|
57141
57979
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
57142
|
-
this.paste(cmd.target, {
|
|
57980
|
+
this.paste(cmd.target, this.copiedData, {
|
|
57143
57981
|
pasteOption,
|
|
57144
57982
|
selectTarget: true,
|
|
57983
|
+
isCutOperation: this._isCutOperation,
|
|
57145
57984
|
});
|
|
57146
57985
|
if (this.paintFormatStatus === "oneOff") {
|
|
57147
57986
|
this.paintFormatStatus = "inactive";
|
|
@@ -57162,9 +58001,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57162
58001
|
top: multipleRowsInSelection ? zone.top : zone.top - 1,
|
|
57163
58002
|
};
|
|
57164
58003
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57165
|
-
|
|
57166
|
-
this.paste([zone], {
|
|
57167
|
-
|
|
58004
|
+
const copiedData = this.copy([copyTarget]);
|
|
58005
|
+
this.paste([zone], copiedData, {
|
|
58006
|
+
isCutOperation: false,
|
|
57168
58007
|
selectTarget: true,
|
|
57169
58008
|
});
|
|
57170
58009
|
}
|
|
@@ -57179,9 +58018,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57179
58018
|
left: multipleColsInSelection ? zone.left : zone.left - 1,
|
|
57180
58019
|
};
|
|
57181
58020
|
this.originSheetId = this.getters.getActiveSheetId();
|
|
57182
|
-
|
|
57183
|
-
this.paste([zone], {
|
|
57184
|
-
|
|
58021
|
+
const copiedData = this.copy([copyTarget]);
|
|
58022
|
+
this.paste([zone], copiedData, {
|
|
58023
|
+
isCutOperation: false,
|
|
57185
58024
|
selectTarget: true,
|
|
57186
58025
|
});
|
|
57187
58026
|
}
|
|
@@ -57197,14 +58036,14 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57197
58036
|
}
|
|
57198
58037
|
break;
|
|
57199
58038
|
}
|
|
57200
|
-
|
|
57201
|
-
this.paste(paste, {});
|
|
58039
|
+
const copiedData = this.copy(cut);
|
|
58040
|
+
this.paste(paste, copiedData, { isCutOperation: true });
|
|
57202
58041
|
break;
|
|
57203
58042
|
}
|
|
57204
58043
|
case "INSERT_CELL": {
|
|
57205
58044
|
const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
|
|
57206
|
-
|
|
57207
|
-
this.paste(paste, {});
|
|
58045
|
+
const copiedData = this.copy(cut);
|
|
58046
|
+
this.paste(paste, copiedData, { isCutOperation: true });
|
|
57208
58047
|
break;
|
|
57209
58048
|
}
|
|
57210
58049
|
case "ADD_COLUMNS_ROWS": {
|
|
@@ -57236,7 +58075,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57236
58075
|
break;
|
|
57237
58076
|
}
|
|
57238
58077
|
case "REPEAT_PASTE": {
|
|
57239
|
-
this.paste(cmd.target, {
|
|
58078
|
+
this.paste(cmd.target, this.copiedData, {
|
|
58079
|
+
isCutOperation: false,
|
|
57240
58080
|
pasteOption: cmd.pasteOption,
|
|
57241
58081
|
selectTarget: true,
|
|
57242
58082
|
});
|
|
@@ -57244,7 +58084,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57244
58084
|
}
|
|
57245
58085
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
57246
58086
|
const zones = this.getters.getSelectedZones();
|
|
57247
|
-
this.copiedData = this.copy(
|
|
58087
|
+
this.copiedData = this.copy(zones);
|
|
57248
58088
|
this.status = "visible";
|
|
57249
58089
|
if (cmd.persistent) {
|
|
57250
58090
|
this.paintFormatStatus = "persistent";
|
|
@@ -57275,7 +58115,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57275
58115
|
}
|
|
57276
58116
|
}
|
|
57277
58117
|
convertOSClipboardData(clipboardData) {
|
|
57278
|
-
this._isCutOperation = false;
|
|
57279
58118
|
const handlers = clipboardHandlersRegistries.figureHandlers
|
|
57280
58119
|
.getAll()
|
|
57281
58120
|
.map((handler) => new handler(this.getters, this.dispatch));
|
|
@@ -57313,7 +58152,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57313
58152
|
for (const handler of this.selectClipboardHandlers(copiedData)) {
|
|
57314
58153
|
const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
|
|
57315
58154
|
...options,
|
|
57316
|
-
isCutOperation: this.isCutOperation(),
|
|
57317
58155
|
});
|
|
57318
58156
|
if (result !== "Success" /* CommandResult.Success */) {
|
|
57319
58157
|
return result;
|
|
@@ -57336,9 +58174,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57336
58174
|
}
|
|
57337
58175
|
return false;
|
|
57338
58176
|
}
|
|
57339
|
-
copy(
|
|
58177
|
+
copy(zones) {
|
|
57340
58178
|
let copiedData = {};
|
|
57341
|
-
this._isCutOperation = operation === "CUT";
|
|
57342
58179
|
const clipboardData = this.getClipboardData(zones);
|
|
57343
58180
|
for (const handler of this.selectClipboardHandlers(clipboardData)) {
|
|
57344
58181
|
const data = handler.copy(clipboardData);
|
|
@@ -57346,8 +58183,8 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57346
58183
|
}
|
|
57347
58184
|
return copiedData;
|
|
57348
58185
|
}
|
|
57349
|
-
paste(zones, options) {
|
|
57350
|
-
if (!
|
|
58186
|
+
paste(zones, copiedData, options) {
|
|
58187
|
+
if (!copiedData) {
|
|
57351
58188
|
return;
|
|
57352
58189
|
}
|
|
57353
58190
|
let zone = undefined;
|
|
@@ -57355,12 +58192,9 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57355
58192
|
let target = {
|
|
57356
58193
|
zones,
|
|
57357
58194
|
};
|
|
57358
|
-
const handlers = this.selectClipboardHandlers(
|
|
58195
|
+
const handlers = this.selectClipboardHandlers(copiedData);
|
|
57359
58196
|
for (const handler of handlers) {
|
|
57360
|
-
const currentTarget = handler.getPasteTarget(zones,
|
|
57361
|
-
...options,
|
|
57362
|
-
isCutOperation: this.isCutOperation(),
|
|
57363
|
-
});
|
|
58197
|
+
const currentTarget = handler.getPasteTarget(zones, copiedData, options);
|
|
57364
58198
|
if (currentTarget.figureId) {
|
|
57365
58199
|
target.figureId = currentTarget.figureId;
|
|
57366
58200
|
}
|
|
@@ -57376,7 +58210,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
57376
58210
|
if (zone !== undefined) {
|
|
57377
58211
|
this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
|
|
57378
58212
|
}
|
|
57379
|
-
handlers.forEach((handler) => handler.paste(target,
|
|
58213
|
+
handlers.forEach((handler) => handler.paste(target, copiedData, options));
|
|
57380
58214
|
if (!options?.selectTarget) {
|
|
57381
58215
|
return;
|
|
57382
58216
|
}
|
|
@@ -59762,6 +60596,7 @@ class BottomBarSheet extends Component {
|
|
|
59762
60596
|
sheetDivRef = useRef("sheetDiv");
|
|
59763
60597
|
sheetNameRef = useRef("sheetNameSpan");
|
|
59764
60598
|
editionState = "initializing";
|
|
60599
|
+
DOMFocusableElementStore;
|
|
59765
60600
|
setup() {
|
|
59766
60601
|
onMounted(() => {
|
|
59767
60602
|
if (this.isSheetActive) {
|
|
@@ -59774,6 +60609,7 @@ class BottomBarSheet extends Component {
|
|
|
59774
60609
|
this.focusInputAndSelectContent();
|
|
59775
60610
|
}
|
|
59776
60611
|
});
|
|
60612
|
+
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
|
|
59777
60613
|
}
|
|
59778
60614
|
focusInputAndSelectContent() {
|
|
59779
60615
|
if (!this.state.isEditing || !this.sheetNameRef.el)
|
|
@@ -59815,9 +60651,11 @@ class BottomBarSheet extends Component {
|
|
|
59815
60651
|
if (ev.key === "Enter") {
|
|
59816
60652
|
ev.preventDefault();
|
|
59817
60653
|
this.stopEdition();
|
|
60654
|
+
this.DOMFocusableElementStore.focus();
|
|
59818
60655
|
}
|
|
59819
60656
|
if (ev.key === "Escape") {
|
|
59820
60657
|
this.cancelEdition();
|
|
60658
|
+
this.DOMFocusableElementStore.focus();
|
|
59821
60659
|
}
|
|
59822
60660
|
}
|
|
59823
60661
|
onClickSheetName(ev) {
|
|
@@ -61866,6 +62704,9 @@ class Spreadsheet extends Component {
|
|
|
61866
62704
|
static template = "o-spreadsheet-Spreadsheet";
|
|
61867
62705
|
static props = {
|
|
61868
62706
|
model: Object,
|
|
62707
|
+
notifyUser: { type: Function, optional: true },
|
|
62708
|
+
raiseError: { type: Function, optional: true },
|
|
62709
|
+
askConfirmation: { type: Function, optional: true },
|
|
61869
62710
|
};
|
|
61870
62711
|
static components = {
|
|
61871
62712
|
TopBar,
|
|
@@ -61912,7 +62753,11 @@ class Spreadsheet extends Component {
|
|
|
61912
62753
|
toggleSidePanel: this.sidePanel.toggle.bind(this.sidePanel),
|
|
61913
62754
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
61914
62755
|
startCellEdition: (content) => this.composerFocusStore.focusGridComposerCell(content),
|
|
62756
|
+
notifyUser: (notification) => this.notificationStore.notifyUser(notification),
|
|
62757
|
+
askConfirmation: (text, confirm, cancel) => this.notificationStore.askConfirmation(text, confirm, cancel),
|
|
62758
|
+
raiseError: (text, cb) => this.notificationStore.raiseError(text, cb),
|
|
61915
62759
|
});
|
|
62760
|
+
this.notificationStore.updateNotificationCallbacks({ ...this.props });
|
|
61916
62761
|
useEffect(() => {
|
|
61917
62762
|
/**
|
|
61918
62763
|
* Only refocus the grid if the active element is not a child of the spreadsheet
|
|
@@ -61935,6 +62780,9 @@ class Spreadsheet extends Component {
|
|
|
61935
62780
|
if (nextProps.model !== this.props.model) {
|
|
61936
62781
|
throw new Error("Changing the props model is not supported at the moment.");
|
|
61937
62782
|
}
|
|
62783
|
+
if (!deepEquals(nextProps, this.props)) {
|
|
62784
|
+
this.notificationStore.updateNotificationCallbacks({ ...nextProps });
|
|
62785
|
+
}
|
|
61938
62786
|
});
|
|
61939
62787
|
const render = batched(this.render.bind(this, true));
|
|
61940
62788
|
onMounted(() => {
|
|
@@ -61952,7 +62800,7 @@ class Spreadsheet extends Component {
|
|
|
61952
62800
|
bindModelEvents() {
|
|
61953
62801
|
this.model.on("update", this, () => this.render(true));
|
|
61954
62802
|
this.model.on("notify-ui", this, (notification) => this.notificationStore.notifyUser(notification));
|
|
61955
|
-
this.model.on("raise-error-ui", this, ({ text }) => this.
|
|
62803
|
+
this.model.on("raise-error-ui", this, ({ text }) => this.notificationStore.raiseError(text));
|
|
61956
62804
|
}
|
|
61957
62805
|
unbindModelEvents() {
|
|
61958
62806
|
this.model.off("update", this);
|
|
@@ -63507,10 +64355,13 @@ function createChart(chart, chartSheetIndex, data) {
|
|
|
63507
64355
|
});
|
|
63508
64356
|
// <manualLayout/> to manually position the chart in the figure container
|
|
63509
64357
|
let title = escapeXml ``;
|
|
63510
|
-
if (chart.data.title) {
|
|
64358
|
+
if (chart.data.title?.text) {
|
|
64359
|
+
const color = chart.data.title.color
|
|
64360
|
+
? toXlsxHexColor(chart.data.title.color)
|
|
64361
|
+
: chart.data.fontColor;
|
|
63511
64362
|
title = escapeXml /*xml*/ `
|
|
63512
64363
|
<c:title>
|
|
63513
|
-
${insertText(chart.data.title, chart.data.
|
|
64364
|
+
${insertText(chart.data.title.text, color, DEFAULT_CHART_FONT_SIZE, chart.data.title)}
|
|
63514
64365
|
<c:overlay val="0" />
|
|
63515
64366
|
</c:title>
|
|
63516
64367
|
`;
|
|
@@ -63598,7 +64449,7 @@ function lineAttributes(params) {
|
|
|
63598
64449
|
</a:ln>
|
|
63599
64450
|
`;
|
|
63600
64451
|
}
|
|
63601
|
-
function insertText(text, fontColor = "000000", fontsize =
|
|
64452
|
+
function insertText(text, fontColor = "000000", fontsize = DEFAULT_CHART_FONT_SIZE, style = {}) {
|
|
63602
64453
|
return escapeXml /*xml*/ `
|
|
63603
64454
|
<c:tx>
|
|
63604
64455
|
<c:rich>
|
|
@@ -63606,13 +64457,13 @@ function insertText(text, fontColor = "000000", fontsize = 22) {
|
|
|
63606
64457
|
<a:lstStyle />
|
|
63607
64458
|
<a:p>
|
|
63608
64459
|
<a:pPr lvl="0">
|
|
63609
|
-
<a:defRPr b="0">
|
|
64460
|
+
<a:defRPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}">
|
|
63610
64461
|
${solidFill(fontColor)}
|
|
63611
64462
|
<a:latin typeface="+mn-lt"/>
|
|
63612
64463
|
</a:defRPr>
|
|
63613
64464
|
</a:pPr>
|
|
63614
64465
|
<a:r> <!-- Runs -->
|
|
63615
|
-
<a:rPr sz="${fontsize * 100}"/>
|
|
64466
|
+
<a:rPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}" sz="${fontsize * 100}"/>
|
|
63616
64467
|
<a:t>${text}</a:t>
|
|
63617
64468
|
</a:r>
|
|
63618
64469
|
</a:p>
|
|
@@ -63641,6 +64492,24 @@ function insertTextProperties(fontsize = 12, fontColor = "000000", bold = false,
|
|
|
63641
64492
|
</c:txPr>
|
|
63642
64493
|
`;
|
|
63643
64494
|
}
|
|
64495
|
+
function extractDataSetLabel(label) {
|
|
64496
|
+
if (!label) {
|
|
64497
|
+
return escapeXml /*xml*/ ``;
|
|
64498
|
+
}
|
|
64499
|
+
if ("text" in label && label.text) {
|
|
64500
|
+
return escapeXml /*xml*/ `
|
|
64501
|
+
<c:tx><c:v>${label.text}</c:v></c:tx>
|
|
64502
|
+
`;
|
|
64503
|
+
}
|
|
64504
|
+
if ("reference" in label && label.reference) {
|
|
64505
|
+
return escapeXml /*xml*/ `
|
|
64506
|
+
<c:tx>
|
|
64507
|
+
${stringRef(label.reference)}
|
|
64508
|
+
</c:tx>
|
|
64509
|
+
`;
|
|
64510
|
+
}
|
|
64511
|
+
return escapeXml /*xml*/ ``;
|
|
64512
|
+
}
|
|
63644
64513
|
function addBarChart(chart) {
|
|
63645
64514
|
// gapWitdh and overlap that define the space between clusters (in %) and the overlap between datasets (from -100: completely scattered to 100, completely overlapped)
|
|
63646
64515
|
// see gapWidth : https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_gapWidth_topic_ID0EFVEQB.html#topic_ID0EFVEQB
|
|
@@ -63648,46 +64517,72 @@ function addBarChart(chart) {
|
|
|
63648
64517
|
//
|
|
63649
64518
|
// overlap and gapWitdh seems to be by default at -20 and 20 in chart.js.
|
|
63650
64519
|
// 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
|
|
64520
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64521
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64522
|
+
const leftDataSetsNodes = [];
|
|
64523
|
+
const rightDataSetsNodes = [];
|
|
63653
64524
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
63654
64525
|
const color = toXlsxHexColor(colors.next());
|
|
63655
64526
|
const dataShapeProperty = shapeProperty({
|
|
63656
64527
|
backgroundColor: color,
|
|
63657
64528
|
line: { color },
|
|
63658
64529
|
});
|
|
63659
|
-
|
|
64530
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63660
64531
|
<c:ser>
|
|
63661
64532
|
<c:idx val="${dsIndex}"/>
|
|
63662
64533
|
<c:order val="${dsIndex}"/>
|
|
63663
|
-
${
|
|
64534
|
+
${extractDataSetLabel(dataset.label)}
|
|
63664
64535
|
${dataShapeProperty}
|
|
63665
64536
|
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63666
64537
|
<c:val> <!-- x-coordinate values -->
|
|
63667
64538
|
${numberRef(dataset.range)}
|
|
63668
64539
|
</c:val>
|
|
63669
64540
|
</c:ser>
|
|
63670
|
-
|
|
64541
|
+
`;
|
|
64542
|
+
if (dataset.rightYAxis) {
|
|
64543
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64544
|
+
}
|
|
64545
|
+
else {
|
|
64546
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64547
|
+
}
|
|
63671
64548
|
}
|
|
63672
|
-
// Excel does not support this feature
|
|
63673
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63674
64549
|
const grouping = chart.stacked ? "stacked" : "clustered";
|
|
63675
64550
|
const overlap = chart.stacked ? 100 : -20;
|
|
63676
64551
|
return escapeXml /*xml*/ `
|
|
63677
|
-
|
|
63678
|
-
|
|
63679
|
-
|
|
63680
|
-
|
|
63681
|
-
|
|
63682
|
-
|
|
63683
|
-
|
|
63684
|
-
|
|
63685
|
-
|
|
63686
|
-
|
|
63687
|
-
|
|
63688
|
-
|
|
63689
|
-
|
|
63690
|
-
|
|
64552
|
+
${leftDataSetsNodes.length
|
|
64553
|
+
? escapeXml /*xml*/ `
|
|
64554
|
+
<c:barChart>
|
|
64555
|
+
<c:barDir val="col"/>
|
|
64556
|
+
<c:grouping val="${grouping}"/>
|
|
64557
|
+
<c:overlap val="${overlap}"/>
|
|
64558
|
+
<c:gapWidth val="70"/>
|
|
64559
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64560
|
+
<c:varyColors val="0"/>
|
|
64561
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64562
|
+
<c:axId val="${catAxId}" />
|
|
64563
|
+
<c:axId val="${valAxId}" />
|
|
64564
|
+
</c:barChart>
|
|
64565
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64566
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64567
|
+
`
|
|
64568
|
+
: ""}
|
|
64569
|
+
${rightDataSetsNodes.length
|
|
64570
|
+
? escapeXml /*xml*/ `
|
|
64571
|
+
<c:barChart>
|
|
64572
|
+
<c:barDir val="col"/>
|
|
64573
|
+
<c:grouping val="${grouping}"/>
|
|
64574
|
+
<c:overlap val="${overlap}"/>
|
|
64575
|
+
<c:gapWidth val="70"/>
|
|
64576
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64577
|
+
<c:varyColors val="0"/>
|
|
64578
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64579
|
+
<c:axId val="${catAxId + 1}" />
|
|
64580
|
+
<c:axId val="${valAxId + 1}" />
|
|
64581
|
+
</c:barChart>
|
|
64582
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64583
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64584
|
+
`
|
|
64585
|
+
: ""}`;
|
|
63691
64586
|
}
|
|
63692
64587
|
function addComboChart(chart) {
|
|
63693
64588
|
// 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 +64591,38 @@ function addComboChart(chart) {
|
|
|
63696
64591
|
//
|
|
63697
64592
|
// overlap and gapWitdh seems to be by default at -20 and 20 in chart.js.
|
|
63698
64593
|
// 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
|
-
|
|
64594
|
+
const dataSets = chart.dataSets;
|
|
64595
|
+
const dataSetsColors = dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64596
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64597
|
+
let dataSet = dataSets[0];
|
|
64598
|
+
const firstColor = toXlsxHexColor(colors.next());
|
|
64599
|
+
const useRightAxisForBarSerie = dataSet.rightYAxis ?? false;
|
|
64600
|
+
const barDataSetNode = escapeXml /*xml*/ `
|
|
64601
|
+
<c:ser>
|
|
64602
|
+
<c:idx val="0"/>
|
|
64603
|
+
<c:order val="0"/>
|
|
64604
|
+
${extractDataSetLabel(dataSet.label)}
|
|
64605
|
+
${shapeProperty({
|
|
64606
|
+
backgroundColor: firstColor,
|
|
64607
|
+
line: { color: firstColor },
|
|
64608
|
+
})}
|
|
64609
|
+
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
64610
|
+
<!-- x-coordinate values -->
|
|
64611
|
+
<c:val>
|
|
64612
|
+
${numberRef(dataSet.range)}
|
|
64613
|
+
</c:val>
|
|
64614
|
+
</c:ser>
|
|
64615
|
+
`;
|
|
64616
|
+
const leftDataSetsNodes = [];
|
|
64617
|
+
const rightDataSetsNodes = [];
|
|
64618
|
+
for (let dsIndex = 1; dsIndex < dataSets.length; dsIndex++) {
|
|
64619
|
+
dataSet = dataSets[dsIndex];
|
|
63702
64620
|
const color = toXlsxHexColor(colors.next());
|
|
63703
64621
|
const dataShapeProperty = shapeProperty({
|
|
63704
64622
|
backgroundColor: color,
|
|
63705
64623
|
line: { color },
|
|
63706
64624
|
});
|
|
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*/ `
|
|
64625
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63721
64626
|
<c:ser>
|
|
63722
64627
|
<c:idx val="${dsIndex}"/>
|
|
63723
64628
|
<c:order val="${dsIndex}"/>
|
|
@@ -63725,18 +64630,24 @@ function addComboChart(chart) {
|
|
|
63725
64630
|
<c:marker>
|
|
63726
64631
|
<c:symbol val="circle" />
|
|
63727
64632
|
<c:size val="5"/>
|
|
64633
|
+
${dataShapeProperty}
|
|
63728
64634
|
</c:marker>
|
|
63729
|
-
${
|
|
64635
|
+
${extractDataSetLabel(dataSet.label)}
|
|
63730
64636
|
${dataShapeProperty}
|
|
63731
|
-
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
63732
|
-
|
|
63733
|
-
|
|
64637
|
+
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
64638
|
+
<!-- x-coordinate values -->
|
|
64639
|
+
<c:val>
|
|
64640
|
+
${numberRef(dataSet.range)}
|
|
63734
64641
|
</c:val>
|
|
63735
64642
|
</c:ser>
|
|
63736
|
-
|
|
64643
|
+
`;
|
|
64644
|
+
if (dataSet.rightYAxis) {
|
|
64645
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64646
|
+
}
|
|
64647
|
+
else {
|
|
64648
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64649
|
+
}
|
|
63737
64650
|
}
|
|
63738
|
-
// Excel does not support this feature
|
|
63739
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63740
64651
|
const overlap = chart.stacked ? 100 : -20;
|
|
63741
64652
|
return escapeXml /*xml*/ `
|
|
63742
64653
|
<c:barChart>
|
|
@@ -63746,34 +64657,63 @@ function addComboChart(chart) {
|
|
|
63746
64657
|
<c:gapWidth val="70"/>
|
|
63747
64658
|
<!-- each data marker in the series does not have a different color -->
|
|
63748
64659
|
<c:varyColors val="0"/>
|
|
63749
|
-
${
|
|
63750
|
-
<c:axId val="${catAxId}" />
|
|
63751
|
-
<c:axId val="${valAxId}" />
|
|
64660
|
+
${barDataSetNode}
|
|
64661
|
+
<c:axId val="${catAxId + (useRightAxisForBarSerie ? 1 : 0)}" />
|
|
64662
|
+
<c:axId val="${valAxId + (useRightAxisForBarSerie ? 1 : 0)}" />
|
|
63752
64663
|
</c:barChart>
|
|
63753
|
-
|
|
63754
|
-
|
|
63755
|
-
|
|
63756
|
-
|
|
63757
|
-
|
|
63758
|
-
|
|
63759
|
-
|
|
63760
|
-
|
|
63761
|
-
|
|
63762
|
-
|
|
64664
|
+
${leftDataSetsNodes.length
|
|
64665
|
+
? escapeXml /*xml*/ `
|
|
64666
|
+
<c:lineChart>
|
|
64667
|
+
<c:grouping val="standard"/>
|
|
64668
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64669
|
+
<c:varyColors val="0"/>
|
|
64670
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64671
|
+
<c:axId val="${catAxId}" />
|
|
64672
|
+
<c:axId val="${valAxId}" />
|
|
64673
|
+
</c:lineChart>
|
|
64674
|
+
`
|
|
64675
|
+
: ""}
|
|
64676
|
+
${rightDataSetsNodes.length
|
|
64677
|
+
? escapeXml /*xml*/ `
|
|
64678
|
+
<c:lineChart>
|
|
64679
|
+
<c:grouping val="standard"/>
|
|
64680
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64681
|
+
<c:varyColors val="0"/>
|
|
64682
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64683
|
+
<c:axId val="${catAxId + 1}" />
|
|
64684
|
+
<c:axId val="${valAxId + 1}" />
|
|
64685
|
+
</c:lineChart>
|
|
64686
|
+
`
|
|
64687
|
+
: ""}
|
|
64688
|
+
${!useRightAxisForBarSerie || leftDataSetsNodes.length
|
|
64689
|
+
? escapeXml /*xml*/ `
|
|
64690
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64691
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64692
|
+
`
|
|
64693
|
+
: ""}
|
|
64694
|
+
${useRightAxisForBarSerie || rightDataSetsNodes.length
|
|
64695
|
+
? escapeXml /*xml*/ `
|
|
64696
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length || !useRightAxisForBarSerie ? 1 : 0)}
|
|
64697
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64698
|
+
`
|
|
64699
|
+
: ""}
|
|
63763
64700
|
`;
|
|
63764
64701
|
}
|
|
63765
64702
|
function addLineChart(chart) {
|
|
63766
|
-
const
|
|
63767
|
-
const
|
|
64703
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64704
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64705
|
+
const leftDataSetsNodes = [];
|
|
64706
|
+
const rightDataSetsNodes = [];
|
|
63768
64707
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
64708
|
+
const color = toXlsxHexColor(colors.next());
|
|
63769
64709
|
const dataShapeProperty = shapeProperty({
|
|
63770
64710
|
line: {
|
|
63771
64711
|
width: 2.5,
|
|
63772
64712
|
style: "solid",
|
|
63773
|
-
color
|
|
64713
|
+
color,
|
|
63774
64714
|
},
|
|
63775
64715
|
});
|
|
63776
|
-
|
|
64716
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63777
64717
|
<c:ser>
|
|
63778
64718
|
<c:idx val="${dsIndex}"/>
|
|
63779
64719
|
<c:order val="${dsIndex}"/>
|
|
@@ -63781,37 +64721,63 @@ function addLineChart(chart) {
|
|
|
63781
64721
|
<c:marker>
|
|
63782
64722
|
<c:symbol val="circle" />
|
|
63783
64723
|
<c:size val="5"/>
|
|
64724
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
63784
64725
|
</c:marker>
|
|
63785
|
-
${
|
|
64726
|
+
${extractDataSetLabel(dataset.label)}
|
|
63786
64727
|
${dataShapeProperty}
|
|
63787
64728
|
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
63788
64729
|
<c:val> <!-- x-coordinate values -->
|
|
63789
64730
|
${numberRef(dataset.range)}
|
|
63790
64731
|
</c:val>
|
|
63791
64732
|
</c:ser>
|
|
63792
|
-
|
|
64733
|
+
`;
|
|
64734
|
+
if (dataset.rightYAxis) {
|
|
64735
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64736
|
+
}
|
|
64737
|
+
else {
|
|
64738
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64739
|
+
}
|
|
63793
64740
|
}
|
|
63794
|
-
// Excel does not support this feature
|
|
63795
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63796
64741
|
const grouping = chart.stacked ? "stacked" : "standard";
|
|
63797
64742
|
return escapeXml /*xml*/ `
|
|
63798
|
-
|
|
63799
|
-
|
|
63800
|
-
|
|
63801
|
-
|
|
63802
|
-
|
|
63803
|
-
|
|
63804
|
-
|
|
63805
|
-
|
|
63806
|
-
|
|
63807
|
-
|
|
64743
|
+
${leftDataSetsNodes.length
|
|
64744
|
+
? escapeXml /*xml*/ `
|
|
64745
|
+
<c:lineChart>
|
|
64746
|
+
<c:grouping val="${grouping}"/>
|
|
64747
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64748
|
+
<c:varyColors val="0"/>
|
|
64749
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64750
|
+
<c:axId val="${catAxId}" />
|
|
64751
|
+
<c:axId val="${valAxId}" />
|
|
64752
|
+
</c:lineChart>
|
|
64753
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64754
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64755
|
+
`
|
|
64756
|
+
: ""}
|
|
64757
|
+
${rightDataSetsNodes.length
|
|
64758
|
+
? escapeXml /*xml*/ `
|
|
64759
|
+
<c:lineChart>
|
|
64760
|
+
<c:grouping val="${grouping}"/>
|
|
64761
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64762
|
+
<c:varyColors val="0"/>
|
|
64763
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64764
|
+
<c:axId val="${catAxId + 1}" />
|
|
64765
|
+
<c:axId val="${valAxId + 1}" />
|
|
64766
|
+
</c:lineChart>
|
|
64767
|
+
${addAx("b", "c:catAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64768
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64769
|
+
`
|
|
64770
|
+
: ""}
|
|
63808
64771
|
`;
|
|
63809
64772
|
}
|
|
63810
64773
|
function addScatterChart(chart) {
|
|
63811
|
-
const
|
|
63812
|
-
const
|
|
64774
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
64775
|
+
const colors = new ColorGenerator(dataSetsColors);
|
|
64776
|
+
const leftDataSetsNodes = [];
|
|
64777
|
+
const rightDataSetsNodes = [];
|
|
63813
64778
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
63814
|
-
|
|
64779
|
+
const color = toXlsxHexColor(colors.next());
|
|
64780
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
63815
64781
|
<c:ser>
|
|
63816
64782
|
<c:idx val="${dsIndex}"/>
|
|
63817
64783
|
<c:order val="${dsIndex}"/>
|
|
@@ -63826,8 +64792,9 @@ function addScatterChart(chart) {
|
|
|
63826
64792
|
<c:marker>
|
|
63827
64793
|
<c:symbol val="circle" />
|
|
63828
64794
|
<c:size val="5"/>
|
|
63829
|
-
${shapeProperty({ backgroundColor:
|
|
64795
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
63830
64796
|
</c:marker>
|
|
64797
|
+
${extractDataSetLabel(dataset.label)}
|
|
63831
64798
|
${chart.labelRange
|
|
63832
64799
|
? escapeXml /*xml*/ `<c:xVal> <!-- x-coordinate values -->
|
|
63833
64800
|
${numberRef(chart.labelRange)}
|
|
@@ -63837,24 +64804,46 @@ function addScatterChart(chart) {
|
|
|
63837
64804
|
${numberRef(dataset.range)}
|
|
63838
64805
|
</c:yVal>
|
|
63839
64806
|
</c:ser>
|
|
63840
|
-
|
|
64807
|
+
`;
|
|
64808
|
+
if (dataset.rightYAxis) {
|
|
64809
|
+
rightDataSetsNodes.push(dataSetNode);
|
|
64810
|
+
}
|
|
64811
|
+
else {
|
|
64812
|
+
leftDataSetsNodes.push(dataSetNode);
|
|
64813
|
+
}
|
|
63841
64814
|
}
|
|
63842
|
-
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
63843
64815
|
return escapeXml /*xml*/ `
|
|
63844
|
-
|
|
63845
|
-
|
|
63846
|
-
<c:
|
|
63847
|
-
|
|
63848
|
-
|
|
63849
|
-
|
|
63850
|
-
|
|
63851
|
-
|
|
63852
|
-
|
|
63853
|
-
|
|
63854
|
-
|
|
64816
|
+
${leftDataSetsNodes.length
|
|
64817
|
+
? escapeXml /*xml*/ `
|
|
64818
|
+
<c:scatterChart>
|
|
64819
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64820
|
+
<c:varyColors val="0"/>
|
|
64821
|
+
<c:scatterStyle val="lineMarker"/>
|
|
64822
|
+
${joinXmlNodes(leftDataSetsNodes)}
|
|
64823
|
+
<c:axId val="${catAxId}" />
|
|
64824
|
+
<c:axId val="${valAxId}" />
|
|
64825
|
+
</c:scatterChart>
|
|
64826
|
+
${addAx("b", "c:valAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
64827
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
64828
|
+
`
|
|
64829
|
+
: ""}
|
|
64830
|
+
${rightDataSetsNodes.length
|
|
64831
|
+
? escapeXml /*xml*/ `
|
|
64832
|
+
<c:scatterChart>
|
|
64833
|
+
<!-- each data marker in the series does not have a different color -->
|
|
64834
|
+
<c:varyColors val="0"/>
|
|
64835
|
+
<c:scatterStyle val="lineMarker"/>
|
|
64836
|
+
${joinXmlNodes(rightDataSetsNodes)}
|
|
64837
|
+
<c:axId val="${catAxId + 1}" />
|
|
64838
|
+
<c:axId val="${valAxId + 1}" />
|
|
64839
|
+
</c:scatterChart>
|
|
64840
|
+
${addAx("b", "c:valAx", catAxId + 1, valAxId + 1, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
64841
|
+
${addAx("r", "c:valAx", valAxId + 1, catAxId + 1, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
64842
|
+
`
|
|
64843
|
+
: ""}`;
|
|
63855
64844
|
}
|
|
63856
64845
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
63857
|
-
const colors = new
|
|
64846
|
+
const colors = new ColorGenerator();
|
|
63858
64847
|
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
63859
64848
|
const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
|
|
63860
64849
|
const dataSetsNodes = [];
|
|
@@ -63878,7 +64867,7 @@ function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSiz
|
|
|
63878
64867
|
<c:ser>
|
|
63879
64868
|
<c:idx val="${dsIndex}"/>
|
|
63880
64869
|
<c:order val="${dsIndex}"/>
|
|
63881
|
-
${
|
|
64870
|
+
${extractDataSetLabel(dataset.label)}
|
|
63882
64871
|
${joinXmlNodes(dataPoints)}
|
|
63883
64872
|
${insertDataLabels({ showLeaderLines: true })}
|
|
63884
64873
|
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""}
|
|
@@ -63910,14 +64899,16 @@ function insertDataLabels({ showLeaderLines } = { showLeaderLines: false }) {
|
|
|
63910
64899
|
</dLbls>
|
|
63911
64900
|
`;
|
|
63912
64901
|
}
|
|
63913
|
-
function addAx(position, axisName, axId, crossAxId,
|
|
64902
|
+
function addAx(position, axisName, axId, crossAxId, title, defaultFontColor, deleteAxis = 0) {
|
|
63914
64903
|
// Each Axis present inside a graph needs to be identified by an unsigned integer in order to be referenced by its crossAxis.
|
|
63915
64904
|
// I.e. x-axis, will reference y-axis and vice-versa.
|
|
64905
|
+
const color = title?.color ? toXlsxHexColor(title.color) : defaultFontColor;
|
|
63916
64906
|
return escapeXml /*xml*/ `
|
|
63917
64907
|
<${axisName}>
|
|
63918
64908
|
<c:axId val="${axId}"/>
|
|
63919
64909
|
<c:crossAx val="${crossAxId}"/> <!-- reference to the other axe of the chart -->
|
|
63920
|
-
<c:
|
|
64910
|
+
<c:crosses val="${position === "b" || position === "l" ? "min" : "max"}"/>
|
|
64911
|
+
<c:delete val="${deleteAxis}"/> <!-- by default, axis are not displayed -->
|
|
63921
64912
|
<c:scaling>
|
|
63922
64913
|
<c:orientation val="minMax" />
|
|
63923
64914
|
</c:scaling>
|
|
@@ -63927,9 +64918,9 @@ function addAx(position, axisName, axId, crossAxId, { fontColor }) {
|
|
|
63927
64918
|
<c:minorTickMark val="none" />
|
|
63928
64919
|
<c:numFmt formatCode="General" sourceLinked="1" />
|
|
63929
64920
|
<c:title>
|
|
63930
|
-
${insertText("")}
|
|
64921
|
+
${insertText(title?.text ?? "", color, 10, title)}
|
|
63931
64922
|
</c:title>
|
|
63932
|
-
${insertTextProperties(10,
|
|
64923
|
+
${insertTextProperties(10, defaultFontColor)}
|
|
63933
64924
|
</${axisName}>
|
|
63934
64925
|
<!-- <tickLblPos/> omitted -->
|
|
63935
64926
|
`;
|
|
@@ -64810,7 +65801,11 @@ function addRows(construct, data, sheet) {
|
|
|
64810
65801
|
let cellNode = escapeXml ``;
|
|
64811
65802
|
// Either formula or static value inside the cell
|
|
64812
65803
|
if (cell.isFormula) {
|
|
64813
|
-
|
|
65804
|
+
const res = addFormula(cell);
|
|
65805
|
+
if (!res) {
|
|
65806
|
+
continue;
|
|
65807
|
+
}
|
|
65808
|
+
({ attrs: additionalAttrs, node: cellNode } = res);
|
|
64814
65809
|
}
|
|
64815
65810
|
else if (cell.content && isMarkdownLink(cell.content)) {
|
|
64816
65811
|
const { label } = parseMarkdownLink(cell.content);
|
|
@@ -65816,13 +66811,14 @@ const helpers = {
|
|
|
65816
66811
|
UuidGenerator,
|
|
65817
66812
|
formatValue,
|
|
65818
66813
|
createCurrencyFormat,
|
|
66814
|
+
ColorGenerator,
|
|
65819
66815
|
computeTextWidth,
|
|
65820
66816
|
createEmptyWorkbookData,
|
|
65821
66817
|
createEmptySheet,
|
|
65822
66818
|
createEmptyExcelSheet,
|
|
65823
66819
|
getDefaultChartJsRuntime,
|
|
65824
66820
|
chartFontColor,
|
|
65825
|
-
|
|
66821
|
+
getChartAxisTitleRuntime,
|
|
65826
66822
|
getFillingMode,
|
|
65827
66823
|
rgbaToHex,
|
|
65828
66824
|
colorToRGBA,
|
|
@@ -65879,9 +66875,10 @@ const components = {
|
|
|
65879
66875
|
GridOverlay,
|
|
65880
66876
|
ScorecardChart,
|
|
65881
66877
|
LineConfigPanel,
|
|
65882
|
-
GenericChartDesignPanel,
|
|
65883
66878
|
BarConfigPanel,
|
|
66879
|
+
PieChartDesignPanel,
|
|
65884
66880
|
GenericChartConfigPanel,
|
|
66881
|
+
ChartWithAxisDesignPanel,
|
|
65885
66882
|
GaugeChartConfigPanel,
|
|
65886
66883
|
GaugeChartDesignPanel,
|
|
65887
66884
|
ScorecardChartConfigPanel,
|
|
@@ -65937,6 +66934,6 @@ const constants = {
|
|
|
65937
66934
|
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
66935
|
|
|
65939
66936
|
|
|
65940
|
-
__info__.version = "17.3.0
|
|
65941
|
-
__info__.date = "2024-05-
|
|
65942
|
-
__info__.hash = "
|
|
66937
|
+
__info__.version = "17.3.0";
|
|
66938
|
+
__info__.date = "2024-05-31T14:21:26.547Z";
|
|
66939
|
+
__info__.hash = "271202e";
|