@odoo/o-spreadsheet 18.5.0-alpha.6 → 18.5.0-alpha.8
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 +2145 -623
- package/dist/o-spreadsheet.d.ts +486 -291
- package/dist/o-spreadsheet.esm.js +2145 -623
- package/dist/o-spreadsheet.iife.js +2145 -623
- package/dist/o-spreadsheet.iife.min.js +491 -490
- package/dist/o_spreadsheet.xml +229 -41
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.5.0-alpha.
|
|
6
|
-
* @date 2025-08-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.5.0-alpha.8
|
|
6
|
+
* @date 2025-08-18T08:17:58.775Z
|
|
7
|
+
* @hash 994f1cb
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -200,6 +200,7 @@ const CHART_PADDING_BOTTOM = 10;
|
|
|
200
200
|
const CHART_PADDING_TOP = 15;
|
|
201
201
|
const CHART_TITLE_FONT_SIZE = 16;
|
|
202
202
|
const CHART_AXIS_TITLE_FONT_SIZE = 12;
|
|
203
|
+
const MASTER_CHART_HEIGHT = 60;
|
|
203
204
|
const SCORECARD_CHART_TITLE_FONT_SIZE = 14;
|
|
204
205
|
const PIVOT_TOKEN_COLOR = "#F28C28";
|
|
205
206
|
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
@@ -415,6 +416,7 @@ const PIVOT_TABLE_CONFIG = {
|
|
|
415
416
|
};
|
|
416
417
|
const PIVOT_INDENT = 15;
|
|
417
418
|
const PIVOT_COLLAPSE_ICON_SIZE = 12;
|
|
419
|
+
const PIVOT_MAX_NUMBER_OF_CELLS = 1e5;
|
|
418
420
|
const DEFAULT_CURRENCY = {
|
|
419
421
|
symbol: "$",
|
|
420
422
|
position: "before",
|
|
@@ -2657,6 +2659,7 @@ const readonlyAllowedCommands = new Set([
|
|
|
2657
2659
|
"SET_FORMULA_VISIBILITY",
|
|
2658
2660
|
"UPDATE_FILTER",
|
|
2659
2661
|
"UPDATE_CHART",
|
|
2662
|
+
"UPDATE_CAROUSEL_ACTIVE_ITEM",
|
|
2660
2663
|
]);
|
|
2661
2664
|
const coreTypes = new Set([
|
|
2662
2665
|
/** CELLS */
|
|
@@ -2699,6 +2702,8 @@ const coreTypes = new Set([
|
|
|
2699
2702
|
"CREATE_FIGURE",
|
|
2700
2703
|
"DELETE_FIGURE",
|
|
2701
2704
|
"UPDATE_FIGURE",
|
|
2705
|
+
"CREATE_CAROUSEL",
|
|
2706
|
+
"UPDATE_CAROUSEL",
|
|
2702
2707
|
/** FORMATTING */
|
|
2703
2708
|
"SET_FORMATTING",
|
|
2704
2709
|
"CLEAR_FORMATTING",
|
|
@@ -2708,6 +2713,7 @@ const coreTypes = new Set([
|
|
|
2708
2713
|
/** CHART */
|
|
2709
2714
|
"CREATE_CHART",
|
|
2710
2715
|
"UPDATE_CHART",
|
|
2716
|
+
"DELETE_CHART",
|
|
2711
2717
|
/** FILTERS */
|
|
2712
2718
|
"CREATE_TABLE",
|
|
2713
2719
|
"REMOVE_TABLE",
|
|
@@ -2902,6 +2908,7 @@ exports.CommandResult = void 0;
|
|
|
2902
2908
|
CommandResult["InvalidColor"] = "InvalidColor";
|
|
2903
2909
|
CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
|
|
2904
2910
|
CommandResult["InvalidPivotCustomField"] = "InvalidPivotCustomField";
|
|
2911
|
+
CommandResult["MissingFigureArguments"] = "MissingFigureArguments";
|
|
2905
2912
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
2906
2913
|
|
|
2907
2914
|
const availableConditionalFormatOperators = new Set([
|
|
@@ -9222,7 +9229,7 @@ class ChartClipboardHandler extends AbstractFigureClipboardHandler {
|
|
|
9222
9229
|
return;
|
|
9223
9230
|
}
|
|
9224
9231
|
const copiedFigure = { ...figure };
|
|
9225
|
-
const chart = this.getters.
|
|
9232
|
+
const chart = this.getters.getChartFromFigureId(data.figureId);
|
|
9226
9233
|
if (!chart) {
|
|
9227
9234
|
throw new Error(`No chart for the given id: ${data.figureId}`);
|
|
9228
9235
|
}
|
|
@@ -9258,6 +9265,7 @@ class ChartClipboardHandler extends AbstractFigureClipboardHandler {
|
|
|
9258
9265
|
}
|
|
9259
9266
|
this.dispatch("CREATE_CHART", {
|
|
9260
9267
|
figureId,
|
|
9268
|
+
chartId: figureId,
|
|
9261
9269
|
sheetId,
|
|
9262
9270
|
definition: copy.getDefinition(),
|
|
9263
9271
|
col,
|
|
@@ -19030,6 +19038,211 @@ var logical = /*#__PURE__*/Object.freeze({
|
|
|
19030
19038
|
XOR: XOR
|
|
19031
19039
|
});
|
|
19032
19040
|
|
|
19041
|
+
const CfTerms = {
|
|
19042
|
+
Errors: {
|
|
19043
|
+
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid"),
|
|
19044
|
+
["FirstArgMissing" /* CommandResult.FirstArgMissing */]: _t("The argument is missing. Please provide a value"),
|
|
19045
|
+
["SecondArgMissing" /* CommandResult.SecondArgMissing */]: _t("The second argument is missing. Please provide a value"),
|
|
19046
|
+
["MinNaN" /* CommandResult.MinNaN */]: _t("The minpoint must be a number"),
|
|
19047
|
+
["MidNaN" /* CommandResult.MidNaN */]: _t("The midpoint must be a number"),
|
|
19048
|
+
["MaxNaN" /* CommandResult.MaxNaN */]: _t("The maxpoint must be a number"),
|
|
19049
|
+
["ValueUpperInflectionNaN" /* CommandResult.ValueUpperInflectionNaN */]: _t("The first value must be a number"),
|
|
19050
|
+
["ValueLowerInflectionNaN" /* CommandResult.ValueLowerInflectionNaN */]: _t("The second value must be a number"),
|
|
19051
|
+
["MinBiggerThanMax" /* CommandResult.MinBiggerThanMax */]: _t("Minimum must be smaller then Maximum"),
|
|
19052
|
+
["MinBiggerThanMid" /* CommandResult.MinBiggerThanMid */]: _t("Minimum must be smaller then Midpoint"),
|
|
19053
|
+
["MidBiggerThanMax" /* CommandResult.MidBiggerThanMax */]: _t("Midpoint must be smaller then Maximum"),
|
|
19054
|
+
["LowerBiggerThanUpper" /* CommandResult.LowerBiggerThanUpper */]: _t("Lower inflection point must be smaller than upper inflection point"),
|
|
19055
|
+
["MinInvalidFormula" /* CommandResult.MinInvalidFormula */]: _t("Invalid Minpoint formula"),
|
|
19056
|
+
["MaxInvalidFormula" /* CommandResult.MaxInvalidFormula */]: _t("Invalid Maxpoint formula"),
|
|
19057
|
+
["MidInvalidFormula" /* CommandResult.MidInvalidFormula */]: _t("Invalid Midpoint formula"),
|
|
19058
|
+
["ValueUpperInvalidFormula" /* CommandResult.ValueUpperInvalidFormula */]: _t("Invalid upper inflection point formula"),
|
|
19059
|
+
["ValueLowerInvalidFormula" /* CommandResult.ValueLowerInvalidFormula */]: _t("Invalid lower inflection point formula"),
|
|
19060
|
+
["EmptyRange" /* CommandResult.EmptyRange */]: _t("A range needs to be defined"),
|
|
19061
|
+
["ValueCellIsInvalidFormula" /* CommandResult.ValueCellIsInvalidFormula */]: _t("At least one of the provided values is an invalid formula"),
|
|
19062
|
+
Unexpected: _t("The rule is invalid for an unknown reason"),
|
|
19063
|
+
},
|
|
19064
|
+
ColorScale: _t("Color scale"),
|
|
19065
|
+
IconSet: _t("Icon set"),
|
|
19066
|
+
DataBar: _t("Data bar"),
|
|
19067
|
+
};
|
|
19068
|
+
const ChartTerms = {
|
|
19069
|
+
Series: _t("Series"),
|
|
19070
|
+
BackgroundColor: _t("Background color"),
|
|
19071
|
+
StackedBarChart: _t("Stacked bar chart"),
|
|
19072
|
+
StackedLineChart: _t("Stacked line chart"),
|
|
19073
|
+
StackedAreaChart: _t("Stacked area chart"),
|
|
19074
|
+
StackedColumnChart: _t("Stacked column chart"),
|
|
19075
|
+
CumulativeData: _t("Cumulative data"),
|
|
19076
|
+
TreatLabelsAsText: _t("Treat labels as text"),
|
|
19077
|
+
AggregatedChart: _t("Aggregate"),
|
|
19078
|
+
Errors: {
|
|
19079
|
+
Unexpected: _t("The chart definition is invalid for an unknown reason"),
|
|
19080
|
+
// BASIC CHART ERRORS (LINE | BAR | PIE)
|
|
19081
|
+
["InvalidDataSet" /* CommandResult.InvalidDataSet */]: _t("The dataset is invalid"),
|
|
19082
|
+
["InvalidLabelRange" /* CommandResult.InvalidLabelRange */]: _t("Labels are invalid"),
|
|
19083
|
+
// SCORECARD CHART ERRORS
|
|
19084
|
+
["InvalidScorecardKeyValue" /* CommandResult.InvalidScorecardKeyValue */]: _t("The key value is invalid"),
|
|
19085
|
+
["InvalidScorecardBaseline" /* CommandResult.InvalidScorecardBaseline */]: _t("The baseline value is invalid"),
|
|
19086
|
+
// GAUGE CHART ERRORS
|
|
19087
|
+
["InvalidGaugeDataRange" /* CommandResult.InvalidGaugeDataRange */]: _t("The data range is invalid"),
|
|
19088
|
+
["EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */]: _t("A minimum range limit value is needed"),
|
|
19089
|
+
["GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */]: _t("The minimum range limit value must be a number"),
|
|
19090
|
+
["EmptyGaugeRangeMax" /* CommandResult.EmptyGaugeRangeMax */]: _t("A maximum range limit value is needed"),
|
|
19091
|
+
["GaugeRangeMaxNaN" /* CommandResult.GaugeRangeMaxNaN */]: _t("The maximum range limit value must be a number"),
|
|
19092
|
+
["GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */]: _t("The lower inflection point value must be a number"),
|
|
19093
|
+
["GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */]: _t("The upper inflection point value must be a number"),
|
|
19094
|
+
},
|
|
19095
|
+
GeoChart: {
|
|
19096
|
+
ColorScales: {
|
|
19097
|
+
blues: _t("Blues"),
|
|
19098
|
+
cividis: _t("Cividis"),
|
|
19099
|
+
greens: _t("Greens"),
|
|
19100
|
+
greys: _t("Greys"),
|
|
19101
|
+
oranges: _t("Oranges"),
|
|
19102
|
+
purples: _t("Purples"),
|
|
19103
|
+
rainbow: _t("Rainbow"),
|
|
19104
|
+
reds: _t("Reds"),
|
|
19105
|
+
viridis: _t("Viridis"),
|
|
19106
|
+
},
|
|
19107
|
+
},
|
|
19108
|
+
};
|
|
19109
|
+
const CustomCurrencyTerms = {
|
|
19110
|
+
Custom: _t("Custom"),
|
|
19111
|
+
};
|
|
19112
|
+
const MergeErrorMessage = _t("Merged cells are preventing this operation. Unmerge those cells and try again.");
|
|
19113
|
+
const SplitToColumnsTerms = {
|
|
19114
|
+
Errors: {
|
|
19115
|
+
Unexpected: _t("Cannot split the selection for an unknown reason"),
|
|
19116
|
+
["NoSplitSeparatorInSelection" /* CommandResult.NoSplitSeparatorInSelection */]: _t("There is no match for the selected separator in the selection"),
|
|
19117
|
+
["MoreThanOneColumnSelected" /* CommandResult.MoreThanOneColumnSelected */]: _t("Only a selection from a single column can be split"),
|
|
19118
|
+
["SplitWillOverwriteContent" /* CommandResult.SplitWillOverwriteContent */]: _t("Splitting will overwrite existing content"),
|
|
19119
|
+
},
|
|
19120
|
+
};
|
|
19121
|
+
const RemoveDuplicateTerms = {
|
|
19122
|
+
Errors: {
|
|
19123
|
+
Unexpected: _t("Cannot remove duplicates for an unknown reason"),
|
|
19124
|
+
["MoreThanOneRangeSelected" /* CommandResult.MoreThanOneRangeSelected */]: _t("Please select only one range of cells"),
|
|
19125
|
+
["EmptyTarget" /* CommandResult.EmptyTarget */]: _t("Please select a range of cells containing values."),
|
|
19126
|
+
["NoColumnsProvided" /* CommandResult.NoColumnsProvided */]: _t("Please select at latest one column to analyze."),
|
|
19127
|
+
//TODO: Remove it when accept to copy and paste merge cells
|
|
19128
|
+
["WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */]: _t("This operation is not possible due to a merge. Please remove the merges first than try again."),
|
|
19129
|
+
},
|
|
19130
|
+
};
|
|
19131
|
+
const DVTerms = {
|
|
19132
|
+
DateIs: {
|
|
19133
|
+
today: _t("today"),
|
|
19134
|
+
yesterday: _t("yesterday"),
|
|
19135
|
+
tomorrow: _t("tomorrow"),
|
|
19136
|
+
lastWeek: _t("in the past week"),
|
|
19137
|
+
lastMonth: _t("in the past month"),
|
|
19138
|
+
lastYear: _t("in the past year"),
|
|
19139
|
+
},
|
|
19140
|
+
DateIsBefore: {
|
|
19141
|
+
today: _t("today"),
|
|
19142
|
+
yesterday: _t("yesterday"),
|
|
19143
|
+
tomorrow: _t("tomorrow"),
|
|
19144
|
+
lastWeek: _t("one week ago"),
|
|
19145
|
+
lastMonth: _t("one month ago"),
|
|
19146
|
+
lastYear: _t("one year ago"),
|
|
19147
|
+
},
|
|
19148
|
+
CriterionError: {
|
|
19149
|
+
notEmptyValue: _t("The value must not be empty"),
|
|
19150
|
+
numberValue: _t("The value must be a number"),
|
|
19151
|
+
dateValue: _t("The value must be a date"),
|
|
19152
|
+
validRange: _t("The value must be a valid range"),
|
|
19153
|
+
validFormula: _t("The formula must be valid"),
|
|
19154
|
+
},
|
|
19155
|
+
Errors: {
|
|
19156
|
+
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid."),
|
|
19157
|
+
["InvalidDataValidationCriterionValue" /* CommandResult.InvalidDataValidationCriterionValue */]: _t("One or more of the provided criteria values are invalid. Please review and correct them."),
|
|
19158
|
+
["InvalidNumberOfCriterionValues" /* CommandResult.InvalidNumberOfCriterionValues */]: _t("One or more of the provided criteria values are missing."),
|
|
19159
|
+
Unexpected: _t("The rule is invalid for an unknown reason."),
|
|
19160
|
+
},
|
|
19161
|
+
};
|
|
19162
|
+
const TableTerms = {
|
|
19163
|
+
Errors: {
|
|
19164
|
+
Unexpected: _t("The table zone is invalid for an unknown reason"),
|
|
19165
|
+
["TableOverlap" /* CommandResult.TableOverlap */]: _t("You cannot create overlapping tables."),
|
|
19166
|
+
["NonContinuousTargets" /* CommandResult.NonContinuousTargets */]: _t("A table can only be created on a continuous selection."),
|
|
19167
|
+
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid"),
|
|
19168
|
+
["TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */]: _t("The range is out of the sheet"),
|
|
19169
|
+
},
|
|
19170
|
+
Checkboxes: {
|
|
19171
|
+
hasFilters: _t("Filter button"),
|
|
19172
|
+
headerRow: _t("Header row(s)"),
|
|
19173
|
+
bandedRows: _t("Banded rows"),
|
|
19174
|
+
firstColumn: _t("First column"),
|
|
19175
|
+
lastColumn: _t("Last column"),
|
|
19176
|
+
bandedColumns: _t("Banded columns"),
|
|
19177
|
+
automaticAutofill: _t("Automatically autofill formulas"),
|
|
19178
|
+
totalRow: _t("Total row"),
|
|
19179
|
+
isDynamic: _t("Auto-adjust to formula result"),
|
|
19180
|
+
},
|
|
19181
|
+
Tooltips: {
|
|
19182
|
+
filterWithoutHeader: _t("Cannot have filters without a header row"),
|
|
19183
|
+
isDynamic: _t("For tables based on array formulas only"),
|
|
19184
|
+
},
|
|
19185
|
+
};
|
|
19186
|
+
const measureDisplayTerms = {
|
|
19187
|
+
labels: {
|
|
19188
|
+
no_calculations: _t("No calculations"),
|
|
19189
|
+
"%_of_grand_total": _t("% of grand total"),
|
|
19190
|
+
"%_of_col_total": _t("% of column total"),
|
|
19191
|
+
"%_of_row_total": _t("% of row total"),
|
|
19192
|
+
"%_of": _t("% of"),
|
|
19193
|
+
"%_of_parent_row_total": _t("% of parent row total"),
|
|
19194
|
+
"%_of_parent_col_total": _t("% of parent column total"),
|
|
19195
|
+
"%_of_parent_total": _t("% of parent total"),
|
|
19196
|
+
difference_from: _t("Difference from"),
|
|
19197
|
+
"%_difference_from": _t("% difference from"),
|
|
19198
|
+
running_total: _t("Running total"),
|
|
19199
|
+
"%_running_total": _t("% Running total"),
|
|
19200
|
+
rank_asc: _t("Rank smallest to largest"),
|
|
19201
|
+
rank_desc: _t("Rank largest to smallest"),
|
|
19202
|
+
index: _t("Index"),
|
|
19203
|
+
},
|
|
19204
|
+
descriptions: {
|
|
19205
|
+
"%_of_grand_total": () => _t("Displayed as % of grand total"),
|
|
19206
|
+
"%_of_col_total": () => _t("Displayed as % of column total"),
|
|
19207
|
+
"%_of_row_total": () => _t("Displayed as % of row total"),
|
|
19208
|
+
"%_of": (field) => _t('Displayed as % of "%s"', field),
|
|
19209
|
+
"%_of_parent_row_total": (field) => _t('Displayed as % of parent row total of "%s"', field),
|
|
19210
|
+
"%_of_parent_col_total": () => _t("Displayed as % of parent column total"),
|
|
19211
|
+
"%_of_parent_total": (field) => _t('Displayed as % of parent "%s" total', field),
|
|
19212
|
+
difference_from: (field) => _t('Displayed as difference from "%s"', field),
|
|
19213
|
+
"%_difference_from": (field) => _t('Displayed as % difference from "%s"', field),
|
|
19214
|
+
running_total: (field) => _t('Displayed as running total based on "%s"', field),
|
|
19215
|
+
"%_running_total": (field) => _t('Displayed as % running total based on "%s"', field),
|
|
19216
|
+
rank_asc: (field) => _t('Displayed as rank from smallest to largest based on "%s"', field),
|
|
19217
|
+
rank_desc: (field) => _t('Displayed as rank largest to smallest based on "%s"', field),
|
|
19218
|
+
index: () => _t("Displayed as index"),
|
|
19219
|
+
},
|
|
19220
|
+
documentation: {
|
|
19221
|
+
no_calculations: _t("Displays the value that is entered in the field."),
|
|
19222
|
+
"%_of_grand_total": _t("Displays values as a percentage of the grand total of all the values or data points in the report."),
|
|
19223
|
+
"%_of_col_total": _t("Displays all the values in each column or series as a percentage of the total for the column or series."),
|
|
19224
|
+
"%_of_row_total": _t("Displays the value in each row or category as a percentage of the total for the row or category."),
|
|
19225
|
+
"%_of": _t("Displays values as a percentage of the value of the Base item in the Base field."),
|
|
19226
|
+
"%_of_parent_row_total": _t("Calculates values as follows:\n(value for the item) / (value for the parent item on rows)"),
|
|
19227
|
+
"%_of_parent_col_total": _t("Calculates values as follows:\n(value for the item) / (value for the parent item on columns)"),
|
|
19228
|
+
"%_of_parent_total": _t("Calculates values as follows:\n(value for the item) / (value for the parent item of the selected Base field)"),
|
|
19229
|
+
difference_from: _t("Displays values as the difference from the value of the Base item in the Base field."),
|
|
19230
|
+
"%_difference_from": _t("Displays values as the percentage difference from the value of the Base item in the Base field."),
|
|
19231
|
+
running_total: _t("Displays the value for successive items in the Base field as a running total."),
|
|
19232
|
+
"%_running_total": _t("Calculates the value as a percentage for successive items in the Base field that are displayed as a running total."),
|
|
19233
|
+
rank_asc: _t("Displays the rank of selected values in a specific field, listing the smallest item in the field as 1, and each larger value with a higher rank value."),
|
|
19234
|
+
rank_desc: _t("Displays the rank of selected values in a specific field, listing the largest item in the field as 1, and each smaller value with a higher rank value."),
|
|
19235
|
+
index: _t("Calculates values as follows:\n((value in cell) x (Grand Total of Grand Totals)) / ((Grand Row Total) x (Grand Column Total))"),
|
|
19236
|
+
},
|
|
19237
|
+
};
|
|
19238
|
+
function getPivotTooBigErrorMessage(numberOfCells, locale) {
|
|
19239
|
+
const formattedNumber = formatValue(numberOfCells, {
|
|
19240
|
+
format: "0,00",
|
|
19241
|
+
locale: locale,
|
|
19242
|
+
});
|
|
19243
|
+
return _t("Oops—this pivot table is quite large (%s cells). Try simplifying it using the side panel.", formattedNumber);
|
|
19244
|
+
}
|
|
19245
|
+
|
|
19033
19246
|
/**
|
|
19034
19247
|
* Get the pivot ID from the formula pivot ID.
|
|
19035
19248
|
*/
|
|
@@ -19640,6 +19853,9 @@ const PIVOT = {
|
|
|
19640
19853
|
return error;
|
|
19641
19854
|
}
|
|
19642
19855
|
const table = pivot.getCollapsedTableStructure();
|
|
19856
|
+
if (table.numberOfCells > PIVOT_MAX_NUMBER_OF_CELLS) {
|
|
19857
|
+
return new EvaluationError(getPivotTooBigErrorMessage(table.numberOfCells, this.locale));
|
|
19858
|
+
}
|
|
19643
19859
|
const cells = table.getPivotCells(visibilityOptions);
|
|
19644
19860
|
let headerRows = 0;
|
|
19645
19861
|
if (visibilityOptions.displayColumnHeaders) {
|
|
@@ -19738,7 +19954,7 @@ const OFFSET = {
|
|
|
19738
19954
|
right: startingCol + offsetWidth - 1,
|
|
19739
19955
|
bottom: startingRow + offsetHeight - 1,
|
|
19740
19956
|
};
|
|
19741
|
-
const range = this.getters.getRangeFromZone(
|
|
19957
|
+
const range = this.getters.getRangeFromZone(sheetId, dependencyZone);
|
|
19742
19958
|
if (range.invalidXc || range.invalidSheetName) {
|
|
19743
19959
|
return new InvalidReferenceError();
|
|
19744
19960
|
}
|
|
@@ -22021,12 +22237,12 @@ function getPieColors(colors, dataSetsValues) {
|
|
|
22021
22237
|
}
|
|
22022
22238
|
return pieColors;
|
|
22023
22239
|
}
|
|
22024
|
-
function truncateLabel(label) {
|
|
22240
|
+
function truncateLabel(label, maxLen = MAX_CHAR_LABEL) {
|
|
22025
22241
|
if (!label) {
|
|
22026
22242
|
return "";
|
|
22027
22243
|
}
|
|
22028
|
-
if (label.length >
|
|
22029
|
-
return label.substring(0,
|
|
22244
|
+
if (label.length > maxLen) {
|
|
22245
|
+
return label.substring(0, maxLen) + "…";
|
|
22030
22246
|
}
|
|
22031
22247
|
return label;
|
|
22032
22248
|
}
|
|
@@ -22998,7 +23214,7 @@ chartJsExtensionRegistry.add("sunburstHoverPlugin", {
|
|
|
22998
23214
|
class ChartJsComponent extends owl.Component {
|
|
22999
23215
|
static template = "o-spreadsheet-ChartJsComponent";
|
|
23000
23216
|
static props = {
|
|
23001
|
-
|
|
23217
|
+
chartId: String,
|
|
23002
23218
|
isFullScreen: { type: Boolean, optional: true },
|
|
23003
23219
|
};
|
|
23004
23220
|
canvas = owl.useRef("graphContainer");
|
|
@@ -23013,7 +23229,7 @@ class ChartJsComponent extends owl.Component {
|
|
|
23013
23229
|
return `background-color: ${this.background}`;
|
|
23014
23230
|
}
|
|
23015
23231
|
get chartRuntime() {
|
|
23016
|
-
const runtime = this.env.model.getters.getChartRuntime(this.props.
|
|
23232
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
23017
23233
|
if (!("chartJsConfig" in runtime)) {
|
|
23018
23234
|
throw new Error("Unsupported chart runtime");
|
|
23019
23235
|
}
|
|
@@ -23028,30 +23244,37 @@ class ChartJsComponent extends owl.Component {
|
|
|
23028
23244
|
const runtime = this.chartRuntime;
|
|
23029
23245
|
this.currentRuntime = runtime;
|
|
23030
23246
|
// Note: chartJS modify the runtime in place, so it's important to give it a copy
|
|
23031
|
-
this.createChart(deepCopy(runtime
|
|
23247
|
+
this.createChart(deepCopy(runtime));
|
|
23032
23248
|
});
|
|
23033
|
-
owl.onWillUnmount(
|
|
23249
|
+
owl.onWillUnmount(this.unmount.bind(this));
|
|
23034
23250
|
owl.useEffect(() => {
|
|
23035
23251
|
const runtime = this.chartRuntime;
|
|
23036
23252
|
if (runtime !== this.currentRuntime) {
|
|
23037
23253
|
if (runtime.chartJsConfig.type !== this.currentRuntime.chartJsConfig.type) {
|
|
23038
23254
|
this.chart?.destroy();
|
|
23039
|
-
this.createChart(deepCopy(runtime
|
|
23255
|
+
this.createChart(deepCopy(runtime));
|
|
23040
23256
|
}
|
|
23041
23257
|
else {
|
|
23042
|
-
this.updateChartJs(deepCopy(runtime
|
|
23258
|
+
this.updateChartJs(deepCopy(runtime));
|
|
23043
23259
|
}
|
|
23044
23260
|
this.currentRuntime = runtime;
|
|
23045
23261
|
}
|
|
23046
23262
|
else if (this.currentDevicePixelRatio !== window.devicePixelRatio) {
|
|
23047
23263
|
this.currentDevicePixelRatio = window.devicePixelRatio;
|
|
23048
|
-
this.updateChartJs(deepCopy(this.currentRuntime
|
|
23264
|
+
this.updateChartJs(deepCopy(this.currentRuntime));
|
|
23049
23265
|
}
|
|
23050
23266
|
});
|
|
23051
23267
|
}
|
|
23052
|
-
|
|
23053
|
-
|
|
23054
|
-
|
|
23268
|
+
unmount() {
|
|
23269
|
+
this.chart?.destroy();
|
|
23270
|
+
}
|
|
23271
|
+
get shouldAnimate() {
|
|
23272
|
+
return this.env.model.getters.isDashboard();
|
|
23273
|
+
}
|
|
23274
|
+
createChart(chartRuntime) {
|
|
23275
|
+
let chartData = chartRuntime.chartJsConfig;
|
|
23276
|
+
if (this.shouldAnimate && this.animationStore) {
|
|
23277
|
+
const chartType = this.env.model.getters.getChart(this.props.chartId)?.type;
|
|
23055
23278
|
if (chartType && this.animationStore.animationPlayed[this.animationFigureId] !== chartType) {
|
|
23056
23279
|
chartData = this.enableAnimationInChartData(chartData);
|
|
23057
23280
|
this.animationStore.disableAnimationForChart(this.animationFigureId, chartType);
|
|
@@ -23061,9 +23284,10 @@ class ChartJsComponent extends owl.Component {
|
|
|
23061
23284
|
const ctx = canvas.getContext("2d");
|
|
23062
23285
|
this.chart = new window.Chart(ctx, chartData);
|
|
23063
23286
|
}
|
|
23064
|
-
updateChartJs(
|
|
23065
|
-
|
|
23066
|
-
|
|
23287
|
+
updateChartJs(chartRuntime) {
|
|
23288
|
+
let chartData = chartRuntime.chartJsConfig;
|
|
23289
|
+
if (this.shouldAnimate) {
|
|
23290
|
+
const chartType = this.env.model.getters.getChart(this.props.chartId)?.type;
|
|
23067
23291
|
if (chartType && this.hasChartDataChanged() && this.animationStore) {
|
|
23068
23292
|
chartData = this.enableAnimationInChartData(chartData);
|
|
23069
23293
|
this.animationStore.disableAnimationForChart(this.animationFigureId, chartType);
|
|
@@ -23091,9 +23315,7 @@ class ChartJsComponent extends owl.Component {
|
|
|
23091
23315
|
};
|
|
23092
23316
|
}
|
|
23093
23317
|
get animationFigureId() {
|
|
23094
|
-
return this.props.isFullScreen
|
|
23095
|
-
? this.props.figureUI.id + "-fullscreen"
|
|
23096
|
-
: this.props.figureUI.id;
|
|
23318
|
+
return this.props.isFullScreen ? this.props.chartId + "-fullscreen" : this.props.chartId;
|
|
23097
23319
|
}
|
|
23098
23320
|
}
|
|
23099
23321
|
|
|
@@ -23758,14 +23980,14 @@ class ScorecardChartConfigBuilder {
|
|
|
23758
23980
|
class ScorecardChart extends owl.Component {
|
|
23759
23981
|
static template = "o-spreadsheet-ScorecardChart";
|
|
23760
23982
|
static props = {
|
|
23761
|
-
|
|
23983
|
+
chartId: String,
|
|
23762
23984
|
};
|
|
23763
23985
|
canvas = owl.useRef("chartContainer");
|
|
23764
23986
|
get runtime() {
|
|
23765
|
-
return this.env.model.getters.getChartRuntime(this.props.
|
|
23987
|
+
return this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
23766
23988
|
}
|
|
23767
23989
|
get title() {
|
|
23768
|
-
const title = this.env.model.getters.getChartDefinition(this.props.
|
|
23990
|
+
const title = this.env.model.getters.getChartDefinition(this.props.chartId).title.text ?? "";
|
|
23769
23991
|
// chart titles are extracted from .json files and they are translated at runtime here
|
|
23770
23992
|
return _t(title);
|
|
23771
23993
|
}
|
|
@@ -24471,204 +24693,6 @@ const backgroundColorChartJSPlugin = {
|
|
|
24471
24693
|
},
|
|
24472
24694
|
};
|
|
24473
24695
|
|
|
24474
|
-
const CfTerms = {
|
|
24475
|
-
Errors: {
|
|
24476
|
-
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid"),
|
|
24477
|
-
["FirstArgMissing" /* CommandResult.FirstArgMissing */]: _t("The argument is missing. Please provide a value"),
|
|
24478
|
-
["SecondArgMissing" /* CommandResult.SecondArgMissing */]: _t("The second argument is missing. Please provide a value"),
|
|
24479
|
-
["MinNaN" /* CommandResult.MinNaN */]: _t("The minpoint must be a number"),
|
|
24480
|
-
["MidNaN" /* CommandResult.MidNaN */]: _t("The midpoint must be a number"),
|
|
24481
|
-
["MaxNaN" /* CommandResult.MaxNaN */]: _t("The maxpoint must be a number"),
|
|
24482
|
-
["ValueUpperInflectionNaN" /* CommandResult.ValueUpperInflectionNaN */]: _t("The first value must be a number"),
|
|
24483
|
-
["ValueLowerInflectionNaN" /* CommandResult.ValueLowerInflectionNaN */]: _t("The second value must be a number"),
|
|
24484
|
-
["MinBiggerThanMax" /* CommandResult.MinBiggerThanMax */]: _t("Minimum must be smaller then Maximum"),
|
|
24485
|
-
["MinBiggerThanMid" /* CommandResult.MinBiggerThanMid */]: _t("Minimum must be smaller then Midpoint"),
|
|
24486
|
-
["MidBiggerThanMax" /* CommandResult.MidBiggerThanMax */]: _t("Midpoint must be smaller then Maximum"),
|
|
24487
|
-
["LowerBiggerThanUpper" /* CommandResult.LowerBiggerThanUpper */]: _t("Lower inflection point must be smaller than upper inflection point"),
|
|
24488
|
-
["MinInvalidFormula" /* CommandResult.MinInvalidFormula */]: _t("Invalid Minpoint formula"),
|
|
24489
|
-
["MaxInvalidFormula" /* CommandResult.MaxInvalidFormula */]: _t("Invalid Maxpoint formula"),
|
|
24490
|
-
["MidInvalidFormula" /* CommandResult.MidInvalidFormula */]: _t("Invalid Midpoint formula"),
|
|
24491
|
-
["ValueUpperInvalidFormula" /* CommandResult.ValueUpperInvalidFormula */]: _t("Invalid upper inflection point formula"),
|
|
24492
|
-
["ValueLowerInvalidFormula" /* CommandResult.ValueLowerInvalidFormula */]: _t("Invalid lower inflection point formula"),
|
|
24493
|
-
["EmptyRange" /* CommandResult.EmptyRange */]: _t("A range needs to be defined"),
|
|
24494
|
-
["ValueCellIsInvalidFormula" /* CommandResult.ValueCellIsInvalidFormula */]: _t("At least one of the provided values is an invalid formula"),
|
|
24495
|
-
Unexpected: _t("The rule is invalid for an unknown reason"),
|
|
24496
|
-
},
|
|
24497
|
-
ColorScale: _t("Color scale"),
|
|
24498
|
-
IconSet: _t("Icon set"),
|
|
24499
|
-
DataBar: _t("Data bar"),
|
|
24500
|
-
};
|
|
24501
|
-
const ChartTerms = {
|
|
24502
|
-
Series: _t("Series"),
|
|
24503
|
-
BackgroundColor: _t("Background color"),
|
|
24504
|
-
StackedBarChart: _t("Stacked bar chart"),
|
|
24505
|
-
StackedLineChart: _t("Stacked line chart"),
|
|
24506
|
-
StackedAreaChart: _t("Stacked area chart"),
|
|
24507
|
-
StackedColumnChart: _t("Stacked column chart"),
|
|
24508
|
-
CumulativeData: _t("Cumulative data"),
|
|
24509
|
-
TreatLabelsAsText: _t("Treat labels as text"),
|
|
24510
|
-
AggregatedChart: _t("Aggregate"),
|
|
24511
|
-
Errors: {
|
|
24512
|
-
Unexpected: _t("The chart definition is invalid for an unknown reason"),
|
|
24513
|
-
// BASIC CHART ERRORS (LINE | BAR | PIE)
|
|
24514
|
-
["InvalidDataSet" /* CommandResult.InvalidDataSet */]: _t("The dataset is invalid"),
|
|
24515
|
-
["InvalidLabelRange" /* CommandResult.InvalidLabelRange */]: _t("Labels are invalid"),
|
|
24516
|
-
// SCORECARD CHART ERRORS
|
|
24517
|
-
["InvalidScorecardKeyValue" /* CommandResult.InvalidScorecardKeyValue */]: _t("The key value is invalid"),
|
|
24518
|
-
["InvalidScorecardBaseline" /* CommandResult.InvalidScorecardBaseline */]: _t("The baseline value is invalid"),
|
|
24519
|
-
// GAUGE CHART ERRORS
|
|
24520
|
-
["InvalidGaugeDataRange" /* CommandResult.InvalidGaugeDataRange */]: _t("The data range is invalid"),
|
|
24521
|
-
["EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */]: _t("A minimum range limit value is needed"),
|
|
24522
|
-
["GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */]: _t("The minimum range limit value must be a number"),
|
|
24523
|
-
["EmptyGaugeRangeMax" /* CommandResult.EmptyGaugeRangeMax */]: _t("A maximum range limit value is needed"),
|
|
24524
|
-
["GaugeRangeMaxNaN" /* CommandResult.GaugeRangeMaxNaN */]: _t("The maximum range limit value must be a number"),
|
|
24525
|
-
["GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */]: _t("The lower inflection point value must be a number"),
|
|
24526
|
-
["GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */]: _t("The upper inflection point value must be a number"),
|
|
24527
|
-
},
|
|
24528
|
-
GeoChart: {
|
|
24529
|
-
ColorScales: {
|
|
24530
|
-
blues: _t("Blues"),
|
|
24531
|
-
cividis: _t("Cividis"),
|
|
24532
|
-
greens: _t("Greens"),
|
|
24533
|
-
greys: _t("Greys"),
|
|
24534
|
-
oranges: _t("Oranges"),
|
|
24535
|
-
purples: _t("Purples"),
|
|
24536
|
-
rainbow: _t("Rainbow"),
|
|
24537
|
-
reds: _t("Reds"),
|
|
24538
|
-
viridis: _t("Viridis"),
|
|
24539
|
-
},
|
|
24540
|
-
},
|
|
24541
|
-
};
|
|
24542
|
-
const CustomCurrencyTerms = {
|
|
24543
|
-
Custom: _t("Custom"),
|
|
24544
|
-
};
|
|
24545
|
-
const MergeErrorMessage = _t("Merged cells are preventing this operation. Unmerge those cells and try again.");
|
|
24546
|
-
const SplitToColumnsTerms = {
|
|
24547
|
-
Errors: {
|
|
24548
|
-
Unexpected: _t("Cannot split the selection for an unknown reason"),
|
|
24549
|
-
["NoSplitSeparatorInSelection" /* CommandResult.NoSplitSeparatorInSelection */]: _t("There is no match for the selected separator in the selection"),
|
|
24550
|
-
["MoreThanOneColumnSelected" /* CommandResult.MoreThanOneColumnSelected */]: _t("Only a selection from a single column can be split"),
|
|
24551
|
-
["SplitWillOverwriteContent" /* CommandResult.SplitWillOverwriteContent */]: _t("Splitting will overwrite existing content"),
|
|
24552
|
-
},
|
|
24553
|
-
};
|
|
24554
|
-
const RemoveDuplicateTerms = {
|
|
24555
|
-
Errors: {
|
|
24556
|
-
Unexpected: _t("Cannot remove duplicates for an unknown reason"),
|
|
24557
|
-
["MoreThanOneRangeSelected" /* CommandResult.MoreThanOneRangeSelected */]: _t("Please select only one range of cells"),
|
|
24558
|
-
["EmptyTarget" /* CommandResult.EmptyTarget */]: _t("Please select a range of cells containing values."),
|
|
24559
|
-
["NoColumnsProvided" /* CommandResult.NoColumnsProvided */]: _t("Please select at latest one column to analyze."),
|
|
24560
|
-
//TODO: Remove it when accept to copy and paste merge cells
|
|
24561
|
-
["WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */]: _t("This operation is not possible due to a merge. Please remove the merges first than try again."),
|
|
24562
|
-
},
|
|
24563
|
-
};
|
|
24564
|
-
const DVTerms = {
|
|
24565
|
-
DateIs: {
|
|
24566
|
-
today: _t("today"),
|
|
24567
|
-
yesterday: _t("yesterday"),
|
|
24568
|
-
tomorrow: _t("tomorrow"),
|
|
24569
|
-
lastWeek: _t("in the past week"),
|
|
24570
|
-
lastMonth: _t("in the past month"),
|
|
24571
|
-
lastYear: _t("in the past year"),
|
|
24572
|
-
},
|
|
24573
|
-
DateIsBefore: {
|
|
24574
|
-
today: _t("today"),
|
|
24575
|
-
yesterday: _t("yesterday"),
|
|
24576
|
-
tomorrow: _t("tomorrow"),
|
|
24577
|
-
lastWeek: _t("one week ago"),
|
|
24578
|
-
lastMonth: _t("one month ago"),
|
|
24579
|
-
lastYear: _t("one year ago"),
|
|
24580
|
-
},
|
|
24581
|
-
CriterionError: {
|
|
24582
|
-
notEmptyValue: _t("The value must not be empty"),
|
|
24583
|
-
numberValue: _t("The value must be a number"),
|
|
24584
|
-
dateValue: _t("The value must be a date"),
|
|
24585
|
-
validRange: _t("The value must be a valid range"),
|
|
24586
|
-
validFormula: _t("The formula must be valid"),
|
|
24587
|
-
},
|
|
24588
|
-
Errors: {
|
|
24589
|
-
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid."),
|
|
24590
|
-
["InvalidDataValidationCriterionValue" /* CommandResult.InvalidDataValidationCriterionValue */]: _t("One or more of the provided criteria values are invalid. Please review and correct them."),
|
|
24591
|
-
["InvalidNumberOfCriterionValues" /* CommandResult.InvalidNumberOfCriterionValues */]: _t("One or more of the provided criteria values are missing."),
|
|
24592
|
-
Unexpected: _t("The rule is invalid for an unknown reason."),
|
|
24593
|
-
},
|
|
24594
|
-
};
|
|
24595
|
-
const TableTerms = {
|
|
24596
|
-
Errors: {
|
|
24597
|
-
Unexpected: _t("The table zone is invalid for an unknown reason"),
|
|
24598
|
-
["TableOverlap" /* CommandResult.TableOverlap */]: _t("You cannot create overlapping tables."),
|
|
24599
|
-
["NonContinuousTargets" /* CommandResult.NonContinuousTargets */]: _t("A table can only be created on a continuous selection."),
|
|
24600
|
-
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid"),
|
|
24601
|
-
["TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */]: _t("The range is out of the sheet"),
|
|
24602
|
-
},
|
|
24603
|
-
Checkboxes: {
|
|
24604
|
-
hasFilters: _t("Filter button"),
|
|
24605
|
-
headerRow: _t("Header row(s)"),
|
|
24606
|
-
bandedRows: _t("Banded rows"),
|
|
24607
|
-
firstColumn: _t("First column"),
|
|
24608
|
-
lastColumn: _t("Last column"),
|
|
24609
|
-
bandedColumns: _t("Banded columns"),
|
|
24610
|
-
automaticAutofill: _t("Automatically autofill formulas"),
|
|
24611
|
-
totalRow: _t("Total row"),
|
|
24612
|
-
isDynamic: _t("Auto-adjust to formula result"),
|
|
24613
|
-
},
|
|
24614
|
-
Tooltips: {
|
|
24615
|
-
filterWithoutHeader: _t("Cannot have filters without a header row"),
|
|
24616
|
-
isDynamic: _t("For tables based on array formulas only"),
|
|
24617
|
-
},
|
|
24618
|
-
};
|
|
24619
|
-
const measureDisplayTerms = {
|
|
24620
|
-
labels: {
|
|
24621
|
-
no_calculations: _t("No calculations"),
|
|
24622
|
-
"%_of_grand_total": _t("% of grand total"),
|
|
24623
|
-
"%_of_col_total": _t("% of column total"),
|
|
24624
|
-
"%_of_row_total": _t("% of row total"),
|
|
24625
|
-
"%_of": _t("% of"),
|
|
24626
|
-
"%_of_parent_row_total": _t("% of parent row total"),
|
|
24627
|
-
"%_of_parent_col_total": _t("% of parent column total"),
|
|
24628
|
-
"%_of_parent_total": _t("% of parent total"),
|
|
24629
|
-
difference_from: _t("Difference from"),
|
|
24630
|
-
"%_difference_from": _t("% difference from"),
|
|
24631
|
-
running_total: _t("Running total"),
|
|
24632
|
-
"%_running_total": _t("% Running total"),
|
|
24633
|
-
rank_asc: _t("Rank smallest to largest"),
|
|
24634
|
-
rank_desc: _t("Rank largest to smallest"),
|
|
24635
|
-
index: _t("Index"),
|
|
24636
|
-
},
|
|
24637
|
-
descriptions: {
|
|
24638
|
-
"%_of_grand_total": () => _t("Displayed as % of grand total"),
|
|
24639
|
-
"%_of_col_total": () => _t("Displayed as % of column total"),
|
|
24640
|
-
"%_of_row_total": () => _t("Displayed as % of row total"),
|
|
24641
|
-
"%_of": (field) => _t('Displayed as % of "%s"', field),
|
|
24642
|
-
"%_of_parent_row_total": (field) => _t('Displayed as % of parent row total of "%s"', field),
|
|
24643
|
-
"%_of_parent_col_total": () => _t("Displayed as % of parent column total"),
|
|
24644
|
-
"%_of_parent_total": (field) => _t('Displayed as % of parent "%s" total', field),
|
|
24645
|
-
difference_from: (field) => _t('Displayed as difference from "%s"', field),
|
|
24646
|
-
"%_difference_from": (field) => _t('Displayed as % difference from "%s"', field),
|
|
24647
|
-
running_total: (field) => _t('Displayed as running total based on "%s"', field),
|
|
24648
|
-
"%_running_total": (field) => _t('Displayed as % running total based on "%s"', field),
|
|
24649
|
-
rank_asc: (field) => _t('Displayed as rank from smallest to largest based on "%s"', field),
|
|
24650
|
-
rank_desc: (field) => _t('Displayed as rank largest to smallest based on "%s"', field),
|
|
24651
|
-
index: () => _t("Displayed as index"),
|
|
24652
|
-
},
|
|
24653
|
-
documentation: {
|
|
24654
|
-
no_calculations: _t("Displays the value that is entered in the field."),
|
|
24655
|
-
"%_of_grand_total": _t("Displays values as a percentage of the grand total of all the values or data points in the report."),
|
|
24656
|
-
"%_of_col_total": _t("Displays all the values in each column or series as a percentage of the total for the column or series."),
|
|
24657
|
-
"%_of_row_total": _t("Displays the value in each row or category as a percentage of the total for the row or category."),
|
|
24658
|
-
"%_of": _t("Displays values as a percentage of the value of the Base item in the Base field."),
|
|
24659
|
-
"%_of_parent_row_total": _t("Calculates values as follows:\n(value for the item) / (value for the parent item on rows)"),
|
|
24660
|
-
"%_of_parent_col_total": _t("Calculates values as follows:\n(value for the item) / (value for the parent item on columns)"),
|
|
24661
|
-
"%_of_parent_total": _t("Calculates values as follows:\n(value for the item) / (value for the parent item of the selected Base field)"),
|
|
24662
|
-
difference_from: _t("Displays values as the difference from the value of the Base item in the Base field."),
|
|
24663
|
-
"%_difference_from": _t("Displays values as the percentage difference from the value of the Base item in the Base field."),
|
|
24664
|
-
running_total: _t("Displays the value for successive items in the Base field as a running total."),
|
|
24665
|
-
"%_running_total": _t("Calculates the value as a percentage for successive items in the Base field that are displayed as a running total."),
|
|
24666
|
-
rank_asc: _t("Displays the rank of selected values in a specific field, listing the smallest item in the field as 1, and each larger value with a higher rank value."),
|
|
24667
|
-
rank_desc: _t("Displays the rank of selected values in a specific field, listing the largest item in the field as 1, and each smaller value with a higher rank value."),
|
|
24668
|
-
index: _t("Calculates values as follows:\n((value in cell) x (Grand Total of Grand Totals)) / ((Grand Row Total) x (Grand Column Total))"),
|
|
24669
|
-
},
|
|
24670
|
-
};
|
|
24671
|
-
|
|
24672
24696
|
const UNIT_LENGTH = {
|
|
24673
24697
|
second: 1000,
|
|
24674
24698
|
minute: 1000 * 60,
|
|
@@ -26017,7 +26041,7 @@ function getChartAxis(definition, position, type, options) {
|
|
|
26017
26041
|
ticks: {
|
|
26018
26042
|
padding: 5,
|
|
26019
26043
|
color: fontColor,
|
|
26020
|
-
callback: function (tickValue) {
|
|
26044
|
+
callback: function (tickValue, index, ticks) {
|
|
26021
26045
|
// Category axis callback's internal tick value is the index of the label
|
|
26022
26046
|
// https://www.chartjs.org/docs/latest/axes/labelling.html#creating-custom-tick-formats
|
|
26023
26047
|
return truncateLabel(this.getLabelForValue(tickValue));
|
|
@@ -26589,6 +26613,7 @@ class BarChart extends AbstractChart {
|
|
|
26589
26613
|
axesDesign;
|
|
26590
26614
|
horizontal;
|
|
26591
26615
|
showValues;
|
|
26616
|
+
zoomable;
|
|
26592
26617
|
constructor(definition, sheetId, getters) {
|
|
26593
26618
|
super(definition, sheetId, getters);
|
|
26594
26619
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
@@ -26602,6 +26627,7 @@ class BarChart extends AbstractChart {
|
|
|
26602
26627
|
this.axesDesign = definition.axesDesign;
|
|
26603
26628
|
this.horizontal = definition.horizontal;
|
|
26604
26629
|
this.showValues = definition.showValues;
|
|
26630
|
+
this.zoomable = definition.zoomable;
|
|
26605
26631
|
}
|
|
26606
26632
|
static transformDefinition(chartSheetId, definition, applyChange) {
|
|
26607
26633
|
return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange);
|
|
@@ -26623,6 +26649,7 @@ class BarChart extends AbstractChart {
|
|
|
26623
26649
|
axesDesign: context.axesDesign,
|
|
26624
26650
|
showValues: context.showValues,
|
|
26625
26651
|
horizontal: context.horizontal,
|
|
26652
|
+
zoomable: context.zoomable,
|
|
26626
26653
|
};
|
|
26627
26654
|
}
|
|
26628
26655
|
getContextCreation() {
|
|
@@ -26677,6 +26704,7 @@ class BarChart extends AbstractChart {
|
|
|
26677
26704
|
axesDesign: this.axesDesign,
|
|
26678
26705
|
horizontal: this.horizontal,
|
|
26679
26706
|
showValues: this.showValues,
|
|
26707
|
+
zoomable: this.horizontal ? undefined : this.zoomable,
|
|
26680
26708
|
};
|
|
26681
26709
|
}
|
|
26682
26710
|
getDefinitionForExcel() {
|
|
@@ -26725,6 +26753,621 @@ function createBarChartRuntime(chart, getters) {
|
|
|
26725
26753
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
26726
26754
|
}
|
|
26727
26755
|
|
|
26756
|
+
class FullScreenChartStore extends SpreadsheetStore {
|
|
26757
|
+
mutators = ["toggleFullScreenChart"];
|
|
26758
|
+
fullScreenFigure = undefined;
|
|
26759
|
+
toggleFullScreenChart(figureId) {
|
|
26760
|
+
if (this.fullScreenFigure?.id === figureId) {
|
|
26761
|
+
this.fullScreenFigure = undefined;
|
|
26762
|
+
}
|
|
26763
|
+
else {
|
|
26764
|
+
this.makeFullScreen(figureId);
|
|
26765
|
+
}
|
|
26766
|
+
}
|
|
26767
|
+
makeFullScreen(figureId) {
|
|
26768
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
26769
|
+
const figure = this.getters.getFigure(sheetId, figureId);
|
|
26770
|
+
if (figure) {
|
|
26771
|
+
this.fullScreenFigure = { ...figure, x: 0, y: 0, width: 0, height: 0 };
|
|
26772
|
+
}
|
|
26773
|
+
}
|
|
26774
|
+
}
|
|
26775
|
+
|
|
26776
|
+
const TREND_LINE_AXES_IDS = [TREND_LINE_XAXIS_ID, MOVING_AVERAGE_TREND_LINE_XAXIS_ID];
|
|
26777
|
+
const ZOOMABLE_AXIS_IDS = ["x", ...TREND_LINE_AXES_IDS];
|
|
26778
|
+
class ZoomableChartStore extends SpreadsheetStore {
|
|
26779
|
+
mutators = [
|
|
26780
|
+
"resetAxisLimits",
|
|
26781
|
+
"updateAxisLimits",
|
|
26782
|
+
"updateTrendLineConfiguration",
|
|
26783
|
+
"clearAxisLimits",
|
|
26784
|
+
];
|
|
26785
|
+
originalAxisLimits = {};
|
|
26786
|
+
currentAxesLimits = {};
|
|
26787
|
+
idConversion = {};
|
|
26788
|
+
handle(cmd) {
|
|
26789
|
+
switch (cmd.type) {
|
|
26790
|
+
case "DELETE_FIGURE":
|
|
26791
|
+
if (cmd.figureId && this.idConversion[cmd.figureId]) {
|
|
26792
|
+
for (const chartId of this.idConversion[cmd.figureId]) {
|
|
26793
|
+
delete this.originalAxisLimits[chartId];
|
|
26794
|
+
delete this.currentAxesLimits[chartId];
|
|
26795
|
+
}
|
|
26796
|
+
}
|
|
26797
|
+
break;
|
|
26798
|
+
case "UPDATE_CHART":
|
|
26799
|
+
const type = cmd.definition.type;
|
|
26800
|
+
const chartId = `${type}-${cmd.figureId}`;
|
|
26801
|
+
if (!this.idConversion[cmd.figureId]) {
|
|
26802
|
+
this.idConversion[cmd.figureId] = new Set();
|
|
26803
|
+
}
|
|
26804
|
+
this.idConversion[cmd.figureId].add(chartId);
|
|
26805
|
+
if (!("zoomable" in cmd.definition && cmd.definition.zoomable)) {
|
|
26806
|
+
this.clearAxisLimits(chartId);
|
|
26807
|
+
}
|
|
26808
|
+
break;
|
|
26809
|
+
}
|
|
26810
|
+
}
|
|
26811
|
+
clearAxisLimits(chartId) {
|
|
26812
|
+
delete this.originalAxisLimits[chartId];
|
|
26813
|
+
delete this.currentAxesLimits[chartId];
|
|
26814
|
+
return "noStateChange";
|
|
26815
|
+
}
|
|
26816
|
+
resetAxisLimits(chartId, limits) {
|
|
26817
|
+
for (const axisId of ZOOMABLE_AXIS_IDS) {
|
|
26818
|
+
if (limits?.[axisId]) {
|
|
26819
|
+
if (!this.originalAxisLimits[chartId]?.[axisId]) {
|
|
26820
|
+
this.originalAxisLimits[chartId] = {
|
|
26821
|
+
...this.originalAxisLimits[chartId],
|
|
26822
|
+
[axisId]: {},
|
|
26823
|
+
};
|
|
26824
|
+
}
|
|
26825
|
+
this.originalAxisLimits[chartId][axisId]["min"] = limits[axisId].min;
|
|
26826
|
+
this.originalAxisLimits[chartId][axisId]["max"] = limits[axisId].max;
|
|
26827
|
+
}
|
|
26828
|
+
else {
|
|
26829
|
+
if (this.originalAxisLimits[chartId]?.[axisId]) {
|
|
26830
|
+
delete this.originalAxisLimits[chartId][axisId];
|
|
26831
|
+
}
|
|
26832
|
+
}
|
|
26833
|
+
}
|
|
26834
|
+
return "noStateChange";
|
|
26835
|
+
}
|
|
26836
|
+
updateAxisLimits(chartId, limits) {
|
|
26837
|
+
if (limits === undefined) {
|
|
26838
|
+
delete this.currentAxesLimits[chartId];
|
|
26839
|
+
return "noStateChange";
|
|
26840
|
+
}
|
|
26841
|
+
let { min, max } = limits;
|
|
26842
|
+
if (min > max) {
|
|
26843
|
+
[min, max] = [max, min];
|
|
26844
|
+
}
|
|
26845
|
+
this.currentAxesLimits[chartId] = { x: { min, max } };
|
|
26846
|
+
return "noStateChange";
|
|
26847
|
+
}
|
|
26848
|
+
/* Update the trend line axis configuration based on the current axis limits.
|
|
26849
|
+
* This function calculates the new limits for the trend line axes based on the current x-axis
|
|
26850
|
+
* limits and the original limits of the trend line axes.
|
|
26851
|
+
* It assumes that the origininal trend line axes are linear transformations of the original x-axis
|
|
26852
|
+
* limits and applies the same transformation to the current x-axis limits to get the new limits
|
|
26853
|
+
* for the current trend line axes.
|
|
26854
|
+
*/
|
|
26855
|
+
updateTrendLineConfiguration(chartId) {
|
|
26856
|
+
if (!this.originalAxisLimits[chartId]) {
|
|
26857
|
+
return "noStateChange";
|
|
26858
|
+
}
|
|
26859
|
+
const chartLimits = this.originalAxisLimits[chartId].x;
|
|
26860
|
+
if (chartLimits === undefined) {
|
|
26861
|
+
return "noStateChange";
|
|
26862
|
+
}
|
|
26863
|
+
for (const axisId of TREND_LINE_AXES_IDS) {
|
|
26864
|
+
if (!this.originalAxisLimits[chartId][axisId]) {
|
|
26865
|
+
continue;
|
|
26866
|
+
}
|
|
26867
|
+
if (!this.currentAxesLimits[chartId]?.[axisId]) {
|
|
26868
|
+
this.currentAxesLimits[chartId] = {
|
|
26869
|
+
...this.currentAxesLimits[chartId],
|
|
26870
|
+
[axisId]: {},
|
|
26871
|
+
};
|
|
26872
|
+
}
|
|
26873
|
+
if (this.currentAxesLimits[chartId]?.x === undefined) {
|
|
26874
|
+
return "noStateChange";
|
|
26875
|
+
}
|
|
26876
|
+
const realRange = chartLimits.max - chartLimits.min;
|
|
26877
|
+
const trendingLimits = this.originalAxisLimits[chartId][axisId];
|
|
26878
|
+
const trendingRange = trendingLimits.max - trendingLimits.min;
|
|
26879
|
+
const slope = trendingRange / realRange;
|
|
26880
|
+
const intercept = trendingLimits.min - chartLimits.min * slope;
|
|
26881
|
+
const newXMin = this.currentAxesLimits[chartId].x.min;
|
|
26882
|
+
const newXMax = this.currentAxesLimits[chartId].x.max;
|
|
26883
|
+
this.currentAxesLimits[chartId][axisId].min = newXMin * slope + intercept;
|
|
26884
|
+
this.currentAxesLimits[chartId][axisId].max = newXMax * slope + intercept;
|
|
26885
|
+
}
|
|
26886
|
+
return "noStateChange";
|
|
26887
|
+
}
|
|
26888
|
+
}
|
|
26889
|
+
|
|
26890
|
+
const zoomWindowPlugin = {
|
|
26891
|
+
id: "zoomWindowPlugin",
|
|
26892
|
+
afterDatasetsDraw: function (chart, args, options) {
|
|
26893
|
+
if (!options.getLowerBound || !options.getUpperBound) {
|
|
26894
|
+
return;
|
|
26895
|
+
}
|
|
26896
|
+
const { ctx, chartArea: { left, right, top, bottom }, } = chart;
|
|
26897
|
+
let lowerBound = options.getLowerBound() ?? left;
|
|
26898
|
+
let upperBound = options.getUpperBound() ?? right;
|
|
26899
|
+
if (lowerBound > upperBound) {
|
|
26900
|
+
[lowerBound, upperBound] = [upperBound, lowerBound];
|
|
26901
|
+
}
|
|
26902
|
+
lowerBound = Math.max(left, lowerBound);
|
|
26903
|
+
upperBound = Math.min(right, upperBound);
|
|
26904
|
+
if (lowerBound === left) {
|
|
26905
|
+
lowerBound -= 1;
|
|
26906
|
+
}
|
|
26907
|
+
if (upperBound === right) {
|
|
26908
|
+
upperBound += 1;
|
|
26909
|
+
}
|
|
26910
|
+
ctx.save();
|
|
26911
|
+
ctx.fillStyle = "rgba(255,255,255,0.5)";
|
|
26912
|
+
ctx.beginPath();
|
|
26913
|
+
ctx.rect(left, bottom, lowerBound - left, top - bottom);
|
|
26914
|
+
ctx.rect(upperBound, bottom, right - upperBound, top - bottom);
|
|
26915
|
+
ctx.fill();
|
|
26916
|
+
ctx.beginPath();
|
|
26917
|
+
ctx.strokeStyle = "#bbb";
|
|
26918
|
+
ctx.rect(lowerBound, bottom, upperBound - lowerBound, top - bottom);
|
|
26919
|
+
ctx.stroke();
|
|
26920
|
+
ctx.lineWidth = 2;
|
|
26921
|
+
ctx.beginPath();
|
|
26922
|
+
ctx.moveTo(lowerBound - 3, (top + bottom) / 2 - 7);
|
|
26923
|
+
ctx.lineTo(lowerBound - 3, (top + bottom) / 2 + 7);
|
|
26924
|
+
ctx.stroke();
|
|
26925
|
+
ctx.beginPath();
|
|
26926
|
+
ctx.moveTo(upperBound + 3, (top + bottom) / 2 - 7);
|
|
26927
|
+
ctx.lineTo(upperBound + 3, (top + bottom) / 2 + 7);
|
|
26928
|
+
ctx.stroke();
|
|
26929
|
+
ctx.restore();
|
|
26930
|
+
},
|
|
26931
|
+
};
|
|
26932
|
+
|
|
26933
|
+
css /* scss */ `
|
|
26934
|
+
.o-spreadsheet {
|
|
26935
|
+
.o-master-chart-container {
|
|
26936
|
+
height: ${MASTER_CHART_HEIGHT}px;
|
|
26937
|
+
}
|
|
26938
|
+
}
|
|
26939
|
+
`;
|
|
26940
|
+
chartJsExtensionRegistry.add("zoomWindowPlugin", {
|
|
26941
|
+
register: (Chart) => Chart.register(zoomWindowPlugin),
|
|
26942
|
+
unregister: (Chart) => Chart.unregister(zoomWindowPlugin),
|
|
26943
|
+
});
|
|
26944
|
+
class ZoomableChartJsComponent extends ChartJsComponent {
|
|
26945
|
+
static template = "o-spreadsheet-ZoomableChartJsComponent";
|
|
26946
|
+
store;
|
|
26947
|
+
fullScreenChartStore;
|
|
26948
|
+
masterChartCanvas = owl.useRef("masterChartCanvas");
|
|
26949
|
+
masterChart;
|
|
26950
|
+
mode;
|
|
26951
|
+
hasLinearScale;
|
|
26952
|
+
isBarChart;
|
|
26953
|
+
chartId = "";
|
|
26954
|
+
datasetBoundaries = { xMin: 0, xMax: 0 };
|
|
26955
|
+
removeEventListeners = () => { };
|
|
26956
|
+
setup() {
|
|
26957
|
+
this.store = useStore(ZoomableChartStore);
|
|
26958
|
+
this.fullScreenChartStore = useStore(FullScreenChartStore);
|
|
26959
|
+
super.setup();
|
|
26960
|
+
}
|
|
26961
|
+
unmount() {
|
|
26962
|
+
super.unmount();
|
|
26963
|
+
this.masterChart?.destroy();
|
|
26964
|
+
this.removeEventListeners();
|
|
26965
|
+
}
|
|
26966
|
+
get containerStyle() {
|
|
26967
|
+
const height = this.sliceable ? `calc(100% - ${MASTER_CHART_HEIGHT}px)` : "100%";
|
|
26968
|
+
return `
|
|
26969
|
+
height:${height};
|
|
26970
|
+
`;
|
|
26971
|
+
}
|
|
26972
|
+
get sliceable() {
|
|
26973
|
+
if (this.env.isDashboard()) {
|
|
26974
|
+
const fullScreenFigureId = this.fullScreenChartStore.fullScreenFigure?.id;
|
|
26975
|
+
const chartFigureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
|
|
26976
|
+
if (fullScreenFigureId === chartFigureId) {
|
|
26977
|
+
return true;
|
|
26978
|
+
}
|
|
26979
|
+
}
|
|
26980
|
+
const definition = this.env.model.getters.getChartDefinition(this.props.chartId);
|
|
26981
|
+
return ("zoomable" in definition && definition?.zoomable) ?? false;
|
|
26982
|
+
}
|
|
26983
|
+
get axisOffset() {
|
|
26984
|
+
return !this.hasLinearScale && this.isBarChart ? 0.5 : 0;
|
|
26985
|
+
}
|
|
26986
|
+
getMasterChartConfiguration(chartData) {
|
|
26987
|
+
const config = chartData;
|
|
26988
|
+
return {
|
|
26989
|
+
...config,
|
|
26990
|
+
options: {
|
|
26991
|
+
...config.options,
|
|
26992
|
+
plugins: {
|
|
26993
|
+
...config.options.plugins,
|
|
26994
|
+
zoomWindowPlugin: {
|
|
26995
|
+
getLowerBound: () => this.lowerBound,
|
|
26996
|
+
getUpperBound: () => this.upperBound,
|
|
26997
|
+
},
|
|
26998
|
+
},
|
|
26999
|
+
},
|
|
27000
|
+
};
|
|
27001
|
+
}
|
|
27002
|
+
getDetailChartConfiguration(chartData) {
|
|
27003
|
+
if (!this.sliceable) {
|
|
27004
|
+
return chartData;
|
|
27005
|
+
}
|
|
27006
|
+
const xAxis = this.store.currentAxesLimits[this.chartId]?.x;
|
|
27007
|
+
const xScale = {
|
|
27008
|
+
...chartData.options.scales?.x,
|
|
27009
|
+
};
|
|
27010
|
+
if (xAxis?.min !== undefined) {
|
|
27011
|
+
xScale.min = this.hasLinearScale ? xAxis.min : Math.ceil(xAxis.min) - this.axisOffset;
|
|
27012
|
+
}
|
|
27013
|
+
if (xAxis?.max !== undefined) {
|
|
27014
|
+
xScale.max = this.hasLinearScale ? xAxis.max : Math.floor(xAxis.max) - this.axisOffset;
|
|
27015
|
+
}
|
|
27016
|
+
return {
|
|
27017
|
+
...chartData,
|
|
27018
|
+
options: {
|
|
27019
|
+
...chartData.options,
|
|
27020
|
+
scales: {
|
|
27021
|
+
...chartData.options.scales,
|
|
27022
|
+
x: xScale,
|
|
27023
|
+
},
|
|
27024
|
+
layout: {
|
|
27025
|
+
...chartData.options.layout,
|
|
27026
|
+
padding: {
|
|
27027
|
+
...chartData.options.layout?.padding,
|
|
27028
|
+
bottom: 5,
|
|
27029
|
+
},
|
|
27030
|
+
},
|
|
27031
|
+
},
|
|
27032
|
+
};
|
|
27033
|
+
}
|
|
27034
|
+
getAxisLimitsFromDataset(chartData) {
|
|
27035
|
+
const data = chartData.data.datasets.map((ds) => ds.data).flat();
|
|
27036
|
+
const xValues = data.map((d, i) => (typeof d === "object" && d !== null ? d.x : i));
|
|
27037
|
+
const xMin = Math.min(...xValues);
|
|
27038
|
+
const xMax = Math.max(...xValues);
|
|
27039
|
+
return { xMin, xMax };
|
|
27040
|
+
}
|
|
27041
|
+
get shouldAnimate() {
|
|
27042
|
+
return this.env.model.getters.isDashboard() && !this.sliceable;
|
|
27043
|
+
}
|
|
27044
|
+
createChart(chartRuntime) {
|
|
27045
|
+
const chartData = chartRuntime.chartJsConfig;
|
|
27046
|
+
this.isBarChart = chartData.type === "bar";
|
|
27047
|
+
this.chartId = `${chartData.type}-${this.props.chartId}`;
|
|
27048
|
+
this.datasetBoundaries = this.getAxisLimitsFromDataset(chartData);
|
|
27049
|
+
if (this.sliceable) {
|
|
27050
|
+
const updatedData = this.getDetailChartConfiguration(chartData);
|
|
27051
|
+
chartRuntime.chartJsConfig = updatedData;
|
|
27052
|
+
}
|
|
27053
|
+
super.createChart(chartRuntime);
|
|
27054
|
+
this.hasLinearScale = this.chart?.scales?.x.type === "linear";
|
|
27055
|
+
if (!this.sliceable || !("masterChartConfig" in chartRuntime)) {
|
|
27056
|
+
return;
|
|
27057
|
+
}
|
|
27058
|
+
this.masterChart?.destroy();
|
|
27059
|
+
const masterChartCtx = this.masterChartCanvas.el.getContext("2d");
|
|
27060
|
+
this.masterChart = new window.Chart(masterChartCtx, this.getMasterChartConfiguration(chartRuntime["masterChartConfig"]));
|
|
27061
|
+
this.resetAxesLimits();
|
|
27062
|
+
}
|
|
27063
|
+
updateChartJs(chartRuntime) {
|
|
27064
|
+
const chartData = chartRuntime.chartJsConfig;
|
|
27065
|
+
const newDatasetBoundaries = this.getAxisLimitsFromDataset(chartData);
|
|
27066
|
+
if (this.datasetBoundaries.xMin !== newDatasetBoundaries.xMin ||
|
|
27067
|
+
this.datasetBoundaries.xMax !== newDatasetBoundaries.xMax) {
|
|
27068
|
+
this.store.clearAxisLimits(this.chartId);
|
|
27069
|
+
this.datasetBoundaries = newDatasetBoundaries;
|
|
27070
|
+
}
|
|
27071
|
+
this.isBarChart = chartData?.type === "bar";
|
|
27072
|
+
this.chartId = `${chartData.type}-${this.props.chartId}`;
|
|
27073
|
+
if (this.sliceable) {
|
|
27074
|
+
const updatedData = this.getDetailChartConfiguration(chartData);
|
|
27075
|
+
chartRuntime.chartJsConfig = updatedData;
|
|
27076
|
+
}
|
|
27077
|
+
super.updateChartJs(chartRuntime);
|
|
27078
|
+
this.hasLinearScale = this.chart?.scales?.x.type === "linear";
|
|
27079
|
+
if (!this.sliceable || !("masterChartConfig" in chartRuntime)) {
|
|
27080
|
+
this.masterChart = undefined;
|
|
27081
|
+
}
|
|
27082
|
+
else {
|
|
27083
|
+
const masterChartConfig = this.getMasterChartConfiguration(chartRuntime["masterChartConfig"]);
|
|
27084
|
+
if (!this.masterChart) {
|
|
27085
|
+
const masterChartCtx = this.masterChartCanvas.el.getContext("2d");
|
|
27086
|
+
this.masterChart = new window.Chart(masterChartCtx, masterChartConfig);
|
|
27087
|
+
}
|
|
27088
|
+
else {
|
|
27089
|
+
this.masterChart.data = masterChartConfig.data;
|
|
27090
|
+
this.masterChart.config.options = masterChartConfig.options;
|
|
27091
|
+
this.masterChart.update();
|
|
27092
|
+
}
|
|
27093
|
+
}
|
|
27094
|
+
this.resetAxesLimits();
|
|
27095
|
+
}
|
|
27096
|
+
resetAxesLimits() {
|
|
27097
|
+
if (!this.chart) {
|
|
27098
|
+
return;
|
|
27099
|
+
}
|
|
27100
|
+
const previousAxisLimits = this.store.originalAxisLimits[this.chartId];
|
|
27101
|
+
if (previousAxisLimits?.x?.min === undefined && previousAxisLimits?.x?.max === undefined) {
|
|
27102
|
+
let scales = this.masterChart
|
|
27103
|
+
? this.masterChart.scales
|
|
27104
|
+
: this.chart.scales;
|
|
27105
|
+
if (!this.hasLinearScale && scales?.x) {
|
|
27106
|
+
scales = {
|
|
27107
|
+
...scales,
|
|
27108
|
+
x: {
|
|
27109
|
+
min: Math.ceil(scales.x.min) - this.axisOffset,
|
|
27110
|
+
max: Math.floor(scales.x.max) + this.axisOffset,
|
|
27111
|
+
},
|
|
27112
|
+
};
|
|
27113
|
+
}
|
|
27114
|
+
this.store.resetAxisLimits(this.chartId, scales);
|
|
27115
|
+
return;
|
|
27116
|
+
}
|
|
27117
|
+
this.updateTrendingLineAxes();
|
|
27118
|
+
this.chart.update();
|
|
27119
|
+
if (!this.masterChart) {
|
|
27120
|
+
return;
|
|
27121
|
+
}
|
|
27122
|
+
this.masterChart.update();
|
|
27123
|
+
}
|
|
27124
|
+
updateTrendingLineAxes() {
|
|
27125
|
+
this.store.updateTrendLineConfiguration(this.chartId);
|
|
27126
|
+
const config = this.store.currentAxesLimits[this.chartId];
|
|
27127
|
+
for (const axisId of [TREND_LINE_XAXIS_ID, MOVING_AVERAGE_TREND_LINE_XAXIS_ID]) {
|
|
27128
|
+
if (!this.chart?.config.options?.scales?.[axisId] || !config?.[axisId]) {
|
|
27129
|
+
continue;
|
|
27130
|
+
}
|
|
27131
|
+
this.chart.config.options.scales[axisId].min = config[axisId].min;
|
|
27132
|
+
this.chart.config.options.scales[axisId].max = config[axisId].max;
|
|
27133
|
+
}
|
|
27134
|
+
}
|
|
27135
|
+
get upperBound() {
|
|
27136
|
+
return this.computePosition(this.store.currentAxesLimits[this.chartId]?.x?.max);
|
|
27137
|
+
}
|
|
27138
|
+
get lowerBound() {
|
|
27139
|
+
return this.computePosition(this.store.currentAxesLimits[this.chartId]?.x?.min);
|
|
27140
|
+
}
|
|
27141
|
+
computePosition(value) {
|
|
27142
|
+
if (value === undefined || !this.masterChart?.scales?.x) {
|
|
27143
|
+
return undefined;
|
|
27144
|
+
}
|
|
27145
|
+
const scale = this.masterChart.scales.x;
|
|
27146
|
+
if (this.hasLinearScale) {
|
|
27147
|
+
return scale.getPixelForValue(value);
|
|
27148
|
+
}
|
|
27149
|
+
if (!this.masterChart.chartArea) {
|
|
27150
|
+
return undefined;
|
|
27151
|
+
}
|
|
27152
|
+
const { left, right } = this.masterChart.chartArea;
|
|
27153
|
+
const { min, max } = scale;
|
|
27154
|
+
const offset = this.axisOffset;
|
|
27155
|
+
return left + ((right - left) * (offset + value - min)) / (2 * offset + max - min);
|
|
27156
|
+
}
|
|
27157
|
+
computeCoordinate(position) {
|
|
27158
|
+
if (!this.masterChart) {
|
|
27159
|
+
return undefined;
|
|
27160
|
+
}
|
|
27161
|
+
const scale = this.masterChart.scales.x;
|
|
27162
|
+
if (this.hasLinearScale) {
|
|
27163
|
+
const value = scale.getValueForPixel(position);
|
|
27164
|
+
if (value === undefined) {
|
|
27165
|
+
return undefined;
|
|
27166
|
+
}
|
|
27167
|
+
return Math.round(value * 100) / 100;
|
|
27168
|
+
}
|
|
27169
|
+
const { left, right } = this.masterChart.chartArea;
|
|
27170
|
+
const offset = this.axisOffset;
|
|
27171
|
+
return (scale.min -
|
|
27172
|
+
offset +
|
|
27173
|
+
((scale.max + 2 * offset - scale.min) * (position - left)) / (right - left));
|
|
27174
|
+
}
|
|
27175
|
+
updateAxisLimits(xMin, xMax) {
|
|
27176
|
+
if (!this.hasLinearScale) {
|
|
27177
|
+
this.chart.config.options.scales.x.min = Math.ceil(xMin);
|
|
27178
|
+
this.chart.config.options.scales.x.max = Math.floor(xMax);
|
|
27179
|
+
}
|
|
27180
|
+
else {
|
|
27181
|
+
this.chart.config.options.scales.x.min = xMin;
|
|
27182
|
+
this.chart.config.options.scales.x.max = xMax;
|
|
27183
|
+
}
|
|
27184
|
+
this.store.updateAxisLimits(this.chartId, { min: xMin, max: xMax });
|
|
27185
|
+
this.updateTrendingLineAxes();
|
|
27186
|
+
this.masterChart?.update();
|
|
27187
|
+
this.chart?.update();
|
|
27188
|
+
}
|
|
27189
|
+
onPointerDownInMasterChart(ev) {
|
|
27190
|
+
this.removeEventListeners();
|
|
27191
|
+
const position = ev.offsetX;
|
|
27192
|
+
if (!this.masterChart?.chartArea || !this.chart?.scales.x) {
|
|
27193
|
+
return;
|
|
27194
|
+
}
|
|
27195
|
+
const { left, right, top, bottom } = this.masterChart.chartArea;
|
|
27196
|
+
const xMax = this.upperBound ?? right;
|
|
27197
|
+
const xMin = this.lowerBound ?? left;
|
|
27198
|
+
if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
|
|
27199
|
+
return;
|
|
27200
|
+
}
|
|
27201
|
+
ev.preventDefault();
|
|
27202
|
+
ev.stopPropagation();
|
|
27203
|
+
let startingPositionOnChart, windowSize, startX;
|
|
27204
|
+
const startingEventPosition = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
|
|
27205
|
+
if ((xMin !== left || xMax !== right) && position > xMin + 5 && position < xMax - 5) {
|
|
27206
|
+
startingPositionOnChart = ev.offsetX - xMin;
|
|
27207
|
+
this.mode = "moveInMaster";
|
|
27208
|
+
const currentLimits = this.store.currentAxesLimits[this.chartId]?.x;
|
|
27209
|
+
windowSize =
|
|
27210
|
+
(currentLimits?.max ?? this.chart.scales.x.max) -
|
|
27211
|
+
(currentLimits?.min ?? this.chart.scales.x.min);
|
|
27212
|
+
}
|
|
27213
|
+
else {
|
|
27214
|
+
this.mode = "selectInMaster";
|
|
27215
|
+
if (Math.abs(position - xMin) < 5) {
|
|
27216
|
+
startingPositionOnChart = xMax;
|
|
27217
|
+
}
|
|
27218
|
+
else if (Math.abs(position - xMax) < 5) {
|
|
27219
|
+
startingPositionOnChart = xMin;
|
|
27220
|
+
}
|
|
27221
|
+
else {
|
|
27222
|
+
startingPositionOnChart = clip(position, left, right);
|
|
27223
|
+
}
|
|
27224
|
+
startX = this.computeCoordinate(startingPositionOnChart);
|
|
27225
|
+
}
|
|
27226
|
+
const originalXMin = this.store.originalAxisLimits[this.chartId].x.min;
|
|
27227
|
+
const originalXMax = this.store.originalAxisLimits[this.chartId].x.max;
|
|
27228
|
+
const computeNewAxisLimits = (position) => {
|
|
27229
|
+
let xMin, xMax;
|
|
27230
|
+
const { left, right } = this.masterChart.chartArea;
|
|
27231
|
+
if (this.mode === "moveInMaster") {
|
|
27232
|
+
xMin = this.computeCoordinate(position - startingPositionOnChart);
|
|
27233
|
+
if (xMin < originalXMin) {
|
|
27234
|
+
xMin = originalXMin;
|
|
27235
|
+
}
|
|
27236
|
+
else if (xMin > originalXMax - windowSize) {
|
|
27237
|
+
xMin = originalXMax - windowSize;
|
|
27238
|
+
}
|
|
27239
|
+
xMax = xMin + windowSize;
|
|
27240
|
+
}
|
|
27241
|
+
else if (this.mode === "selectInMaster") {
|
|
27242
|
+
const upperBound = clip(position, left, right);
|
|
27243
|
+
if (Math.abs(startingPositionOnChart - upperBound) > 5) {
|
|
27244
|
+
const endX = this.computeCoordinate(upperBound);
|
|
27245
|
+
if (startX === undefined || endX === undefined) {
|
|
27246
|
+
return {};
|
|
27247
|
+
}
|
|
27248
|
+
xMin = Math.min(startX, endX);
|
|
27249
|
+
xMax = Math.max(startX, endX);
|
|
27250
|
+
}
|
|
27251
|
+
}
|
|
27252
|
+
return { min: xMin, max: xMax };
|
|
27253
|
+
};
|
|
27254
|
+
const onDragFromMasterChart = (ev) => {
|
|
27255
|
+
const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
|
|
27256
|
+
if (Math.abs(position - startingEventPosition) < 5) {
|
|
27257
|
+
return;
|
|
27258
|
+
}
|
|
27259
|
+
const { min: xMin, max: xMax } = computeNewAxisLimits(position);
|
|
27260
|
+
if (xMin !== undefined && xMax !== undefined) {
|
|
27261
|
+
this.updateAxisLimits(xMin, xMax);
|
|
27262
|
+
}
|
|
27263
|
+
};
|
|
27264
|
+
const onPointerUpInMasterChart = (ev) => {
|
|
27265
|
+
this.removeEventListeners();
|
|
27266
|
+
const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
|
|
27267
|
+
if (Math.abs(position - startingEventPosition) > 5) {
|
|
27268
|
+
let { min: xMin, max: xMax } = computeNewAxisLimits(position);
|
|
27269
|
+
if (xMin !== undefined && xMax !== undefined) {
|
|
27270
|
+
if (!this.hasLinearScale) {
|
|
27271
|
+
if (this.mode === "moveInMaster" && windowSize && !this.isBarChart) {
|
|
27272
|
+
xMin = Math.round(xMin) - this.axisOffset;
|
|
27273
|
+
xMax = xMin + windowSize;
|
|
27274
|
+
}
|
|
27275
|
+
else {
|
|
27276
|
+
xMin = Math.ceil(xMin) - this.axisOffset;
|
|
27277
|
+
xMax = Math.floor(xMax) + this.axisOffset;
|
|
27278
|
+
}
|
|
27279
|
+
}
|
|
27280
|
+
this.updateAxisLimits(xMin, xMax);
|
|
27281
|
+
}
|
|
27282
|
+
}
|
|
27283
|
+
this.mode = undefined;
|
|
27284
|
+
};
|
|
27285
|
+
this.removeEventListeners = () => {
|
|
27286
|
+
window.removeEventListener("pointermove", onDragFromMasterChart, true);
|
|
27287
|
+
window.removeEventListener("pointerup", onPointerUpInMasterChart, true);
|
|
27288
|
+
};
|
|
27289
|
+
window.addEventListener("pointermove", onDragFromMasterChart, true);
|
|
27290
|
+
window.addEventListener("pointerup", onPointerUpInMasterChart, true);
|
|
27291
|
+
}
|
|
27292
|
+
onPointerMoveInMasterChart(ev) {
|
|
27293
|
+
const { offsetX: x, offsetY: y } = ev;
|
|
27294
|
+
if (this.mode === undefined) {
|
|
27295
|
+
const target = ev.target;
|
|
27296
|
+
if (!this.masterChart?.chartArea) {
|
|
27297
|
+
target["style"].cursor = "default";
|
|
27298
|
+
return;
|
|
27299
|
+
}
|
|
27300
|
+
const { left, right, top, bottom } = this.masterChart.chartArea;
|
|
27301
|
+
const start = this.lowerBound ?? left;
|
|
27302
|
+
const end = this.upperBound ?? right;
|
|
27303
|
+
if (y < top || y > bottom) {
|
|
27304
|
+
target["style"].cursor = "default";
|
|
27305
|
+
}
|
|
27306
|
+
else if (Math.abs(start - x) < 5 || Math.abs(end - x) < 5) {
|
|
27307
|
+
target["style"].cursor = "ew-resize";
|
|
27308
|
+
}
|
|
27309
|
+
else if (start < x && x < end && (start !== left || end !== right)) {
|
|
27310
|
+
target["style"].cursor = "grab";
|
|
27311
|
+
}
|
|
27312
|
+
else {
|
|
27313
|
+
target["style"].cursor = "crosshair";
|
|
27314
|
+
}
|
|
27315
|
+
}
|
|
27316
|
+
}
|
|
27317
|
+
onMouseLeaveMasterChart(ev) {
|
|
27318
|
+
const target = ev.target;
|
|
27319
|
+
if (!target) {
|
|
27320
|
+
return;
|
|
27321
|
+
}
|
|
27322
|
+
target["style"].cursor = "default";
|
|
27323
|
+
}
|
|
27324
|
+
onDoubleClickInMasterChart(ev) {
|
|
27325
|
+
this.mode = undefined;
|
|
27326
|
+
const position = ev.offsetX;
|
|
27327
|
+
if (!this.masterChart?.chartArea || !this.chart?.scales.x) {
|
|
27328
|
+
return;
|
|
27329
|
+
}
|
|
27330
|
+
const { left, right, top, bottom } = this.masterChart.chartArea;
|
|
27331
|
+
let upperBound = this.upperBound ?? right;
|
|
27332
|
+
let lowerBound = this.lowerBound ?? left;
|
|
27333
|
+
if (upperBound < lowerBound) {
|
|
27334
|
+
[upperBound, lowerBound] = [lowerBound, upperBound];
|
|
27335
|
+
}
|
|
27336
|
+
if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
|
|
27337
|
+
return;
|
|
27338
|
+
}
|
|
27339
|
+
ev.preventDefault();
|
|
27340
|
+
ev.stopPropagation();
|
|
27341
|
+
let { min: xMin, max: xMax } = this.store.currentAxesLimits[this.chartId]?.x ?? this.chart.scales.x;
|
|
27342
|
+
const originalAxisLimits = this.store.originalAxisLimits[this.chartId].x;
|
|
27343
|
+
if (!originalAxisLimits) {
|
|
27344
|
+
return;
|
|
27345
|
+
}
|
|
27346
|
+
let originalXMin = originalAxisLimits.min;
|
|
27347
|
+
let originalXMax = originalAxisLimits.max;
|
|
27348
|
+
if (this.hasLinearScale) {
|
|
27349
|
+
originalXMin = Math.ceil(originalXMin) - this.axisOffset;
|
|
27350
|
+
originalXMax = Math.floor(originalXMax) + this.axisOffset;
|
|
27351
|
+
}
|
|
27352
|
+
if (Math.abs(position - lowerBound) < 5) {
|
|
27353
|
+
// Reset to original min
|
|
27354
|
+
xMin = originalXMin;
|
|
27355
|
+
}
|
|
27356
|
+
else if (Math.abs(position - upperBound) < 5) {
|
|
27357
|
+
xMax = originalXMax;
|
|
27358
|
+
}
|
|
27359
|
+
else if (lowerBound < position && position < upperBound) {
|
|
27360
|
+
// Reset to original limits
|
|
27361
|
+
xMin = originalXMin;
|
|
27362
|
+
xMax = originalXMax;
|
|
27363
|
+
}
|
|
27364
|
+
else {
|
|
27365
|
+
return;
|
|
27366
|
+
}
|
|
27367
|
+
this.updateAxisLimits(xMin, xMax);
|
|
27368
|
+
}
|
|
27369
|
+
}
|
|
27370
|
+
|
|
26728
27371
|
const cellAnimationRegistry = new Registry();
|
|
26729
27372
|
cellAnimationRegistry.add("animatedBackgroundColorChange", {
|
|
26730
27373
|
id: "animatedBackgroundColorChange",
|
|
@@ -27087,13 +27730,13 @@ const ANIMATION_DURATION = 1000;
|
|
|
27087
27730
|
class GaugeChartComponent extends owl.Component {
|
|
27088
27731
|
static template = "o-spreadsheet-GaugeChartComponent";
|
|
27089
27732
|
static props = {
|
|
27090
|
-
|
|
27733
|
+
chartId: String,
|
|
27091
27734
|
isFullScreen: { type: Boolean, optional: true },
|
|
27092
27735
|
};
|
|
27093
27736
|
canvas = owl.useRef("chartContainer");
|
|
27094
27737
|
animationStore;
|
|
27095
27738
|
get runtime() {
|
|
27096
|
-
return this.env.model.getters.getChartRuntime(this.props.
|
|
27739
|
+
return this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
27097
27740
|
}
|
|
27098
27741
|
setup() {
|
|
27099
27742
|
if (this.env.model.getters.isDashboard()) {
|
|
@@ -27141,9 +27784,7 @@ class GaugeChartComponent extends owl.Component {
|
|
|
27141
27784
|
return this.canvas.el;
|
|
27142
27785
|
}
|
|
27143
27786
|
get animationFigureId() {
|
|
27144
|
-
return this.props.isFullScreen
|
|
27145
|
-
? this.props.figureUI.id + "-fullscreen"
|
|
27146
|
-
: this.props.figureUI.id;
|
|
27787
|
+
return this.props.isFullScreen ? this.props.chartId + "-fullscreen" : this.props.chartId;
|
|
27147
27788
|
}
|
|
27148
27789
|
}
|
|
27149
27790
|
/**
|
|
@@ -27200,6 +27841,7 @@ class ComboChart extends AbstractChart {
|
|
|
27200
27841
|
type = "combo";
|
|
27201
27842
|
showValues;
|
|
27202
27843
|
hideDataMarkers;
|
|
27844
|
+
zoomable;
|
|
27203
27845
|
constructor(definition, sheetId, getters) {
|
|
27204
27846
|
super(definition, sheetId, getters);
|
|
27205
27847
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
@@ -27212,6 +27854,7 @@ class ComboChart extends AbstractChart {
|
|
|
27212
27854
|
this.axesDesign = definition.axesDesign;
|
|
27213
27855
|
this.showValues = definition.showValues;
|
|
27214
27856
|
this.hideDataMarkers = definition.hideDataMarkers;
|
|
27857
|
+
this.zoomable = definition.zoomable;
|
|
27215
27858
|
}
|
|
27216
27859
|
static transformDefinition(chartSheetId, definition, applyChange) {
|
|
27217
27860
|
return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange);
|
|
@@ -27261,6 +27904,7 @@ class ComboChart extends AbstractChart {
|
|
|
27261
27904
|
axesDesign: this.axesDesign,
|
|
27262
27905
|
showValues: this.showValues,
|
|
27263
27906
|
hideDataMarkers: this.hideDataMarkers,
|
|
27907
|
+
zoomable: this.zoomable,
|
|
27264
27908
|
};
|
|
27265
27909
|
}
|
|
27266
27910
|
getDefinitionForExcel() {
|
|
@@ -27304,6 +27948,7 @@ class ComboChart extends AbstractChart {
|
|
|
27304
27948
|
axesDesign: context.axesDesign,
|
|
27305
27949
|
showValues: context.showValues,
|
|
27306
27950
|
hideDataMarkers: context.hideDataMarkers,
|
|
27951
|
+
zoomable: context.zoomable,
|
|
27307
27952
|
};
|
|
27308
27953
|
}
|
|
27309
27954
|
duplicateInDuplicatedSheet(newSheetId) {
|
|
@@ -27909,6 +28554,7 @@ class LineChart extends AbstractChart {
|
|
|
27909
28554
|
fillArea;
|
|
27910
28555
|
showValues;
|
|
27911
28556
|
hideDataMarkers;
|
|
28557
|
+
zoomable;
|
|
27912
28558
|
constructor(definition, sheetId, getters) {
|
|
27913
28559
|
super(definition, sheetId, getters);
|
|
27914
28560
|
this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
@@ -27925,6 +28571,7 @@ class LineChart extends AbstractChart {
|
|
|
27925
28571
|
this.fillArea = definition.fillArea;
|
|
27926
28572
|
this.showValues = definition.showValues;
|
|
27927
28573
|
this.hideDataMarkers = definition.hideDataMarkers;
|
|
28574
|
+
this.zoomable = definition.zoomable;
|
|
27928
28575
|
}
|
|
27929
28576
|
static validateChartDefinition(validator, definition) {
|
|
27930
28577
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -27949,6 +28596,7 @@ class LineChart extends AbstractChart {
|
|
|
27949
28596
|
fillArea: context.fillArea,
|
|
27950
28597
|
showValues: context.showValues,
|
|
27951
28598
|
hideDataMarkers: context.hideDataMarkers,
|
|
28599
|
+
zoomable: context.zoomable,
|
|
27952
28600
|
};
|
|
27953
28601
|
}
|
|
27954
28602
|
getDefinition() {
|
|
@@ -27980,6 +28628,7 @@ class LineChart extends AbstractChart {
|
|
|
27980
28628
|
fillArea: this.fillArea,
|
|
27981
28629
|
showValues: this.showValues,
|
|
27982
28630
|
hideDataMarkers: this.hideDataMarkers,
|
|
28631
|
+
zoomable: this.zoomable,
|
|
27983
28632
|
};
|
|
27984
28633
|
}
|
|
27985
28634
|
getContextCreation() {
|
|
@@ -28502,6 +29151,7 @@ class ScatterChart extends AbstractChart {
|
|
|
28502
29151
|
dataSetDesign;
|
|
28503
29152
|
axesDesign;
|
|
28504
29153
|
showValues;
|
|
29154
|
+
zoomable;
|
|
28505
29155
|
constructor(definition, sheetId, getters) {
|
|
28506
29156
|
super(definition, sheetId, getters);
|
|
28507
29157
|
this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
@@ -28514,6 +29164,7 @@ class ScatterChart extends AbstractChart {
|
|
|
28514
29164
|
this.dataSetDesign = definition.dataSets;
|
|
28515
29165
|
this.axesDesign = definition.axesDesign;
|
|
28516
29166
|
this.showValues = definition.showValues;
|
|
29167
|
+
this.zoomable = definition.zoomable;
|
|
28517
29168
|
}
|
|
28518
29169
|
static validateChartDefinition(validator, definition) {
|
|
28519
29170
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -28534,6 +29185,7 @@ class ScatterChart extends AbstractChart {
|
|
|
28534
29185
|
aggregated: context.aggregated ?? false,
|
|
28535
29186
|
axesDesign: context.axesDesign,
|
|
28536
29187
|
showValues: context.showValues,
|
|
29188
|
+
zoomable: context.zoomable,
|
|
28537
29189
|
};
|
|
28538
29190
|
}
|
|
28539
29191
|
getDefinition() {
|
|
@@ -28561,6 +29213,7 @@ class ScatterChart extends AbstractChart {
|
|
|
28561
29213
|
aggregated: this.aggregated,
|
|
28562
29214
|
axesDesign: this.axesDesign,
|
|
28563
29215
|
showValues: this.showValues,
|
|
29216
|
+
zoomable: this.zoomable,
|
|
28564
29217
|
};
|
|
28565
29218
|
}
|
|
28566
29219
|
getContextCreation() {
|
|
@@ -28945,6 +29598,7 @@ class WaterfallChart extends AbstractChart {
|
|
|
28945
29598
|
dataSetDesign;
|
|
28946
29599
|
axesDesign;
|
|
28947
29600
|
showValues;
|
|
29601
|
+
zoomable;
|
|
28948
29602
|
constructor(definition, sheetId, getters) {
|
|
28949
29603
|
super(definition, sheetId, getters);
|
|
28950
29604
|
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
@@ -28963,6 +29617,7 @@ class WaterfallChart extends AbstractChart {
|
|
|
28963
29617
|
this.dataSetDesign = definition.dataSets;
|
|
28964
29618
|
this.axesDesign = definition.axesDesign;
|
|
28965
29619
|
this.showValues = definition.showValues;
|
|
29620
|
+
this.zoomable = definition.zoomable;
|
|
28966
29621
|
}
|
|
28967
29622
|
static transformDefinition(chartSheetId, definition, applyChange) {
|
|
28968
29623
|
return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange);
|
|
@@ -28986,6 +29641,7 @@ class WaterfallChart extends AbstractChart {
|
|
|
28986
29641
|
firstValueAsSubtotal: context.firstValueAsSubtotal ?? false,
|
|
28987
29642
|
axesDesign: context.axesDesign,
|
|
28988
29643
|
showValues: context.showValues,
|
|
29644
|
+
zoomable: context.zoomable ?? false,
|
|
28989
29645
|
};
|
|
28990
29646
|
}
|
|
28991
29647
|
getContextCreation() {
|
|
@@ -29045,6 +29701,7 @@ class WaterfallChart extends AbstractChart {
|
|
|
29045
29701
|
firstValueAsSubtotal: this.firstValueAsSubtotal,
|
|
29046
29702
|
axesDesign: this.axesDesign,
|
|
29047
29703
|
showValues: this.showValues,
|
|
29704
|
+
zoomable: this.zoomable,
|
|
29048
29705
|
};
|
|
29049
29706
|
}
|
|
29050
29707
|
getDefinitionForExcel() {
|
|
@@ -29221,14 +29878,14 @@ chartRegistry.add("treemap", {
|
|
|
29221
29878
|
sequence: 100,
|
|
29222
29879
|
});
|
|
29223
29880
|
const chartComponentRegistry = new Registry();
|
|
29224
|
-
chartComponentRegistry.add("line",
|
|
29225
|
-
chartComponentRegistry.add("bar",
|
|
29226
|
-
chartComponentRegistry.add("combo",
|
|
29881
|
+
chartComponentRegistry.add("line", ZoomableChartJsComponent);
|
|
29882
|
+
chartComponentRegistry.add("bar", ZoomableChartJsComponent);
|
|
29883
|
+
chartComponentRegistry.add("combo", ZoomableChartJsComponent);
|
|
29227
29884
|
chartComponentRegistry.add("pie", ChartJsComponent);
|
|
29228
29885
|
chartComponentRegistry.add("gauge", GaugeChartComponent);
|
|
29229
|
-
chartComponentRegistry.add("scatter",
|
|
29886
|
+
chartComponentRegistry.add("scatter", ZoomableChartJsComponent);
|
|
29230
29887
|
chartComponentRegistry.add("scorecard", ScorecardChart);
|
|
29231
|
-
chartComponentRegistry.add("waterfall",
|
|
29888
|
+
chartComponentRegistry.add("waterfall", ZoomableChartJsComponent);
|
|
29232
29889
|
chartComponentRegistry.add("pyramid", ChartJsComponent);
|
|
29233
29890
|
chartComponentRegistry.add("radar", ChartJsComponent);
|
|
29234
29891
|
chartComponentRegistry.add("geo", ChartJsComponent);
|
|
@@ -29427,12 +30084,70 @@ chartSubtypeRegistry
|
|
|
29427
30084
|
preview: "o-spreadsheet-ChartPreview.TREE_MAP_CHART",
|
|
29428
30085
|
});
|
|
29429
30086
|
|
|
30087
|
+
function generateMasterChartConfig(chartJsConfig) {
|
|
30088
|
+
return {
|
|
30089
|
+
...chartJsConfig,
|
|
30090
|
+
data: {
|
|
30091
|
+
...chartJsConfig.data,
|
|
30092
|
+
datasets: chartJsConfig.data.datasets
|
|
30093
|
+
.filter((ds) => !isTrendLineAxis(ds["xAxisID"]))
|
|
30094
|
+
.map((ds) => ({
|
|
30095
|
+
...ds,
|
|
30096
|
+
pointRadius: 0,
|
|
30097
|
+
showLine: true,
|
|
30098
|
+
})),
|
|
30099
|
+
},
|
|
30100
|
+
options: {
|
|
30101
|
+
...chartJsConfig.options,
|
|
30102
|
+
hover: { mode: null },
|
|
30103
|
+
plugins: {
|
|
30104
|
+
...chartJsConfig.options.plugins,
|
|
30105
|
+
title: { display: false },
|
|
30106
|
+
legend: { display: false },
|
|
30107
|
+
tooltip: { enabled: false },
|
|
30108
|
+
chartShowValuesPlugin: undefined,
|
|
30109
|
+
},
|
|
30110
|
+
layout: {
|
|
30111
|
+
padding: {
|
|
30112
|
+
...chartJsConfig.options.layout?.padding,
|
|
30113
|
+
top: 5,
|
|
30114
|
+
bottom: 10,
|
|
30115
|
+
},
|
|
30116
|
+
},
|
|
30117
|
+
scales: {
|
|
30118
|
+
y: {
|
|
30119
|
+
...chartJsConfig.options.scales?.y,
|
|
30120
|
+
display: false,
|
|
30121
|
+
},
|
|
30122
|
+
y1: {
|
|
30123
|
+
...chartJsConfig.options.scales?.y1,
|
|
30124
|
+
display: false,
|
|
30125
|
+
},
|
|
30126
|
+
x: {
|
|
30127
|
+
...chartJsConfig.options.scales?.x,
|
|
30128
|
+
title: undefined,
|
|
30129
|
+
ticks: {
|
|
30130
|
+
...chartJsConfig.options.scales?.x?.ticks,
|
|
30131
|
+
callback: function (value) {
|
|
30132
|
+
return truncateLabel(chartJsConfig.options.scales?.x?.ticks?.callback?.call(this, value), 5);
|
|
30133
|
+
},
|
|
30134
|
+
padding: 0,
|
|
30135
|
+
font: {
|
|
30136
|
+
size: 9,
|
|
30137
|
+
},
|
|
30138
|
+
},
|
|
30139
|
+
},
|
|
30140
|
+
},
|
|
30141
|
+
},
|
|
30142
|
+
};
|
|
30143
|
+
}
|
|
30144
|
+
|
|
29430
30145
|
/**
|
|
29431
30146
|
* Create a function used to create a Chart based on the definition
|
|
29432
30147
|
*/
|
|
29433
30148
|
function chartFactory(getters) {
|
|
29434
30149
|
const builders = chartRegistry.getAll().sort((a, b) => a.sequence - b.sequence);
|
|
29435
|
-
function createChart(
|
|
30150
|
+
function createChart(figureId, definition, sheetId) {
|
|
29436
30151
|
const builder = builders.find((builder) => builder.match(definition.type));
|
|
29437
30152
|
if (!builder) {
|
|
29438
30153
|
throw new Error(`No builder for this chart: ${definition.type}`);
|
|
@@ -29452,7 +30167,13 @@ function chartRuntimeFactory(getters) {
|
|
|
29452
30167
|
if (!builder) {
|
|
29453
30168
|
throw new Error("No runtime builder for this chart.");
|
|
29454
30169
|
}
|
|
29455
|
-
|
|
30170
|
+
const runtime = builder.getChartRuntime(chart, getters);
|
|
30171
|
+
const definition = chart.getDefinition();
|
|
30172
|
+
if ("chartJsConfig" in runtime && /line|combo|bar|scatter|waterfall/.test(definition.type)) {
|
|
30173
|
+
const chartJsConfig = runtime.chartJsConfig;
|
|
30174
|
+
runtime["masterChartConfig"] = generateMasterChartConfig(chartJsConfig);
|
|
30175
|
+
}
|
|
30176
|
+
return runtime;
|
|
29456
30177
|
}
|
|
29457
30178
|
return createRuntimeChart;
|
|
29458
30179
|
}
|
|
@@ -29783,6 +30504,8 @@ function getDefaultXLSXStructure(data) {
|
|
|
29783
30504
|
return {
|
|
29784
30505
|
relsFiles: [],
|
|
29785
30506
|
sharedStrings: [],
|
|
30507
|
+
chartIds: [],
|
|
30508
|
+
imageIds: [],
|
|
29786
30509
|
// default Values that will always be part of the style sheet
|
|
29787
30510
|
styles: [
|
|
29788
30511
|
{
|
|
@@ -29860,6 +30583,10 @@ function escapeQueryNameSpaces(query) {
|
|
|
29860
30583
|
}
|
|
29861
30584
|
|
|
29862
30585
|
function getChartMenuActions(figureId, onFigureDeleted, env) {
|
|
30586
|
+
const chartId = env.model.getters.getChartIdFromFigureId(figureId);
|
|
30587
|
+
if (!chartId) {
|
|
30588
|
+
return [];
|
|
30589
|
+
}
|
|
29863
30590
|
const menuItemSpecs = [
|
|
29864
30591
|
{
|
|
29865
30592
|
id: "edit",
|
|
@@ -29882,8 +30609,8 @@ function getChartMenuActions(figureId, onFigureDeleted, env) {
|
|
|
29882
30609
|
execute: async () => {
|
|
29883
30610
|
const figureSheetId = env.model.getters.getFigureSheetId(figureId);
|
|
29884
30611
|
const figure = env.model.getters.getFigure(figureSheetId, figureId);
|
|
29885
|
-
const chartType = env.model.getters.getChartType(
|
|
29886
|
-
const runtime = env.model.getters.getChartRuntime(
|
|
30612
|
+
const chartType = env.model.getters.getChartType(chartId);
|
|
30613
|
+
const runtime = env.model.getters.getChartRuntime(chartId);
|
|
29887
30614
|
const imageUrl = chartToImageUrl(runtime, figure, chartType);
|
|
29888
30615
|
const innerHTML = `<img src="${xmlEscape(imageUrl)}" />`;
|
|
29889
30616
|
const blob = await chartToImageFile(runtime, figure, chartType);
|
|
@@ -29903,8 +30630,8 @@ function getChartMenuActions(figureId, onFigureDeleted, env) {
|
|
|
29903
30630
|
execute: async () => {
|
|
29904
30631
|
const figureSheetId = env.model.getters.getFigureSheetId(figureId);
|
|
29905
30632
|
const figure = env.model.getters.getFigure(figureSheetId, figureId);
|
|
29906
|
-
const chartType = env.model.getters.getChartType(
|
|
29907
|
-
const runtime = env.model.getters.getChartRuntime(
|
|
30633
|
+
const chartType = env.model.getters.getChartType(chartId);
|
|
30634
|
+
const runtime = env.model.getters.getChartRuntime(chartId);
|
|
29908
30635
|
const url = chartToImageUrl(runtime, figure, chartType);
|
|
29909
30636
|
downloadFile(url, "chart");
|
|
29910
30637
|
},
|
|
@@ -29963,6 +30690,35 @@ function getImageMenuActions(figureId, onFigureDeleted, env) {
|
|
|
29963
30690
|
];
|
|
29964
30691
|
return createActions(menuItemSpecs);
|
|
29965
30692
|
}
|
|
30693
|
+
function getCarouselMenuActions(figureId, onFigureDeleted, env) {
|
|
30694
|
+
const menuItemSpecs = [
|
|
30695
|
+
{
|
|
30696
|
+
id: "edit_carousel",
|
|
30697
|
+
name: _t("Edit carousel"),
|
|
30698
|
+
sequence: 1,
|
|
30699
|
+
execute: () => {
|
|
30700
|
+
env.model.dispatch("SELECT_FIGURE", { figureId });
|
|
30701
|
+
env.openSidePanel("CarouselPanel", { figureId });
|
|
30702
|
+
},
|
|
30703
|
+
icon: "o-spreadsheet-Icon.EDIT",
|
|
30704
|
+
isEnabled: (env) => !env.isSmall,
|
|
30705
|
+
},
|
|
30706
|
+
{
|
|
30707
|
+
id: "edit_chart",
|
|
30708
|
+
name: _t("Edit chart"),
|
|
30709
|
+
sequence: 1,
|
|
30710
|
+
execute: () => {
|
|
30711
|
+
env.model.dispatch("SELECT_FIGURE", { figureId });
|
|
30712
|
+
env.openSidePanel("ChartPanel", {});
|
|
30713
|
+
},
|
|
30714
|
+
icon: "o-spreadsheet-Icon.EDIT",
|
|
30715
|
+
isEnabled: (env) => !env.isSmall,
|
|
30716
|
+
isVisible: (env) => env.model.getters.getSelectedCarouselItem(figureId)?.type === "chart",
|
|
30717
|
+
},
|
|
30718
|
+
getDeleteMenuItem(figureId, onFigureDeleted, env),
|
|
30719
|
+
];
|
|
30720
|
+
return createActions(menuItemSpecs).filter((action) => env.model.getters.isReadonly() ? action.isReadonlyAllowed : true);
|
|
30721
|
+
}
|
|
29966
30722
|
function getCopyMenuItem(figureId, env, copiedNotificationMessage) {
|
|
29967
30723
|
return {
|
|
29968
30724
|
id: "copy",
|
|
@@ -30011,24 +30767,101 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
|
|
|
30011
30767
|
};
|
|
30012
30768
|
}
|
|
30013
30769
|
|
|
30014
|
-
|
|
30015
|
-
|
|
30016
|
-
|
|
30017
|
-
|
|
30018
|
-
|
|
30019
|
-
|
|
30770
|
+
const CAROUSEL_DEFAULT_CHART_DEFINITION = {
|
|
30771
|
+
type: "bar",
|
|
30772
|
+
title: {},
|
|
30773
|
+
stacked: false,
|
|
30774
|
+
dataSetsHaveTitle: false,
|
|
30775
|
+
dataSets: [],
|
|
30776
|
+
legendPosition: "top",
|
|
30777
|
+
};
|
|
30778
|
+
function getCarouselItemPreview(getters, item) {
|
|
30779
|
+
if (item.type === "carouselDataView") {
|
|
30780
|
+
return "o-spreadsheet-Icon.LIST";
|
|
30781
|
+
}
|
|
30782
|
+
const definition = getters.getChartDefinition(item.chartId);
|
|
30783
|
+
const matchedChart = chartSubtypeRegistry.getAll().find((c) => c.matcher?.(definition)) ||
|
|
30784
|
+
chartSubtypeRegistry.get(definition.type);
|
|
30785
|
+
return matchedChart.preview;
|
|
30786
|
+
}
|
|
30787
|
+
function getCarouselItemTitle(getters, item) {
|
|
30788
|
+
if (item.title) {
|
|
30789
|
+
return item.title;
|
|
30790
|
+
}
|
|
30791
|
+
if (item.type === "carouselDataView") {
|
|
30792
|
+
return _t("Data");
|
|
30793
|
+
}
|
|
30794
|
+
const definition = getters.getChartDefinition(item.chartId);
|
|
30795
|
+
const matchedChart = chartSubtypeRegistry.getAll().find((c) => c.matcher?.(definition)) ||
|
|
30796
|
+
chartSubtypeRegistry.get(definition.type);
|
|
30797
|
+
return matchedChart.displayName;
|
|
30798
|
+
}
|
|
30799
|
+
|
|
30800
|
+
class CarouselFigure extends owl.Component {
|
|
30801
|
+
static template = "o-spreadsheet-CarouselFigure";
|
|
30802
|
+
static props = {
|
|
30803
|
+
figureUI: Object,
|
|
30804
|
+
onFigureDeleted: Function,
|
|
30805
|
+
editFigureStyle: { type: Function, optional: true },
|
|
30806
|
+
};
|
|
30807
|
+
static components = {};
|
|
30808
|
+
setup() {
|
|
30809
|
+
owl.useEffect(() => {
|
|
30810
|
+
if (this.selectedCarouselItem?.type === "carouselDataView") {
|
|
30811
|
+
this.props.editFigureStyle?.({ "pointer-events": "none" });
|
|
30812
|
+
}
|
|
30813
|
+
else {
|
|
30814
|
+
this.props.editFigureStyle?.({ "pointer-events": "auto" });
|
|
30815
|
+
}
|
|
30816
|
+
});
|
|
30817
|
+
}
|
|
30818
|
+
get carousel() {
|
|
30819
|
+
return this.env.model.getters.getCarousel(this.props.figureUI.id);
|
|
30820
|
+
}
|
|
30821
|
+
get selectedCarouselItem() {
|
|
30822
|
+
return this.env.model.getters.getSelectedCarouselItem(this.props.figureUI.id);
|
|
30823
|
+
}
|
|
30824
|
+
get chartComponent() {
|
|
30825
|
+
const selectedItem = this.selectedCarouselItem;
|
|
30826
|
+
if (selectedItem?.type !== "chart") {
|
|
30827
|
+
throw new Error("Selected item is not a chart");
|
|
30020
30828
|
}
|
|
30021
|
-
|
|
30022
|
-
|
|
30829
|
+
const type = this.env.model.getters.getChartType(selectedItem.chartId);
|
|
30830
|
+
const component = chartComponentRegistry.get(type);
|
|
30831
|
+
if (!component) {
|
|
30832
|
+
throw new Error(`Component is not defined for type ${type}`);
|
|
30023
30833
|
}
|
|
30834
|
+
return component;
|
|
30024
30835
|
}
|
|
30025
|
-
|
|
30026
|
-
|
|
30027
|
-
|
|
30028
|
-
|
|
30029
|
-
|
|
30836
|
+
onCarouselDoubleClick() {
|
|
30837
|
+
this.env.model.dispatch("SELECT_FIGURE", { figureId: this.props.figureUI.id });
|
|
30838
|
+
this.env.openSidePanel("CarouselPanel", { figureId: this.props.figureUI.id });
|
|
30839
|
+
}
|
|
30840
|
+
isItemSelected(item) {
|
|
30841
|
+
const selectedItem = this.selectedCarouselItem;
|
|
30842
|
+
return deepEquals(selectedItem, item);
|
|
30843
|
+
}
|
|
30844
|
+
getItemTitle(item) {
|
|
30845
|
+
return getCarouselItemTitle(this.env.model.getters, item);
|
|
30846
|
+
}
|
|
30847
|
+
onCarouselTabClick(item) {
|
|
30848
|
+
this.env.model.dispatch("UPDATE_CAROUSEL_ACTIVE_ITEM", {
|
|
30849
|
+
figureId: this.props.figureUI.id,
|
|
30850
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
30851
|
+
item,
|
|
30852
|
+
});
|
|
30853
|
+
if (item.type === "carouselDataView" &&
|
|
30854
|
+
this.env.model.getters.getSelectedFigureId() === this.props.figureUI.id) {
|
|
30855
|
+
this.env.model.dispatch("SELECT_FIGURE", { figureId: null });
|
|
30030
30856
|
}
|
|
30031
30857
|
}
|
|
30858
|
+
get headerStyle() {
|
|
30859
|
+
const cssProperties = {};
|
|
30860
|
+
if (this.selectedCarouselItem?.type === "carouselDataView") {
|
|
30861
|
+
cssProperties["background-color"] = "#ffffff";
|
|
30862
|
+
}
|
|
30863
|
+
return cssPropertiesToCss(cssProperties);
|
|
30864
|
+
}
|
|
30032
30865
|
}
|
|
30033
30866
|
|
|
30034
30867
|
/**
|
|
@@ -30795,9 +31628,9 @@ class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
|
30795
31628
|
this.originalChartDefinition = this.getters.getChartDefinition(chartId);
|
|
30796
31629
|
}
|
|
30797
31630
|
updateType(type) {
|
|
30798
|
-
const
|
|
30799
|
-
const currentDefinition = this.getters.getChartDefinition(
|
|
30800
|
-
if (currentDefinition
|
|
31631
|
+
const chartId = this.chartId;
|
|
31632
|
+
const currentDefinition = this.getters.getChartDefinition(chartId);
|
|
31633
|
+
if (currentDefinition?.type === type) {
|
|
30801
31634
|
return;
|
|
30802
31635
|
}
|
|
30803
31636
|
let definition;
|
|
@@ -30807,7 +31640,7 @@ class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
|
30807
31640
|
else {
|
|
30808
31641
|
const newChartInfo = chartSubtypeRegistry.get(type);
|
|
30809
31642
|
const ChartClass = chartRegistry.get(newChartInfo.chartType);
|
|
30810
|
-
const chartCreationContext = this.getters.getContextCreationChart(
|
|
31643
|
+
const chartCreationContext = this.getters.getContextCreationChart(chartId);
|
|
30811
31644
|
if (!chartCreationContext)
|
|
30812
31645
|
return;
|
|
30813
31646
|
definition = {
|
|
@@ -30817,7 +31650,8 @@ class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
|
30817
31650
|
}
|
|
30818
31651
|
this.model.dispatch("UPDATE_CHART", {
|
|
30819
31652
|
definition,
|
|
30820
|
-
|
|
31653
|
+
chartId,
|
|
31654
|
+
figureId: this.getters.getFigureIdFromChartId(chartId),
|
|
30821
31655
|
sheetId: this.getters.getActiveSheetId(),
|
|
30822
31656
|
});
|
|
30823
31657
|
}
|
|
@@ -30838,17 +31672,17 @@ class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
|
30838
31672
|
class ChartDashboardMenu extends owl.Component {
|
|
30839
31673
|
static template = "o-spreadsheet-ChartDashboardMenu";
|
|
30840
31674
|
static components = { MenuPopover };
|
|
30841
|
-
static props = {
|
|
31675
|
+
static props = { chartId: String };
|
|
30842
31676
|
fullScreenFigureStore;
|
|
30843
31677
|
store;
|
|
30844
31678
|
menuState = owl.useState({ isOpen: false, anchorRect: null, menuItems: [] });
|
|
30845
31679
|
setup() {
|
|
30846
31680
|
super.setup();
|
|
30847
|
-
this.store = useLocalStore(ChartDashboardMenuStore, this.props.
|
|
31681
|
+
this.store = useLocalStore(ChartDashboardMenuStore, this.props.chartId);
|
|
30848
31682
|
this.fullScreenFigureStore = useStore(FullScreenChartStore);
|
|
30849
|
-
owl.onWillUpdateProps(({
|
|
30850
|
-
if (
|
|
30851
|
-
this.store.reset(
|
|
31683
|
+
owl.onWillUpdateProps(({ chartId }) => {
|
|
31684
|
+
if (chartId !== this.props.chartId) {
|
|
31685
|
+
this.store.reset(chartId);
|
|
30852
31686
|
}
|
|
30853
31687
|
});
|
|
30854
31688
|
}
|
|
@@ -30856,26 +31690,28 @@ class ChartDashboardMenu extends owl.Component {
|
|
|
30856
31690
|
return [this.fullScreenMenuItem, ...this.store.changeChartTypeMenuItems].filter(isDefined);
|
|
30857
31691
|
}
|
|
30858
31692
|
get backgroundColor() {
|
|
30859
|
-
const color = this.env.model.getters.getChartDefinition(this.props.
|
|
31693
|
+
const color = this.env.model.getters.getChartDefinition(this.props.chartId).background;
|
|
30860
31694
|
return "background-color: " + (color || BACKGROUND_CHART_COLOR);
|
|
30861
31695
|
}
|
|
30862
31696
|
openContextMenu(ev) {
|
|
30863
31697
|
this.menuState.isOpen = true;
|
|
30864
31698
|
this.menuState.anchorRect = { x: ev.clientX, y: ev.clientY, width: 0, height: 0 };
|
|
30865
|
-
|
|
31699
|
+
const figureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
|
|
31700
|
+
this.menuState.menuItems = getChartMenuActions(figureId, () => { }, this.env);
|
|
30866
31701
|
}
|
|
30867
31702
|
get fullScreenMenuItem() {
|
|
30868
|
-
const definition = this.env.model.getters.getChartDefinition(this.props.
|
|
31703
|
+
const definition = this.env.model.getters.getChartDefinition(this.props.chartId);
|
|
31704
|
+
const figureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
|
|
30869
31705
|
if (definition.type === "scorecard") {
|
|
30870
31706
|
return undefined;
|
|
30871
31707
|
}
|
|
30872
|
-
if (this.props.
|
|
31708
|
+
if (this.props.chartId === this.fullScreenFigureStore.fullScreenFigure?.id) {
|
|
30873
31709
|
return {
|
|
30874
31710
|
id: "fullScreenChart",
|
|
30875
31711
|
label: _t("Exit Full Screen"),
|
|
30876
31712
|
iconClass: "fa fa-compress",
|
|
30877
31713
|
onClick: () => {
|
|
30878
|
-
this.fullScreenFigureStore.toggleFullScreenChart(
|
|
31714
|
+
this.fullScreenFigureStore.toggleFullScreenChart(figureId);
|
|
30879
31715
|
},
|
|
30880
31716
|
};
|
|
30881
31717
|
}
|
|
@@ -30884,27 +31720,18 @@ class ChartDashboardMenu extends owl.Component {
|
|
|
30884
31720
|
label: _t("Full Screen"),
|
|
30885
31721
|
iconClass: "fa fa-expand",
|
|
30886
31722
|
onClick: () => {
|
|
30887
|
-
this.fullScreenFigureStore.toggleFullScreenChart(
|
|
31723
|
+
this.fullScreenFigureStore.toggleFullScreenChart(figureId);
|
|
30888
31724
|
},
|
|
30889
31725
|
};
|
|
30890
31726
|
}
|
|
30891
31727
|
}
|
|
30892
31728
|
|
|
30893
|
-
// -----------------------------------------------------------------------------
|
|
30894
|
-
// STYLE
|
|
30895
|
-
// -----------------------------------------------------------------------------
|
|
30896
|
-
css /* scss */ `
|
|
30897
|
-
.o-chart-container {
|
|
30898
|
-
width: 100%;
|
|
30899
|
-
height: 100%;
|
|
30900
|
-
position: relative;
|
|
30901
|
-
}
|
|
30902
|
-
`;
|
|
30903
31729
|
class ChartFigure extends owl.Component {
|
|
30904
31730
|
static template = "o-spreadsheet-ChartFigure";
|
|
30905
31731
|
static props = {
|
|
30906
31732
|
figureUI: Object,
|
|
30907
31733
|
onFigureDeleted: Function,
|
|
31734
|
+
editFigureStyle: { type: Function, optional: true },
|
|
30908
31735
|
};
|
|
30909
31736
|
static components = { ChartDashboardMenu };
|
|
30910
31737
|
onDoubleClick() {
|
|
@@ -30912,7 +31739,14 @@ class ChartFigure extends owl.Component {
|
|
|
30912
31739
|
this.env.openSidePanel("ChartPanel");
|
|
30913
31740
|
}
|
|
30914
31741
|
get chartType() {
|
|
30915
|
-
return this.env.model.getters.getChartType(this.
|
|
31742
|
+
return this.env.model.getters.getChartType(this.chartId);
|
|
31743
|
+
}
|
|
31744
|
+
get chartId() {
|
|
31745
|
+
const chartId = this.env.model.getters.getChartIdFromFigureId(this.props.figureUI.id);
|
|
31746
|
+
if (!chartId) {
|
|
31747
|
+
throw new Error(`No chart found for figure ID: ${this.props.figureUI.id}`);
|
|
31748
|
+
}
|
|
31749
|
+
return chartId;
|
|
30916
31750
|
}
|
|
30917
31751
|
get chartComponent() {
|
|
30918
31752
|
const type = this.chartType;
|
|
@@ -30929,6 +31763,7 @@ class ImageFigure extends owl.Component {
|
|
|
30929
31763
|
static props = {
|
|
30930
31764
|
figureUI: Object,
|
|
30931
31765
|
onFigureDeleted: Function,
|
|
31766
|
+
editFigureStyle: { type: Function, optional: true },
|
|
30932
31767
|
};
|
|
30933
31768
|
static components = {};
|
|
30934
31769
|
// ---------------------------------------------------------------------------
|
|
@@ -30955,6 +31790,10 @@ figureRegistry.add("image", {
|
|
|
30955
31790
|
borderWidth: 0,
|
|
30956
31791
|
menuBuilder: getImageMenuActions,
|
|
30957
31792
|
});
|
|
31793
|
+
figureRegistry.add("carousel", {
|
|
31794
|
+
Component: CarouselFigure,
|
|
31795
|
+
menuBuilder: getCarouselMenuActions,
|
|
31796
|
+
});
|
|
30958
31797
|
|
|
30959
31798
|
// -----------------------------------------------------------------------------
|
|
30960
31799
|
// STYLE
|
|
@@ -30981,6 +31820,7 @@ css /*SCSS*/ `
|
|
|
30981
31820
|
.o-figure-wrapper {
|
|
30982
31821
|
position: absolute;
|
|
30983
31822
|
box-sizing: content-box;
|
|
31823
|
+
pointer-events: auto;
|
|
30984
31824
|
|
|
30985
31825
|
.o-fig-anchor {
|
|
30986
31826
|
z-index: ${ComponentsImportance.FigureAnchor};
|
|
@@ -31039,6 +31879,7 @@ class FigureComponent extends owl.Component {
|
|
|
31039
31879
|
static props = {
|
|
31040
31880
|
figureUI: Object,
|
|
31041
31881
|
style: { type: String, optional: true },
|
|
31882
|
+
class: { type: String, optional: true },
|
|
31042
31883
|
onFigureDeleted: { type: Function, optional: true },
|
|
31043
31884
|
onMouseDown: { type: Function, optional: true },
|
|
31044
31885
|
onClickAnchor: { type: Function, optional: true },
|
|
@@ -31051,6 +31892,7 @@ class FigureComponent extends owl.Component {
|
|
|
31051
31892
|
};
|
|
31052
31893
|
menuState = owl.useState({ isOpen: false, anchorRect: null, menuItems: [] });
|
|
31053
31894
|
figureRef = owl.useRef("figure");
|
|
31895
|
+
figureWrapperRef = owl.useRef("figureWrapper");
|
|
31054
31896
|
menuButtonRef = owl.useRef("menuButton");
|
|
31055
31897
|
borderWidth;
|
|
31056
31898
|
get isSelected() {
|
|
@@ -31243,6 +32085,13 @@ class FigureComponent extends owl.Component {
|
|
|
31243
32085
|
.get(this.props.figureUI.tag)
|
|
31244
32086
|
.menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
|
|
31245
32087
|
}
|
|
32088
|
+
editWrapperStyle(properties) {
|
|
32089
|
+
if (this.figureWrapperRef.el) {
|
|
32090
|
+
for (const property in properties) {
|
|
32091
|
+
this.figureWrapperRef.el.style.setProperty(property, properties[property] || null);
|
|
32092
|
+
}
|
|
32093
|
+
}
|
|
32094
|
+
}
|
|
31246
32095
|
}
|
|
31247
32096
|
|
|
31248
32097
|
class DelayedHoveredCellStore extends SpreadsheetStore {
|
|
@@ -38775,16 +39624,15 @@ function pushElement(property, propertyList) {
|
|
|
38775
39624
|
reverseLookup.set(canonical, maxId);
|
|
38776
39625
|
return maxId;
|
|
38777
39626
|
}
|
|
38778
|
-
const chartIds = [];
|
|
38779
39627
|
/**
|
|
38780
39628
|
* Convert a chart o-spreadsheet id to a xlsx id which
|
|
38781
39629
|
* are unsigned integers (starting from 1).
|
|
38782
39630
|
*/
|
|
38783
|
-
function convertChartId(chartId) {
|
|
38784
|
-
const xlsxId = chartIds.findIndex((id) => id === chartId);
|
|
39631
|
+
function convertChartId(chartId, construct) {
|
|
39632
|
+
const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
|
|
38785
39633
|
if (xlsxId === -1) {
|
|
38786
|
-
chartIds.push(chartId);
|
|
38787
|
-
return chartIds.length;
|
|
39634
|
+
construct.chartIds.push(chartId);
|
|
39635
|
+
return construct.chartIds.length;
|
|
38788
39636
|
}
|
|
38789
39637
|
return xlsxId + 1;
|
|
38790
39638
|
}
|
|
@@ -41179,6 +42027,8 @@ class XlsxReader {
|
|
|
41179
42027
|
sheets: sheets,
|
|
41180
42028
|
sharedStrings,
|
|
41181
42029
|
externalBooks,
|
|
42030
|
+
chartIds: [],
|
|
42031
|
+
imageIds: [],
|
|
41182
42032
|
};
|
|
41183
42033
|
}
|
|
41184
42034
|
buildXlsxFileStructure() {
|
|
@@ -41856,6 +42706,18 @@ migrationStepRegistry
|
|
|
41856
42706
|
}
|
|
41857
42707
|
return data;
|
|
41858
42708
|
},
|
|
42709
|
+
})
|
|
42710
|
+
.add("18.5.1", {
|
|
42711
|
+
migrate(data) {
|
|
42712
|
+
for (const sheet of data.sheets || []) {
|
|
42713
|
+
for (const figure of sheet.figures || []) {
|
|
42714
|
+
if (figure.tag === "chart") {
|
|
42715
|
+
figure.data.chartId = figure.id;
|
|
42716
|
+
}
|
|
42717
|
+
}
|
|
42718
|
+
}
|
|
42719
|
+
return data;
|
|
42720
|
+
},
|
|
41859
42721
|
});
|
|
41860
42722
|
function fixOverlappingFilters(data) {
|
|
41861
42723
|
for (const sheet of data.sheets || []) {
|
|
@@ -42109,7 +42971,12 @@ function fixChartDefinitions(data, initialMessages) {
|
|
|
42109
42971
|
sheet.figures?.forEach((figure) => {
|
|
42110
42972
|
if (figure.tag === "chart") {
|
|
42111
42973
|
// chart definition
|
|
42112
|
-
|
|
42974
|
+
if (data.version && compareVersions(String(data.version), "18.5.1") <= 0) {
|
|
42975
|
+
map[figure.data.chartId] = figure.data;
|
|
42976
|
+
}
|
|
42977
|
+
else {
|
|
42978
|
+
map[figure.id] = figure.data;
|
|
42979
|
+
}
|
|
42113
42980
|
}
|
|
42114
42981
|
});
|
|
42115
42982
|
}
|
|
@@ -42120,20 +42987,20 @@ function fixChartDefinitions(data, initialMessages) {
|
|
|
42120
42987
|
let command = cmd;
|
|
42121
42988
|
switch (cmd.type) {
|
|
42122
42989
|
case "CREATE_CHART":
|
|
42123
|
-
map[cmd.
|
|
42990
|
+
map[cmd.chartId] = cmd.definition;
|
|
42124
42991
|
break;
|
|
42125
42992
|
case "UPDATE_CHART":
|
|
42126
|
-
if (!map[cmd.
|
|
42993
|
+
if (!map[cmd.chartId]) {
|
|
42127
42994
|
/** the chart does not exist on the map, it might have been created after a duplicate sheet.
|
|
42128
42995
|
* We don't have access to the definition, so we skip the command.
|
|
42129
42996
|
*/
|
|
42130
|
-
console.log(`Fix chart definition: chart with id ${cmd.
|
|
42997
|
+
console.log(`Fix chart definition: chart with id ${cmd.chartId} not found.`);
|
|
42131
42998
|
continue;
|
|
42132
42999
|
}
|
|
42133
|
-
const definition = map[cmd.
|
|
43000
|
+
const definition = map[cmd.chartId];
|
|
42134
43001
|
const newDefinition = { ...definition, ...cmd.definition };
|
|
42135
43002
|
command = { ...cmd, definition: newDefinition };
|
|
42136
|
-
map[cmd.
|
|
43003
|
+
map[cmd.chartId] = newDefinition;
|
|
42137
43004
|
break;
|
|
42138
43005
|
}
|
|
42139
43006
|
commands.push(command);
|
|
@@ -42706,6 +43573,7 @@ const CREATE_CHART = (env) => {
|
|
|
42706
43573
|
const result = env.model.dispatch("CREATE_CHART", {
|
|
42707
43574
|
sheetId,
|
|
42708
43575
|
figureId,
|
|
43576
|
+
chartId: figureId,
|
|
42709
43577
|
col,
|
|
42710
43578
|
row,
|
|
42711
43579
|
offset,
|
|
@@ -42717,6 +43585,26 @@ const CREATE_CHART = (env) => {
|
|
|
42717
43585
|
env.openSidePanel("ChartPanel");
|
|
42718
43586
|
}
|
|
42719
43587
|
};
|
|
43588
|
+
const CREATE_CAROUSEL = (env) => {
|
|
43589
|
+
const getters = env.model.getters;
|
|
43590
|
+
const figureId = env.model.uuidGenerator.smallUuid();
|
|
43591
|
+
const sheetId = getters.getActiveSheetId();
|
|
43592
|
+
const size = { width: DEFAULT_FIGURE_WIDTH, height: DEFAULT_FIGURE_HEIGHT };
|
|
43593
|
+
const { col, row, offset } = centerFigurePosition(getters, size);
|
|
43594
|
+
const result = env.model.dispatch("CREATE_CAROUSEL", {
|
|
43595
|
+
sheetId,
|
|
43596
|
+
figureId,
|
|
43597
|
+
col,
|
|
43598
|
+
row,
|
|
43599
|
+
offset,
|
|
43600
|
+
size,
|
|
43601
|
+
definition: { items: [] },
|
|
43602
|
+
});
|
|
43603
|
+
if (result.isSuccessful) {
|
|
43604
|
+
env.model.dispatch("SELECT_FIGURE", { figureId });
|
|
43605
|
+
env.openSidePanel("CarouselPanel", { figureId });
|
|
43606
|
+
}
|
|
43607
|
+
};
|
|
42720
43608
|
//------------------------------------------------------------------------------
|
|
42721
43609
|
// Pivots
|
|
42722
43610
|
//------------------------------------------------------------------------------
|
|
@@ -42753,10 +43641,18 @@ const REINSERT_STATIC_PIVOT_CHILDREN = (env) => env.model.getters.getPivotIds().
|
|
|
42753
43641
|
sequence: index,
|
|
42754
43642
|
execute: (env) => {
|
|
42755
43643
|
const zone = env.model.getters.getSelectedZone();
|
|
42756
|
-
const table = env.model.getters.getPivot(pivotId).getExpandedTableStructure()
|
|
43644
|
+
const table = env.model.getters.getPivot(pivotId).getExpandedTableStructure();
|
|
43645
|
+
if (table.numberOfCells > PIVOT_MAX_NUMBER_OF_CELLS) {
|
|
43646
|
+
env.notifyUser({
|
|
43647
|
+
type: "warning",
|
|
43648
|
+
text: getPivotTooBigErrorMessage(table.numberOfCells, env.model.getters.getLocale()),
|
|
43649
|
+
sticky: true,
|
|
43650
|
+
});
|
|
43651
|
+
return;
|
|
43652
|
+
}
|
|
42757
43653
|
env.model.dispatch("INSERT_PIVOT_WITH_TABLE", {
|
|
42758
43654
|
pivotId,
|
|
42759
|
-
table,
|
|
43655
|
+
table: table.export(),
|
|
42760
43656
|
col: zone.left,
|
|
42761
43657
|
row: zone.top,
|
|
42762
43658
|
sheetId: env.model.getters.getActiveSheetId(),
|
|
@@ -43968,6 +44864,12 @@ const insertChart = {
|
|
|
43968
44864
|
isEnabled: (env) => !env.isSmall,
|
|
43969
44865
|
icon: "o-spreadsheet-Icon.INSERT_CHART",
|
|
43970
44866
|
};
|
|
44867
|
+
const insertCarousel = {
|
|
44868
|
+
name: _t("Carousel"),
|
|
44869
|
+
execute: CREATE_CAROUSEL,
|
|
44870
|
+
isEnabled: (env) => !env.isSmall,
|
|
44871
|
+
icon: "o-spreadsheet-Icon.CAROUSEL",
|
|
44872
|
+
};
|
|
43971
44873
|
const insertPivot = {
|
|
43972
44874
|
name: _t("Pivot table"),
|
|
43973
44875
|
execute: CREATE_PIVOT,
|
|
@@ -44088,7 +44990,7 @@ const insertDropdown = {
|
|
|
44088
44990
|
env.openSidePanel("DataValidationEditor", {
|
|
44089
44991
|
rule: localizeDataValidationRule(rule, env.model.getters.getLocale()),
|
|
44090
44992
|
onExit: () => {
|
|
44091
|
-
env.
|
|
44993
|
+
env.replaceSidePanel("DataValidation", "DataValidationEditor");
|
|
44092
44994
|
},
|
|
44093
44995
|
});
|
|
44094
44996
|
},
|
|
@@ -44824,6 +45726,9 @@ class SpreadsheetPivotTable {
|
|
|
44824
45726
|
return [row, ...this.rowTreeToRows(node.children, row)];
|
|
44825
45727
|
});
|
|
44826
45728
|
}
|
|
45729
|
+
get numberOfCells() {
|
|
45730
|
+
return this.rows.length * this.getNumberOfDataColumns();
|
|
45731
|
+
}
|
|
44827
45732
|
}
|
|
44828
45733
|
const EMPTY_PIVOT_CELL = { type: "EMPTY" };
|
|
44829
45734
|
|
|
@@ -48058,6 +48963,7 @@ class FiguresContainer extends owl.Component {
|
|
|
48058
48963
|
horizontalSnap: undefined,
|
|
48059
48964
|
verticalSnap: undefined,
|
|
48060
48965
|
cancelDnd: undefined,
|
|
48966
|
+
overlappingCarousel: undefined,
|
|
48061
48967
|
});
|
|
48062
48968
|
setup() {
|
|
48063
48969
|
owl.onMounted(() => {
|
|
@@ -48080,6 +48986,7 @@ class FiguresContainer extends owl.Component {
|
|
|
48080
48986
|
this.dnd.draggedFigure = undefined;
|
|
48081
48987
|
this.dnd.horizontalSnap = undefined;
|
|
48082
48988
|
this.dnd.verticalSnap = undefined;
|
|
48989
|
+
this.dnd.overlappingCarousel = undefined;
|
|
48083
48990
|
this.dnd.cancelDnd = undefined;
|
|
48084
48991
|
}
|
|
48085
48992
|
});
|
|
@@ -48218,26 +49125,46 @@ class FiguresContainer extends owl.Component {
|
|
|
48218
49125
|
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
48219
49126
|
const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFigure, maxDimensions, initialScrollPosition, getters.getActiveSheetScrollInfo());
|
|
48220
49127
|
const otherFigures = this.getOtherFigures(initialFigure.id);
|
|
48221
|
-
const
|
|
48222
|
-
this.dnd.
|
|
48223
|
-
|
|
48224
|
-
|
|
49128
|
+
const overlappingCarousel = this.getCarouselOverlappingChart(draggedFigure, otherFigures);
|
|
49129
|
+
this.dnd.overlappingCarousel = overlappingCarousel;
|
|
49130
|
+
if (!overlappingCarousel) {
|
|
49131
|
+
const snapResult = snapForMove(getters, draggedFigure, otherFigures);
|
|
49132
|
+
this.dnd.draggedFigure = snapResult.snappedFigure;
|
|
49133
|
+
this.dnd.horizontalSnap = this.getSnap(snapResult.horizontalSnapLine);
|
|
49134
|
+
this.dnd.verticalSnap = this.getSnap(snapResult.verticalSnapLine);
|
|
49135
|
+
}
|
|
49136
|
+
else {
|
|
49137
|
+
this.dnd.draggedFigure = draggedFigure;
|
|
49138
|
+
this.dnd.horizontalSnap = undefined;
|
|
49139
|
+
this.dnd.verticalSnap = undefined;
|
|
49140
|
+
}
|
|
48225
49141
|
};
|
|
48226
49142
|
const onMouseUp = (ev) => {
|
|
48227
49143
|
if (!this.dnd.draggedFigure) {
|
|
48228
49144
|
return;
|
|
48229
49145
|
}
|
|
48230
49146
|
const { col, row, offset } = this.env.model.getters.getPositionAnchorOffset(this.dnd.draggedFigure);
|
|
49147
|
+
if (!this.dnd.overlappingCarousel) {
|
|
49148
|
+
this.env.model.dispatch("UPDATE_FIGURE", {
|
|
49149
|
+
sheetId,
|
|
49150
|
+
figureId: figureUI.id,
|
|
49151
|
+
offset,
|
|
49152
|
+
col,
|
|
49153
|
+
row,
|
|
49154
|
+
});
|
|
49155
|
+
}
|
|
49156
|
+
else {
|
|
49157
|
+
this.env.model.dispatch("ADD_FIGURE_CHART_TO_CAROUSEL", {
|
|
49158
|
+
sheetId,
|
|
49159
|
+
carouselFigureId: this.dnd.overlappingCarousel.id,
|
|
49160
|
+
chartFigureId: figureUI.id,
|
|
49161
|
+
});
|
|
49162
|
+
this.props.onFigureDeleted();
|
|
49163
|
+
}
|
|
48231
49164
|
this.dnd.draggedFigure = undefined;
|
|
48232
49165
|
this.dnd.horizontalSnap = undefined;
|
|
48233
49166
|
this.dnd.verticalSnap = undefined;
|
|
48234
|
-
this.
|
|
48235
|
-
sheetId,
|
|
48236
|
-
figureId: figureUI.id,
|
|
48237
|
-
offset,
|
|
48238
|
-
col,
|
|
48239
|
-
row,
|
|
48240
|
-
});
|
|
49167
|
+
this.dnd.overlappingCarousel = undefined;
|
|
48241
49168
|
};
|
|
48242
49169
|
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48243
49170
|
}
|
|
@@ -48289,6 +49216,7 @@ class FiguresContainer extends owl.Component {
|
|
|
48289
49216
|
this.dnd.draggedFigure = undefined;
|
|
48290
49217
|
this.dnd.horizontalSnap = undefined;
|
|
48291
49218
|
this.dnd.verticalSnap = undefined;
|
|
49219
|
+
this.dnd.overlappingCarousel = undefined;
|
|
48292
49220
|
};
|
|
48293
49221
|
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48294
49222
|
}
|
|
@@ -48305,10 +49233,15 @@ class FiguresContainer extends owl.Component {
|
|
|
48305
49233
|
if (figureUI.id !== this.dnd.draggedFigure?.id)
|
|
48306
49234
|
return "";
|
|
48307
49235
|
return cssPropertiesToCss({
|
|
48308
|
-
opacity: "0.9",
|
|
49236
|
+
opacity: this.dnd.overlappingCarousel?.id ? "0.6" : "0.9",
|
|
48309
49237
|
cursor: "grabbing",
|
|
48310
49238
|
});
|
|
48311
49239
|
}
|
|
49240
|
+
getFigureClass(figureUI) {
|
|
49241
|
+
if (figureUI.id !== this.dnd.overlappingCarousel?.id)
|
|
49242
|
+
return "";
|
|
49243
|
+
return "o-add-to-carousel";
|
|
49244
|
+
}
|
|
48312
49245
|
getSnap(snapLine) {
|
|
48313
49246
|
if (!snapLine || !this.dnd.draggedFigure)
|
|
48314
49247
|
return undefined;
|
|
@@ -48355,6 +49288,20 @@ class FiguresContainer extends owl.Component {
|
|
|
48355
49288
|
});
|
|
48356
49289
|
}
|
|
48357
49290
|
}
|
|
49291
|
+
getCarouselOverlappingChart(figureUI, otherFigures) {
|
|
49292
|
+
if (figureUI.tag !== "chart") {
|
|
49293
|
+
return undefined;
|
|
49294
|
+
}
|
|
49295
|
+
const minimumOverlap = 20; // Minimum overlap in pixels to consider a carousel overlapping
|
|
49296
|
+
const carousels = otherFigures.filter((f) => f.tag === "carousel");
|
|
49297
|
+
return carousels.find((carousel) => {
|
|
49298
|
+
const xOverlap = Math.max(0, Math.min(figureUI.x + figureUI.width, carousel.x + carousel.width) -
|
|
49299
|
+
Math.max(figureUI.x, carousel.x));
|
|
49300
|
+
const yOverlap = Math.max(0, Math.min(figureUI.y + figureUI.height, carousel.y + carousel.height) -
|
|
49301
|
+
Math.max(figureUI.y, carousel.y));
|
|
49302
|
+
return xOverlap >= minimumOverlap && yOverlap >= minimumOverlap;
|
|
49303
|
+
});
|
|
49304
|
+
}
|
|
48358
49305
|
}
|
|
48359
49306
|
|
|
48360
49307
|
css /* scss */ `
|
|
@@ -51037,6 +51984,226 @@ class Selection extends owl.Component {
|
|
|
51037
51984
|
}
|
|
51038
51985
|
}
|
|
51039
51986
|
|
|
51987
|
+
function useAutofocus({ refName }) {
|
|
51988
|
+
const ref = owl.useRef(refName);
|
|
51989
|
+
owl.useEffect((el) => {
|
|
51990
|
+
el?.focus();
|
|
51991
|
+
}, () => [ref.el]);
|
|
51992
|
+
}
|
|
51993
|
+
|
|
51994
|
+
css /* scss */ `
|
|
51995
|
+
.o-spreadsheet {
|
|
51996
|
+
.os-input {
|
|
51997
|
+
border-width: 0 0 1px 0;
|
|
51998
|
+
border-color: transparent;
|
|
51999
|
+
outline: none;
|
|
52000
|
+
text-overflow: ellipsis;
|
|
52001
|
+
color: ${TEXT_BODY};
|
|
52002
|
+
}
|
|
52003
|
+
.os-input:hover,
|
|
52004
|
+
.os-input:focus {
|
|
52005
|
+
border-color: ${GRAY_300};
|
|
52006
|
+
}
|
|
52007
|
+
}
|
|
52008
|
+
`;
|
|
52009
|
+
class TextInput extends owl.Component {
|
|
52010
|
+
static template = "o-spreadsheet-TextInput";
|
|
52011
|
+
static props = {
|
|
52012
|
+
value: String,
|
|
52013
|
+
onChange: Function,
|
|
52014
|
+
class: {
|
|
52015
|
+
type: String,
|
|
52016
|
+
optional: true,
|
|
52017
|
+
},
|
|
52018
|
+
id: {
|
|
52019
|
+
type: String,
|
|
52020
|
+
optional: true,
|
|
52021
|
+
},
|
|
52022
|
+
placeholder: {
|
|
52023
|
+
type: String,
|
|
52024
|
+
optional: true,
|
|
52025
|
+
},
|
|
52026
|
+
autofocus: {
|
|
52027
|
+
type: Boolean,
|
|
52028
|
+
optional: true,
|
|
52029
|
+
},
|
|
52030
|
+
};
|
|
52031
|
+
inputRef = owl.useRef("input");
|
|
52032
|
+
setup() {
|
|
52033
|
+
owl.useExternalListener(window, "click", (ev) => {
|
|
52034
|
+
if (ev.target !== this.inputRef.el && this.inputRef.el?.value !== this.props.value) {
|
|
52035
|
+
this.save();
|
|
52036
|
+
}
|
|
52037
|
+
}, { capture: true });
|
|
52038
|
+
if (this.props.autofocus) {
|
|
52039
|
+
useAutofocus({ refName: "input" });
|
|
52040
|
+
}
|
|
52041
|
+
}
|
|
52042
|
+
onKeyDown(ev) {
|
|
52043
|
+
switch (ev.key) {
|
|
52044
|
+
case "Enter":
|
|
52045
|
+
this.save();
|
|
52046
|
+
ev.preventDefault();
|
|
52047
|
+
ev.stopPropagation();
|
|
52048
|
+
break;
|
|
52049
|
+
case "Escape":
|
|
52050
|
+
if (this.inputRef.el) {
|
|
52051
|
+
this.inputRef.el.value = this.props.value;
|
|
52052
|
+
this.inputRef.el.blur();
|
|
52053
|
+
}
|
|
52054
|
+
ev.preventDefault();
|
|
52055
|
+
ev.stopPropagation();
|
|
52056
|
+
break;
|
|
52057
|
+
}
|
|
52058
|
+
}
|
|
52059
|
+
save() {
|
|
52060
|
+
const currentValue = (this.inputRef.el?.value || "").trim();
|
|
52061
|
+
if (currentValue !== this.props.value) {
|
|
52062
|
+
this.props.onChange(currentValue);
|
|
52063
|
+
}
|
|
52064
|
+
this.inputRef.el?.blur();
|
|
52065
|
+
}
|
|
52066
|
+
onMouseDown(ev) {
|
|
52067
|
+
// Stop the event if the input is not focused, we handle everything in onMouseUp
|
|
52068
|
+
if (ev.target !== document.activeElement) {
|
|
52069
|
+
ev.preventDefault();
|
|
52070
|
+
ev.stopPropagation();
|
|
52071
|
+
}
|
|
52072
|
+
}
|
|
52073
|
+
onMouseUp(ev) {
|
|
52074
|
+
const target = ev.target;
|
|
52075
|
+
if (target !== document.activeElement) {
|
|
52076
|
+
target.focus();
|
|
52077
|
+
target.select();
|
|
52078
|
+
ev.preventDefault();
|
|
52079
|
+
ev.stopPropagation();
|
|
52080
|
+
}
|
|
52081
|
+
}
|
|
52082
|
+
}
|
|
52083
|
+
|
|
52084
|
+
class CarouselPanel extends owl.Component {
|
|
52085
|
+
static template = "o-spreadsheet-CarouselPanel";
|
|
52086
|
+
static props = { onCloseSidePanel: Function, figureId: String };
|
|
52087
|
+
static components = { TextInput };
|
|
52088
|
+
dragAndDrop = useDragAndDropListItems();
|
|
52089
|
+
previewListRef = owl.useRef("previewList");
|
|
52090
|
+
setup() {
|
|
52091
|
+
let lastCarouselItems = [...this.carouselItems];
|
|
52092
|
+
owl.onWillUpdateProps(() => {
|
|
52093
|
+
if (!deepEquals(this.carouselItems, lastCarouselItems)) {
|
|
52094
|
+
this.dragAndDrop.cancel();
|
|
52095
|
+
}
|
|
52096
|
+
lastCarouselItems = [...this.carouselItems];
|
|
52097
|
+
});
|
|
52098
|
+
}
|
|
52099
|
+
get carouselItems() {
|
|
52100
|
+
return this.env.model.getters.getCarousel(this.props.figureId).items;
|
|
52101
|
+
}
|
|
52102
|
+
getPreviewDivStyle(item) {
|
|
52103
|
+
return this.dragAndDrop.itemsStyle[this.getItemId(item)] || "";
|
|
52104
|
+
}
|
|
52105
|
+
getItemId(item) {
|
|
52106
|
+
return item.type === "chart" ? item.chartId : "transparent-carousel";
|
|
52107
|
+
}
|
|
52108
|
+
addNewChartToCarousel() {
|
|
52109
|
+
this.env.model.dispatch("ADD_NEW_CHART_TO_CAROUSEL", {
|
|
52110
|
+
figureId: this.props.figureId,
|
|
52111
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
52112
|
+
});
|
|
52113
|
+
}
|
|
52114
|
+
get hasDataView() {
|
|
52115
|
+
return this.carouselItems.some((item) => item.type === "carouselDataView");
|
|
52116
|
+
}
|
|
52117
|
+
addDataViewToCarousel() {
|
|
52118
|
+
const carousel = this.env.model.getters.getCarousel(this.props.figureId);
|
|
52119
|
+
this.env.model.dispatch("UPDATE_CAROUSEL", {
|
|
52120
|
+
figureId: this.props.figureId,
|
|
52121
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
52122
|
+
definition: { items: [...carousel.items, { type: "carouselDataView" }] },
|
|
52123
|
+
});
|
|
52124
|
+
}
|
|
52125
|
+
activateCarouselItem(item) {
|
|
52126
|
+
this.env.model.dispatch("UPDATE_CAROUSEL_ACTIVE_ITEM", {
|
|
52127
|
+
figureId: this.props.figureId,
|
|
52128
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
52129
|
+
item,
|
|
52130
|
+
});
|
|
52131
|
+
}
|
|
52132
|
+
editCarouselItem(item) {
|
|
52133
|
+
if (item.type === "chart") {
|
|
52134
|
+
this.activateCarouselItem(item);
|
|
52135
|
+
this.env.model.dispatch("SELECT_FIGURE", { figureId: this.props.figureId });
|
|
52136
|
+
this.env.openSidePanel("ChartPanel", { chartId: item.chartId });
|
|
52137
|
+
}
|
|
52138
|
+
}
|
|
52139
|
+
renameCarouselItem(item, newName) {
|
|
52140
|
+
const trimmedName = newName.trim();
|
|
52141
|
+
if (!trimmedName || trimmedName === this.getItemTitle(item).toString()) {
|
|
52142
|
+
return;
|
|
52143
|
+
}
|
|
52144
|
+
const items = [...this.carouselItems];
|
|
52145
|
+
const itemIndex = this.carouselItems.findIndex((itm) => deepEquals(itm, item));
|
|
52146
|
+
if (itemIndex !== -1) {
|
|
52147
|
+
items[itemIndex] = { ...item, title: trimmedName };
|
|
52148
|
+
this.env.model.dispatch("UPDATE_CAROUSEL", {
|
|
52149
|
+
figureId: this.props.figureId,
|
|
52150
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
52151
|
+
definition: { items },
|
|
52152
|
+
});
|
|
52153
|
+
}
|
|
52154
|
+
}
|
|
52155
|
+
deleteCarouselItem(item) {
|
|
52156
|
+
const carousel = this.env.model.getters.getCarousel(this.props.figureId);
|
|
52157
|
+
const items = carousel.items.filter((itm) => !deepEquals(itm, item));
|
|
52158
|
+
this.env.model.dispatch("UPDATE_CAROUSEL", {
|
|
52159
|
+
figureId: this.props.figureId,
|
|
52160
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
52161
|
+
definition: { items },
|
|
52162
|
+
});
|
|
52163
|
+
}
|
|
52164
|
+
onDragHandleMouseDown(item, event) {
|
|
52165
|
+
if (event.button !== 0)
|
|
52166
|
+
return;
|
|
52167
|
+
const previewRects = Array.from(this.previewListRef.el.children).map((previewEl) => getBoundingRectAsPOJO(previewEl));
|
|
52168
|
+
const items = this.carouselItems.map((item, index) => ({
|
|
52169
|
+
id: this.getItemId(item),
|
|
52170
|
+
size: previewRects[index].height,
|
|
52171
|
+
position: previewRects[index].y,
|
|
52172
|
+
}));
|
|
52173
|
+
this.dragAndDrop.start("vertical", {
|
|
52174
|
+
draggedItemId: this.getItemId(item),
|
|
52175
|
+
initialMousePosition: event.clientY,
|
|
52176
|
+
items: items,
|
|
52177
|
+
scrollableContainerEl: this.previewListRef.el,
|
|
52178
|
+
onDragEnd: (itemId, finalIndex) => this.onDragEnd(item, finalIndex),
|
|
52179
|
+
});
|
|
52180
|
+
}
|
|
52181
|
+
onDragEnd(item, finalIndex) {
|
|
52182
|
+
const originalIndex = this.carouselItems.findIndex((itm) => deepEquals(itm, item));
|
|
52183
|
+
if (originalIndex === -1 || originalIndex === finalIndex) {
|
|
52184
|
+
return;
|
|
52185
|
+
}
|
|
52186
|
+
const carousel = this.env.model.getters.getCarousel(this.props.figureId);
|
|
52187
|
+
const items = [...carousel.items];
|
|
52188
|
+
items.splice(originalIndex, 1);
|
|
52189
|
+
items.splice(finalIndex, 0, item);
|
|
52190
|
+
this.env.model.dispatch("UPDATE_CAROUSEL", {
|
|
52191
|
+
figureId: this.props.figureId,
|
|
52192
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
52193
|
+
definition: { items },
|
|
52194
|
+
});
|
|
52195
|
+
}
|
|
52196
|
+
getItemTitle(item) {
|
|
52197
|
+
return getCarouselItemTitle(this.env.model.getters, item);
|
|
52198
|
+
}
|
|
52199
|
+
getItemPreview(item) {
|
|
52200
|
+
return getCarouselItemPreview(this.env.model.getters, item);
|
|
52201
|
+
}
|
|
52202
|
+
get carouselAddChartInfoMessage() {
|
|
52203
|
+
return _t("Add a chart to the carousel. You can also add a chart by dragging and dropping it over the carousel figure.");
|
|
52204
|
+
}
|
|
52205
|
+
}
|
|
52206
|
+
|
|
51040
52207
|
class ChartDataSeries extends owl.Component {
|
|
51041
52208
|
static template = "o-spreadsheet.ChartDataSeries";
|
|
51042
52209
|
static components = { SelectionInput, Section };
|
|
@@ -51103,7 +52270,7 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51103
52270
|
ChartErrorSection,
|
|
51104
52271
|
};
|
|
51105
52272
|
static props = {
|
|
51106
|
-
|
|
52273
|
+
chartId: String,
|
|
51107
52274
|
definition: Object,
|
|
51108
52275
|
updateChart: Function,
|
|
51109
52276
|
canUpdateChart: Function,
|
|
@@ -51161,7 +52328,7 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51161
52328
|
];
|
|
51162
52329
|
}
|
|
51163
52330
|
onUpdateDataSetsHaveTitle(dataSetsHaveTitle) {
|
|
51164
|
-
this.props.updateChart(this.props.
|
|
52331
|
+
this.props.updateChart(this.props.chartId, {
|
|
51165
52332
|
dataSetsHaveTitle,
|
|
51166
52333
|
});
|
|
51167
52334
|
}
|
|
@@ -51233,7 +52400,7 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51233
52400
|
return;
|
|
51234
52401
|
}
|
|
51235
52402
|
const labelRange = dataSets.length > 1 ? dataSets.shift().dataRange : "";
|
|
51236
|
-
this.props.updateChart(this.props.
|
|
52403
|
+
this.props.updateChart(this.props.chartId, {
|
|
51237
52404
|
labelRange,
|
|
51238
52405
|
dataSets,
|
|
51239
52406
|
});
|
|
@@ -51250,7 +52417,7 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51250
52417
|
...this.dataSets?.[i],
|
|
51251
52418
|
dataRange,
|
|
51252
52419
|
}));
|
|
51253
|
-
this.state.datasetDispatchResult = this.props.canUpdateChart(this.props.
|
|
52420
|
+
this.state.datasetDispatchResult = this.props.canUpdateChart(this.props.chartId, {
|
|
51254
52421
|
dataSets: this.dataSets,
|
|
51255
52422
|
});
|
|
51256
52423
|
}
|
|
@@ -51262,7 +52429,7 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51262
52429
|
backgroundColor: colors[i],
|
|
51263
52430
|
...this.dataSets[i],
|
|
51264
52431
|
}));
|
|
51265
|
-
this.state.datasetDispatchResult = this.props.updateChart(this.props.
|
|
52432
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.chartId, {
|
|
51266
52433
|
dataSets: this.dataSets,
|
|
51267
52434
|
});
|
|
51268
52435
|
}
|
|
@@ -51275,18 +52442,18 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51275
52442
|
...ds,
|
|
51276
52443
|
}))
|
|
51277
52444
|
.filter((_, i) => i !== index);
|
|
51278
|
-
this.state.datasetDispatchResult = this.props.updateChart(this.props.
|
|
52445
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.chartId, {
|
|
51279
52446
|
dataSets: this.dataSets,
|
|
51280
52447
|
});
|
|
51281
52448
|
}
|
|
51282
52449
|
onDataSeriesConfirmed() {
|
|
51283
52450
|
this.dataSets = this.splitRanges;
|
|
51284
52451
|
this.datasetOrientation = this.computeDatasetOrientation();
|
|
51285
|
-
this.state.datasetDispatchResult = this.props.updateChart(this.props.
|
|
52452
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.chartId, {
|
|
51286
52453
|
dataSets: this.dataSets,
|
|
51287
52454
|
});
|
|
51288
52455
|
if (this.state.datasetDispatchResult.isSuccessful) {
|
|
51289
|
-
this.dataSets = this.env.model.getters.getChartDefinition(this.props.
|
|
52456
|
+
this.dataSets = this.env.model.getters.getChartDefinition(this.props.chartId).dataSets;
|
|
51290
52457
|
}
|
|
51291
52458
|
}
|
|
51292
52459
|
get splitRanges() {
|
|
@@ -51377,12 +52544,12 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51377
52544
|
*/
|
|
51378
52545
|
onLabelRangeChanged(ranges) {
|
|
51379
52546
|
this.labelRange = ranges[0];
|
|
51380
|
-
this.state.labelsDispatchResult = this.props.canUpdateChart(this.props.
|
|
52547
|
+
this.state.labelsDispatchResult = this.props.canUpdateChart(this.props.chartId, {
|
|
51381
52548
|
labelRange: this.labelRange,
|
|
51382
52549
|
});
|
|
51383
52550
|
}
|
|
51384
52551
|
onLabelRangeConfirmed() {
|
|
51385
|
-
this.state.labelsDispatchResult = this.props.updateChart(this.props.
|
|
52552
|
+
this.state.labelsDispatchResult = this.props.updateChart(this.props.chartId, {
|
|
51386
52553
|
labelRange: this.labelRange,
|
|
51387
52554
|
});
|
|
51388
52555
|
}
|
|
@@ -51390,7 +52557,7 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51390
52557
|
return this.labelRange || "";
|
|
51391
52558
|
}
|
|
51392
52559
|
onUpdateAggregated(aggregated) {
|
|
51393
|
-
this.props.updateChart(this.props.
|
|
52560
|
+
this.props.updateChart(this.props.chartId, {
|
|
51394
52561
|
aggregated,
|
|
51395
52562
|
});
|
|
51396
52563
|
}
|
|
@@ -51422,7 +52589,8 @@ class GenericChartConfigPanel extends owl.Component {
|
|
|
51422
52589
|
}
|
|
51423
52590
|
const zonesBySheetName = {};
|
|
51424
52591
|
const transposedDatasets = [];
|
|
51425
|
-
const
|
|
52592
|
+
const figureId = getters.getFigureIdFromChartId(this.props.chartId);
|
|
52593
|
+
const figureSheetId = getters.getFigureSheetId(figureId);
|
|
51426
52594
|
let name = getters.getActiveSheet().name;
|
|
51427
52595
|
if (figureSheetId) {
|
|
51428
52596
|
name = getters.getSheet(figureSheetId).name;
|
|
@@ -51482,7 +52650,7 @@ class BarConfigPanel extends GenericChartConfigPanel {
|
|
|
51482
52650
|
: this.chartTerms.StackedColumnChart;
|
|
51483
52651
|
}
|
|
51484
52652
|
onUpdateStacked(stacked) {
|
|
51485
|
-
this.props.updateChart(this.props.
|
|
52653
|
+
this.props.updateChart(this.props.chartId, {
|
|
51486
52654
|
stacked,
|
|
51487
52655
|
});
|
|
51488
52656
|
}
|
|
@@ -51976,7 +53144,7 @@ class ChartTitle extends owl.Component {
|
|
|
51976
53144
|
class AxisDesignEditor extends owl.Component {
|
|
51977
53145
|
static template = "o-spreadsheet-AxisDesignEditor";
|
|
51978
53146
|
static components = { Section, ChartTitle, BadgeSelection };
|
|
51979
|
-
static props = {
|
|
53147
|
+
static props = { chartId: String, definition: Object, updateChart: Function, axesList: Array };
|
|
51980
53148
|
state = owl.useState({ currentAxis: "x" });
|
|
51981
53149
|
defaultFontSize = CHART_AXIS_TITLE_FONT_SIZE;
|
|
51982
53150
|
get axisTitleStyle() {
|
|
@@ -52001,7 +53169,7 @@ class AxisDesignEditor extends owl.Component {
|
|
|
52001
53169
|
text,
|
|
52002
53170
|
},
|
|
52003
53171
|
};
|
|
52004
|
-
this.props.updateChart(this.props.
|
|
53172
|
+
this.props.updateChart(this.props.chartId, { axesDesign });
|
|
52005
53173
|
}
|
|
52006
53174
|
updateAxisTitleStyle(style) {
|
|
52007
53175
|
const axesDesign = deepCopy(this.props.definition.axesDesign) ?? {};
|
|
@@ -52009,7 +53177,7 @@ class AxisDesignEditor extends owl.Component {
|
|
|
52009
53177
|
...axesDesign[this.state.currentAxis],
|
|
52010
53178
|
title: style,
|
|
52011
53179
|
};
|
|
52012
|
-
this.props.updateChart(this.props.
|
|
53180
|
+
this.props.updateChart(this.props.chartId, { axesDesign });
|
|
52013
53181
|
}
|
|
52014
53182
|
}
|
|
52015
53183
|
|
|
@@ -52062,7 +53230,7 @@ class GeneralDesignEditor extends owl.Component {
|
|
|
52062
53230
|
RadioSelection,
|
|
52063
53231
|
};
|
|
52064
53232
|
static props = {
|
|
52065
|
-
|
|
53233
|
+
chartId: String,
|
|
52066
53234
|
definition: Object,
|
|
52067
53235
|
updateChart: Function,
|
|
52068
53236
|
canUpdateChart: Function,
|
|
@@ -52086,17 +53254,17 @@ class GeneralDesignEditor extends owl.Component {
|
|
|
52086
53254
|
this.state.activeTool = isOpen ? "" : tool;
|
|
52087
53255
|
}
|
|
52088
53256
|
updateBackgroundColor(color) {
|
|
52089
|
-
this.props.updateChart(this.props.
|
|
53257
|
+
this.props.updateChart(this.props.chartId, {
|
|
52090
53258
|
background: color,
|
|
52091
53259
|
});
|
|
52092
53260
|
}
|
|
52093
53261
|
updateTitle(newTitle) {
|
|
52094
53262
|
const title = { ...this.title, text: newTitle };
|
|
52095
|
-
this.props.updateChart(this.props.
|
|
53263
|
+
this.props.updateChart(this.props.chartId, { title });
|
|
52096
53264
|
}
|
|
52097
53265
|
updateChartTitleStyle(style) {
|
|
52098
53266
|
const title = { ...this.title, ...style };
|
|
52099
|
-
this.props.updateChart(this.props.
|
|
53267
|
+
this.props.updateChart(this.props.chartId, { title });
|
|
52100
53268
|
this.state.activeTool = "";
|
|
52101
53269
|
}
|
|
52102
53270
|
}
|
|
@@ -52107,13 +53275,13 @@ class ChartLegend extends owl.Component {
|
|
|
52107
53275
|
Section,
|
|
52108
53276
|
};
|
|
52109
53277
|
static props = {
|
|
52110
|
-
|
|
53278
|
+
chartId: String,
|
|
52111
53279
|
definition: Object,
|
|
52112
53280
|
updateChart: Function,
|
|
52113
53281
|
canUpdateChart: Function,
|
|
52114
53282
|
};
|
|
52115
53283
|
updateLegendPosition(ev) {
|
|
52116
|
-
this.props.updateChart(this.props.
|
|
53284
|
+
this.props.updateChart(this.props.chartId, {
|
|
52117
53285
|
legendPosition: ev.target.value,
|
|
52118
53286
|
});
|
|
52119
53287
|
}
|
|
@@ -52127,7 +53295,7 @@ class SeriesDesignEditor extends owl.Component {
|
|
|
52127
53295
|
RoundColorPicker,
|
|
52128
53296
|
};
|
|
52129
53297
|
static props = {
|
|
52130
|
-
|
|
53298
|
+
chartId: String,
|
|
52131
53299
|
definition: Object,
|
|
52132
53300
|
updateChart: Function,
|
|
52133
53301
|
canUpdateChart: Function,
|
|
@@ -52135,7 +53303,7 @@ class SeriesDesignEditor extends owl.Component {
|
|
|
52135
53303
|
};
|
|
52136
53304
|
state = owl.useState({ index: 0 });
|
|
52137
53305
|
getDataSeries() {
|
|
52138
|
-
const runtime = this.env.model.getters.getChartRuntime(this.props.
|
|
53306
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
52139
53307
|
if (!runtime || !("chartJsConfig" in runtime)) {
|
|
52140
53308
|
return [];
|
|
52141
53309
|
}
|
|
@@ -52154,7 +53322,7 @@ class SeriesDesignEditor extends owl.Component {
|
|
|
52154
53322
|
...dataSets[this.state.index],
|
|
52155
53323
|
backgroundColor: color,
|
|
52156
53324
|
};
|
|
52157
|
-
this.props.updateChart(this.props.
|
|
53325
|
+
this.props.updateChart(this.props.chartId, { dataSets });
|
|
52158
53326
|
}
|
|
52159
53327
|
getDataSeriesColor() {
|
|
52160
53328
|
const dataSets = this.props.definition.dataSets;
|
|
@@ -52174,7 +53342,7 @@ class SeriesDesignEditor extends owl.Component {
|
|
|
52174
53342
|
...dataSets[this.state.index],
|
|
52175
53343
|
label,
|
|
52176
53344
|
};
|
|
52177
|
-
this.props.updateChart(this.props.
|
|
53345
|
+
this.props.updateChart(this.props.chartId, { dataSets });
|
|
52178
53346
|
}
|
|
52179
53347
|
getDataSeriesLabel() {
|
|
52180
53348
|
const dataSets = this.props.definition.dataSets;
|
|
@@ -52192,7 +53360,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
52192
53360
|
RoundColorPicker,
|
|
52193
53361
|
};
|
|
52194
53362
|
static props = {
|
|
52195
|
-
|
|
53363
|
+
chartId: String,
|
|
52196
53364
|
definition: Object,
|
|
52197
53365
|
canUpdateChart: Function,
|
|
52198
53366
|
updateChart: Function,
|
|
@@ -52208,7 +53376,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
52208
53376
|
...dataSets[index],
|
|
52209
53377
|
yAxisId: axis === "left" ? "y" : "y1",
|
|
52210
53378
|
};
|
|
52211
|
-
this.props.updateChart(this.props.
|
|
53379
|
+
this.props.updateChart(this.props.chartId, { dataSets });
|
|
52212
53380
|
}
|
|
52213
53381
|
getDataSerieAxis(index) {
|
|
52214
53382
|
const dataSets = this.props.definition.dataSets;
|
|
@@ -52234,7 +53402,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
52234
53402
|
display,
|
|
52235
53403
|
},
|
|
52236
53404
|
};
|
|
52237
|
-
this.props.updateChart(this.props.
|
|
53405
|
+
this.props.updateChart(this.props.chartId, { dataSets });
|
|
52238
53406
|
}
|
|
52239
53407
|
getTrendLineConfiguration(index) {
|
|
52240
53408
|
const dataSets = this.props.definition.dataSets;
|
|
@@ -52275,7 +53443,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
52275
53443
|
this.updateTrendLineValue(index, { order: parseInt(element.value) });
|
|
52276
53444
|
}
|
|
52277
53445
|
getMaxPolynomialDegree(index) {
|
|
52278
|
-
const runtime = this.env.model.getters.getChartRuntime(this.props.
|
|
53446
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
52279
53447
|
return Math.min(10, runtime.chartJsConfig.data.datasets[index].data.length - 1);
|
|
52280
53448
|
}
|
|
52281
53449
|
get defaultWindowSize() {
|
|
@@ -52317,7 +53485,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
52317
53485
|
...config,
|
|
52318
53486
|
},
|
|
52319
53487
|
};
|
|
52320
|
-
this.props.updateChart(this.props.
|
|
53488
|
+
this.props.updateChart(this.props.chartId, { dataSets });
|
|
52321
53489
|
}
|
|
52322
53490
|
}
|
|
52323
53491
|
|
|
@@ -52327,7 +53495,7 @@ class ChartShowValues extends owl.Component {
|
|
|
52327
53495
|
Checkbox,
|
|
52328
53496
|
};
|
|
52329
53497
|
static props = {
|
|
52330
|
-
|
|
53498
|
+
chartId: String,
|
|
52331
53499
|
definition: Object,
|
|
52332
53500
|
updateChart: Function,
|
|
52333
53501
|
canUpdateChart: Function,
|
|
@@ -52347,7 +53515,7 @@ class ChartWithAxisDesignPanel extends owl.Component {
|
|
|
52347
53515
|
ChartShowValues,
|
|
52348
53516
|
};
|
|
52349
53517
|
static props = {
|
|
52350
|
-
|
|
53518
|
+
chartId: String,
|
|
52351
53519
|
definition: Object,
|
|
52352
53520
|
canUpdateChart: Function,
|
|
52353
53521
|
updateChart: Function,
|
|
@@ -52371,17 +53539,30 @@ class ChartShowDataMarkers extends owl.Component {
|
|
|
52371
53539
|
Checkbox,
|
|
52372
53540
|
};
|
|
52373
53541
|
static props = {
|
|
52374
|
-
|
|
53542
|
+
chartId: String,
|
|
52375
53543
|
definition: Object,
|
|
52376
53544
|
updateChart: Function,
|
|
52377
53545
|
canUpdateChart: Function,
|
|
52378
53546
|
};
|
|
52379
53547
|
}
|
|
52380
53548
|
|
|
52381
|
-
class
|
|
52382
|
-
static template = "o-spreadsheet-
|
|
53549
|
+
class GenericZoomableChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
53550
|
+
static template = "o-spreadsheet-GenericZoomableChartDesignPanel";
|
|
52383
53551
|
static components = {
|
|
52384
53552
|
...ChartWithAxisDesignPanel.components,
|
|
53553
|
+
Checkbox,
|
|
53554
|
+
};
|
|
53555
|
+
onToggleZoom(zoomable) {
|
|
53556
|
+
this.props.updateChart(this.props.chartId, {
|
|
53557
|
+
zoomable,
|
|
53558
|
+
});
|
|
53559
|
+
}
|
|
53560
|
+
}
|
|
53561
|
+
|
|
53562
|
+
class ComboChartDesignPanel extends GenericZoomableChartDesignPanel {
|
|
53563
|
+
static template = "o-spreadsheet-ComboChartDesignPanel";
|
|
53564
|
+
static components = {
|
|
53565
|
+
...GenericZoomableChartDesignPanel.components,
|
|
52385
53566
|
ChartShowDataMarkers,
|
|
52386
53567
|
RadioSelection,
|
|
52387
53568
|
};
|
|
@@ -52398,7 +53579,7 @@ class ComboChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
|
52398
53579
|
...dataSets[index],
|
|
52399
53580
|
type,
|
|
52400
53581
|
};
|
|
52401
|
-
this.props.updateChart(this.props.
|
|
53582
|
+
this.props.updateChart(this.props.chartId, { dataSets });
|
|
52402
53583
|
}
|
|
52403
53584
|
getDataSeriesType(index) {
|
|
52404
53585
|
const dataSets = this.props.definition.dataSets;
|
|
@@ -52434,7 +53615,7 @@ class FunnelChartConfigPanel extends GenericChartConfigPanel {
|
|
|
52434
53615
|
];
|
|
52435
53616
|
}
|
|
52436
53617
|
onUpdateCumulative(cumulative) {
|
|
52437
|
-
this.props.updateChart(this.props.
|
|
53618
|
+
this.props.updateChart(this.props.chartId, {
|
|
52438
53619
|
cumulative,
|
|
52439
53620
|
});
|
|
52440
53621
|
}
|
|
@@ -52450,13 +53631,13 @@ class FunnelChartDesignPanel extends owl.Component {
|
|
|
52450
53631
|
Section,
|
|
52451
53632
|
};
|
|
52452
53633
|
static props = {
|
|
52453
|
-
|
|
53634
|
+
chartId: String,
|
|
52454
53635
|
definition: Object,
|
|
52455
53636
|
updateChart: Function,
|
|
52456
53637
|
canUpdateChart: Function,
|
|
52457
53638
|
};
|
|
52458
53639
|
getFunnelColorItems() {
|
|
52459
|
-
const runtime = this.env.model.getters.getChartRuntime(this.props.
|
|
53640
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
52460
53641
|
const labels = (runtime.chartJsConfig.data.labels || []);
|
|
52461
53642
|
const colors = getFunnelLabelColors(labels, this.props.definition.funnelColors);
|
|
52462
53643
|
return labels.map((label, index) => ({
|
|
@@ -52466,7 +53647,7 @@ class FunnelChartDesignPanel extends owl.Component {
|
|
|
52466
53647
|
}
|
|
52467
53648
|
updateFunnelItemColor(index, color) {
|
|
52468
53649
|
const funnelColors = replaceItemAtIndex(this.props.definition.funnelColors || [], color, index);
|
|
52469
|
-
this.props.updateChart(this.props.
|
|
53650
|
+
this.props.updateChart(this.props.chartId, { funnelColors });
|
|
52470
53651
|
}
|
|
52471
53652
|
}
|
|
52472
53653
|
|
|
@@ -52474,7 +53655,7 @@ class GaugeChartConfigPanel extends owl.Component {
|
|
|
52474
53655
|
static template = "o-spreadsheet-GaugeChartConfigPanel";
|
|
52475
53656
|
static components = { ChartErrorSection, ChartDataSeries };
|
|
52476
53657
|
static props = {
|
|
52477
|
-
|
|
53658
|
+
chartId: String,
|
|
52478
53659
|
definition: Object,
|
|
52479
53660
|
updateChart: Function,
|
|
52480
53661
|
canUpdateChart: Function,
|
|
@@ -52492,12 +53673,12 @@ class GaugeChartConfigPanel extends owl.Component {
|
|
|
52492
53673
|
}
|
|
52493
53674
|
onDataRangeChanged(ranges) {
|
|
52494
53675
|
this.dataRange = ranges[0];
|
|
52495
|
-
this.state.dataRangeDispatchResult = this.props.canUpdateChart(this.props.
|
|
53676
|
+
this.state.dataRangeDispatchResult = this.props.canUpdateChart(this.props.chartId, {
|
|
52496
53677
|
dataRange: this.dataRange,
|
|
52497
53678
|
});
|
|
52498
53679
|
}
|
|
52499
53680
|
updateDataRange() {
|
|
52500
|
-
this.state.dataRangeDispatchResult = this.props.updateChart(this.props.
|
|
53681
|
+
this.state.dataRangeDispatchResult = this.props.updateChart(this.props.chartId, {
|
|
52501
53682
|
dataRange: this.dataRange,
|
|
52502
53683
|
});
|
|
52503
53684
|
}
|
|
@@ -52556,7 +53737,7 @@ class GaugeChartDesignPanel extends owl.Component {
|
|
|
52556
53737
|
StandaloneComposer,
|
|
52557
53738
|
};
|
|
52558
53739
|
static props = {
|
|
52559
|
-
|
|
53740
|
+
chartId: String,
|
|
52560
53741
|
definition: Object,
|
|
52561
53742
|
updateChart: Function,
|
|
52562
53743
|
canUpdateChart: { type: Function, optional: true },
|
|
@@ -52597,7 +53778,7 @@ class GaugeChartDesignPanel extends owl.Component {
|
|
|
52597
53778
|
updateSectionRule(sectionRule) {
|
|
52598
53779
|
this.state.sectionRuleCancelledReasons = [];
|
|
52599
53780
|
this.state.sectionRuleCancelledReasons.push(...this.checkSectionRuleFormulasAreValid(this.state.sectionRule));
|
|
52600
|
-
const dispatchResult = this.props.updateChart(this.props.
|
|
53781
|
+
const dispatchResult = this.props.updateChart(this.props.chartId, {
|
|
52601
53782
|
sectionRule,
|
|
52602
53783
|
});
|
|
52603
53784
|
if (dispatchResult.isSuccessful) {
|
|
@@ -52660,9 +53841,9 @@ class GaugeChartDesignPanel extends owl.Component {
|
|
|
52660
53841
|
return tryToNumber(toScalar(evaluatedValue), locale) !== undefined;
|
|
52661
53842
|
}
|
|
52662
53843
|
get sheetId() {
|
|
52663
|
-
const chart = this.env.model.getters.getChart(this.props.
|
|
53844
|
+
const chart = this.env.model.getters.getChart(this.props.chartId);
|
|
52664
53845
|
if (!chart) {
|
|
52665
|
-
throw new Error("Chart not found with id " + this.props.
|
|
53846
|
+
throw new Error("Chart not found with id " + this.props.chartId);
|
|
52666
53847
|
}
|
|
52667
53848
|
return chart.sheetId;
|
|
52668
53849
|
}
|
|
@@ -52672,13 +53853,13 @@ class GeoChartRegionSelectSection extends owl.Component {
|
|
|
52672
53853
|
static template = "o-spreadsheet-GeoChartRegionSelectSection";
|
|
52673
53854
|
static components = { Section };
|
|
52674
53855
|
static props = {
|
|
52675
|
-
|
|
53856
|
+
chartId: String,
|
|
52676
53857
|
definition: Object,
|
|
52677
53858
|
updateChart: Function,
|
|
52678
53859
|
};
|
|
52679
53860
|
updateSelectedRegion(ev) {
|
|
52680
53861
|
const value = ev.target.value;
|
|
52681
|
-
this.props.updateChart(this.props.
|
|
53862
|
+
this.props.updateChart(this.props.chartId, { region: value });
|
|
52682
53863
|
}
|
|
52683
53864
|
get availableRegions() {
|
|
52684
53865
|
return this.env.model.getters.getGeoChartAvailableRegions();
|
|
@@ -52728,14 +53909,14 @@ class GeoChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
|
52728
53909
|
: this.updateColorScale(value);
|
|
52729
53910
|
}
|
|
52730
53911
|
updateColorScale(colorScale) {
|
|
52731
|
-
this.props.updateChart(this.props.
|
|
53912
|
+
this.props.updateChart(this.props.chartId, { colorScale });
|
|
52732
53913
|
}
|
|
52733
53914
|
updateMissingValueColor(color) {
|
|
52734
|
-
this.props.updateChart(this.props.
|
|
53915
|
+
this.props.updateChart(this.props.chartId, { missingValueColor: color });
|
|
52735
53916
|
}
|
|
52736
53917
|
updateLegendPosition(ev) {
|
|
52737
53918
|
const value = ev.target.value;
|
|
52738
|
-
this.props.updateChart(this.props.
|
|
53919
|
+
this.props.updateChart(this.props.chartId, { legendPosition: value });
|
|
52739
53920
|
}
|
|
52740
53921
|
get selectedColorScale() {
|
|
52741
53922
|
return typeof this.props.definition.colorScale === "object"
|
|
@@ -52784,7 +53965,7 @@ class HierarchicalChartConfigPanel extends GenericChartConfigPanel {
|
|
|
52784
53965
|
class LineConfigPanel extends GenericChartConfigPanel {
|
|
52785
53966
|
static template = "o-spreadsheet-LineConfigPanel";
|
|
52786
53967
|
get canTreatLabelsAsText() {
|
|
52787
|
-
const chart = this.env.model.getters.getChart(this.props.
|
|
53968
|
+
const chart = this.env.model.getters.getChart(this.props.chartId);
|
|
52788
53969
|
if (chart && chart instanceof LineChart) {
|
|
52789
53970
|
return canChartParseLabels(chart.getDefinition(), chart.dataSets, chart.labelRange, this.env.model.getters);
|
|
52790
53971
|
}
|
|
@@ -52809,26 +53990,26 @@ class LineConfigPanel extends GenericChartConfigPanel {
|
|
|
52809
53990
|
return options;
|
|
52810
53991
|
}
|
|
52811
53992
|
onUpdateLabelsAsText(labelsAsText) {
|
|
52812
|
-
this.props.updateChart(this.props.
|
|
53993
|
+
this.props.updateChart(this.props.chartId, {
|
|
52813
53994
|
labelsAsText,
|
|
52814
53995
|
});
|
|
52815
53996
|
}
|
|
52816
53997
|
onUpdateStacked(stacked) {
|
|
52817
|
-
this.props.updateChart(this.props.
|
|
53998
|
+
this.props.updateChart(this.props.chartId, {
|
|
52818
53999
|
stacked,
|
|
52819
54000
|
});
|
|
52820
54001
|
}
|
|
52821
54002
|
onUpdateCumulative(cumulative) {
|
|
52822
|
-
this.props.updateChart(this.props.
|
|
54003
|
+
this.props.updateChart(this.props.chartId, {
|
|
52823
54004
|
cumulative,
|
|
52824
54005
|
});
|
|
52825
54006
|
}
|
|
52826
54007
|
}
|
|
52827
54008
|
|
|
52828
|
-
class LineChartDesignPanel extends
|
|
54009
|
+
class LineChartDesignPanel extends GenericZoomableChartDesignPanel {
|
|
52829
54010
|
static template = "o-spreadsheet-LineChartDesignPanel";
|
|
52830
54011
|
static components = {
|
|
52831
|
-
...
|
|
54012
|
+
...GenericZoomableChartDesignPanel.components,
|
|
52832
54013
|
ChartShowDataMarkers,
|
|
52833
54014
|
};
|
|
52834
54015
|
}
|
|
@@ -52856,13 +54037,13 @@ class PieChartDesignPanel extends owl.Component {
|
|
|
52856
54037
|
PieHoleSize,
|
|
52857
54038
|
};
|
|
52858
54039
|
static props = {
|
|
52859
|
-
|
|
54040
|
+
chartId: String,
|
|
52860
54041
|
definition: Object,
|
|
52861
54042
|
updateChart: Function,
|
|
52862
54043
|
canUpdateChart: { type: Function, optional: true },
|
|
52863
54044
|
};
|
|
52864
54045
|
onPieHoleSizeChange(pieHolePercentage) {
|
|
52865
|
-
this.props.updateChart(this.props.
|
|
54046
|
+
this.props.updateChart(this.props.chartId, {
|
|
52866
54047
|
...this.props.definition,
|
|
52867
54048
|
pieHolePercentage,
|
|
52868
54049
|
});
|
|
@@ -52883,7 +54064,7 @@ class RadarChartDesignPanel extends owl.Component {
|
|
|
52883
54064
|
ChartShowDataMarkers,
|
|
52884
54065
|
};
|
|
52885
54066
|
static props = {
|
|
52886
|
-
|
|
54067
|
+
chartId: String,
|
|
52887
54068
|
definition: Object,
|
|
52888
54069
|
canUpdateChart: Function,
|
|
52889
54070
|
updateChart: Function,
|
|
@@ -52893,14 +54074,14 @@ class RadarChartDesignPanel extends owl.Component {
|
|
|
52893
54074
|
class ScatterConfigPanel extends GenericChartConfigPanel {
|
|
52894
54075
|
static template = "o-spreadsheet-ScatterConfigPanel";
|
|
52895
54076
|
get canTreatLabelsAsText() {
|
|
52896
|
-
const chart = this.env.model.getters.getChart(this.props.
|
|
54077
|
+
const chart = this.env.model.getters.getChart(this.props.chartId);
|
|
52897
54078
|
if (chart && chart instanceof ScatterChart) {
|
|
52898
54079
|
return canChartParseLabels(chart.getDefinition(), chart.dataSets, chart.labelRange, this.env.model.getters);
|
|
52899
54080
|
}
|
|
52900
54081
|
return false;
|
|
52901
54082
|
}
|
|
52902
54083
|
onUpdateLabelsAsText(labelsAsText) {
|
|
52903
|
-
this.props.updateChart(this.props.
|
|
54084
|
+
this.props.updateChart(this.props.chartId, {
|
|
52904
54085
|
labelsAsText,
|
|
52905
54086
|
});
|
|
52906
54087
|
}
|
|
@@ -52922,7 +54103,7 @@ class ScorecardChartConfigPanel extends owl.Component {
|
|
|
52922
54103
|
static template = "o-spreadsheet-ScorecardChartConfigPanel";
|
|
52923
54104
|
static components = { SelectionInput, ChartErrorSection, Section };
|
|
52924
54105
|
static props = {
|
|
52925
|
-
|
|
54106
|
+
chartId: String,
|
|
52926
54107
|
definition: Object,
|
|
52927
54108
|
updateChart: Function,
|
|
52928
54109
|
canUpdateChart: Function,
|
|
@@ -52948,12 +54129,12 @@ class ScorecardChartConfigPanel extends owl.Component {
|
|
|
52948
54129
|
}
|
|
52949
54130
|
onKeyValueRangeChanged(ranges) {
|
|
52950
54131
|
this.keyValue = ranges[0];
|
|
52951
|
-
this.state.keyValueDispatchResult = this.props.canUpdateChart(this.props.
|
|
54132
|
+
this.state.keyValueDispatchResult = this.props.canUpdateChart(this.props.chartId, {
|
|
52952
54133
|
keyValue: this.keyValue,
|
|
52953
54134
|
});
|
|
52954
54135
|
}
|
|
52955
54136
|
updateKeyValueRange() {
|
|
52956
|
-
this.state.keyValueDispatchResult = this.props.updateChart(this.props.
|
|
54137
|
+
this.state.keyValueDispatchResult = this.props.updateChart(this.props.chartId, {
|
|
52957
54138
|
keyValue: this.keyValue,
|
|
52958
54139
|
});
|
|
52959
54140
|
}
|
|
@@ -52962,12 +54143,12 @@ class ScorecardChartConfigPanel extends owl.Component {
|
|
|
52962
54143
|
}
|
|
52963
54144
|
onBaselineRangeChanged(ranges) {
|
|
52964
54145
|
this.baseline = ranges[0];
|
|
52965
|
-
this.state.baselineDispatchResult = this.props.canUpdateChart(this.props.
|
|
54146
|
+
this.state.baselineDispatchResult = this.props.canUpdateChart(this.props.chartId, {
|
|
52966
54147
|
baseline: this.baseline,
|
|
52967
54148
|
});
|
|
52968
54149
|
}
|
|
52969
54150
|
updateBaselineRange() {
|
|
52970
|
-
this.state.baselineDispatchResult = this.props.updateChart(this.props.
|
|
54151
|
+
this.state.baselineDispatchResult = this.props.updateChart(this.props.chartId, {
|
|
52971
54152
|
baseline: this.baseline,
|
|
52972
54153
|
});
|
|
52973
54154
|
}
|
|
@@ -52975,7 +54156,7 @@ class ScorecardChartConfigPanel extends owl.Component {
|
|
|
52975
54156
|
return this.baseline || "";
|
|
52976
54157
|
}
|
|
52977
54158
|
updateBaselineMode(ev) {
|
|
52978
|
-
this.props.updateChart(this.props.
|
|
54159
|
+
this.props.updateChart(this.props.chartId, { baselineMode: ev.target.value });
|
|
52979
54160
|
}
|
|
52980
54161
|
}
|
|
52981
54162
|
|
|
@@ -52990,7 +54171,7 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
52990
54171
|
ChartTitle,
|
|
52991
54172
|
};
|
|
52992
54173
|
static props = {
|
|
52993
|
-
|
|
54174
|
+
chartId: String,
|
|
52994
54175
|
definition: Object,
|
|
52995
54176
|
updateChart: Function,
|
|
52996
54177
|
canUpdateChart: { type: Function, optional: true },
|
|
@@ -53007,7 +54188,7 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
53007
54188
|
return SCORECARD_CHART_TITLE_FONT_SIZE;
|
|
53008
54189
|
}
|
|
53009
54190
|
updateHumanizeNumbers(humanize) {
|
|
53010
|
-
this.props.updateChart(this.props.
|
|
54191
|
+
this.props.updateChart(this.props.chartId, { humanize });
|
|
53011
54192
|
}
|
|
53012
54193
|
translate(term) {
|
|
53013
54194
|
return _t(term);
|
|
@@ -53015,13 +54196,13 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
53015
54196
|
setColor(color, colorPickerId) {
|
|
53016
54197
|
switch (colorPickerId) {
|
|
53017
54198
|
case "backgroundColor":
|
|
53018
|
-
this.props.updateChart(this.props.
|
|
54199
|
+
this.props.updateChart(this.props.chartId, { background: color });
|
|
53019
54200
|
break;
|
|
53020
54201
|
case "baselineColorDown":
|
|
53021
|
-
this.props.updateChart(this.props.
|
|
54202
|
+
this.props.updateChart(this.props.chartId, { baselineColorDown: color });
|
|
53022
54203
|
break;
|
|
53023
54204
|
case "baselineColorUp":
|
|
53024
|
-
this.props.updateChart(this.props.
|
|
54205
|
+
this.props.updateChart(this.props.chartId, { baselineColorUp: color });
|
|
53025
54206
|
break;
|
|
53026
54207
|
}
|
|
53027
54208
|
}
|
|
@@ -53040,22 +54221,22 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
53040
54221
|
};
|
|
53041
54222
|
}
|
|
53042
54223
|
setKeyText(text) {
|
|
53043
|
-
this.props.updateChart(this.props.
|
|
54224
|
+
this.props.updateChart(this.props.chartId, {
|
|
53044
54225
|
keyDescr: { ...this.props.definition.keyDescr, text },
|
|
53045
54226
|
});
|
|
53046
54227
|
}
|
|
53047
54228
|
updateKeyStyle(style) {
|
|
53048
54229
|
const keyDescr = { ...this.keyStyle, ...style };
|
|
53049
|
-
this.props.updateChart(this.props.
|
|
54230
|
+
this.props.updateChart(this.props.chartId, { keyDescr });
|
|
53050
54231
|
}
|
|
53051
54232
|
setBaselineText(text) {
|
|
53052
|
-
this.props.updateChart(this.props.
|
|
54233
|
+
this.props.updateChart(this.props.chartId, {
|
|
53053
54234
|
baselineDescr: { ...this.props.definition.baselineDescr, text },
|
|
53054
54235
|
});
|
|
53055
54236
|
}
|
|
53056
54237
|
updateBaselineStyle(style) {
|
|
53057
54238
|
const baselineDescr = { ...this.baselineStyle, ...style };
|
|
53058
|
-
this.props.updateChart(this.props.
|
|
54239
|
+
this.props.updateChart(this.props.chartId, { baselineDescr });
|
|
53059
54240
|
}
|
|
53060
54241
|
}
|
|
53061
54242
|
|
|
@@ -53073,7 +54254,7 @@ class SunburstChartDesignPanel extends owl.Component {
|
|
|
53073
54254
|
PieHoleSize,
|
|
53074
54255
|
};
|
|
53075
54256
|
static props = {
|
|
53076
|
-
|
|
54257
|
+
chartId: String,
|
|
53077
54258
|
definition: Object,
|
|
53078
54259
|
updateChart: Function,
|
|
53079
54260
|
canUpdateChart: { type: Function, optional: true },
|
|
@@ -53086,18 +54267,18 @@ class SunburstChartDesignPanel extends owl.Component {
|
|
|
53086
54267
|
return this.props.definition.showLabels ?? SunburstChartDefaults.showLabels;
|
|
53087
54268
|
}
|
|
53088
54269
|
get groupColors() {
|
|
53089
|
-
const
|
|
53090
|
-
const runtime = this.env.model.getters.getChartRuntime(
|
|
54270
|
+
const chartId = this.props.chartId;
|
|
54271
|
+
const runtime = this.env.model.getters.getChartRuntime(chartId);
|
|
53091
54272
|
const dataset = runtime.chartJsConfig.data.datasets[0];
|
|
53092
54273
|
return dataset?.groupColors || [];
|
|
53093
54274
|
}
|
|
53094
54275
|
onGroupColorChanged(index, color) {
|
|
53095
54276
|
const colors = deepCopy(this.props.definition.groupColors) ?? [];
|
|
53096
54277
|
colors[index] = color;
|
|
53097
|
-
this.props.updateChart(this.props.
|
|
54278
|
+
this.props.updateChart(this.props.chartId, { groupColors: colors });
|
|
53098
54279
|
}
|
|
53099
54280
|
onPieHoleSizeChange(pieHolePercentage) {
|
|
53100
|
-
this.props.updateChart(this.props.
|
|
54281
|
+
this.props.updateChart(this.props.chartId, {
|
|
53101
54282
|
...this.props.definition,
|
|
53102
54283
|
pieHolePercentage,
|
|
53103
54284
|
});
|
|
@@ -53111,7 +54292,7 @@ class TreeMapCategoryColors extends owl.Component {
|
|
|
53111
54292
|
RoundColorPicker,
|
|
53112
54293
|
};
|
|
53113
54294
|
static props = {
|
|
53114
|
-
|
|
54295
|
+
chartId: String,
|
|
53115
54296
|
definition: Object,
|
|
53116
54297
|
onColorChanged: Function,
|
|
53117
54298
|
};
|
|
@@ -53123,7 +54304,7 @@ class TreeMapCategoryColors extends owl.Component {
|
|
|
53123
54304
|
return coloringOptions;
|
|
53124
54305
|
}
|
|
53125
54306
|
getTreeGroupAndColors() {
|
|
53126
|
-
const runtime = this.env.model.getters.getChartRuntime(this.props.
|
|
54307
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
53127
54308
|
const config = runtime.chartJsConfig;
|
|
53128
54309
|
return config.data.datasets[0]?.groupColors || [];
|
|
53129
54310
|
}
|
|
@@ -53144,7 +54325,7 @@ class TreeMapColorScale extends owl.Component {
|
|
|
53144
54325
|
static template = "o-spreadsheet-TreeMapColorScale";
|
|
53145
54326
|
static components = { RoundColorPicker };
|
|
53146
54327
|
static props = {
|
|
53147
|
-
|
|
54328
|
+
chartId: String,
|
|
53148
54329
|
definition: Object,
|
|
53149
54330
|
onColorChanged: Function,
|
|
53150
54331
|
};
|
|
@@ -53186,7 +54367,7 @@ class TreeMapChartDesignPanel extends owl.Component {
|
|
|
53186
54367
|
TreeMapColorScale,
|
|
53187
54368
|
};
|
|
53188
54369
|
static props = {
|
|
53189
|
-
|
|
54370
|
+
chartId: String,
|
|
53190
54371
|
definition: Object,
|
|
53191
54372
|
updateChart: Function,
|
|
53192
54373
|
canUpdateChart: { type: Function, optional: true },
|
|
@@ -53210,15 +54391,15 @@ class TreeMapChartDesignPanel extends owl.Component {
|
|
|
53210
54391
|
}
|
|
53211
54392
|
changeColoringOption(option) {
|
|
53212
54393
|
const coloringOptions = option === "categoryColor" ? this.savedColors.categoryColors : this.savedColors.colorScale;
|
|
53213
|
-
this.props.updateChart(this.props.
|
|
54394
|
+
this.props.updateChart(this.props.chartId, { coloringOptions });
|
|
53214
54395
|
}
|
|
53215
54396
|
onCategoryColorChange(coloringOptions) {
|
|
53216
54397
|
this.savedColors.categoryColors = coloringOptions;
|
|
53217
|
-
this.props.updateChart(this.props.
|
|
54398
|
+
this.props.updateChart(this.props.chartId, { coloringOptions });
|
|
53218
54399
|
}
|
|
53219
54400
|
onColorScaleChange(coloringOptions) {
|
|
53220
54401
|
this.savedColors.colorScale = coloringOptions;
|
|
53221
|
-
this.props.updateChart(this.props.
|
|
54402
|
+
this.props.updateChart(this.props.chartId, { coloringOptions });
|
|
53222
54403
|
}
|
|
53223
54404
|
get coloringOptionChoices() {
|
|
53224
54405
|
return [
|
|
@@ -53242,23 +54423,23 @@ class WaterfallChartDesignPanel extends owl.Component {
|
|
|
53242
54423
|
ChartLegend,
|
|
53243
54424
|
};
|
|
53244
54425
|
static props = {
|
|
53245
|
-
|
|
54426
|
+
chartId: String,
|
|
53246
54427
|
definition: Object,
|
|
53247
54428
|
updateChart: Function,
|
|
53248
54429
|
canUpdateChart: { type: Function, optional: true },
|
|
53249
54430
|
};
|
|
53250
54431
|
axisChoices = CHART_AXIS_CHOICES;
|
|
53251
54432
|
onUpdateShowSubTotals(showSubTotals) {
|
|
53252
|
-
this.props.updateChart(this.props.
|
|
54433
|
+
this.props.updateChart(this.props.chartId, { showSubTotals });
|
|
53253
54434
|
}
|
|
53254
54435
|
onUpdateShowConnectorLines(showConnectorLines) {
|
|
53255
|
-
this.props.updateChart(this.props.
|
|
54436
|
+
this.props.updateChart(this.props.chartId, { showConnectorLines });
|
|
53256
54437
|
}
|
|
53257
54438
|
onUpdateFirstValueAsSubtotal(firstValueAsSubtotal) {
|
|
53258
|
-
this.props.updateChart(this.props.
|
|
54439
|
+
this.props.updateChart(this.props.chartId, { firstValueAsSubtotal });
|
|
53259
54440
|
}
|
|
53260
54441
|
updateColor(colorName, color) {
|
|
53261
|
-
this.props.updateChart(this.props.
|
|
54442
|
+
this.props.updateChart(this.props.chartId, { [colorName]: color });
|
|
53262
54443
|
}
|
|
53263
54444
|
get axesList() {
|
|
53264
54445
|
return [
|
|
@@ -53279,10 +54460,15 @@ class WaterfallChartDesignPanel extends owl.Component {
|
|
|
53279
54460
|
CHART_WATERFALL_SUBTOTAL_COLOR);
|
|
53280
54461
|
}
|
|
53281
54462
|
updateVerticalAxisPosition(value) {
|
|
53282
|
-
this.props.updateChart(this.props.
|
|
54463
|
+
this.props.updateChart(this.props.chartId, {
|
|
53283
54464
|
verticalAxisPosition: value,
|
|
53284
54465
|
});
|
|
53285
54466
|
}
|
|
54467
|
+
onToggleZoom(zoomable) {
|
|
54468
|
+
this.props.updateChart(this.props.chartId, {
|
|
54469
|
+
zoomable,
|
|
54470
|
+
});
|
|
54471
|
+
}
|
|
53286
54472
|
}
|
|
53287
54473
|
|
|
53288
54474
|
const chartSidePanelComponentRegistry = new Registry();
|
|
@@ -53293,11 +54479,11 @@ chartSidePanelComponentRegistry
|
|
|
53293
54479
|
})
|
|
53294
54480
|
.add("scatter", {
|
|
53295
54481
|
configuration: ScatterConfigPanel,
|
|
53296
|
-
design:
|
|
54482
|
+
design: GenericZoomableChartDesignPanel,
|
|
53297
54483
|
})
|
|
53298
54484
|
.add("bar", {
|
|
53299
54485
|
configuration: BarConfigPanel,
|
|
53300
|
-
design:
|
|
54486
|
+
design: GenericZoomableChartDesignPanel,
|
|
53301
54487
|
})
|
|
53302
54488
|
.add("combo", {
|
|
53303
54489
|
configuration: GenericChartConfigPanel,
|
|
@@ -53381,7 +54567,7 @@ css /* scss */ `
|
|
|
53381
54567
|
class ChartTypePicker extends owl.Component {
|
|
53382
54568
|
static template = "o-spreadsheet-ChartTypePicker";
|
|
53383
54569
|
static components = { Section, Popover };
|
|
53384
|
-
static props = {
|
|
54570
|
+
static props = { chartId: String, chartPanelStore: Object };
|
|
53385
54571
|
categories = chartCategories;
|
|
53386
54572
|
chartTypeByCategories = {};
|
|
53387
54573
|
popoverRef = owl.useRef("popoverRef");
|
|
@@ -53406,14 +54592,14 @@ class ChartTypePicker extends owl.Component {
|
|
|
53406
54592
|
this.closePopover();
|
|
53407
54593
|
}
|
|
53408
54594
|
onTypeChange(type) {
|
|
53409
|
-
this.props.chartPanelStore.changeChartType(this.props.
|
|
54595
|
+
this.props.chartPanelStore.changeChartType(this.props.chartId, type);
|
|
53410
54596
|
this.closePopover();
|
|
53411
54597
|
}
|
|
53412
|
-
getChartDefinition(
|
|
53413
|
-
return this.env.model.getters.getChartDefinition(
|
|
54598
|
+
getChartDefinition(chartId) {
|
|
54599
|
+
return this.env.model.getters.getChartDefinition(chartId);
|
|
53414
54600
|
}
|
|
53415
54601
|
getSelectedChartSubtypeProperties() {
|
|
53416
|
-
const definition = this.getChartDefinition(this.props.
|
|
54602
|
+
const definition = this.getChartDefinition(this.props.chartId);
|
|
53417
54603
|
const matchedChart = chartSubtypeRegistry
|
|
53418
54604
|
.getAll()
|
|
53419
54605
|
.find((c) => c.matcher?.(definition) || false);
|
|
@@ -53445,34 +54631,36 @@ class MainChartPanelStore extends SpreadsheetStore {
|
|
|
53445
54631
|
activatePanel(panel) {
|
|
53446
54632
|
this.panel = panel;
|
|
53447
54633
|
}
|
|
53448
|
-
changeChartType(
|
|
53449
|
-
const currentCreationContext = this.getters.getContextCreationChart(
|
|
53450
|
-
const savedCreationContext = this.creationContexts[
|
|
54634
|
+
changeChartType(chartId, newDisplayType) {
|
|
54635
|
+
const currentCreationContext = this.getters.getContextCreationChart(chartId);
|
|
54636
|
+
const savedCreationContext = this.creationContexts[chartId] || {};
|
|
53451
54637
|
let newRanges = currentCreationContext?.range;
|
|
53452
54638
|
if (newRanges?.every((range, i) => deepEquals(range, savedCreationContext.range?.[i]))) {
|
|
53453
54639
|
newRanges = Object.assign([], savedCreationContext.range, currentCreationContext?.range);
|
|
53454
54640
|
}
|
|
53455
|
-
this.creationContexts[
|
|
54641
|
+
this.creationContexts[chartId] = {
|
|
53456
54642
|
...savedCreationContext,
|
|
53457
54643
|
...currentCreationContext,
|
|
53458
54644
|
range: newRanges,
|
|
53459
54645
|
};
|
|
54646
|
+
const figureId = this.getters.getFigureIdFromChartId(chartId);
|
|
53460
54647
|
const sheetId = this.getters.getFigureSheetId(figureId);
|
|
53461
54648
|
if (!sheetId) {
|
|
53462
54649
|
return;
|
|
53463
54650
|
}
|
|
53464
|
-
const definition = this.getChartDefinitionFromContextCreation(
|
|
54651
|
+
const definition = this.getChartDefinitionFromContextCreation(chartId, newDisplayType);
|
|
53465
54652
|
this.model.dispatch("UPDATE_CHART", {
|
|
53466
54653
|
definition,
|
|
54654
|
+
chartId,
|
|
53467
54655
|
figureId,
|
|
53468
54656
|
sheetId,
|
|
53469
54657
|
});
|
|
53470
54658
|
}
|
|
53471
|
-
getChartDefinitionFromContextCreation(
|
|
54659
|
+
getChartDefinitionFromContextCreation(chartId, newDisplayType) {
|
|
53472
54660
|
const newChartInfo = chartSubtypeRegistry.get(newDisplayType);
|
|
53473
54661
|
const ChartClass = chartRegistry.get(newChartInfo.chartType);
|
|
53474
54662
|
return {
|
|
53475
|
-
...ChartClass.getChartDefinitionFromContextCreation(this.creationContexts[
|
|
54663
|
+
...ChartClass.getChartDefinitionFromContextCreation(this.creationContexts[chartId]),
|
|
53476
54664
|
...newChartInfo.subtypeDefinition,
|
|
53477
54665
|
};
|
|
53478
54666
|
}
|
|
@@ -53513,15 +54701,15 @@ css /* scss */ `
|
|
|
53513
54701
|
class ChartPanel extends owl.Component {
|
|
53514
54702
|
static template = "o-spreadsheet-ChartPanel";
|
|
53515
54703
|
static components = { Section, ChartTypePicker };
|
|
53516
|
-
static props = { onCloseSidePanel: Function,
|
|
54704
|
+
static props = { onCloseSidePanel: Function, chartId: String };
|
|
53517
54705
|
panelContentRef;
|
|
53518
54706
|
scrollPositions = {
|
|
53519
54707
|
configuration: 0,
|
|
53520
54708
|
design: 0,
|
|
53521
54709
|
};
|
|
53522
54710
|
store;
|
|
53523
|
-
get
|
|
53524
|
-
return this.props.
|
|
54711
|
+
get chartId() {
|
|
54712
|
+
return this.props.chartId;
|
|
53525
54713
|
}
|
|
53526
54714
|
setup() {
|
|
53527
54715
|
this.store = useLocalStore(MainChartPanelStore);
|
|
@@ -53541,45 +54729,49 @@ class ChartPanel extends owl.Component {
|
|
|
53541
54729
|
}
|
|
53542
54730
|
this.store.activatePanel(panel);
|
|
53543
54731
|
}
|
|
53544
|
-
updateChart(
|
|
53545
|
-
|
|
54732
|
+
updateChart(chartId, updateDefinition) {
|
|
54733
|
+
const figureId = this.env.model.getters.getFigureIdFromChartId(chartId);
|
|
54734
|
+
if (chartId !== this.chartId) {
|
|
53546
54735
|
return;
|
|
53547
54736
|
}
|
|
53548
54737
|
const definition = {
|
|
53549
|
-
...this.getChartDefinition(this.
|
|
54738
|
+
...this.getChartDefinition(this.chartId),
|
|
53550
54739
|
...updateDefinition,
|
|
53551
54740
|
};
|
|
53552
54741
|
return this.env.model.dispatch("UPDATE_CHART", {
|
|
53553
54742
|
definition,
|
|
54743
|
+
chartId,
|
|
53554
54744
|
figureId,
|
|
53555
54745
|
sheetId: this.env.model.getters.getFigureSheetId(figureId),
|
|
53556
54746
|
});
|
|
53557
54747
|
}
|
|
53558
|
-
canUpdateChart(
|
|
53559
|
-
|
|
54748
|
+
canUpdateChart(chartId, updateDefinition) {
|
|
54749
|
+
const figureId = this.env.model.getters.getFigureIdFromChartId(chartId);
|
|
54750
|
+
if (chartId !== this.chartId || !this.env.model.getters.isChartDefined(chartId)) {
|
|
53560
54751
|
return;
|
|
53561
54752
|
}
|
|
53562
54753
|
const definition = {
|
|
53563
|
-
...this.getChartDefinition(this.
|
|
54754
|
+
...this.getChartDefinition(this.chartId),
|
|
53564
54755
|
...updateDefinition,
|
|
53565
54756
|
};
|
|
53566
54757
|
return this.env.model.canDispatch("UPDATE_CHART", {
|
|
53567
54758
|
definition,
|
|
54759
|
+
chartId,
|
|
53568
54760
|
figureId,
|
|
53569
54761
|
sheetId: this.env.model.getters.getFigureSheetId(figureId),
|
|
53570
54762
|
});
|
|
53571
54763
|
}
|
|
53572
54764
|
onTypeChange(type) {
|
|
53573
|
-
if (!this.
|
|
54765
|
+
if (!this.chartId) {
|
|
53574
54766
|
return;
|
|
53575
54767
|
}
|
|
53576
|
-
this.store.changeChartType(this.
|
|
54768
|
+
this.store.changeChartType(this.chartId, type);
|
|
53577
54769
|
}
|
|
53578
54770
|
get chartPanel() {
|
|
53579
|
-
if (!this.
|
|
54771
|
+
if (!this.chartId) {
|
|
53580
54772
|
throw new Error("Chart not defined.");
|
|
53581
54773
|
}
|
|
53582
|
-
const type = this.env.model.getters.getChartType(this.
|
|
54774
|
+
const type = this.env.model.getters.getChartType(this.chartId);
|
|
53583
54775
|
if (!type) {
|
|
53584
54776
|
throw new Error("Chart not defined.");
|
|
53585
54777
|
}
|
|
@@ -53589,8 +54781,8 @@ class ChartPanel extends owl.Component {
|
|
|
53589
54781
|
}
|
|
53590
54782
|
return chartPanel;
|
|
53591
54783
|
}
|
|
53592
|
-
getChartDefinition(
|
|
53593
|
-
return this.env.model.getters.getChartDefinition(
|
|
54784
|
+
getChartDefinition(chartId) {
|
|
54785
|
+
return this.env.model.getters.getChartDefinition(chartId);
|
|
53594
54786
|
}
|
|
53595
54787
|
}
|
|
53596
54788
|
|
|
@@ -55527,11 +56719,15 @@ class PivotMeasureDisplayPanel extends owl.Component {
|
|
|
55527
56719
|
this.store = useLocalStore(PivotMeasureDisplayPanelStore, this.props.pivotId, this.props.measure);
|
|
55528
56720
|
}
|
|
55529
56721
|
onSave() {
|
|
55530
|
-
this.env.
|
|
56722
|
+
this.env.replaceSidePanel("PivotSidePanel", `pivot_measure_display_${this.props.pivotId}_${this.props.measure.id}`, {
|
|
56723
|
+
pivotId: this.props.pivotId,
|
|
56724
|
+
});
|
|
55531
56725
|
}
|
|
55532
56726
|
onCancel() {
|
|
55533
56727
|
this.store.cancelMeasureDisplayEdition();
|
|
55534
|
-
this.env.
|
|
56728
|
+
this.env.replaceSidePanel("PivotSidePanel", `pivot_measure_display_${this.props.pivotId}_${this.props.measure.id}`, {
|
|
56729
|
+
pivotId: this.props.pivotId,
|
|
56730
|
+
});
|
|
55535
56731
|
}
|
|
55536
56732
|
get fieldChoices() {
|
|
55537
56733
|
return this.store.fields.map((field) => ({
|
|
@@ -55592,103 +56788,6 @@ class PivotDeferUpdate extends owl.Component {
|
|
|
55592
56788
|
}
|
|
55593
56789
|
}
|
|
55594
56790
|
|
|
55595
|
-
function useAutofocus({ refName }) {
|
|
55596
|
-
const ref = owl.useRef(refName);
|
|
55597
|
-
owl.useEffect((el) => {
|
|
55598
|
-
el?.focus();
|
|
55599
|
-
}, () => [ref.el]);
|
|
55600
|
-
}
|
|
55601
|
-
|
|
55602
|
-
css /* scss */ `
|
|
55603
|
-
.o-spreadsheet {
|
|
55604
|
-
.os-input {
|
|
55605
|
-
border-width: 0 0 1px 0;
|
|
55606
|
-
border-color: transparent;
|
|
55607
|
-
outline: none;
|
|
55608
|
-
text-overflow: ellipsis;
|
|
55609
|
-
color: ${TEXT_BODY};
|
|
55610
|
-
}
|
|
55611
|
-
.os-input:hover,
|
|
55612
|
-
.os-input:focus {
|
|
55613
|
-
border-color: ${GRAY_300};
|
|
55614
|
-
}
|
|
55615
|
-
}
|
|
55616
|
-
`;
|
|
55617
|
-
class TextInput extends owl.Component {
|
|
55618
|
-
static template = "o-spreadsheet-TextInput";
|
|
55619
|
-
static props = {
|
|
55620
|
-
value: String,
|
|
55621
|
-
onChange: Function,
|
|
55622
|
-
class: {
|
|
55623
|
-
type: String,
|
|
55624
|
-
optional: true,
|
|
55625
|
-
},
|
|
55626
|
-
id: {
|
|
55627
|
-
type: String,
|
|
55628
|
-
optional: true,
|
|
55629
|
-
},
|
|
55630
|
-
placeholder: {
|
|
55631
|
-
type: String,
|
|
55632
|
-
optional: true,
|
|
55633
|
-
},
|
|
55634
|
-
autofocus: {
|
|
55635
|
-
type: Boolean,
|
|
55636
|
-
optional: true,
|
|
55637
|
-
},
|
|
55638
|
-
};
|
|
55639
|
-
inputRef = owl.useRef("input");
|
|
55640
|
-
setup() {
|
|
55641
|
-
owl.useExternalListener(window, "click", (ev) => {
|
|
55642
|
-
if (ev.target !== this.inputRef.el && this.inputRef.el?.value !== this.props.value) {
|
|
55643
|
-
this.save();
|
|
55644
|
-
}
|
|
55645
|
-
}, { capture: true });
|
|
55646
|
-
if (this.props.autofocus) {
|
|
55647
|
-
useAutofocus({ refName: "input" });
|
|
55648
|
-
}
|
|
55649
|
-
}
|
|
55650
|
-
onKeyDown(ev) {
|
|
55651
|
-
switch (ev.key) {
|
|
55652
|
-
case "Enter":
|
|
55653
|
-
this.save();
|
|
55654
|
-
ev.preventDefault();
|
|
55655
|
-
ev.stopPropagation();
|
|
55656
|
-
break;
|
|
55657
|
-
case "Escape":
|
|
55658
|
-
if (this.inputRef.el) {
|
|
55659
|
-
this.inputRef.el.value = this.props.value;
|
|
55660
|
-
this.inputRef.el.blur();
|
|
55661
|
-
}
|
|
55662
|
-
ev.preventDefault();
|
|
55663
|
-
ev.stopPropagation();
|
|
55664
|
-
break;
|
|
55665
|
-
}
|
|
55666
|
-
}
|
|
55667
|
-
save() {
|
|
55668
|
-
const currentValue = (this.inputRef.el?.value || "").trim();
|
|
55669
|
-
if (currentValue !== this.props.value) {
|
|
55670
|
-
this.props.onChange(currentValue);
|
|
55671
|
-
}
|
|
55672
|
-
this.inputRef.el?.blur();
|
|
55673
|
-
}
|
|
55674
|
-
onMouseDown(ev) {
|
|
55675
|
-
// Stop the event if the input is not focused, we handle everything in onMouseUp
|
|
55676
|
-
if (ev.target !== document.activeElement) {
|
|
55677
|
-
ev.preventDefault();
|
|
55678
|
-
ev.stopPropagation();
|
|
55679
|
-
}
|
|
55680
|
-
}
|
|
55681
|
-
onMouseUp(ev) {
|
|
55682
|
-
const target = ev.target;
|
|
55683
|
-
if (target !== document.activeElement) {
|
|
55684
|
-
target.focus();
|
|
55685
|
-
target.select();
|
|
55686
|
-
ev.preventDefault();
|
|
55687
|
-
ev.stopPropagation();
|
|
55688
|
-
}
|
|
55689
|
-
}
|
|
55690
|
-
}
|
|
55691
|
-
|
|
55692
56791
|
class PivotCustomGroupsCollapsible extends owl.Component {
|
|
55693
56792
|
static template = "o-spreadsheet-PivotCustomGroupsCollapsible";
|
|
55694
56793
|
static props = {
|
|
@@ -56045,7 +57144,7 @@ class PivotMeasureEditor extends owl.Component {
|
|
|
56045
57144
|
});
|
|
56046
57145
|
}
|
|
56047
57146
|
openShowValuesAs() {
|
|
56048
|
-
this.env.
|
|
57147
|
+
this.env.replaceSidePanel("PivotMeasureDisplayPanel", `pivot_key_${this.props.pivotId}`, {
|
|
56049
57148
|
pivotId: this.props.pivotId,
|
|
56050
57149
|
measure: this.props.measure,
|
|
56051
57150
|
});
|
|
@@ -56306,7 +57405,7 @@ class PivotLayoutConfigurator extends owl.Component {
|
|
|
56306
57405
|
this.props.onDimensionsUpdated(update);
|
|
56307
57406
|
}
|
|
56308
57407
|
getMeasureId(fieldName, aggregator) {
|
|
56309
|
-
const baseId = fieldName + (aggregator ? `:${aggregator}` : "");
|
|
57408
|
+
const baseId = fieldName.replaceAll("'", "") + (aggregator ? `:${aggregator}` : "");
|
|
56310
57409
|
let id = baseId;
|
|
56311
57410
|
let i = 2;
|
|
56312
57411
|
while (this.props.definition.measures.some((m) => m.id === id)) {
|
|
@@ -56384,6 +57483,13 @@ class PivotLayoutConfigurator extends owl.Component {
|
|
|
56384
57483
|
const fieldName = field ? getFieldDisplayName(field) : "";
|
|
56385
57484
|
return measureDisplayTerms.descriptions[measureDisplay.type](fieldName);
|
|
56386
57485
|
}
|
|
57486
|
+
getHugeDimensionErrorMessage(dimension) {
|
|
57487
|
+
const pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
57488
|
+
const possibleValues = pivot.getPossibleFieldValues(dimension);
|
|
57489
|
+
return possibleValues.length > 100
|
|
57490
|
+
? _t("This dimension contains a lot of values (%s), and might slow down the pivot table.", possibleValues.length)
|
|
57491
|
+
: undefined;
|
|
57492
|
+
}
|
|
56387
57493
|
}
|
|
56388
57494
|
|
|
56389
57495
|
class PivotTitleSection extends owl.Component {
|
|
@@ -56557,6 +57663,7 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
56557
57663
|
draft = null;
|
|
56558
57664
|
notification = this.get(NotificationStore);
|
|
56559
57665
|
alreadyNotified = false;
|
|
57666
|
+
alreadyNotifiedForPivotSize = false;
|
|
56560
57667
|
constructor(get, pivotId) {
|
|
56561
57668
|
super(get);
|
|
56562
57669
|
this.pivotId = pivotId;
|
|
@@ -56675,6 +57782,16 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
56675
57782
|
sticky: true,
|
|
56676
57783
|
});
|
|
56677
57784
|
}
|
|
57785
|
+
const pivot = this.getters.getPivot(this.pivotId);
|
|
57786
|
+
const numberOfCells = pivot.isValid() ? pivot.getExpandedTableStructure().numberOfCells : 0;
|
|
57787
|
+
if (!this.alreadyNotifiedForPivotSize && numberOfCells > PIVOT_MAX_NUMBER_OF_CELLS) {
|
|
57788
|
+
this.alreadyNotifiedForPivotSize = true;
|
|
57789
|
+
this.notification.notifyUser({
|
|
57790
|
+
type: "warning",
|
|
57791
|
+
text: getPivotTooBigErrorMessage(numberOfCells, this.getters.getLocale()),
|
|
57792
|
+
sticky: true,
|
|
57793
|
+
});
|
|
57794
|
+
}
|
|
56678
57795
|
}
|
|
56679
57796
|
}
|
|
56680
57797
|
discardPendingUpdate() {
|
|
@@ -57803,11 +58920,12 @@ sidePanelRegistry.add("ChartPanel", {
|
|
|
57803
58920
|
title: _t("Chart"),
|
|
57804
58921
|
Body: ChartPanel,
|
|
57805
58922
|
computeState: (getters, initialProps) => {
|
|
57806
|
-
const figureId = getters.getSelectedFigureId()
|
|
57807
|
-
|
|
58923
|
+
const figureId = getters.getSelectedFigureId();
|
|
58924
|
+
const chartId = figureId ? getters.getChartIdFromFigureId(figureId) : initialProps.chartId;
|
|
58925
|
+
if (!chartId || !getters.isChartDefined(chartId)) {
|
|
57808
58926
|
return { isOpen: false };
|
|
57809
58927
|
}
|
|
57810
|
-
return { isOpen: true, props: {
|
|
58928
|
+
return { isOpen: true, props: { chartId } };
|
|
57811
58929
|
},
|
|
57812
58930
|
});
|
|
57813
58931
|
sidePanelRegistry.add("FindAndReplace", {
|
|
@@ -57888,13 +59006,28 @@ sidePanelRegistry.add("PivotMeasureDisplayPanel", {
|
|
|
57888
59006
|
try {
|
|
57889
59007
|
// This will throw if the pivot or measure does not exist
|
|
57890
59008
|
getters.getPivot(props.pivotId).getMeasure(props.measure.id);
|
|
57891
|
-
return {
|
|
59009
|
+
return {
|
|
59010
|
+
isOpen: true,
|
|
59011
|
+
props,
|
|
59012
|
+
key: `pivot_measure_display_${props.pivotId}_${props.measure.id}`,
|
|
59013
|
+
};
|
|
57892
59014
|
}
|
|
57893
59015
|
catch (e) {
|
|
57894
59016
|
return { isOpen: false };
|
|
57895
59017
|
}
|
|
57896
59018
|
},
|
|
57897
59019
|
});
|
|
59020
|
+
sidePanelRegistry.add("CarouselPanel", {
|
|
59021
|
+
title: _t("Carousel"),
|
|
59022
|
+
Body: CarouselPanel,
|
|
59023
|
+
computeState: (getters, initialProps) => {
|
|
59024
|
+
const figureId = initialProps.figureId || getters.getSelectedFigureId();
|
|
59025
|
+
if (!figureId || !getters.doesCarouselExist(figureId)) {
|
|
59026
|
+
return { isOpen: false };
|
|
59027
|
+
}
|
|
59028
|
+
return { isOpen: true, props: { figureId } };
|
|
59029
|
+
},
|
|
59030
|
+
});
|
|
57898
59031
|
|
|
57899
59032
|
class ScreenWidthStore {
|
|
57900
59033
|
mutators = ["setSmallThreshhold"];
|
|
@@ -57913,6 +59046,7 @@ const MIN_SHEET_VIEW_WIDTH = 150;
|
|
|
57913
59046
|
class SidePanelStore extends SpreadsheetStore {
|
|
57914
59047
|
mutators = [
|
|
57915
59048
|
"open",
|
|
59049
|
+
"replace",
|
|
57916
59050
|
"toggle",
|
|
57917
59051
|
"close",
|
|
57918
59052
|
"changePanelSize",
|
|
@@ -57974,8 +59108,7 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
57974
59108
|
if (!state.isOpen) {
|
|
57975
59109
|
return;
|
|
57976
59110
|
}
|
|
57977
|
-
|
|
57978
|
-
if (!this.mainPanel || !this.mainPanel.isPinned || mainPanelKey === state.key) {
|
|
59111
|
+
if (!this.mainPanel || !this.mainPanel.isPinned || this.mainPanelKey === state.key) {
|
|
57979
59112
|
this._openPanel("mainPanel", newPanelInfo, state);
|
|
57980
59113
|
return;
|
|
57981
59114
|
}
|
|
@@ -57994,6 +59127,34 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
57994
59127
|
}
|
|
57995
59128
|
this._openPanel("secondaryPanel", newPanelInfo, state);
|
|
57996
59129
|
}
|
|
59130
|
+
replace(componentTag, currentPanelKey, initialPanelProps = {}) {
|
|
59131
|
+
const newPanelInfo = { initialPanelProps, componentTag, size: DEFAULT_SIDE_PANEL_SIZE };
|
|
59132
|
+
const state = this.computeState(newPanelInfo);
|
|
59133
|
+
if (!state.isOpen) {
|
|
59134
|
+
return;
|
|
59135
|
+
}
|
|
59136
|
+
const ensureMainPanelExpanded = () => {
|
|
59137
|
+
if (this.mainPanel?.isCollapsed) {
|
|
59138
|
+
this.toggleCollapsePanel("mainPanel");
|
|
59139
|
+
}
|
|
59140
|
+
};
|
|
59141
|
+
// Close the current panel if the target panel is already open
|
|
59142
|
+
const isMainPanel = this.mainPanelKey === state.key;
|
|
59143
|
+
const isSecondaryPanel = this.secondaryPanelKey === state.key;
|
|
59144
|
+
if (isMainPanel && this.secondaryPanel) {
|
|
59145
|
+
this.close();
|
|
59146
|
+
ensureMainPanelExpanded();
|
|
59147
|
+
return;
|
|
59148
|
+
}
|
|
59149
|
+
if (isSecondaryPanel) {
|
|
59150
|
+
this.closeMainPanel();
|
|
59151
|
+
this.togglePinPanel();
|
|
59152
|
+
ensureMainPanelExpanded();
|
|
59153
|
+
return;
|
|
59154
|
+
}
|
|
59155
|
+
const targetPanel = this.mainPanelKey === currentPanelKey ? "mainPanel" : "secondaryPanel";
|
|
59156
|
+
this._openPanel(targetPanel, newPanelInfo, state);
|
|
59157
|
+
}
|
|
57997
59158
|
_openPanel(panel, newPanel, state) {
|
|
57998
59159
|
const currentPanel = this[panel];
|
|
57999
59160
|
if (currentPanel && newPanel.componentTag !== currentPanel.componentTag) {
|
|
@@ -58053,11 +59214,9 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
58053
59214
|
panelInfo.size = size;
|
|
58054
59215
|
}
|
|
58055
59216
|
resetPanelSize(panel) {
|
|
58056
|
-
|
|
58057
|
-
|
|
58058
|
-
return;
|
|
59217
|
+
if (this[panel]) {
|
|
59218
|
+
this[panel].size = DEFAULT_SIDE_PANEL_SIZE;
|
|
58059
59219
|
}
|
|
58060
|
-
panelInfo.size = DEFAULT_SIDE_PANEL_SIZE;
|
|
58061
59220
|
}
|
|
58062
59221
|
togglePinPanel() {
|
|
58063
59222
|
if (!this.mainPanel) {
|
|
@@ -58856,7 +60015,7 @@ class FullScreenChart extends owl.Component {
|
|
|
58856
60015
|
let lastFigureId = undefined;
|
|
58857
60016
|
owl.onWillUpdateProps(() => {
|
|
58858
60017
|
if (lastFigureId !== this.figureUI?.id) {
|
|
58859
|
-
animationStore.enableAnimationForChart(this.
|
|
60018
|
+
animationStore.enableAnimationForChart(this.chartId + "-fullscreen");
|
|
58860
60019
|
}
|
|
58861
60020
|
lastFigureId = this.figureUI?.id;
|
|
58862
60021
|
});
|
|
@@ -58865,6 +60024,11 @@ class FullScreenChart extends owl.Component {
|
|
|
58865
60024
|
get figureUI() {
|
|
58866
60025
|
return this.fullScreenChartStore.fullScreenFigure;
|
|
58867
60026
|
}
|
|
60027
|
+
get chartId() {
|
|
60028
|
+
if (!this.figureUI)
|
|
60029
|
+
return undefined;
|
|
60030
|
+
return this.env.model.getters.getChartIdFromFigureId(this.figureUI?.id);
|
|
60031
|
+
}
|
|
58868
60032
|
exitFullScreen() {
|
|
58869
60033
|
if (this.figureUI) {
|
|
58870
60034
|
this.fullScreenChartStore.toggleFullScreenChart(this.figureUI.id);
|
|
@@ -58876,9 +60040,9 @@ class FullScreenChart extends owl.Component {
|
|
|
58876
60040
|
}
|
|
58877
60041
|
}
|
|
58878
60042
|
get chartComponent() {
|
|
58879
|
-
if (!this.
|
|
60043
|
+
if (!this.chartId)
|
|
58880
60044
|
return undefined;
|
|
58881
|
-
const type = this.env.model.getters.getChartType(this.
|
|
60045
|
+
const type = this.env.model.getters.getChartType(this.chartId);
|
|
58882
60046
|
const component = chartComponentRegistry.get(type);
|
|
58883
60047
|
if (!component) {
|
|
58884
60048
|
throw new Error(`Component is not defined for type ${type}`);
|
|
@@ -60537,6 +61701,7 @@ class ChartPlugin extends CorePlugin {
|
|
|
60537
61701
|
"getChartType",
|
|
60538
61702
|
"getChartIds",
|
|
60539
61703
|
"getChart",
|
|
61704
|
+
"getFigureIdFromChartId",
|
|
60540
61705
|
"getContextCreationChart",
|
|
60541
61706
|
];
|
|
60542
61707
|
charts = {};
|
|
@@ -60544,7 +61709,11 @@ class ChartPlugin extends CorePlugin {
|
|
|
60544
61709
|
validateChartDefinition = (cmd) => validateChartDefinition(this, cmd.definition);
|
|
60545
61710
|
adaptRanges(applyChange) {
|
|
60546
61711
|
for (const [chartId, chart] of Object.entries(this.charts)) {
|
|
60547
|
-
|
|
61712
|
+
if (!chart) {
|
|
61713
|
+
continue;
|
|
61714
|
+
}
|
|
61715
|
+
const newChart = chart.chart.updateRanges(applyChange);
|
|
61716
|
+
this.history.update("charts", chartId, newChart ? { figureId: chart.figureId, chart: newChart } : undefined);
|
|
60548
61717
|
}
|
|
60549
61718
|
}
|
|
60550
61719
|
// ---------------------------------------------------------------------------
|
|
@@ -60553,9 +61722,11 @@ class ChartPlugin extends CorePlugin {
|
|
|
60553
61722
|
allowDispatch(cmd) {
|
|
60554
61723
|
switch (cmd.type) {
|
|
60555
61724
|
case "CREATE_CHART":
|
|
60556
|
-
return this.checkValidations(cmd, this.chainValidations(this.validateChartDefinition, this.checkChartDuplicate));
|
|
61725
|
+
return this.checkValidations(cmd, this.chainValidations(this.checkFigureArguments, this.validateChartDefinition, this.checkChartDuplicate));
|
|
60557
61726
|
case "UPDATE_CHART":
|
|
60558
61727
|
return this.checkValidations(cmd, this.chainValidations(this.validateChartDefinition, this.checkChartExists, this.checkChartChanged));
|
|
61728
|
+
case "DELETE_CHART":
|
|
61729
|
+
return this.checkChartExists(cmd);
|
|
60559
61730
|
default:
|
|
60560
61731
|
return "Success" /* CommandResult.Success */;
|
|
60561
61732
|
}
|
|
@@ -60563,37 +61734,61 @@ class ChartPlugin extends CorePlugin {
|
|
|
60563
61734
|
handle(cmd) {
|
|
60564
61735
|
switch (cmd.type) {
|
|
60565
61736
|
case "CREATE_CHART":
|
|
60566
|
-
|
|
60567
|
-
|
|
61737
|
+
const { col, row, offset, size, sheetId, figureId } = cmd;
|
|
61738
|
+
// If figure position is not defined, it means that the figure already exist (see allowDispatch)
|
|
61739
|
+
if (!this.getters.getFigure(sheetId, figureId) &&
|
|
61740
|
+
offset !== undefined &&
|
|
61741
|
+
col !== undefined &&
|
|
61742
|
+
row !== undefined) {
|
|
61743
|
+
this.addFigure(figureId, sheetId, col, row, offset, size);
|
|
61744
|
+
}
|
|
61745
|
+
this.addChart(cmd.figureId, cmd.chartId, cmd.definition);
|
|
60568
61746
|
break;
|
|
60569
61747
|
case "UPDATE_CHART": {
|
|
60570
|
-
this.addChart(cmd.figureId, cmd.definition);
|
|
61748
|
+
this.addChart(cmd.figureId, cmd.chartId, cmd.definition);
|
|
60571
61749
|
break;
|
|
60572
61750
|
}
|
|
60573
61751
|
case "DUPLICATE_SHEET": {
|
|
60574
|
-
const
|
|
60575
|
-
|
|
60576
|
-
if (
|
|
60577
|
-
|
|
60578
|
-
|
|
60579
|
-
|
|
60580
|
-
|
|
60581
|
-
|
|
60582
|
-
|
|
60583
|
-
|
|
60584
|
-
|
|
60585
|
-
|
|
60586
|
-
|
|
60587
|
-
|
|
60588
|
-
|
|
60589
|
-
|
|
60590
|
-
|
|
61752
|
+
for (const chartId of this.getChartIds(cmd.sheetId)) {
|
|
61753
|
+
const { chart, figureId } = this.charts[chartId] || {};
|
|
61754
|
+
if (!chart || !figureId) {
|
|
61755
|
+
continue;
|
|
61756
|
+
}
|
|
61757
|
+
const fig = this.getters.getFigure(cmd.sheetId, figureId);
|
|
61758
|
+
if (!fig) {
|
|
61759
|
+
continue;
|
|
61760
|
+
}
|
|
61761
|
+
const figureIdBase = figureId.split(FIGURE_ID_SPLITTER).pop();
|
|
61762
|
+
const duplicatedFigureId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${figureIdBase}`;
|
|
61763
|
+
const chartIdBase = chartId.split(FIGURE_ID_SPLITTER).pop();
|
|
61764
|
+
const duplicatedChartId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${chartIdBase}`;
|
|
61765
|
+
const newChart = chart.duplicateInDuplicatedSheet(cmd.sheetIdTo);
|
|
61766
|
+
if (newChart) {
|
|
61767
|
+
this.dispatch("CREATE_CHART", {
|
|
61768
|
+
figureId: duplicatedFigureId,
|
|
61769
|
+
chartId: duplicatedChartId,
|
|
61770
|
+
col: fig.col,
|
|
61771
|
+
row: fig.row,
|
|
61772
|
+
offset: fig.offset,
|
|
61773
|
+
size: { width: fig.width, height: fig.height },
|
|
61774
|
+
definition: newChart.getDefinition(),
|
|
61775
|
+
sheetId: cmd.sheetIdTo,
|
|
61776
|
+
});
|
|
60591
61777
|
}
|
|
60592
61778
|
}
|
|
60593
61779
|
break;
|
|
60594
61780
|
}
|
|
60595
61781
|
case "DELETE_FIGURE":
|
|
60596
|
-
this.
|
|
61782
|
+
for (const chartId in this.charts) {
|
|
61783
|
+
if (this.charts[chartId]?.figureId === cmd.figureId) {
|
|
61784
|
+
this.dispatch("DELETE_CHART", { chartId, sheetId: cmd.sheetId });
|
|
61785
|
+
}
|
|
61786
|
+
}
|
|
61787
|
+
break;
|
|
61788
|
+
case "DELETE_CHART":
|
|
61789
|
+
if (this.isChartDefined(cmd.chartId)) {
|
|
61790
|
+
this.history.update("charts", cmd.chartId, undefined);
|
|
61791
|
+
}
|
|
60597
61792
|
break;
|
|
60598
61793
|
case "DELETE_SHEET":
|
|
60599
61794
|
for (const id of this.getChartIds(cmd.sheetId)) {
|
|
@@ -60605,31 +61800,37 @@ class ChartPlugin extends CorePlugin {
|
|
|
60605
61800
|
// ---------------------------------------------------------------------------
|
|
60606
61801
|
// Getters
|
|
60607
61802
|
// ---------------------------------------------------------------------------
|
|
60608
|
-
getContextCreationChart(
|
|
60609
|
-
return this.charts[
|
|
61803
|
+
getContextCreationChart(chartId) {
|
|
61804
|
+
return this.charts[chartId]?.chart.getContextCreation();
|
|
60610
61805
|
}
|
|
60611
|
-
getChart(
|
|
60612
|
-
return this.charts[
|
|
61806
|
+
getChart(chartId) {
|
|
61807
|
+
return this.charts[chartId]?.chart;
|
|
61808
|
+
}
|
|
61809
|
+
getFigureIdFromChartId(chartId) {
|
|
61810
|
+
if (!this.charts[chartId]) {
|
|
61811
|
+
throw new Error(`Chart with id ${chartId} does not exist.`);
|
|
61812
|
+
}
|
|
61813
|
+
return this.charts[chartId].figureId;
|
|
60613
61814
|
}
|
|
60614
|
-
getChartType(
|
|
60615
|
-
const type = this.charts[
|
|
61815
|
+
getChartType(chartId) {
|
|
61816
|
+
const type = this.charts[chartId]?.chart.type;
|
|
60616
61817
|
if (!type) {
|
|
60617
61818
|
throw new Error("Chart not defined.");
|
|
60618
61819
|
}
|
|
60619
61820
|
return type;
|
|
60620
61821
|
}
|
|
60621
|
-
isChartDefined(
|
|
60622
|
-
return
|
|
61822
|
+
isChartDefined(chartId) {
|
|
61823
|
+
return chartId in this.charts && this.charts !== undefined;
|
|
60623
61824
|
}
|
|
60624
61825
|
getChartIds(sheetId) {
|
|
60625
61826
|
return Object.entries(this.charts)
|
|
60626
|
-
.filter(([, chart]) => chart?.sheetId === sheetId)
|
|
61827
|
+
.filter(([, chart]) => chart?.chart.sheetId === sheetId)
|
|
60627
61828
|
.map(([id]) => id);
|
|
60628
61829
|
}
|
|
60629
|
-
getChartDefinition(
|
|
60630
|
-
const definition = this.charts[
|
|
61830
|
+
getChartDefinition(chartId) {
|
|
61831
|
+
const definition = this.charts[chartId]?.chart.getDefinition();
|
|
60631
61832
|
if (!definition) {
|
|
60632
|
-
throw new Error(`There is no chart with the given
|
|
61833
|
+
throw new Error(`There is no chart with the given id: ${chartId}`);
|
|
60633
61834
|
}
|
|
60634
61835
|
return definition;
|
|
60635
61836
|
}
|
|
@@ -60644,7 +61845,16 @@ class ChartPlugin extends CorePlugin {
|
|
|
60644
61845
|
// figure data should be external IMO => chart should be in sheet.chart
|
|
60645
61846
|
// instead of in figure.data
|
|
60646
61847
|
if (figure.tag === "chart") {
|
|
60647
|
-
|
|
61848
|
+
const chartId = figure.data.chartId;
|
|
61849
|
+
const chart = this.createChart(figure.id, figure.data, sheet.id);
|
|
61850
|
+
this.charts[chartId] = { chart, figureId: figure.id };
|
|
61851
|
+
}
|
|
61852
|
+
else if (figure.tag === "carousel") {
|
|
61853
|
+
for (const chartId in figure.data.chartDefinitions || {}) {
|
|
61854
|
+
const chartDefinition = figure.data.chartDefinitions[chartId];
|
|
61855
|
+
const chart = this.createChart(figure.id, chartDefinition, sheet.id);
|
|
61856
|
+
this.charts[chartId] = { chart, figureId: figure.id };
|
|
61857
|
+
}
|
|
60648
61858
|
}
|
|
60649
61859
|
}
|
|
60650
61860
|
}
|
|
@@ -60658,13 +61868,23 @@ class ChartPlugin extends CorePlugin {
|
|
|
60658
61868
|
const figures = [];
|
|
60659
61869
|
for (const sheetFigure of sheetFigures) {
|
|
60660
61870
|
const figure = sheetFigure;
|
|
60661
|
-
|
|
60662
|
-
|
|
61871
|
+
const chartId = Object.keys(this.charts).find((chartId) => this.charts[chartId]?.figureId === sheetFigure.id);
|
|
61872
|
+
if (figure && figure.tag === "chart" && chartId) {
|
|
61873
|
+
const data = this.charts[chartId]?.chart.getDefinition();
|
|
60663
61874
|
if (data) {
|
|
60664
|
-
figure.data = data;
|
|
61875
|
+
figure.data = { ...data, chartId };
|
|
60665
61876
|
figures.push(figure);
|
|
60666
61877
|
}
|
|
60667
61878
|
}
|
|
61879
|
+
else if (figure && figure.tag === "carousel") {
|
|
61880
|
+
const chartIds = Object.keys(this.charts).filter((chartId) => this.charts[chartId]?.figureId === sheetFigure.id);
|
|
61881
|
+
const data = {};
|
|
61882
|
+
for (const chartId of chartIds) {
|
|
61883
|
+
data[chartId] = this.charts[chartId]?.chart.getDefinition();
|
|
61884
|
+
}
|
|
61885
|
+
figure.data = { chartDefinitions: data };
|
|
61886
|
+
figures.push(figure);
|
|
61887
|
+
}
|
|
60668
61888
|
else {
|
|
60669
61889
|
figures.push(figure);
|
|
60670
61890
|
}
|
|
@@ -60697,27 +61917,40 @@ class ChartPlugin extends CorePlugin {
|
|
|
60697
61917
|
* Add a chart in the local state. If a chart already exists, this chart is
|
|
60698
61918
|
* replaced
|
|
60699
61919
|
*/
|
|
60700
|
-
addChart(
|
|
60701
|
-
const sheetId = this.getters.getFigureSheetId(
|
|
61920
|
+
addChart(figureId, chartId, definition) {
|
|
61921
|
+
const sheetId = this.getters.getFigureSheetId(figureId);
|
|
60702
61922
|
if (sheetId) {
|
|
60703
|
-
|
|
61923
|
+
const chart = this.createChart(figureId, definition, sheetId);
|
|
61924
|
+
this.history.update("charts", chartId, { figureId, chart });
|
|
60704
61925
|
}
|
|
60705
61926
|
}
|
|
60706
61927
|
checkChartDuplicate(cmd) {
|
|
60707
|
-
return this.
|
|
61928
|
+
return this.isChartDefined(cmd.chartId)
|
|
60708
61929
|
? "DuplicatedChartId" /* CommandResult.DuplicatedChartId */
|
|
60709
61930
|
: "Success" /* CommandResult.Success */;
|
|
60710
61931
|
}
|
|
60711
61932
|
checkChartExists(cmd) {
|
|
60712
|
-
return this.isChartDefined(cmd.
|
|
61933
|
+
return this.isChartDefined(cmd.chartId)
|
|
60713
61934
|
? "Success" /* CommandResult.Success */
|
|
60714
61935
|
: "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
|
|
60715
61936
|
}
|
|
60716
61937
|
checkChartChanged(cmd) {
|
|
60717
|
-
|
|
61938
|
+
if (cmd.figureId !== this.charts[cmd.chartId]?.figureId) {
|
|
61939
|
+
return "Success" /* CommandResult.Success */;
|
|
61940
|
+
}
|
|
61941
|
+
return deepEquals(this.getChartDefinition(cmd.chartId), cmd.definition)
|
|
60718
61942
|
? "NoChanges" /* CommandResult.NoChanges */
|
|
60719
61943
|
: "Success" /* CommandResult.Success */;
|
|
60720
61944
|
}
|
|
61945
|
+
/** If the command would create a new figure, there need to be a position & offset defined in the command */
|
|
61946
|
+
checkFigureArguments(cmd) {
|
|
61947
|
+
if (this.getters.getFigure(cmd.sheetId, cmd.figureId)) {
|
|
61948
|
+
return "Success" /* CommandResult.Success */;
|
|
61949
|
+
}
|
|
61950
|
+
return cmd.offset !== undefined && cmd.col !== undefined && cmd.row !== undefined
|
|
61951
|
+
? "Success" /* CommandResult.Success */
|
|
61952
|
+
: "MissingFigureArguments" /* CommandResult.MissingFigureArguments */;
|
|
61953
|
+
}
|
|
60721
61954
|
}
|
|
60722
61955
|
|
|
60723
61956
|
// -----------------------------------------------------------------------------
|
|
@@ -61571,6 +62804,23 @@ class FigurePlugin extends CorePlugin {
|
|
|
61571
62804
|
this.onRowRemove(cmd.sheetId);
|
|
61572
62805
|
}
|
|
61573
62806
|
break;
|
|
62807
|
+
case "DUPLICATE_SHEET": {
|
|
62808
|
+
for (const figureId in this.figures[cmd.sheetId]) {
|
|
62809
|
+
const fig = this.figures[cmd.sheetId]?.[figureId];
|
|
62810
|
+
if (!fig) {
|
|
62811
|
+
continue;
|
|
62812
|
+
}
|
|
62813
|
+
const figureIdBase = figureId.split(FIGURE_ID_SPLITTER).pop();
|
|
62814
|
+
const duplicatedFigureId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${figureIdBase}`;
|
|
62815
|
+
this.dispatch("CREATE_FIGURE", {
|
|
62816
|
+
figureId: duplicatedFigureId,
|
|
62817
|
+
...fig,
|
|
62818
|
+
size: { width: fig.width, height: fig.height },
|
|
62819
|
+
sheetId: cmd.sheetIdTo,
|
|
62820
|
+
});
|
|
62821
|
+
}
|
|
62822
|
+
break;
|
|
62823
|
+
}
|
|
61574
62824
|
}
|
|
61575
62825
|
}
|
|
61576
62826
|
onColRemove(sheetId) {
|
|
@@ -61682,6 +62932,9 @@ class FigurePlugin extends CorePlugin {
|
|
|
61682
62932
|
const figure = { ...this.getFigure(sheetId, figureId), ...update };
|
|
61683
62933
|
for (const [key, value] of Object.entries(update)) {
|
|
61684
62934
|
switch (key) {
|
|
62935
|
+
case "tag":
|
|
62936
|
+
this.history.update("figures", sheetId, figure.id, key, value);
|
|
62937
|
+
break;
|
|
61685
62938
|
case "offset":
|
|
61686
62939
|
this.history.update("figures", sheetId, figure.id, key, value);
|
|
61687
62940
|
break;
|
|
@@ -62109,7 +63362,9 @@ class ImagePlugin extends CorePlugin {
|
|
|
62109
63362
|
handle(cmd) {
|
|
62110
63363
|
switch (cmd.type) {
|
|
62111
63364
|
case "CREATE_IMAGE":
|
|
62112
|
-
this.
|
|
63365
|
+
if (!this.getters.getFigure(cmd.sheetId, cmd.figureId)) {
|
|
63366
|
+
this.addFigure(cmd.figureId, cmd.sheetId, cmd.col, cmd.row, cmd.offset, cmd.size);
|
|
63367
|
+
}
|
|
62113
63368
|
this.history.update("images", cmd.sheetId, cmd.figureId, cmd.definition);
|
|
62114
63369
|
this.syncedImages.add(cmd.definition.path);
|
|
62115
63370
|
break;
|
|
@@ -64247,6 +65502,122 @@ class TablePlugin extends CorePlugin {
|
|
|
64247
65502
|
}
|
|
64248
65503
|
}
|
|
64249
65504
|
|
|
65505
|
+
class CarouselPlugin extends CorePlugin {
|
|
65506
|
+
static getters = ["getCarousel", "doesCarouselExist"];
|
|
65507
|
+
carousels = {};
|
|
65508
|
+
allowDispatch(cmd) {
|
|
65509
|
+
switch (cmd.type) {
|
|
65510
|
+
case "CREATE_CAROUSEL": {
|
|
65511
|
+
if (this.getters.getFigure(cmd.sheetId, cmd.figureId)) {
|
|
65512
|
+
return "DuplicatedFigureId" /* CommandResult.DuplicatedFigureId */;
|
|
65513
|
+
}
|
|
65514
|
+
return "Success" /* CommandResult.Success */;
|
|
65515
|
+
}
|
|
65516
|
+
case "UPDATE_CAROUSEL": {
|
|
65517
|
+
if (!this.carousels[cmd.sheetId]?.[cmd.figureId]) {
|
|
65518
|
+
return "InvalidFigureId" /* CommandResult.InvalidFigureId */;
|
|
65519
|
+
}
|
|
65520
|
+
return "Success" /* CommandResult.Success */;
|
|
65521
|
+
}
|
|
65522
|
+
}
|
|
65523
|
+
return "Success" /* CommandResult.Success */;
|
|
65524
|
+
}
|
|
65525
|
+
handle(cmd) {
|
|
65526
|
+
switch (cmd.type) {
|
|
65527
|
+
case "CREATE_CAROUSEL":
|
|
65528
|
+
if (!this.getters.getFigure(cmd.sheetId, cmd.figureId)) {
|
|
65529
|
+
this.dispatch("CREATE_FIGURE", { ...cmd, tag: "carousel" });
|
|
65530
|
+
}
|
|
65531
|
+
this.history.update("carousels", cmd.sheetId, cmd.figureId, cmd.definition);
|
|
65532
|
+
break;
|
|
65533
|
+
case "UPDATE_CAROUSEL":
|
|
65534
|
+
this.removeDeletedCharts(cmd, this.getters.getCarousel(cmd.figureId).items);
|
|
65535
|
+
this.history.update("carousels", cmd.sheetId, cmd.figureId, cmd.definition);
|
|
65536
|
+
break;
|
|
65537
|
+
case "DUPLICATE_SHEET": {
|
|
65538
|
+
const sheetFiguresFrom = this.getters.getFigures(cmd.sheetId);
|
|
65539
|
+
for (const fig of sheetFiguresFrom) {
|
|
65540
|
+
if (fig.tag === "carousel") {
|
|
65541
|
+
const figureIdBase = fig.id.split(FIGURE_ID_SPLITTER).pop();
|
|
65542
|
+
const duplicatedFigureId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${figureIdBase}`;
|
|
65543
|
+
const carousel = this.getCarousel(fig.id);
|
|
65544
|
+
if (carousel) {
|
|
65545
|
+
const size = { width: fig.width, height: fig.height };
|
|
65546
|
+
this.dispatch("CREATE_CAROUSEL", {
|
|
65547
|
+
sheetId: cmd.sheetIdTo,
|
|
65548
|
+
figureId: duplicatedFigureId,
|
|
65549
|
+
offset: fig.offset,
|
|
65550
|
+
col: fig.col,
|
|
65551
|
+
row: fig.row,
|
|
65552
|
+
size,
|
|
65553
|
+
definition: {
|
|
65554
|
+
items: carousel.items.map((item) => {
|
|
65555
|
+
if (item.type === "carouselDataView") {
|
|
65556
|
+
return { type: "carouselDataView" };
|
|
65557
|
+
}
|
|
65558
|
+
const chartIdBase = item.chartId.split(FIGURE_ID_SPLITTER).pop();
|
|
65559
|
+
const newChartId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${chartIdBase}`;
|
|
65560
|
+
return { type: "chart", chartId: newChartId };
|
|
65561
|
+
}),
|
|
65562
|
+
},
|
|
65563
|
+
});
|
|
65564
|
+
}
|
|
65565
|
+
}
|
|
65566
|
+
}
|
|
65567
|
+
break;
|
|
65568
|
+
}
|
|
65569
|
+
case "DELETE_FIGURE":
|
|
65570
|
+
this.history.update("carousels", cmd.sheetId, cmd.figureId, undefined);
|
|
65571
|
+
break;
|
|
65572
|
+
case "DELETE_SHEET":
|
|
65573
|
+
this.history.update("carousels", cmd.sheetId, undefined);
|
|
65574
|
+
break;
|
|
65575
|
+
}
|
|
65576
|
+
}
|
|
65577
|
+
doesCarouselExist(figureId) {
|
|
65578
|
+
for (const sheetId in this.carousels) {
|
|
65579
|
+
if (this.carousels[sheetId]?.[figureId]) {
|
|
65580
|
+
return true;
|
|
65581
|
+
}
|
|
65582
|
+
}
|
|
65583
|
+
throw false;
|
|
65584
|
+
}
|
|
65585
|
+
getCarousel(figureId) {
|
|
65586
|
+
for (const sheetId in this.carousels) {
|
|
65587
|
+
if (this.carousels[sheetId]?.[figureId]) {
|
|
65588
|
+
return this.carousels[sheetId][figureId];
|
|
65589
|
+
}
|
|
65590
|
+
}
|
|
65591
|
+
throw new Error(`There is no carousel with the given figureId: ${figureId}`);
|
|
65592
|
+
}
|
|
65593
|
+
removeDeletedCharts(cmd, oldItems) {
|
|
65594
|
+
const newChartIds = new Set(cmd.definition.items.filter((item) => item.type === "chart").map((item) => item.chartId));
|
|
65595
|
+
for (const item of oldItems) {
|
|
65596
|
+
if (item.type === "chart" && !newChartIds.has(item.chartId)) {
|
|
65597
|
+
this.dispatch("DELETE_CHART", { chartId: item.chartId, sheetId: cmd.sheetId });
|
|
65598
|
+
}
|
|
65599
|
+
}
|
|
65600
|
+
}
|
|
65601
|
+
import(data) {
|
|
65602
|
+
for (const sheet of data.sheets) {
|
|
65603
|
+
const carousels = (sheet.figures || []).filter((figure) => figure.tag === "carousel");
|
|
65604
|
+
for (const carousel of carousels) {
|
|
65605
|
+
this.history.update("carousels", sheet.id, carousel.id, { items: carousel.data.items });
|
|
65606
|
+
}
|
|
65607
|
+
}
|
|
65608
|
+
}
|
|
65609
|
+
export(data) {
|
|
65610
|
+
for (const sheet of data.sheets) {
|
|
65611
|
+
const carousels = sheet.figures.filter((figure) => figure.tag === "carousel");
|
|
65612
|
+
for (const carousel of carousels) {
|
|
65613
|
+
if (this.carousels[sheet.id]?.[carousel.id]) {
|
|
65614
|
+
carousel.data = { ...carousel.data, ...this.carousels[sheet.id]?.[carousel.id] };
|
|
65615
|
+
}
|
|
65616
|
+
}
|
|
65617
|
+
}
|
|
65618
|
+
}
|
|
65619
|
+
}
|
|
65620
|
+
|
|
64250
65621
|
class HeaderGroupingPlugin extends CorePlugin {
|
|
64251
65622
|
static getters = [
|
|
64252
65623
|
"getHeaderGroups",
|
|
@@ -67202,7 +68573,7 @@ class CustomColorsPlugin extends CoreViewPlugin {
|
|
|
67202
68573
|
break;
|
|
67203
68574
|
case "UPDATE_CHART":
|
|
67204
68575
|
case "CREATE_CHART":
|
|
67205
|
-
this.tryToAddColors(this.getChartColors(cmd.
|
|
68576
|
+
this.tryToAddColors(this.getChartColors(cmd.chartId));
|
|
67206
68577
|
break;
|
|
67207
68578
|
case "UPDATE_CELL":
|
|
67208
68579
|
case "ADD_CONDITIONAL_FORMAT":
|
|
@@ -67334,8 +68705,10 @@ class EvaluationChartPlugin extends CoreViewPlugin {
|
|
|
67334
68705
|
switch (cmd.type) {
|
|
67335
68706
|
case "UPDATE_CHART":
|
|
67336
68707
|
case "CREATE_CHART":
|
|
67337
|
-
|
|
67338
|
-
|
|
68708
|
+
this.charts[cmd.chartId] = undefined;
|
|
68709
|
+
break;
|
|
68710
|
+
case "DELETE_CHART":
|
|
68711
|
+
this.charts[cmd.chartId] = undefined;
|
|
67339
68712
|
break;
|
|
67340
68713
|
case "DELETE_SHEET":
|
|
67341
68714
|
for (const chartId in this.charts) {
|
|
@@ -67346,15 +68719,15 @@ class EvaluationChartPlugin extends CoreViewPlugin {
|
|
|
67346
68719
|
break;
|
|
67347
68720
|
}
|
|
67348
68721
|
}
|
|
67349
|
-
getChartRuntime(
|
|
67350
|
-
if (!this.charts[
|
|
67351
|
-
const chart = this.getters.getChart(
|
|
68722
|
+
getChartRuntime(chartId) {
|
|
68723
|
+
if (!this.charts[chartId]) {
|
|
68724
|
+
const chart = this.getters.getChart(chartId);
|
|
67352
68725
|
if (!chart) {
|
|
67353
|
-
throw new Error(`No chart for the given id: ${
|
|
68726
|
+
throw new Error(`No chart for the given id: ${chartId}`);
|
|
67354
68727
|
}
|
|
67355
|
-
this.charts[
|
|
68728
|
+
this.charts[chartId] = this.createRuntimeChart(chart);
|
|
67356
68729
|
}
|
|
67357
|
-
return this.charts[
|
|
68730
|
+
return this.charts[chartId];
|
|
67358
68731
|
}
|
|
67359
68732
|
/**
|
|
67360
68733
|
* Get the background and textColor of a chart based on the color of the first cell of the main range of the chart.
|
|
@@ -67389,8 +68762,14 @@ class EvaluationChartPlugin extends CoreViewPlugin {
|
|
|
67389
68762
|
if (!figure || figure.tag !== "chart") {
|
|
67390
68763
|
continue;
|
|
67391
68764
|
}
|
|
67392
|
-
const
|
|
67393
|
-
|
|
68765
|
+
const chartId = this.getters
|
|
68766
|
+
.getChartIds(sheet.id)
|
|
68767
|
+
.find((chartId) => this.getters.getFigureIdFromChartId(chartId) === figure.id);
|
|
68768
|
+
if (!chartId) {
|
|
68769
|
+
continue;
|
|
68770
|
+
}
|
|
68771
|
+
const chart = this.getters.getChart(chartId);
|
|
68772
|
+
const figureData = chart?.getDefinitionForExcel(this.getters);
|
|
67394
68773
|
if (figureData) {
|
|
67395
68774
|
figures.push({
|
|
67396
68775
|
...figure,
|
|
@@ -67398,12 +68777,11 @@ class EvaluationChartPlugin extends CoreViewPlugin {
|
|
|
67398
68777
|
});
|
|
67399
68778
|
}
|
|
67400
68779
|
else {
|
|
67401
|
-
const chart = this.getters.getChart(figureId);
|
|
67402
68780
|
if (!chart) {
|
|
67403
68781
|
continue;
|
|
67404
68782
|
}
|
|
67405
|
-
const type = this.getters.getChartType(
|
|
67406
|
-
const runtime = this.getters.getChartRuntime(
|
|
68783
|
+
const type = this.getters.getChartType(chartId);
|
|
68784
|
+
const runtime = this.getters.getChartRuntime(chartId);
|
|
67407
68785
|
const img = chartToImageUrl(runtime, figure, type);
|
|
67408
68786
|
if (img) {
|
|
67409
68787
|
sheet.images.push({
|
|
@@ -70537,7 +71915,9 @@ const specificRangeTransformRegistry = new SpecificRangeTransformRegistry();
|
|
|
70537
71915
|
otRegistry.addTransformation("ADD_COLUMNS_ROWS", ["ADD_COLUMNS_ROWS"], addHeadersTransformation);
|
|
70538
71916
|
otRegistry.addTransformation("REMOVE_COLUMNS_ROWS", ["ADD_COLUMNS_ROWS"], addHeadersTransformation);
|
|
70539
71917
|
otRegistry.addTransformation("DELETE_SHEET", ["MOVE_RANGES"], transformTargetSheetId);
|
|
70540
|
-
otRegistry.addTransformation("DELETE_FIGURE", ["UPDATE_FIGURE", "UPDATE_CHART"], updateChartFigure);
|
|
71918
|
+
otRegistry.addTransformation("DELETE_FIGURE", ["UPDATE_FIGURE", "UPDATE_CHART", "UPDATE_CAROUSEL"], updateChartFigure);
|
|
71919
|
+
otRegistry.addTransformation("DELETE_CHART", ["UPDATE_CHART"], updateChartOnChartDelete);
|
|
71920
|
+
otRegistry.addTransformation("DELETE_CHART", ["UPDATE_CAROUSEL"], updateCarouselOnChartDelete);
|
|
70541
71921
|
otRegistry.addTransformation("CREATE_SHEET", ["CREATE_SHEET"], createSheetTransformation);
|
|
70542
71922
|
otRegistry.addTransformation("ADD_MERGE", ["ADD_MERGE", "REMOVE_MERGE"], mergeTransformation);
|
|
70543
71923
|
otRegistry.addTransformation("ADD_COLUMNS_ROWS", ["FREEZE_COLUMNS", "FREEZE_ROWS"], freezeTransformation);
|
|
@@ -70590,6 +71970,21 @@ function updateChartFigure(toTransform, executed) {
|
|
|
70590
71970
|
}
|
|
70591
71971
|
return toTransform;
|
|
70592
71972
|
}
|
|
71973
|
+
function updateChartOnChartDelete(toTransform, executed) {
|
|
71974
|
+
if (toTransform.chartId === executed.chartId) {
|
|
71975
|
+
return undefined;
|
|
71976
|
+
}
|
|
71977
|
+
return toTransform;
|
|
71978
|
+
}
|
|
71979
|
+
function updateCarouselOnChartDelete(toTransform, executed) {
|
|
71980
|
+
return {
|
|
71981
|
+
...toTransform,
|
|
71982
|
+
definition: {
|
|
71983
|
+
...toTransform.definition,
|
|
71984
|
+
items: toTransform.definition.items.filter((item) => !(item.type === "chart" && item.chartId === executed.chartId)),
|
|
71985
|
+
},
|
|
71986
|
+
};
|
|
71987
|
+
}
|
|
70593
71988
|
function createSheetTransformation(toTransform, executed) {
|
|
70594
71989
|
if (toTransform.sheetId === executed.sheetId) {
|
|
70595
71990
|
toTransform = { ...toTransform, sheetId: `${toTransform.sheetId}~` };
|
|
@@ -72984,9 +74379,11 @@ function repeatRangeDependantCommand(getters, command) {
|
|
|
72984
74379
|
|
|
72985
74380
|
const uuidGenerator = new UuidGenerator();
|
|
72986
74381
|
function repeatCreateChartCommand(getters, cmd) {
|
|
74382
|
+
const id = uuidGenerator.smallUuid();
|
|
72987
74383
|
return {
|
|
72988
74384
|
...repeatSheetDependantCommand(getters, cmd),
|
|
72989
|
-
figureId:
|
|
74385
|
+
figureId: id,
|
|
74386
|
+
chartId: id,
|
|
72990
74387
|
};
|
|
72991
74388
|
}
|
|
72992
74389
|
function repeatCreateImageCommand(getters, cmd) {
|
|
@@ -76196,6 +77593,123 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
76196
77593
|
}
|
|
76197
77594
|
}
|
|
76198
77595
|
|
|
77596
|
+
class CarouselUIPlugin extends UIPlugin {
|
|
77597
|
+
static getters = [
|
|
77598
|
+
"getSelectedCarouselItem",
|
|
77599
|
+
"getChartFromFigureId",
|
|
77600
|
+
"getChartIdFromFigureId",
|
|
77601
|
+
];
|
|
77602
|
+
uuidGenerator = new UuidGenerator();
|
|
77603
|
+
carouselStates = {};
|
|
77604
|
+
handle(cmd) {
|
|
77605
|
+
switch (cmd.type) {
|
|
77606
|
+
case "ADD_NEW_CHART_TO_CAROUSEL":
|
|
77607
|
+
this.addNewChartToCarousel(cmd.figureId, cmd.sheetId);
|
|
77608
|
+
break;
|
|
77609
|
+
case "ADD_FIGURE_CHART_TO_CAROUSEL":
|
|
77610
|
+
this.addFigureChartToCarousel(cmd.carouselFigureId, cmd.chartFigureId, cmd.sheetId);
|
|
77611
|
+
break;
|
|
77612
|
+
case "UPDATE_CAROUSEL_ACTIVE_ITEM":
|
|
77613
|
+
this.carouselStates[cmd.figureId] = cmd.item;
|
|
77614
|
+
break;
|
|
77615
|
+
case "DELETE_FIGURE":
|
|
77616
|
+
delete this.carouselStates[cmd.figureId];
|
|
77617
|
+
break;
|
|
77618
|
+
case "UPDATE_CAROUSEL":
|
|
77619
|
+
this.fixWrongCarouselState(cmd.figureId);
|
|
77620
|
+
break;
|
|
77621
|
+
case "DELETE_CHART":
|
|
77622
|
+
case "UNDO":
|
|
77623
|
+
case "REDO":
|
|
77624
|
+
case "DELETE_SHEET":
|
|
77625
|
+
for (const figureId in this.carouselStates) {
|
|
77626
|
+
this.fixWrongCarouselState(figureId);
|
|
77627
|
+
}
|
|
77628
|
+
break;
|
|
77629
|
+
}
|
|
77630
|
+
}
|
|
77631
|
+
getSelectedCarouselItem(figureId) {
|
|
77632
|
+
const carousel = this.getters.getCarousel(figureId);
|
|
77633
|
+
if (!carousel.items.length) {
|
|
77634
|
+
return undefined;
|
|
77635
|
+
}
|
|
77636
|
+
return this.carouselStates[figureId] ? this.carouselStates[figureId] : carousel.items[0];
|
|
77637
|
+
}
|
|
77638
|
+
getChartFromFigureId(figureId) {
|
|
77639
|
+
const sheetId = this.getters.getFigureSheetId(figureId);
|
|
77640
|
+
if (!sheetId) {
|
|
77641
|
+
return undefined;
|
|
77642
|
+
}
|
|
77643
|
+
const chartId = this.getChartIdFromFigureId(figureId);
|
|
77644
|
+
return chartId ? this.getters.getChart(chartId) : undefined;
|
|
77645
|
+
}
|
|
77646
|
+
getChartIdFromFigureId(figureId) {
|
|
77647
|
+
const sheetId = this.getters.getFigureSheetId(figureId);
|
|
77648
|
+
if (!sheetId) {
|
|
77649
|
+
return undefined;
|
|
77650
|
+
}
|
|
77651
|
+
const figure = this.getters.getFigure(sheetId, figureId);
|
|
77652
|
+
if (!figure || (figure.tag !== "chart" && figure.tag !== "carousel")) {
|
|
77653
|
+
return undefined;
|
|
77654
|
+
}
|
|
77655
|
+
if (figure.tag === "carousel") {
|
|
77656
|
+
const carouselItem = this.getSelectedCarouselItem(figureId);
|
|
77657
|
+
return carouselItem?.type === "chart" ? carouselItem.chartId : undefined;
|
|
77658
|
+
}
|
|
77659
|
+
return this.getters
|
|
77660
|
+
.getChartIds(sheetId)
|
|
77661
|
+
.find((chartId) => this.getters.getFigureIdFromChartId(chartId) === figureId);
|
|
77662
|
+
}
|
|
77663
|
+
fixWrongCarouselState(figureId) {
|
|
77664
|
+
if (!this.getters.doesCarouselExist(figureId)) {
|
|
77665
|
+
delete this.carouselStates[figureId];
|
|
77666
|
+
return;
|
|
77667
|
+
}
|
|
77668
|
+
const carousel = this.getters.getCarousel(figureId);
|
|
77669
|
+
if (!carousel) {
|
|
77670
|
+
delete this.carouselStates[figureId];
|
|
77671
|
+
return;
|
|
77672
|
+
}
|
|
77673
|
+
if (!this.carouselStates[figureId]) {
|
|
77674
|
+
this.carouselStates[figureId] = carousel.items[0];
|
|
77675
|
+
}
|
|
77676
|
+
else if (carousel.items.length === 0) {
|
|
77677
|
+
delete this.carouselStates[figureId];
|
|
77678
|
+
}
|
|
77679
|
+
else if (!carousel.items.some((item) => deepEquals(item, this.carouselStates[figureId]))) {
|
|
77680
|
+
this.carouselStates[figureId] = carousel.items[0];
|
|
77681
|
+
}
|
|
77682
|
+
}
|
|
77683
|
+
addNewChartToCarousel(figureId, sheetId) {
|
|
77684
|
+
const carousel = this.getters.getCarousel(figureId);
|
|
77685
|
+
const chartId = this.uuidGenerator.smallUuid();
|
|
77686
|
+
this.dispatch("CREATE_CHART", {
|
|
77687
|
+
chartId,
|
|
77688
|
+
figureId,
|
|
77689
|
+
sheetId,
|
|
77690
|
+
definition: CAROUSEL_DEFAULT_CHART_DEFINITION,
|
|
77691
|
+
});
|
|
77692
|
+
const definition = { items: [...carousel.items, { type: "chart", chartId }] };
|
|
77693
|
+
this.dispatch("UPDATE_CAROUSEL", { sheetId, figureId, definition });
|
|
77694
|
+
}
|
|
77695
|
+
addFigureChartToCarousel(figureId, chartFigureId, sheetId) {
|
|
77696
|
+
const chartId = this.getChartIdFromFigureId(chartFigureId);
|
|
77697
|
+
if (!chartId) {
|
|
77698
|
+
return;
|
|
77699
|
+
}
|
|
77700
|
+
const carousel = this.getters.getCarousel(figureId);
|
|
77701
|
+
const definition = { items: [...carousel.items, { type: "chart", chartId }] };
|
|
77702
|
+
this.dispatch("UPDATE_CAROUSEL", { sheetId, figureId, definition });
|
|
77703
|
+
this.dispatch("UPDATE_CHART", {
|
|
77704
|
+
sheetId,
|
|
77705
|
+
chartId,
|
|
77706
|
+
figureId,
|
|
77707
|
+
definition: this.getters.getChartDefinition(chartId),
|
|
77708
|
+
});
|
|
77709
|
+
this.dispatch("DELETE_FIGURE", { sheetId, figureId: chartFigureId });
|
|
77710
|
+
}
|
|
77711
|
+
}
|
|
77712
|
+
|
|
76199
77713
|
class HeaderPositionsUIPlugin extends UIPlugin {
|
|
76200
77714
|
static getters = ["getColDimensions", "getRowDimensions", "getColRowOffset"];
|
|
76201
77715
|
headerPositions = {};
|
|
@@ -76327,6 +77841,7 @@ const corePluginRegistry = new Registry()
|
|
|
76327
77841
|
.add("conditional formatting", ConditionalFormatPlugin)
|
|
76328
77842
|
.add("figures", FigurePlugin)
|
|
76329
77843
|
.add("chart", ChartPlugin)
|
|
77844
|
+
.add("carousel", CarouselPlugin)
|
|
76330
77845
|
.add("image", ImagePlugin)
|
|
76331
77846
|
.add("pivot_core", PivotCorePlugin)
|
|
76332
77847
|
.add("spreadsheet_pivot_core", SpreadsheetPivotCorePlugin)
|
|
@@ -76359,7 +77874,8 @@ const statefulUIPluginRegistry = new Registry()
|
|
|
76359
77874
|
.add("table_computed_style", TableComputedStylePlugin)
|
|
76360
77875
|
.add("header_positions", HeaderPositionsUIPlugin)
|
|
76361
77876
|
.add("viewport", SheetViewPlugin)
|
|
76362
|
-
.add("clipboard", ClipboardPlugin)
|
|
77877
|
+
.add("clipboard", ClipboardPlugin)
|
|
77878
|
+
.add("carousel_ui", CarouselUIPlugin);
|
|
76363
77879
|
// Plugins which have a derived state from core data
|
|
76364
77880
|
const coreViewsPluginRegistry = new Registry()
|
|
76365
77881
|
.add("evaluation", EvaluationPlugin)
|
|
@@ -77312,6 +78828,10 @@ topbarMenuRegistry
|
|
|
77312
78828
|
.addChild("insert_chart", ["insert"], {
|
|
77313
78829
|
...insertChart,
|
|
77314
78830
|
sequence: 50,
|
|
78831
|
+
})
|
|
78832
|
+
.addChild("insert_carousel", ["insert"], {
|
|
78833
|
+
...insertCarousel,
|
|
78834
|
+
sequence: 51,
|
|
77315
78835
|
})
|
|
77316
78836
|
.addChild("insert_pivot", ["insert"], {
|
|
77317
78837
|
...insertPivot,
|
|
@@ -78482,9 +80002,7 @@ class ClickableCellsStore extends SpreadsheetStore {
|
|
|
78482
80002
|
}
|
|
78483
80003
|
if (!(xc in clickableCells[sheetId])) {
|
|
78484
80004
|
const clickableCell = this.findClickableItem(position);
|
|
78485
|
-
|
|
78486
|
-
clickableCells[sheetId][xc] = clickableCell;
|
|
78487
|
-
}
|
|
80005
|
+
clickableCells[sheetId][xc] = clickableCell;
|
|
78488
80006
|
}
|
|
78489
80007
|
return clickableCells[sheetId][xc];
|
|
78490
80008
|
}
|
|
@@ -80726,6 +82244,7 @@ class Spreadsheet extends owl.Component {
|
|
|
80726
82244
|
loadLocales: this.model.config.external.loadLocales,
|
|
80727
82245
|
isDashboard: () => this.model.getters.isDashboard(),
|
|
80728
82246
|
openSidePanel: this.sidePanel.open.bind(this.sidePanel),
|
|
82247
|
+
replaceSidePanel: this.sidePanel.replace.bind(this.sidePanel),
|
|
80729
82248
|
toggleSidePanel: this.sidePanel.toggle.bind(this.sidePanel),
|
|
80730
82249
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
80731
82250
|
startCellEdition: (content) => this.composerFocusStore.focusActiveComposer({ content }),
|
|
@@ -83694,7 +85213,7 @@ function commonDataValidationAttributes(dvRule) {
|
|
|
83694
85213
|
];
|
|
83695
85214
|
}
|
|
83696
85215
|
|
|
83697
|
-
function createDrawing(drawingRelIds, sheet, figures) {
|
|
85216
|
+
function createDrawing(drawingRelIds, sheet, figures, construct) {
|
|
83698
85217
|
const namespaces = [
|
|
83699
85218
|
["xmlns:xdr", NAMESPACE.drawing],
|
|
83700
85219
|
["xmlns:r", RELATIONSHIP_NSR],
|
|
@@ -83705,7 +85224,7 @@ function createDrawing(drawingRelIds, sheet, figures) {
|
|
|
83705
85224
|
for (const [figureIndex, figure] of Object.entries(figures)) {
|
|
83706
85225
|
switch (figure?.tag) {
|
|
83707
85226
|
case "chart":
|
|
83708
|
-
figuresNodes.push(createChartDrawing(figure, sheet, drawingRelIds[figureIndex]));
|
|
85227
|
+
figuresNodes.push(createChartDrawing(figure, sheet, drawingRelIds[figureIndex], construct));
|
|
83709
85228
|
break;
|
|
83710
85229
|
case "image":
|
|
83711
85230
|
figuresNodes.push(createImageDrawing(figure, sheet, drawingRelIds[figureIndex]));
|
|
@@ -83767,10 +85286,10 @@ function figureCoordinates(headers, anchor, offset) {
|
|
|
83767
85286
|
offset: convertDotValueToEMU(offset - currentPosition + FIGURE_BORDER_WIDTH),
|
|
83768
85287
|
};
|
|
83769
85288
|
}
|
|
83770
|
-
function createChartDrawing(figure, sheet, chartRelId) {
|
|
85289
|
+
function createChartDrawing(figure, sheet, chartRelId, construct) {
|
|
83771
85290
|
// position
|
|
83772
85291
|
const { from, to } = convertFigureData(figure, sheet);
|
|
83773
|
-
const chartId = convertChartId(figure.id);
|
|
85292
|
+
const chartId = convertChartId(figure.id, construct);
|
|
83774
85293
|
const cNvPrAttrs = [
|
|
83775
85294
|
["id", chartId],
|
|
83776
85295
|
["name", `Chart ${chartId}`],
|
|
@@ -84433,7 +85952,7 @@ function createWorksheets(data, construct) {
|
|
|
84433
85952
|
let drawingNode = escapeXml ``;
|
|
84434
85953
|
const drawingRelIds = [];
|
|
84435
85954
|
for (const chart of sheet.charts) {
|
|
84436
|
-
const xlsxChartId = convertChartId(chart.id);
|
|
85955
|
+
const xlsxChartId = convertChartId(chart.id, construct);
|
|
84437
85956
|
const chartRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
|
|
84438
85957
|
target: `../charts/chart${xlsxChartId}.xml`,
|
|
84439
85958
|
type: XLSX_RELATION_TYPE.chart,
|
|
@@ -84467,7 +85986,7 @@ function createWorksheets(data, construct) {
|
|
|
84467
85986
|
target: `../drawings/drawing${sheetIndex}.xml`,
|
|
84468
85987
|
type: XLSX_RELATION_TYPE.drawing,
|
|
84469
85988
|
});
|
|
84470
|
-
files.push(createXMLFile(createDrawing(drawingRelIds, sheet, drawings), `xl/drawings/drawing${sheetIndex}.xml`, "drawing"));
|
|
85989
|
+
files.push(createXMLFile(createDrawing(drawingRelIds, sheet, drawings, construct), `xl/drawings/drawing${sheetIndex}.xml`, "drawing"));
|
|
84471
85990
|
drawingNode = escapeXml /*xml*/ `<drawing r:id="${drawingRelId}" />`;
|
|
84472
85991
|
}
|
|
84473
85992
|
const sheetXml = escapeXml /*xml*/ `
|
|
@@ -85368,6 +86887,7 @@ const components = {
|
|
|
85368
86887
|
ChartPanel,
|
|
85369
86888
|
ChartFigure,
|
|
85370
86889
|
ChartJsComponent,
|
|
86890
|
+
ZoomableChartJsComponent,
|
|
85371
86891
|
Grid,
|
|
85372
86892
|
GridOverlay,
|
|
85373
86893
|
ScorecardChart,
|
|
@@ -85376,6 +86896,7 @@ const components = {
|
|
|
85376
86896
|
PieChartDesignPanel,
|
|
85377
86897
|
GenericChartConfigPanel,
|
|
85378
86898
|
ChartWithAxisDesignPanel,
|
|
86899
|
+
GenericZoomableChartDesignPanel,
|
|
85379
86900
|
LineChartDesignPanel,
|
|
85380
86901
|
GaugeChartConfigPanel,
|
|
85381
86902
|
GaugeChartDesignPanel,
|
|
@@ -85450,6 +86971,7 @@ const constants = {
|
|
|
85450
86971
|
HIGHLIGHT_COLOR,
|
|
85451
86972
|
PIVOT_TABLE_CONFIG,
|
|
85452
86973
|
ChartTerms,
|
|
86974
|
+
FIGURE_ID_SPLITTER,
|
|
85453
86975
|
};
|
|
85454
86976
|
const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
85455
86977
|
|
|
@@ -85504,6 +87026,6 @@ exports.tokenColors = tokenColors;
|
|
|
85504
87026
|
exports.tokenize = tokenize;
|
|
85505
87027
|
|
|
85506
87028
|
|
|
85507
|
-
__info__.version = "18.5.0-alpha.
|
|
85508
|
-
__info__.date = "2025-08-
|
|
85509
|
-
__info__.hash = "
|
|
87029
|
+
__info__.version = "18.5.0-alpha.8";
|
|
87030
|
+
__info__.date = "2025-08-18T08:17:58.775Z";
|
|
87031
|
+
__info__.hash = "994f1cb";
|