@odoo/o-spreadsheet 17.3.0-alpha.2 → 17.3.0-alpha.3
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 +644 -346
- package/dist/o-spreadsheet.d.ts +118 -109
- package/dist/o-spreadsheet.esm.js +644 -346
- package/dist/o-spreadsheet.iife.js +644 -346
- package/dist/o-spreadsheet.iife.min.js +357 -309
- package/dist/o_spreadsheet.xml +140 -90
- package/package.json +1 -1
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
5
5
|
* @see https://github.com/odoo/o-spreadsheet
|
|
6
|
-
* @version 17.3.0-alpha.
|
|
7
|
-
* @date 2024-04-
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.3.0-alpha.3
|
|
7
|
+
* @date 2024-04-10T12:28:23.658Z
|
|
8
|
+
* @hash 80b5056
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { reactive, useEnv, useSubEnv, useState, onWillUnmount, markRaw, toRaw, Component, useRef, onMounted, useEffect, onPatched, useComponent, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv } from '@odoo/owl';
|
|
@@ -188,7 +188,7 @@ const DEFAULT_GAUGE_LOWER_COLOR = "#cc0000";
|
|
|
188
188
|
const DEFAULT_GAUGE_MIDDLE_COLOR = "#f1c232";
|
|
189
189
|
const DEFAULT_GAUGE_UPPER_COLOR = "#6aa84f";
|
|
190
190
|
const DEFAULT_SCORECARD_BASELINE_MODE = "difference";
|
|
191
|
-
const DEFAULT_SCORECARD_BASELINE_COLOR_UP = "#
|
|
191
|
+
const DEFAULT_SCORECARD_BASELINE_COLOR_UP = "#6AA84F";
|
|
192
192
|
const DEFAULT_SCORECARD_BASELINE_COLOR_DOWN = "#E06666";
|
|
193
193
|
const LINE_FILL_TRANSPARENCY = 0.4;
|
|
194
194
|
// session
|
|
@@ -560,7 +560,7 @@ function deepEquals(o1, o2) {
|
|
|
560
560
|
if (typeof o1 !== typeof o2)
|
|
561
561
|
return false;
|
|
562
562
|
if (typeof o1 !== "object")
|
|
563
|
-
return
|
|
563
|
+
return false;
|
|
564
564
|
// Objects can have different keys if the values are undefined
|
|
565
565
|
for (const key in o2) {
|
|
566
566
|
if (!(key in o1) && o2[key] !== undefined) {
|
|
@@ -1884,6 +1884,11 @@ const invalidateCFEvaluationCommands = new Set([
|
|
|
1884
1884
|
"REMOVE_CONDITIONAL_FORMAT",
|
|
1885
1885
|
"CHANGE_CONDITIONAL_FORMAT_PRIORITY",
|
|
1886
1886
|
]);
|
|
1887
|
+
const invalidateBordersCommands = new Set([
|
|
1888
|
+
"AUTOFILL_CELL",
|
|
1889
|
+
"SET_BORDER",
|
|
1890
|
+
"SET_ZONE_BORDERS",
|
|
1891
|
+
]);
|
|
1887
1892
|
const readonlyAllowedCommands = new Set([
|
|
1888
1893
|
"START",
|
|
1889
1894
|
"ACTIVATE_SHEET",
|
|
@@ -2181,6 +2186,7 @@ const CellErrorType = {
|
|
|
2181
2186
|
BadExpression: "#BAD_EXPR",
|
|
2182
2187
|
CircularDependency: "#CYCLE",
|
|
2183
2188
|
UnknownFunction: "#NAME?",
|
|
2189
|
+
DivisionByZero: "#DIV/0!",
|
|
2184
2190
|
GenericError: "#ERROR",
|
|
2185
2191
|
};
|
|
2186
2192
|
const errorTypes = new Set(Object.values(CellErrorType));
|
|
@@ -2219,9 +2225,9 @@ class UnknownFunctionError extends EvaluationError {
|
|
|
2219
2225
|
|
|
2220
2226
|
// HELPERS
|
|
2221
2227
|
const SORT_TYPES_ORDER = ["number", "string", "boolean", "undefined"];
|
|
2222
|
-
function assert(condition, message) {
|
|
2228
|
+
function assert(condition, message, value) {
|
|
2223
2229
|
if (!condition()) {
|
|
2224
|
-
throw new EvaluationError(message);
|
|
2230
|
+
throw new EvaluationError(message, value);
|
|
2225
2231
|
}
|
|
2226
2232
|
}
|
|
2227
2233
|
function inferFormat(data) {
|
|
@@ -2299,6 +2305,9 @@ function strictToInteger(value, locale) {
|
|
|
2299
2305
|
function assertNumberGreaterThanOrEqualToOne(value) {
|
|
2300
2306
|
assert(() => value >= 1, _t("The function [[FUNCTION_NAME]] expects a number value to be greater than or equal to 1, but receives %s.", value.toString()));
|
|
2301
2307
|
}
|
|
2308
|
+
function assertNotZero(value) {
|
|
2309
|
+
assert(() => value !== 0, _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."), CellErrorType.DivisionByZero);
|
|
2310
|
+
}
|
|
2302
2311
|
function toString(data) {
|
|
2303
2312
|
const value = toValue(data);
|
|
2304
2313
|
switch (typeof value) {
|
|
@@ -3064,6 +3073,9 @@ function applyInternalFormat(value, internalFormat, locale) {
|
|
|
3064
3073
|
return formattedValue;
|
|
3065
3074
|
}
|
|
3066
3075
|
function applyInternalNumberFormat(value, format, locale) {
|
|
3076
|
+
if (value === Infinity) {
|
|
3077
|
+
return "∞" + (format.isPercent ? "%" : "");
|
|
3078
|
+
}
|
|
3067
3079
|
if (format.isPercent) {
|
|
3068
3080
|
value = value * 100;
|
|
3069
3081
|
}
|
|
@@ -3407,6 +3419,46 @@ function roundFormat(format) {
|
|
|
3407
3419
|
});
|
|
3408
3420
|
return convertInternalFormatToFormat(roundedFormat);
|
|
3409
3421
|
}
|
|
3422
|
+
function humanizeNumber({ value, format }, locale) {
|
|
3423
|
+
const numberFormat = formatLargeNumber({
|
|
3424
|
+
value,
|
|
3425
|
+
format,
|
|
3426
|
+
}, undefined, locale);
|
|
3427
|
+
return formatValue(value, { format: numberFormat, locale });
|
|
3428
|
+
}
|
|
3429
|
+
function formatLargeNumber(arg, unit, locale) {
|
|
3430
|
+
let value = 0;
|
|
3431
|
+
try {
|
|
3432
|
+
value = Math.abs(toNumber(arg?.value, locale));
|
|
3433
|
+
}
|
|
3434
|
+
catch (e) {
|
|
3435
|
+
return "";
|
|
3436
|
+
}
|
|
3437
|
+
const format = arg?.format;
|
|
3438
|
+
if (unit !== undefined) {
|
|
3439
|
+
const postFix = unit?.value;
|
|
3440
|
+
switch (postFix) {
|
|
3441
|
+
case "k":
|
|
3442
|
+
return createLargeNumberFormat(format, 1e3, "k");
|
|
3443
|
+
case "m":
|
|
3444
|
+
return createLargeNumberFormat(format, 1e6, "m");
|
|
3445
|
+
case "b":
|
|
3446
|
+
return createLargeNumberFormat(format, 1e9, "b");
|
|
3447
|
+
default:
|
|
3448
|
+
throw new EvaluationError(_t("The formatting unit should be 'k', 'm' or 'b'."));
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
if (value < 1e5) {
|
|
3452
|
+
return createLargeNumberFormat(format, 0, "");
|
|
3453
|
+
}
|
|
3454
|
+
else if (value < 1e8) {
|
|
3455
|
+
return createLargeNumberFormat(format, 1e3, "k");
|
|
3456
|
+
}
|
|
3457
|
+
else if (value < 1e11) {
|
|
3458
|
+
return createLargeNumberFormat(format, 1e6, "m");
|
|
3459
|
+
}
|
|
3460
|
+
return createLargeNumberFormat(format, 1e9, "b");
|
|
3461
|
+
}
|
|
3410
3462
|
function createLargeNumberFormat(format, magnitude, postFix, locale) {
|
|
3411
3463
|
const internalFormat = parseFormat(format || "#,##0");
|
|
3412
3464
|
const largeNumberFormat = [];
|
|
@@ -4599,14 +4651,19 @@ function getDefaultCellHeight(ctx, cell, colSize) {
|
|
|
4599
4651
|
const textWidthCache = {};
|
|
4600
4652
|
function computeTextWidth(context, text, style, fontUnit = "pt") {
|
|
4601
4653
|
const font = computeTextFont(style, fontUnit);
|
|
4654
|
+
context.save();
|
|
4655
|
+
context.font = font;
|
|
4656
|
+
const width = computeCachedTextWidth(context, text);
|
|
4657
|
+
context.restore();
|
|
4658
|
+
return width;
|
|
4659
|
+
}
|
|
4660
|
+
function computeCachedTextWidth(context, text) {
|
|
4661
|
+
const font = context.font;
|
|
4602
4662
|
if (!textWidthCache[font]) {
|
|
4603
4663
|
textWidthCache[font] = {};
|
|
4604
4664
|
}
|
|
4605
4665
|
if (textWidthCache[font][text] === undefined) {
|
|
4606
|
-
context.save();
|
|
4607
|
-
context.font = font;
|
|
4608
4666
|
const textWidth = context.measureText(text).width;
|
|
4609
|
-
context.restore();
|
|
4610
4667
|
textWidthCache[font][text] = textWidth;
|
|
4611
4668
|
}
|
|
4612
4669
|
return textWidthCache[font][text];
|
|
@@ -4751,6 +4808,42 @@ const pxRegex = /([0-9\.]*)px/;
|
|
|
4751
4808
|
function getContextFontSize(font) {
|
|
4752
4809
|
return Number(font.match(pxRegex)?.[1]);
|
|
4753
4810
|
}
|
|
4811
|
+
// Inspired from https://stackoverflow.com/a/10511598
|
|
4812
|
+
function clipTextWithEllipsis(ctx, text, maxWidth) {
|
|
4813
|
+
let width = computeCachedTextWidth(ctx, text);
|
|
4814
|
+
if (width <= maxWidth) {
|
|
4815
|
+
return text;
|
|
4816
|
+
}
|
|
4817
|
+
const ellipsis = "…";
|
|
4818
|
+
const ellipsisWidth = computeCachedTextWidth(ctx, text);
|
|
4819
|
+
if (width <= ellipsisWidth) {
|
|
4820
|
+
return text;
|
|
4821
|
+
}
|
|
4822
|
+
let len = text.length;
|
|
4823
|
+
while (width >= maxWidth - ellipsisWidth && len-- > 0) {
|
|
4824
|
+
text = text.substring(0, len);
|
|
4825
|
+
width = computeCachedTextWidth(ctx, text);
|
|
4826
|
+
}
|
|
4827
|
+
return text + ellipsis;
|
|
4828
|
+
}
|
|
4829
|
+
function splitTextInTwoLines(text) {
|
|
4830
|
+
let spaces = "";
|
|
4831
|
+
while (text[0] === " ") {
|
|
4832
|
+
spaces += " ";
|
|
4833
|
+
text = text.slice(1);
|
|
4834
|
+
}
|
|
4835
|
+
const length = text.length;
|
|
4836
|
+
const middle = Math.floor(length / 2);
|
|
4837
|
+
const leftSpace = text.substring(0, middle).lastIndexOf(" ");
|
|
4838
|
+
const rightSpace = text.substring(middle).indexOf(" ") + middle;
|
|
4839
|
+
if (leftSpace === -1 && rightSpace === middle - 1) {
|
|
4840
|
+
return [spaces + text, ""];
|
|
4841
|
+
}
|
|
4842
|
+
if (leftSpace > length - rightSpace || rightSpace === middle - 1) {
|
|
4843
|
+
return [spaces + text.slice(0, leftSpace), spaces + text.slice(leftSpace + 1)];
|
|
4844
|
+
}
|
|
4845
|
+
return [spaces + text.slice(0, rightSpace), spaces + text.slice(rightSpace + 1)];
|
|
4846
|
+
}
|
|
4754
4847
|
function drawDecoratedText(context, text, position, underline = false, strikethrough = false, strokeWidth = getContextFontSize(context.font) / 10 //This value is defined to get a good looking stroke
|
|
4755
4848
|
) {
|
|
4756
4849
|
context.fillText(text, position.x, position.y);
|
|
@@ -7394,6 +7487,7 @@ const CellIsOperators = {
|
|
|
7394
7487
|
};
|
|
7395
7488
|
const ChartTerms = {
|
|
7396
7489
|
Series: _t("Series"),
|
|
7490
|
+
BackgroundColor: _t("Background color"),
|
|
7397
7491
|
Errors: {
|
|
7398
7492
|
Unexpected: _t("The chart definition is invalid for an unknown reason"),
|
|
7399
7493
|
// BASIC CHART ERRORS (LINE | BAR | PIE)
|
|
@@ -9429,32 +9523,63 @@ function shouldRemoveFirstLabel(labelRange, dataset, dataSetsHaveTitle) {
|
|
|
9429
9523
|
}
|
|
9430
9524
|
return true;
|
|
9431
9525
|
}
|
|
9432
|
-
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9526
|
+
function getChartPositionAtCenterOfViewport(getters, chartSize) {
|
|
9527
|
+
const { x, y } = getters.getMainViewportCoordinates();
|
|
9528
|
+
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
9529
|
+
const { width, height } = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
9530
|
+
const position = {
|
|
9531
|
+
x: x + scrollX + Math.max(0, (width - chartSize.width) / 2),
|
|
9532
|
+
y: y + scrollY + Math.max(0, (height - chartSize.height) / 2),
|
|
9533
|
+
}; // Position at the center of the scrollable viewport
|
|
9534
|
+
return position;
|
|
9535
|
+
}
|
|
9536
|
+
|
|
9537
|
+
function getBaselineText(baseline, keyValue, baselineMode, humanize, locale) {
|
|
9436
9538
|
if (!baseline) {
|
|
9437
9539
|
return "";
|
|
9438
9540
|
}
|
|
9439
9541
|
else if (baselineMode === "text" ||
|
|
9440
9542
|
keyValue?.type !== CellValueType.number ||
|
|
9441
9543
|
baseline.type !== CellValueType.number) {
|
|
9544
|
+
if (humanize) {
|
|
9545
|
+
return humanizeNumber(baseline, locale);
|
|
9546
|
+
}
|
|
9442
9547
|
return baseline.formattedValue;
|
|
9443
9548
|
}
|
|
9549
|
+
let { value, format } = baseline;
|
|
9550
|
+
if (baselineMode === "progress") {
|
|
9551
|
+
value = keyValue.value / value;
|
|
9552
|
+
format = "0.0%";
|
|
9553
|
+
}
|
|
9444
9554
|
else {
|
|
9445
|
-
|
|
9446
|
-
if (baselineMode === "percentage" &&
|
|
9447
|
-
|
|
9555
|
+
value = Math.abs(keyValue.value - value);
|
|
9556
|
+
if (baselineMode === "percentage" && value !== 0) {
|
|
9557
|
+
value = value / baseline.value;
|
|
9448
9558
|
}
|
|
9449
|
-
if (baselineMode
|
|
9450
|
-
|
|
9559
|
+
if (baselineMode === "percentage") {
|
|
9560
|
+
format = "0.0%";
|
|
9451
9561
|
}
|
|
9452
|
-
|
|
9453
|
-
|
|
9562
|
+
if (!format) {
|
|
9563
|
+
value = Math.round(value * 100) / 100;
|
|
9564
|
+
}
|
|
9565
|
+
}
|
|
9566
|
+
if (humanize) {
|
|
9567
|
+
return humanizeNumber({ value, format }, locale);
|
|
9454
9568
|
}
|
|
9569
|
+
return formatValue(value, { format, locale });
|
|
9570
|
+
}
|
|
9571
|
+
function getKeyValueText(keyValueCell, humanize, locale) {
|
|
9572
|
+
if (!keyValueCell) {
|
|
9573
|
+
return "";
|
|
9574
|
+
}
|
|
9575
|
+
if (humanize) {
|
|
9576
|
+
return humanizeNumber(keyValueCell, locale);
|
|
9577
|
+
}
|
|
9578
|
+
return keyValueCell.formattedValue ?? String(keyValueCell.value ?? "");
|
|
9455
9579
|
}
|
|
9456
9580
|
function getBaselineColor(baseline, baselineMode, keyValue, colorUp, colorDown) {
|
|
9457
9581
|
if (baselineMode === "text" ||
|
|
9582
|
+
baselineMode === "progress" ||
|
|
9458
9583
|
baseline?.type !== CellValueType.number ||
|
|
9459
9584
|
keyValue?.type !== CellValueType.number) {
|
|
9460
9585
|
return undefined;
|
|
@@ -9483,17 +9608,6 @@ function getBaselineArrowDirection(baseline, keyValue, baselineMode) {
|
|
|
9483
9608
|
}
|
|
9484
9609
|
return "neutral";
|
|
9485
9610
|
}
|
|
9486
|
-
function getChartPositionAtCenterOfViewport(getters, chartSize) {
|
|
9487
|
-
const { x, y } = getters.getMainViewportCoordinates();
|
|
9488
|
-
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
9489
|
-
const { width, height } = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
9490
|
-
const position = {
|
|
9491
|
-
x: x + scrollX + Math.max(0, (width - chartSize.width) / 2),
|
|
9492
|
-
y: y + scrollY + Math.max(0, (height - chartSize.height) / 2),
|
|
9493
|
-
}; // Position at the center of the scrollable viewport
|
|
9494
|
-
return position;
|
|
9495
|
-
}
|
|
9496
|
-
|
|
9497
9611
|
function checkKeyValue(definition) {
|
|
9498
9612
|
return definition.keyValue && !rangeReference.test(definition.keyValue)
|
|
9499
9613
|
? "InvalidScorecardKeyValue" /* CommandResult.InvalidScorecardKeyValue */
|
|
@@ -9511,10 +9625,12 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
9511
9625
|
baseline;
|
|
9512
9626
|
baselineMode;
|
|
9513
9627
|
baselineDescr;
|
|
9628
|
+
progressBar = false;
|
|
9514
9629
|
background;
|
|
9515
9630
|
baselineColorUp;
|
|
9516
9631
|
baselineColorDown;
|
|
9517
9632
|
fontColor;
|
|
9633
|
+
humanize;
|
|
9518
9634
|
type = "scorecard";
|
|
9519
9635
|
constructor(definition, sheetId, getters) {
|
|
9520
9636
|
super(definition, sheetId, getters);
|
|
@@ -9525,6 +9641,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
9525
9641
|
this.background = definition.background;
|
|
9526
9642
|
this.baselineColorUp = definition.baselineColorUp;
|
|
9527
9643
|
this.baselineColorDown = definition.baselineColorDown;
|
|
9644
|
+
this.humanize = definition.humanize ?? false;
|
|
9528
9645
|
}
|
|
9529
9646
|
static validateChartDefinition(validator, definition) {
|
|
9530
9647
|
return validator.checkValidations(definition, checkKeyValue, checkBaseline);
|
|
@@ -9594,6 +9711,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
9594
9711
|
keyValue: keyValue
|
|
9595
9712
|
? this.getters.getRangeString(keyValue, targetSheetId || this.sheetId)
|
|
9596
9713
|
: undefined,
|
|
9714
|
+
humanize: this.humanize,
|
|
9597
9715
|
};
|
|
9598
9716
|
}
|
|
9599
9717
|
getDefinitionForExcel() {
|
|
@@ -9619,7 +9737,7 @@ function drawScoreChart(structure, canvas) {
|
|
|
9619
9737
|
if (structure.title) {
|
|
9620
9738
|
ctx.font = structure.title.style.font;
|
|
9621
9739
|
ctx.fillStyle = structure.title.style.color;
|
|
9622
|
-
ctx.fillText(structure.title.text, structure.title.position.x, structure.title.position.y);
|
|
9740
|
+
ctx.fillText(clipTextWithEllipsis(ctx, structure.title.text, canvas.width - structure.title.position.x), structure.title.position.x, structure.title.position.y);
|
|
9623
9741
|
}
|
|
9624
9742
|
if (structure.baseline) {
|
|
9625
9743
|
ctx.font = structure.baseline.style.font;
|
|
@@ -9646,20 +9764,41 @@ function drawScoreChart(structure, canvas) {
|
|
|
9646
9764
|
ctx.restore();
|
|
9647
9765
|
}
|
|
9648
9766
|
if (structure.baselineDescr) {
|
|
9649
|
-
|
|
9650
|
-
ctx.
|
|
9651
|
-
ctx.
|
|
9767
|
+
const descr = structure.baselineDescr[0];
|
|
9768
|
+
ctx.font = descr.style.font;
|
|
9769
|
+
ctx.fillStyle = descr.style.color;
|
|
9770
|
+
for (const description of structure.baselineDescr) {
|
|
9771
|
+
ctx.fillText(clipTextWithEllipsis(ctx, description.text, canvas.width - description.position.x), description.position.x, description.position.y);
|
|
9772
|
+
}
|
|
9652
9773
|
}
|
|
9653
9774
|
if (structure.key) {
|
|
9654
9775
|
ctx.font = structure.key.style.font;
|
|
9655
9776
|
ctx.fillStyle = structure.key.style.color;
|
|
9656
9777
|
drawDecoratedText(ctx, structure.key.text, structure.key.position, structure.key.style.underline, structure.key.style.strikethrough);
|
|
9657
9778
|
}
|
|
9779
|
+
if (structure.progressBar) {
|
|
9780
|
+
ctx.fillStyle = structure.progressBar.style.backgroundColor;
|
|
9781
|
+
ctx.beginPath();
|
|
9782
|
+
ctx.roundRect(structure.progressBar.position.x, structure.progressBar.position.y, structure.progressBar.dimension.width, structure.progressBar.dimension.height, structure.progressBar.dimension.height / 2);
|
|
9783
|
+
ctx.fill();
|
|
9784
|
+
ctx.fillStyle = structure.progressBar.style.color;
|
|
9785
|
+
ctx.beginPath();
|
|
9786
|
+
if (structure.progressBar.value > 0) {
|
|
9787
|
+
ctx.roundRect(structure.progressBar.position.x, structure.progressBar.position.y, structure.progressBar.dimension.width *
|
|
9788
|
+
Math.max(0, Math.min(1.0, structure.progressBar.value)), structure.progressBar.dimension.height, structure.progressBar.dimension.height / 2);
|
|
9789
|
+
}
|
|
9790
|
+
else {
|
|
9791
|
+
const width = structure.progressBar.dimension.width *
|
|
9792
|
+
Math.max(0, Math.min(1.0, -structure.progressBar.value));
|
|
9793
|
+
ctx.roundRect(structure.progressBar.position.x + structure.progressBar.dimension.width - width, structure.progressBar.position.y, width, structure.progressBar.dimension.height, structure.progressBar.dimension.height / 2);
|
|
9794
|
+
}
|
|
9795
|
+
ctx.fill();
|
|
9796
|
+
}
|
|
9658
9797
|
}
|
|
9659
9798
|
function createScorecardChartRuntime(chart, getters) {
|
|
9660
|
-
let keyValue = "";
|
|
9661
9799
|
let formattedKeyValue = "";
|
|
9662
9800
|
let keyValueCell;
|
|
9801
|
+
const locale = getters.getLocale();
|
|
9663
9802
|
if (chart.keyValue) {
|
|
9664
9803
|
const keyValuePosition = {
|
|
9665
9804
|
sheetId: chart.keyValue.sheetId,
|
|
@@ -9667,31 +9806,33 @@ function createScorecardChartRuntime(chart, getters) {
|
|
|
9667
9806
|
row: chart.keyValue.zone.top,
|
|
9668
9807
|
};
|
|
9669
9808
|
keyValueCell = getters.getEvaluatedCell(keyValuePosition);
|
|
9670
|
-
|
|
9671
|
-
formattedKeyValue = keyValueCell.formattedValue;
|
|
9809
|
+
formattedKeyValue = getKeyValueText(keyValueCell, chart.humanize ?? false, locale);
|
|
9672
9810
|
}
|
|
9673
9811
|
let baselineCell;
|
|
9674
9812
|
const baseline = chart.baseline;
|
|
9675
9813
|
if (baseline) {
|
|
9676
9814
|
const baselinePosition = {
|
|
9677
|
-
sheetId:
|
|
9678
|
-
col:
|
|
9679
|
-
row:
|
|
9815
|
+
sheetId: baseline.sheetId,
|
|
9816
|
+
col: baseline.zone.left,
|
|
9817
|
+
row: baseline.zone.top,
|
|
9680
9818
|
};
|
|
9681
9819
|
baselineCell = getters.getEvaluatedCell(baselinePosition);
|
|
9682
9820
|
}
|
|
9683
9821
|
const { background, fontColor } = getters.getStyleOfSingleCellChart(chart.background, chart.keyValue);
|
|
9684
|
-
const
|
|
9822
|
+
const baselineDisplay = getBaselineText(baselineCell, keyValueCell, chart.baselineMode, chart.humanize ?? false, locale);
|
|
9823
|
+
const baselineValue = chart.baselineMode === "progress" && isNumber(baselineDisplay, locale)
|
|
9824
|
+
? toNumber(baselineDisplay, locale)
|
|
9825
|
+
: 0;
|
|
9685
9826
|
return {
|
|
9686
9827
|
title: _t(chart.title),
|
|
9687
|
-
keyValue: formattedKeyValue
|
|
9688
|
-
baselineDisplay
|
|
9828
|
+
keyValue: formattedKeyValue,
|
|
9829
|
+
baselineDisplay,
|
|
9689
9830
|
baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, chart.baselineMode),
|
|
9690
9831
|
baselineColor: getBaselineColor(baselineCell, chart.baselineMode, keyValueCell, chart.baselineColorUp, chart.baselineColorDown),
|
|
9691
|
-
baselineDescr: chart.baselineDescr ? _t(chart.baselineDescr) : "",
|
|
9832
|
+
baselineDescr: chart.baselineMode !== "progress" && chart.baselineDescr ? _t(chart.baselineDescr) : "",
|
|
9692
9833
|
fontColor,
|
|
9693
9834
|
background,
|
|
9694
|
-
baselineStyle: chart.baselineMode !== "percentage" && baseline
|
|
9835
|
+
baselineStyle: chart.baselineMode !== "percentage" && chart.baselineMode !== "progress" && baseline
|
|
9695
9836
|
? getters.getCellStyle({
|
|
9696
9837
|
sheetId: baseline.sheetId,
|
|
9697
9838
|
col: baseline.zone.left,
|
|
@@ -9705,17 +9846,21 @@ function createScorecardChartRuntime(chart, getters) {
|
|
|
9705
9846
|
row: chart.keyValue.zone.top,
|
|
9706
9847
|
})
|
|
9707
9848
|
: undefined,
|
|
9849
|
+
progressBar: chart.baselineMode === "progress"
|
|
9850
|
+
? {
|
|
9851
|
+
value: baselineValue,
|
|
9852
|
+
color: baselineValue > 0 ? chart.baselineColorUp : chart.baselineColorDown,
|
|
9853
|
+
}
|
|
9854
|
+
: undefined,
|
|
9708
9855
|
};
|
|
9709
9856
|
}
|
|
9710
9857
|
|
|
9711
9858
|
/* Sizes of boxes containing the texts, in percentage of the Chart size */
|
|
9712
9859
|
const TITLE_FONT_SIZE = 18;
|
|
9713
|
-
const
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
const
|
|
9717
|
-
/* Padding at the border of the chart, in percentage of the chart width */
|
|
9718
|
-
const CHART_PADDING_RATIO = 0.02;
|
|
9860
|
+
const KEY_BOX_HEIGHT_RATIO = 0.8;
|
|
9861
|
+
/* Padding at the border of the chart */
|
|
9862
|
+
const CHART_PADDING = 10;
|
|
9863
|
+
const BOTTOM_PADDING_RATIO = 0.05;
|
|
9719
9864
|
/**
|
|
9720
9865
|
* Line height (in em)
|
|
9721
9866
|
* Having a line heigh =1em (=font size) don't work, the font will overflow.
|
|
@@ -9755,31 +9900,37 @@ class ScorecardChartConfigBuilder {
|
|
|
9755
9900
|
},
|
|
9756
9901
|
};
|
|
9757
9902
|
const style = this.getTextStyles();
|
|
9758
|
-
|
|
9903
|
+
let titleHeight = 0;
|
|
9759
9904
|
if (this.title) {
|
|
9905
|
+
({ height: titleHeight } = this.getFullTextDimensions(this.title, style.title.font));
|
|
9760
9906
|
structure.title = {
|
|
9761
9907
|
text: this.title,
|
|
9762
9908
|
style: style.title,
|
|
9763
9909
|
position: {
|
|
9764
|
-
x:
|
|
9765
|
-
y:
|
|
9910
|
+
x: CHART_PADDING,
|
|
9911
|
+
y: CHART_PADDING / 2 + titleHeight,
|
|
9766
9912
|
},
|
|
9767
9913
|
};
|
|
9768
9914
|
}
|
|
9769
9915
|
const baselineArrowSize = style.baselineArrow?.size ?? 0;
|
|
9770
|
-
|
|
9771
|
-
|
|
9916
|
+
let { height: baselineHeight, width: baselineWidth } = this.getTextDimensions(this.baseline, style.baselineValue.font);
|
|
9917
|
+
if (!this.baseline) {
|
|
9918
|
+
baselineHeight = this.getTextDimensions(this.baselineDescr, style.baselineDescr.font).height;
|
|
9919
|
+
}
|
|
9920
|
+
const baselineDescrWidth = style.baselineDescr.isSplit
|
|
9921
|
+
? Math.max(...splitTextInTwoLines(this.baselineDescr).map((line) => this.getTextDimensions(line, style.baselineDescr.font).width))
|
|
9922
|
+
: this.getTextDimensions(this.baselineDescr, style.baselineDescr.font).width;
|
|
9772
9923
|
structure.baseline = {
|
|
9773
9924
|
text: this.baseline,
|
|
9774
9925
|
style: style.baselineValue,
|
|
9775
9926
|
position: {
|
|
9776
9927
|
x: (this.width - baselineWidth - baselineDescrWidth + baselineArrowSize) / 2,
|
|
9777
9928
|
y: this.keyValue
|
|
9778
|
-
? this.height -
|
|
9779
|
-
: this.height - (this.height - titleHeight - baselineHeight) / 2 -
|
|
9929
|
+
? this.height * (1 - BOTTOM_PADDING_RATIO * (this.runtime.progressBar ? 1 : 2))
|
|
9930
|
+
: this.height - (this.height - titleHeight - baselineHeight) / 2 - CHART_PADDING,
|
|
9780
9931
|
},
|
|
9781
9932
|
};
|
|
9782
|
-
if (style.baselineArrow) {
|
|
9933
|
+
if (style.baselineArrow && !this.runtime.progressBar) {
|
|
9783
9934
|
structure.baselineArrow = {
|
|
9784
9935
|
direction: this.baselineArrow,
|
|
9785
9936
|
style: style.baselineArrow,
|
|
@@ -9790,23 +9941,68 @@ class ScorecardChartConfigBuilder {
|
|
|
9790
9941
|
};
|
|
9791
9942
|
}
|
|
9792
9943
|
if (this.baselineDescr) {
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9944
|
+
const position = {
|
|
9945
|
+
x: structure.baseline.position.x + baselineWidth,
|
|
9946
|
+
y: structure.baseline.position.y,
|
|
9947
|
+
};
|
|
9948
|
+
if (style.baselineDescr.isSplit) {
|
|
9949
|
+
const description = splitTextInTwoLines(this.baselineDescr);
|
|
9950
|
+
const measure = this.context.measureText(description[1]);
|
|
9951
|
+
const deltaY = measure.fontBoundingBoxAscent + measure.fontBoundingBoxDescent;
|
|
9952
|
+
structure.baselineDescr = [
|
|
9953
|
+
{
|
|
9954
|
+
text: description[0],
|
|
9955
|
+
style: style.baselineDescr,
|
|
9956
|
+
position: {
|
|
9957
|
+
x: position.x,
|
|
9958
|
+
y: position.y - deltaY,
|
|
9959
|
+
},
|
|
9960
|
+
},
|
|
9961
|
+
{
|
|
9962
|
+
text: description[1],
|
|
9963
|
+
style: style.baselineDescr,
|
|
9964
|
+
position,
|
|
9965
|
+
},
|
|
9966
|
+
];
|
|
9967
|
+
}
|
|
9968
|
+
else {
|
|
9969
|
+
structure.baselineDescr = [
|
|
9970
|
+
{
|
|
9971
|
+
text: this.baselineDescr,
|
|
9972
|
+
style: style.baselineDescr,
|
|
9973
|
+
position,
|
|
9974
|
+
},
|
|
9975
|
+
];
|
|
9976
|
+
}
|
|
9977
|
+
}
|
|
9978
|
+
let progressBarHeight = 0;
|
|
9979
|
+
if (this.runtime.progressBar) {
|
|
9980
|
+
progressBarHeight = this.height * 0.05;
|
|
9981
|
+
structure.progressBar = {
|
|
9796
9982
|
position: {
|
|
9797
|
-
x:
|
|
9798
|
-
y:
|
|
9983
|
+
x: 2 * CHART_PADDING,
|
|
9984
|
+
y: this.height * (1 - 2 * BOTTOM_PADDING_RATIO) - baselineHeight - progressBarHeight,
|
|
9985
|
+
},
|
|
9986
|
+
dimension: {
|
|
9987
|
+
height: progressBarHeight,
|
|
9988
|
+
width: this.width - 4 * CHART_PADDING,
|
|
9989
|
+
},
|
|
9990
|
+
value: this.runtime.progressBar.value,
|
|
9991
|
+
style: {
|
|
9992
|
+
color: this.runtime.progressBar.color,
|
|
9993
|
+
backgroundColor: this.secondaryFontColor,
|
|
9799
9994
|
},
|
|
9800
9995
|
};
|
|
9801
9996
|
}
|
|
9802
|
-
const {
|
|
9997
|
+
const { width: keyWidth, height: keyHeight } = this.getFullTextDimensions(this.keyValue, style.keyValue.font);
|
|
9803
9998
|
if (this.keyValue) {
|
|
9804
9999
|
structure.key = {
|
|
9805
10000
|
text: this.keyValue,
|
|
9806
10001
|
style: style.keyValue,
|
|
9807
10002
|
position: {
|
|
9808
10003
|
x: (this.width - keyWidth) / 2,
|
|
9809
|
-
y:
|
|
10004
|
+
y: this.height * (0.5 - BOTTOM_PADDING_RATIO * 2) +
|
|
10005
|
+
(titleHeight + keyHeight / (this.baseline || this.baselineDescr ? 2 : 1.2)) / 2,
|
|
9810
10006
|
},
|
|
9811
10007
|
};
|
|
9812
10008
|
}
|
|
@@ -9833,9 +10029,6 @@ class ScorecardChartConfigBuilder {
|
|
|
9833
10029
|
get secondaryFontColor() {
|
|
9834
10030
|
return relativeLuminance(this.backgroundColor) > 0.3 ? "#525252" : "#C8C8C8";
|
|
9835
10031
|
}
|
|
9836
|
-
get chartPadding() {
|
|
9837
|
-
return this.width * CHART_PADDING_RATIO;
|
|
9838
|
-
}
|
|
9839
10032
|
getTextDimensions(text, font) {
|
|
9840
10033
|
this.context.font = font;
|
|
9841
10034
|
const measure = this.context.measureText(text);
|
|
@@ -9844,16 +10037,44 @@ class ScorecardChartConfigBuilder {
|
|
|
9844
10037
|
height: measure.actualBoundingBoxAscent + measure.actualBoundingBoxDescent,
|
|
9845
10038
|
};
|
|
9846
10039
|
}
|
|
10040
|
+
getFullTextDimensions(text, font) {
|
|
10041
|
+
this.context.font = font;
|
|
10042
|
+
const measure = this.context.measureText(text);
|
|
10043
|
+
return {
|
|
10044
|
+
width: measure.width,
|
|
10045
|
+
height: measure.fontBoundingBoxAscent + measure.fontBoundingBoxDescent,
|
|
10046
|
+
};
|
|
10047
|
+
}
|
|
9847
10048
|
getTextStyles() {
|
|
9848
10049
|
// If the widest text overflows horizontally, scale it down, and apply the same scaling factors to all the other fonts.
|
|
9849
|
-
const maxLineWidth = this.width
|
|
9850
|
-
const
|
|
9851
|
-
const baseFontSize = widestElement.getElementMaxFontSize(this.getDrawableHeight(), this);
|
|
9852
|
-
const fontSizeMatchingWidth = getFontSizeMatchingWidth(maxLineWidth, baseFontSize, (fontSize) => widestElement.getElementWidth(fontSize, this.context, this));
|
|
9853
|
-
let scalingFactor = fontSizeMatchingWidth / baseFontSize;
|
|
10050
|
+
const maxLineWidth = this.width - 2 * CHART_PADDING;
|
|
10051
|
+
const drawableHeight = this.getDrawableHeight();
|
|
9854
10052
|
// Fonts sizes in px
|
|
9855
|
-
const
|
|
9856
|
-
const
|
|
10053
|
+
const keyValueElement = new KeyValueElement(this.runtime.keyValueStyle);
|
|
10054
|
+
const heightFont = keyValueElement.getElementMaxFontSize(drawableHeight, this);
|
|
10055
|
+
const widthFont = getFontSizeMatchingWidth(maxLineWidth, 600, (fontSize) => keyValueElement.getElementWidth(fontSize, this.context, this));
|
|
10056
|
+
const keyFontSize = Math.min(heightFont, widthFont);
|
|
10057
|
+
let baselineValueFontSize = Math.floor(keyFontSize * 0.5);
|
|
10058
|
+
this.context.font = getDefaultContextFont(baselineValueFontSize, this.runtime.baselineStyle?.bold, this.runtime.baselineStyle?.italic);
|
|
10059
|
+
const baselineText = this.baselineArrow !== "neutral" ? "A " + this.baseline : this.baseline;
|
|
10060
|
+
const baselineValueWidth = computeCachedTextWidth(this.context, baselineText);
|
|
10061
|
+
const remainingWidth = maxLineWidth - baselineValueWidth;
|
|
10062
|
+
let baselineDescrFontSize = getFontSizeMatchingWidth(remainingWidth, baselineValueFontSize, (fontSize) => computeTextWidth(this.context, this.baselineDescr, { fontSize }));
|
|
10063
|
+
let isBaselineSplit = false;
|
|
10064
|
+
if (baselineDescrFontSize < baselineValueFontSize / 2.5) {
|
|
10065
|
+
isBaselineSplit = true;
|
|
10066
|
+
baselineDescrFontSize = Math.floor(baselineValueFontSize / 2.5);
|
|
10067
|
+
for (const line of splitTextInTwoLines(this.baselineDescr)) {
|
|
10068
|
+
const lineWidth = getFontSizeMatchingWidth(remainingWidth, baselineValueFontSize, (fontSize) => {
|
|
10069
|
+
this.context.font = getDefaultContextFont(fontSize);
|
|
10070
|
+
return this.context.measureText(line).width;
|
|
10071
|
+
});
|
|
10072
|
+
baselineDescrFontSize = Math.min(baselineDescrFontSize, lineWidth);
|
|
10073
|
+
}
|
|
10074
|
+
}
|
|
10075
|
+
if (this.runtime.progressBar) {
|
|
10076
|
+
baselineValueFontSize /= 1.5;
|
|
10077
|
+
}
|
|
9857
10078
|
return {
|
|
9858
10079
|
title: {
|
|
9859
10080
|
font: getDefaultContextFont(TITLE_FONT_SIZE),
|
|
@@ -9866,7 +10087,7 @@ class ScorecardChartConfigBuilder {
|
|
|
9866
10087
|
underline: this.runtime.keyValueStyle?.underline,
|
|
9867
10088
|
},
|
|
9868
10089
|
baselineValue: {
|
|
9869
|
-
font: getDefaultContextFont(
|
|
10090
|
+
font: getDefaultContextFont(baselineValueFontSize, this.runtime.baselineStyle?.bold, this.runtime.baselineStyle?.italic),
|
|
9870
10091
|
strikethrough: this.runtime.baselineStyle?.strikethrough,
|
|
9871
10092
|
underline: this.runtime.baselineStyle?.underline,
|
|
9872
10093
|
color: this.runtime.baselineStyle?.textColor ||
|
|
@@ -9874,33 +10095,25 @@ class ScorecardChartConfigBuilder {
|
|
|
9874
10095
|
this.secondaryFontColor,
|
|
9875
10096
|
},
|
|
9876
10097
|
baselineDescr: {
|
|
9877
|
-
font: getDefaultContextFont(
|
|
10098
|
+
font: getDefaultContextFont(baselineDescrFontSize),
|
|
10099
|
+
isSplit: isBaselineSplit,
|
|
9878
10100
|
color: this.secondaryFontColor,
|
|
9879
10101
|
},
|
|
9880
|
-
baselineArrow: this.baselineArrow === "neutral"
|
|
10102
|
+
baselineArrow: this.baselineArrow === "neutral" || this.runtime.progressBar
|
|
9881
10103
|
? undefined
|
|
9882
10104
|
: {
|
|
9883
|
-
size: this.keyValue ? 0.8 *
|
|
10105
|
+
size: this.keyValue ? 0.8 * baselineValueFontSize : 0,
|
|
9884
10106
|
color: this.runtime.baselineColor || this.secondaryFontColor,
|
|
9885
10107
|
},
|
|
9886
10108
|
};
|
|
9887
10109
|
}
|
|
9888
10110
|
/** Get the height of the chart minus all the vertical paddings */
|
|
9889
10111
|
getDrawableHeight() {
|
|
9890
|
-
const verticalPadding =
|
|
9891
|
-
let availableHeight = this.height - verticalPadding;
|
|
10112
|
+
const verticalPadding = CHART_PADDING + this.height * BOTTOM_PADDING_RATIO;
|
|
10113
|
+
let availableHeight = this.height - 2 * verticalPadding;
|
|
9892
10114
|
availableHeight -= this.title ? TITLE_FONT_SIZE * LINE_HEIGHT : 0;
|
|
9893
10115
|
return availableHeight;
|
|
9894
10116
|
}
|
|
9895
|
-
/** Return the element with he widest text in the chart */
|
|
9896
|
-
getWidestElement() {
|
|
9897
|
-
const baseline = new BaselineElement(this.runtime.baselineStyle);
|
|
9898
|
-
const keyValue = new KeyValueElement(this.runtime.keyValueStyle);
|
|
9899
|
-
return baseline.getElementWidth(BASELINE_BOX_HEIGHT_RATIO, this.context, this) >
|
|
9900
|
-
keyValue.getElementWidth(KEY_BOX_HEIGHT_RATIO, this.context, this)
|
|
9901
|
-
? baseline
|
|
9902
|
-
: keyValue;
|
|
9903
|
-
}
|
|
9904
10117
|
}
|
|
9905
10118
|
class ScorecardScalableElement {
|
|
9906
10119
|
style;
|
|
@@ -9909,29 +10122,7 @@ class ScorecardScalableElement {
|
|
|
9909
10122
|
}
|
|
9910
10123
|
measureTextWidth(ctx, text, fontSize) {
|
|
9911
10124
|
ctx.font = getDefaultContextFont(fontSize, this.style.bold, this.style.italic);
|
|
9912
|
-
return ctx
|
|
9913
|
-
}
|
|
9914
|
-
}
|
|
9915
|
-
class BaselineElement extends ScorecardScalableElement {
|
|
9916
|
-
getElementWidth(fontSize, ctx, chart) {
|
|
9917
|
-
if (!chart.runtime) {
|
|
9918
|
-
return 0;
|
|
9919
|
-
}
|
|
9920
|
-
const baselineStr = chart.baseline;
|
|
9921
|
-
// Put mock text to simulate the width of the up/down arrow
|
|
9922
|
-
const largeText = chart.baselineArrow !== "neutral" ? "A " + baselineStr : baselineStr;
|
|
9923
|
-
let textWidth = this.measureTextWidth(ctx, largeText, fontSize);
|
|
9924
|
-
// Baseline descr font size should be smaller than baseline font size
|
|
9925
|
-
textWidth += this.measureTextWidth(ctx, chart.baselineDescr, fontSize * BASELINE_DESCR_FONT_RATIO);
|
|
9926
|
-
return textWidth;
|
|
9927
|
-
}
|
|
9928
|
-
getElementMaxFontSize(availableHeight, chart) {
|
|
9929
|
-
if (!chart.runtime) {
|
|
9930
|
-
return 0;
|
|
9931
|
-
}
|
|
9932
|
-
const haveBaseline = chart.baseline !== "" || chart.baselineDescr;
|
|
9933
|
-
const maxHeight = haveBaseline ? BASELINE_BOX_HEIGHT_RATIO * availableHeight : 0;
|
|
9934
|
-
return maxHeight / LINE_HEIGHT;
|
|
10125
|
+
return computeCachedTextWidth(ctx, text);
|
|
9935
10126
|
}
|
|
9936
10127
|
}
|
|
9937
10128
|
class KeyValueElement extends ScorecardScalableElement {
|
|
@@ -10861,33 +11052,6 @@ var array = /*#__PURE__*/Object.freeze({
|
|
|
10861
11052
|
// -----------------------------------------------------------------------------
|
|
10862
11053
|
// FORMAT.LARGE.NUMBER
|
|
10863
11054
|
// -----------------------------------------------------------------------------
|
|
10864
|
-
function formatLargeNumber(arg, unit, locale) {
|
|
10865
|
-
const value = Math.abs(toNumber(arg?.value, locale));
|
|
10866
|
-
const format = arg?.format;
|
|
10867
|
-
if (unit !== undefined) {
|
|
10868
|
-
const postFix = unit?.value;
|
|
10869
|
-
switch (postFix) {
|
|
10870
|
-
case "k":
|
|
10871
|
-
return createLargeNumberFormat(format, 1e3, "k");
|
|
10872
|
-
case "m":
|
|
10873
|
-
return createLargeNumberFormat(format, 1e6, "m");
|
|
10874
|
-
case "b":
|
|
10875
|
-
return createLargeNumberFormat(format, 1e9, "b");
|
|
10876
|
-
default:
|
|
10877
|
-
throw new EvaluationError(_t("The formatting unit should be 'k', 'm' or 'b'."));
|
|
10878
|
-
}
|
|
10879
|
-
}
|
|
10880
|
-
if (value < 1e5) {
|
|
10881
|
-
return createLargeNumberFormat(format, 0, "");
|
|
10882
|
-
}
|
|
10883
|
-
else if (value < 1e8) {
|
|
10884
|
-
return createLargeNumberFormat(format, 1e3, "k");
|
|
10885
|
-
}
|
|
10886
|
-
else if (value < 1e11) {
|
|
10887
|
-
return createLargeNumberFormat(format, 1e6, "m");
|
|
10888
|
-
}
|
|
10889
|
-
return createLargeNumberFormat(format, 1e9, "b");
|
|
10890
|
-
}
|
|
10891
11055
|
const FORMAT_LARGE_NUMBER = {
|
|
10892
11056
|
description: _t("Apply a large number format"),
|
|
10893
11057
|
args: [
|
|
@@ -11049,7 +11213,7 @@ const ATAN2 = {
|
|
|
11049
11213
|
compute: function (x, y) {
|
|
11050
11214
|
const _x = toNumber(x, this.locale);
|
|
11051
11215
|
const _y = toNumber(y, this.locale);
|
|
11052
|
-
assert(() => _x !== 0 || _y !== 0, _t("Function [[FUNCTION_NAME]] caused a divide by zero error."));
|
|
11216
|
+
assert(() => _x !== 0 || _y !== 0, _t("Function [[FUNCTION_NAME]] caused a divide by zero error."), CellErrorType.DivisionByZero);
|
|
11053
11217
|
return Math.atan2(_y, _x);
|
|
11054
11218
|
},
|
|
11055
11219
|
isExported: true,
|
|
@@ -11179,7 +11343,7 @@ const COT = {
|
|
|
11179
11343
|
returns: ["NUMBER"],
|
|
11180
11344
|
compute: function (angle) {
|
|
11181
11345
|
const _angle = toNumber(angle, this.locale);
|
|
11182
|
-
|
|
11346
|
+
assertNotZero(_angle);
|
|
11183
11347
|
return 1 / Math.tan(_angle);
|
|
11184
11348
|
},
|
|
11185
11349
|
isExported: true,
|
|
@@ -11193,7 +11357,7 @@ const COTH = {
|
|
|
11193
11357
|
returns: ["NUMBER"],
|
|
11194
11358
|
compute: function (value) {
|
|
11195
11359
|
const _value = toNumber(value, this.locale);
|
|
11196
|
-
|
|
11360
|
+
assertNotZero(_value);
|
|
11197
11361
|
return 1 / Math.tanh(_value);
|
|
11198
11362
|
},
|
|
11199
11363
|
isExported: true,
|
|
@@ -11321,7 +11485,7 @@ const CSC = {
|
|
|
11321
11485
|
returns: ["NUMBER"],
|
|
11322
11486
|
compute: function (angle) {
|
|
11323
11487
|
const _angle = toNumber(angle, this.locale);
|
|
11324
|
-
|
|
11488
|
+
assertNotZero(_angle);
|
|
11325
11489
|
return 1 / Math.sin(_angle);
|
|
11326
11490
|
},
|
|
11327
11491
|
isExported: true,
|
|
@@ -11335,7 +11499,7 @@ const CSCH = {
|
|
|
11335
11499
|
returns: ["NUMBER"],
|
|
11336
11500
|
compute: function (value) {
|
|
11337
11501
|
const _value = toNumber(value, this.locale);
|
|
11338
|
-
|
|
11502
|
+
assertNotZero(_value);
|
|
11339
11503
|
return 1 / Math.sinh(_value);
|
|
11340
11504
|
},
|
|
11341
11505
|
isExported: true,
|
|
@@ -11534,7 +11698,7 @@ const LN = {
|
|
|
11534
11698
|
// MOD
|
|
11535
11699
|
// -----------------------------------------------------------------------------
|
|
11536
11700
|
function mod(dividend, divisor) {
|
|
11537
|
-
assert(() => divisor !== 0, _t("The divisor must be different from 0."));
|
|
11701
|
+
assert(() => divisor !== 0, _t("The divisor must be different from 0."), CellErrorType.DivisionByZero);
|
|
11538
11702
|
const modulus = dividend % divisor;
|
|
11539
11703
|
// -42 % 10 = -2 but we want 8, so need the code below
|
|
11540
11704
|
if ((modulus > 0 && divisor < 0) || (modulus < 0 && divisor > 0)) {
|
|
@@ -12103,7 +12267,7 @@ function average(values, locale) {
|
|
|
12103
12267
|
count += 1;
|
|
12104
12268
|
return acc + a;
|
|
12105
12269
|
}, 0, locale);
|
|
12106
|
-
|
|
12270
|
+
assertNotZero(count);
|
|
12107
12271
|
return sum / count;
|
|
12108
12272
|
}
|
|
12109
12273
|
function countNumbers(values, locale) {
|
|
@@ -12170,7 +12334,7 @@ function filterAndFlatData(dataY, dataX) {
|
|
|
12170
12334
|
function covariance(dataY, dataX, isSample) {
|
|
12171
12335
|
const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
|
|
12172
12336
|
const count = flatDataY.length;
|
|
12173
|
-
assert(() => count !== 0 && (!isSample || count !== 1), _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."));
|
|
12337
|
+
assert(() => count !== 0 && (!isSample || count !== 1), _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."), CellErrorType.DivisionByZero);
|
|
12174
12338
|
let sumY = 0;
|
|
12175
12339
|
let sumX = 0;
|
|
12176
12340
|
for (let i = 0; i < count; i++) {
|
|
@@ -12193,7 +12357,7 @@ function variance(args, isSample, textAs0, locale) {
|
|
|
12193
12357
|
count += 1;
|
|
12194
12358
|
return acc + a;
|
|
12195
12359
|
}, 0, locale);
|
|
12196
|
-
assert(() => count !== 0 && (!isSample || count !== 1), _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."));
|
|
12360
|
+
assert(() => count !== 0 && (!isSample || count !== 1), _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."), CellErrorType.DivisionByZero);
|
|
12197
12361
|
const average = sum / count;
|
|
12198
12362
|
return (reduceFunction(args, (acc, a) => acc + Math.pow(a - average, 2), 0, locale) /
|
|
12199
12363
|
(count - (isSample ? 1 : 0)));
|
|
@@ -12390,7 +12554,7 @@ const AVEDEV = {
|
|
|
12390
12554
|
count += 1;
|
|
12391
12555
|
return acc + a;
|
|
12392
12556
|
}, 0, this.locale);
|
|
12393
|
-
|
|
12557
|
+
assertNotZero(count);
|
|
12394
12558
|
const average = sum / count;
|
|
12395
12559
|
return reduceNumbers(values, (acc, a) => acc + Math.abs(average - a), 0, this.locale) / count;
|
|
12396
12560
|
},
|
|
@@ -12462,7 +12626,7 @@ const AVERAGE_WEIGHTED = {
|
|
|
12462
12626
|
}
|
|
12463
12627
|
}
|
|
12464
12628
|
}
|
|
12465
|
-
|
|
12629
|
+
assertNotZero(count);
|
|
12466
12630
|
return { value: sum / count, format: inferFormat(args[0]) };
|
|
12467
12631
|
},
|
|
12468
12632
|
};
|
|
@@ -12482,7 +12646,7 @@ const AVERAGEA = {
|
|
|
12482
12646
|
count += 1;
|
|
12483
12647
|
return acc + a;
|
|
12484
12648
|
}, 0, this.locale);
|
|
12485
|
-
|
|
12649
|
+
assertNotZero(count);
|
|
12486
12650
|
return {
|
|
12487
12651
|
value: sum / count,
|
|
12488
12652
|
format: inferFormat(args[0]),
|
|
@@ -12512,7 +12676,7 @@ const AVERAGEIF = {
|
|
|
12512
12676
|
sum += value;
|
|
12513
12677
|
}
|
|
12514
12678
|
}, this.locale);
|
|
12515
|
-
|
|
12679
|
+
assertNotZero(count);
|
|
12516
12680
|
return sum / count;
|
|
12517
12681
|
},
|
|
12518
12682
|
isExported: true,
|
|
@@ -12541,7 +12705,7 @@ const AVERAGEIFS = {
|
|
|
12541
12705
|
sum += value;
|
|
12542
12706
|
}
|
|
12543
12707
|
}, this.locale);
|
|
12544
|
-
|
|
12708
|
+
assertNotZero(count);
|
|
12545
12709
|
return sum / count;
|
|
12546
12710
|
},
|
|
12547
12711
|
isExported: true,
|
|
@@ -17966,7 +18130,7 @@ const DIVIDE = {
|
|
|
17966
18130
|
returns: ["NUMBER"],
|
|
17967
18131
|
compute: function (dividend, divisor) {
|
|
17968
18132
|
const _divisor = toNumber(divisor, this.locale);
|
|
17969
|
-
assert(() => _divisor !== 0, _t("The divisor must be different from zero."));
|
|
18133
|
+
assert(() => _divisor !== 0, _t("The divisor must be different from zero."), CellErrorType.DivisionByZero);
|
|
17970
18134
|
return {
|
|
17971
18135
|
value: toNumber(dividend, this.locale) / _divisor,
|
|
17972
18136
|
format: dividend?.format || divisor?.format,
|
|
@@ -21011,7 +21175,21 @@ class ScatterChart extends AbstractChart {
|
|
|
21011
21175
|
return new ScatterChart(definition, this.sheetId, this.getters);
|
|
21012
21176
|
}
|
|
21013
21177
|
getDefinitionForExcel() {
|
|
21014
|
-
|
|
21178
|
+
// Excel does not support aggregating labels
|
|
21179
|
+
if (this.aggregated) {
|
|
21180
|
+
return undefined;
|
|
21181
|
+
}
|
|
21182
|
+
const dataSets = this.dataSets
|
|
21183
|
+
.map((ds) => toExcelDataset(this.getters, ds))
|
|
21184
|
+
.filter((ds) => ds.range !== "");
|
|
21185
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
21186
|
+
return {
|
|
21187
|
+
...this.getDefinition(),
|
|
21188
|
+
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
21189
|
+
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
21190
|
+
dataSets,
|
|
21191
|
+
labelRange,
|
|
21192
|
+
};
|
|
21015
21193
|
}
|
|
21016
21194
|
copyForSheetId(sheetId) {
|
|
21017
21195
|
const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
|
|
@@ -27439,13 +27617,30 @@ class ColorPickerWidget extends Component {
|
|
|
27439
27617
|
}
|
|
27440
27618
|
}
|
|
27441
27619
|
|
|
27442
|
-
|
|
27443
|
-
|
|
27444
|
-
|
|
27620
|
+
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
27621
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
27622
|
+
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
27623
|
+
</svg>
|
|
27624
|
+
`;
|
|
27625
|
+
css /* scss */ `
|
|
27626
|
+
.o-round-color-picker-button {
|
|
27627
|
+
width: 15px;
|
|
27628
|
+
height: 15px;
|
|
27629
|
+
cursor: pointer;
|
|
27630
|
+
border: 1px solid #aaa;
|
|
27631
|
+
background-position: 1px 1px;
|
|
27632
|
+
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
27633
|
+
}
|
|
27634
|
+
`;
|
|
27635
|
+
class RoundColorPicker extends Component {
|
|
27636
|
+
static template = "o-spreadsheet.RoundColorPicker";
|
|
27637
|
+
static components = { ColorPickerWidget, Section, ColorPicker };
|
|
27445
27638
|
static props = {
|
|
27446
27639
|
currentColor: { type: String, optional: true },
|
|
27640
|
+
title: { type: String, optional: true },
|
|
27447
27641
|
onColorPicked: Function,
|
|
27448
27642
|
};
|
|
27643
|
+
colorPickerButtonRef = useRef("colorPickerButton");
|
|
27449
27644
|
state;
|
|
27450
27645
|
setup() {
|
|
27451
27646
|
this.state = useState({ pickerOpened: false });
|
|
@@ -27457,6 +27652,19 @@ class ChartColor extends Component {
|
|
|
27457
27652
|
togglePicker() {
|
|
27458
27653
|
this.state.pickerOpened = !this.state.pickerOpened;
|
|
27459
27654
|
}
|
|
27655
|
+
onColorPicked(color) {
|
|
27656
|
+
this.props.onColorPicked(color);
|
|
27657
|
+
this.state.pickerOpened = false;
|
|
27658
|
+
}
|
|
27659
|
+
get colorPickerAnchorRect() {
|
|
27660
|
+
const button = this.colorPickerButtonRef.el;
|
|
27661
|
+
return getBoundingRectAsPOJO(button);
|
|
27662
|
+
}
|
|
27663
|
+
get buttonStyle() {
|
|
27664
|
+
return cssPropertiesToCss({
|
|
27665
|
+
background: this.props.currentColor,
|
|
27666
|
+
});
|
|
27667
|
+
}
|
|
27460
27668
|
}
|
|
27461
27669
|
|
|
27462
27670
|
class ChartTitle extends Component {
|
|
@@ -27470,7 +27678,7 @@ class ChartTitle extends Component {
|
|
|
27470
27678
|
|
|
27471
27679
|
class LineBarPieDesignPanel extends Component {
|
|
27472
27680
|
static template = "o-spreadsheet-LineBarPieDesignPanel";
|
|
27473
|
-
static components = {
|
|
27681
|
+
static components = { RoundColorPicker, ChartTitle, Section };
|
|
27474
27682
|
static props = {
|
|
27475
27683
|
figureId: String,
|
|
27476
27684
|
definition: Object,
|
|
@@ -27493,6 +27701,9 @@ class LineBarPieDesignPanel extends Component {
|
|
|
27493
27701
|
[attr]: ev.target.value,
|
|
27494
27702
|
});
|
|
27495
27703
|
}
|
|
27704
|
+
get backgroundColorTitle() {
|
|
27705
|
+
return ChartTerms.BackgroundColor;
|
|
27706
|
+
}
|
|
27496
27707
|
}
|
|
27497
27708
|
|
|
27498
27709
|
class BarChartDesignPanel extends LineBarPieDesignPanel {
|
|
@@ -27562,6 +27773,10 @@ css /* scss */ `
|
|
|
27562
27773
|
line-height: 18px;
|
|
27563
27774
|
width: 100%;
|
|
27564
27775
|
}
|
|
27776
|
+
td {
|
|
27777
|
+
box-sizing: border-box;
|
|
27778
|
+
height: 30px;
|
|
27779
|
+
}
|
|
27565
27780
|
th.o-gauge-color-set-colorPicker {
|
|
27566
27781
|
width: 8%;
|
|
27567
27782
|
}
|
|
@@ -27584,7 +27799,12 @@ css /* scss */ `
|
|
|
27584
27799
|
`;
|
|
27585
27800
|
class GaugeChartDesignPanel extends Component {
|
|
27586
27801
|
static template = "o-spreadsheet-GaugeChartDesignPanel";
|
|
27587
|
-
static components = {
|
|
27802
|
+
static components = {
|
|
27803
|
+
ChartErrorSection,
|
|
27804
|
+
RoundColorPicker,
|
|
27805
|
+
ChartTitle,
|
|
27806
|
+
Section,
|
|
27807
|
+
};
|
|
27588
27808
|
static props = {
|
|
27589
27809
|
figureId: String,
|
|
27590
27810
|
definition: Object,
|
|
@@ -27596,9 +27816,6 @@ class GaugeChartDesignPanel extends Component {
|
|
|
27596
27816
|
sectionRuleDispatchResult: undefined,
|
|
27597
27817
|
sectionRule: deepCopy(this.props.definition.sectionRule),
|
|
27598
27818
|
});
|
|
27599
|
-
setup() {
|
|
27600
|
-
useExternalListener(window, "click", this.closeMenus);
|
|
27601
|
-
}
|
|
27602
27819
|
get title() {
|
|
27603
27820
|
return _t(this.props.definition.title);
|
|
27604
27821
|
}
|
|
@@ -27639,27 +27856,22 @@ class GaugeChartDesignPanel extends Component {
|
|
|
27639
27856
|
const sectionRule = deepCopy(this.state.sectionRule);
|
|
27640
27857
|
sectionRule.colors[target] = color;
|
|
27641
27858
|
this.updateSectionRule(sectionRule);
|
|
27642
|
-
this.closeMenus();
|
|
27643
|
-
}
|
|
27644
|
-
toggleMenu(menu) {
|
|
27645
|
-
const isSelected = this.state.openedMenu === menu;
|
|
27646
|
-
this.closeMenus();
|
|
27647
|
-
if (!isSelected) {
|
|
27648
|
-
this.state.openedMenu = menu;
|
|
27649
|
-
}
|
|
27650
27859
|
}
|
|
27651
27860
|
updateSectionRule(sectionRule) {
|
|
27652
27861
|
this.state.sectionRuleDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
27653
27862
|
sectionRule,
|
|
27654
27863
|
});
|
|
27864
|
+
if (this.state.sectionRuleDispatchResult.isSuccessful) {
|
|
27865
|
+
this.state.sectionRule = deepCopy(sectionRule);
|
|
27866
|
+
}
|
|
27655
27867
|
}
|
|
27656
27868
|
canUpdateSectionRule(sectionRule) {
|
|
27657
27869
|
this.state.sectionRuleDispatchResult = this.props.canUpdateChart(this.props.figureId, {
|
|
27658
27870
|
sectionRule,
|
|
27659
27871
|
});
|
|
27660
27872
|
}
|
|
27661
|
-
|
|
27662
|
-
|
|
27873
|
+
get backgroundColorTitle() {
|
|
27874
|
+
return ChartTerms.BackgroundColor;
|
|
27663
27875
|
}
|
|
27664
27876
|
}
|
|
27665
27877
|
|
|
@@ -27807,39 +28019,36 @@ class ScorecardChartConfigPanel extends Component {
|
|
|
27807
28019
|
|
|
27808
28020
|
class ScorecardChartDesignPanel extends Component {
|
|
27809
28021
|
static template = "o-spreadsheet-ScorecardChartDesignPanel";
|
|
27810
|
-
static components = {
|
|
28022
|
+
static components = { RoundColorPicker, ChartTitle, Section, Checkbox };
|
|
27811
28023
|
static props = {
|
|
27812
28024
|
figureId: String,
|
|
27813
28025
|
definition: Object,
|
|
27814
28026
|
updateChart: Function,
|
|
27815
28027
|
canUpdateChart: Function,
|
|
27816
28028
|
};
|
|
27817
|
-
state = useState({
|
|
27818
|
-
openedColorPicker: undefined,
|
|
27819
|
-
});
|
|
27820
|
-
setup() {
|
|
27821
|
-
useExternalListener(window, "click", this.closeMenus);
|
|
27822
|
-
}
|
|
27823
28029
|
get title() {
|
|
27824
28030
|
return _t(this.props.definition.title);
|
|
27825
28031
|
}
|
|
28032
|
+
get colorsSectionTitle() {
|
|
28033
|
+
return this.props.definition.baselineMode === "progress"
|
|
28034
|
+
? _t("Progress bar colors")
|
|
28035
|
+
: _t("Baseline colors");
|
|
28036
|
+
}
|
|
28037
|
+
get humanizeNumbersLabel() {
|
|
28038
|
+
return _t("Humanize numbers");
|
|
28039
|
+
}
|
|
27826
28040
|
updateTitle(title) {
|
|
27827
28041
|
this.props.updateChart(this.props.figureId, { title });
|
|
27828
28042
|
}
|
|
28043
|
+
updateHumanizeNumbers(humanize) {
|
|
28044
|
+
this.props.updateChart(this.props.figureId, { humanize });
|
|
28045
|
+
}
|
|
27829
28046
|
translate(term) {
|
|
27830
28047
|
return _t(term);
|
|
27831
28048
|
}
|
|
27832
28049
|
updateBaselineDescr(ev) {
|
|
27833
28050
|
this.props.updateChart(this.props.figureId, { baselineDescr: ev.target.value });
|
|
27834
28051
|
}
|
|
27835
|
-
toggleColorPicker(colorPickerId) {
|
|
27836
|
-
if (this.state.openedColorPicker === colorPickerId) {
|
|
27837
|
-
this.state.openedColorPicker = undefined;
|
|
27838
|
-
}
|
|
27839
|
-
else {
|
|
27840
|
-
this.state.openedColorPicker = colorPickerId;
|
|
27841
|
-
}
|
|
27842
|
-
}
|
|
27843
28052
|
setColor(color, colorPickerId) {
|
|
27844
28053
|
switch (colorPickerId) {
|
|
27845
28054
|
case "backgroundColor":
|
|
@@ -27852,10 +28061,9 @@ class ScorecardChartDesignPanel extends Component {
|
|
|
27852
28061
|
this.props.updateChart(this.props.figureId, { baselineColorUp: color });
|
|
27853
28062
|
break;
|
|
27854
28063
|
}
|
|
27855
|
-
this.closeMenus();
|
|
27856
28064
|
}
|
|
27857
|
-
|
|
27858
|
-
|
|
28065
|
+
get backgroundColorTitle() {
|
|
28066
|
+
return ChartTerms.BackgroundColor;
|
|
27859
28067
|
}
|
|
27860
28068
|
}
|
|
27861
28069
|
|
|
@@ -28804,6 +29012,7 @@ class ConditionalFormattingEditor extends Component {
|
|
|
28804
29012
|
ColorPickerWidget,
|
|
28805
29013
|
ConditionalFormatPreviewList,
|
|
28806
29014
|
Section,
|
|
29015
|
+
RoundColorPicker,
|
|
28807
29016
|
};
|
|
28808
29017
|
icons = ICONS;
|
|
28809
29018
|
cellIsOperators = CellIsOperators;
|
|
@@ -32308,6 +32517,7 @@ class Composer extends Component {
|
|
|
32308
32517
|
onComposerCellFocused: { type: Function, optional: true },
|
|
32309
32518
|
onComposerContentFocused: Function,
|
|
32310
32519
|
isDefaultFocus: { type: Boolean, optional: true },
|
|
32520
|
+
onInputContextMenu: { type: Function, optional: true },
|
|
32311
32521
|
};
|
|
32312
32522
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
32313
32523
|
static defaultProps = {
|
|
@@ -32358,6 +32568,9 @@ class Composer extends Component {
|
|
|
32358
32568
|
assistantStyle.right = `0px`;
|
|
32359
32569
|
}
|
|
32360
32570
|
}
|
|
32571
|
+
else if (this.props.delimitation) {
|
|
32572
|
+
assistantStyle["max-height"] = `${this.props.delimitation.height}px`;
|
|
32573
|
+
}
|
|
32361
32574
|
return cssPropertiesToCss(assistantStyle);
|
|
32362
32575
|
}
|
|
32363
32576
|
// we can't allow input events to be triggered while we remove and add back the content of the composer in processContent
|
|
@@ -32644,6 +32857,11 @@ class Composer extends Component {
|
|
|
32644
32857
|
}
|
|
32645
32858
|
}
|
|
32646
32859
|
}
|
|
32860
|
+
onContextMenu(ev) {
|
|
32861
|
+
if (this.composerStore.editionMode === "inactive") {
|
|
32862
|
+
this.props.onInputContextMenu?.(ev);
|
|
32863
|
+
}
|
|
32864
|
+
}
|
|
32647
32865
|
// ---------------------------------------------------------------------------
|
|
32648
32866
|
// Private
|
|
32649
32867
|
// ---------------------------------------------------------------------------
|
|
@@ -32865,6 +33083,7 @@ class GridComposer extends Component {
|
|
|
32865
33083
|
static template = "o-spreadsheet-GridComposer";
|
|
32866
33084
|
static props = {
|
|
32867
33085
|
gridDims: Object,
|
|
33086
|
+
onInputContextMenu: Function,
|
|
32868
33087
|
};
|
|
32869
33088
|
static components = { Composer };
|
|
32870
33089
|
rect = this.defaultRect;
|
|
@@ -32912,6 +33131,7 @@ class GridComposer extends Component {
|
|
|
32912
33131
|
isDefaultFocus: true,
|
|
32913
33132
|
onComposerContentFocused: () => this.composerFocusStore.focusGridComposerContent(),
|
|
32914
33133
|
onComposerCellFocused: (content) => this.composerFocusStore.focusGridComposerCell(content),
|
|
33134
|
+
onInputContextMenu: this.props.onInputContextMenu,
|
|
32915
33135
|
};
|
|
32916
33136
|
}
|
|
32917
33137
|
get containerStyle() {
|
|
@@ -33010,7 +33230,6 @@ class GridCellIcon extends Component {
|
|
|
33010
33230
|
cellPosition: Object,
|
|
33011
33231
|
horizontalAlign: { type: String, optional: true },
|
|
33012
33232
|
verticalAlign: { type: String, optional: true },
|
|
33013
|
-
offset: { type: Object, optional: true },
|
|
33014
33233
|
slots: Object,
|
|
33015
33234
|
};
|
|
33016
33235
|
get iconStyle() {
|
|
@@ -33021,8 +33240,8 @@ class GridCellIcon extends Component {
|
|
|
33021
33240
|
const x = this.getIconHorizontalPosition(rect, cellPosition);
|
|
33022
33241
|
const y = this.getIconVerticalPosition(rect, cellPosition);
|
|
33023
33242
|
return cssPropertiesToCss({
|
|
33024
|
-
top: `${y
|
|
33025
|
-
left: `${x
|
|
33243
|
+
top: `${y}px`,
|
|
33244
|
+
left: `${x}px`,
|
|
33026
33245
|
});
|
|
33027
33246
|
}
|
|
33028
33247
|
getIconVerticalPosition(rect, cellPosition) {
|
|
@@ -33062,83 +33281,6 @@ class GridCellIcon extends Component {
|
|
|
33062
33281
|
}
|
|
33063
33282
|
}
|
|
33064
33283
|
|
|
33065
|
-
css /* scss */ `
|
|
33066
|
-
.o-filter-icon {
|
|
33067
|
-
color: ${FILTERS_COLOR};
|
|
33068
|
-
display: flex;
|
|
33069
|
-
align-items: center;
|
|
33070
|
-
justify-content: center;
|
|
33071
|
-
width: ${GRID_ICON_EDGE_LENGTH}px;
|
|
33072
|
-
height: ${GRID_ICON_EDGE_LENGTH}px;
|
|
33073
|
-
|
|
33074
|
-
&:hover {
|
|
33075
|
-
background: ${FILTERS_COLOR};
|
|
33076
|
-
color: #fff;
|
|
33077
|
-
}
|
|
33078
|
-
|
|
33079
|
-
&.o-high-contrast {
|
|
33080
|
-
color: #defade;
|
|
33081
|
-
}
|
|
33082
|
-
&.o-high-contrast:hover {
|
|
33083
|
-
color: ${FILTERS_COLOR};
|
|
33084
|
-
background: #fff;
|
|
33085
|
-
}
|
|
33086
|
-
}
|
|
33087
|
-
.o-filter-icon:hover {
|
|
33088
|
-
background: ${FILTERS_COLOR};
|
|
33089
|
-
color: #fff;
|
|
33090
|
-
}
|
|
33091
|
-
`;
|
|
33092
|
-
class FilterIcon extends Component {
|
|
33093
|
-
static template = "o-spreadsheet-FilterIcon";
|
|
33094
|
-
static props = {
|
|
33095
|
-
cellPosition: Object,
|
|
33096
|
-
};
|
|
33097
|
-
cellPopovers;
|
|
33098
|
-
setup() {
|
|
33099
|
-
this.cellPopovers = useStore(CellPopoverStore);
|
|
33100
|
-
}
|
|
33101
|
-
onClick() {
|
|
33102
|
-
const position = this.props.cellPosition;
|
|
33103
|
-
const activePopover = this.cellPopovers.persistentCellPopover;
|
|
33104
|
-
const { col, row } = position;
|
|
33105
|
-
if (activePopover.isOpen &&
|
|
33106
|
-
activePopover.col === col &&
|
|
33107
|
-
activePopover.row === row &&
|
|
33108
|
-
activePopover.type === "FilterMenu") {
|
|
33109
|
-
this.cellPopovers.close();
|
|
33110
|
-
return;
|
|
33111
|
-
}
|
|
33112
|
-
this.cellPopovers.open({ col, row }, "FilterMenu");
|
|
33113
|
-
}
|
|
33114
|
-
get isFilterActive() {
|
|
33115
|
-
return this.env.model.getters.isFilterActive(this.props.cellPosition);
|
|
33116
|
-
}
|
|
33117
|
-
get iconClass() {
|
|
33118
|
-
const cellStyle = this.env.model.getters.getCellComputedStyle(this.props.cellPosition);
|
|
33119
|
-
const luminance = relativeLuminance(cellStyle.fillColor || "#fff");
|
|
33120
|
-
return luminance < 0.45 ? "o-high-contrast" : "";
|
|
33121
|
-
}
|
|
33122
|
-
}
|
|
33123
|
-
|
|
33124
|
-
class FilterIconsOverlay extends Component {
|
|
33125
|
-
static template = "o-spreadsheet-FilterIconsOverlay";
|
|
33126
|
-
static props = {
|
|
33127
|
-
gridPosition: { type: Object, optional: true },
|
|
33128
|
-
};
|
|
33129
|
-
static components = {
|
|
33130
|
-
GridCellIcon,
|
|
33131
|
-
FilterIcon,
|
|
33132
|
-
};
|
|
33133
|
-
static defaultProps = {
|
|
33134
|
-
gridPosition: { x: 0, y: 0 },
|
|
33135
|
-
};
|
|
33136
|
-
getFilterHeadersPositions() {
|
|
33137
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
33138
|
-
return this.env.model.getters.getFilterHeaders(sheetId);
|
|
33139
|
-
}
|
|
33140
|
-
}
|
|
33141
|
-
|
|
33142
33284
|
const CHECKBOX_WIDTH = 15;
|
|
33143
33285
|
const MARGIN = (GRID_ICON_EDGE_LENGTH - CHECKBOX_WIDTH) / 2;
|
|
33144
33286
|
css /* scss */ `
|
|
@@ -33806,6 +33948,80 @@ class FiguresContainer extends Component {
|
|
|
33806
33948
|
}
|
|
33807
33949
|
}
|
|
33808
33950
|
|
|
33951
|
+
css /* scss */ `
|
|
33952
|
+
.o-filter-icon {
|
|
33953
|
+
color: ${FILTERS_COLOR};
|
|
33954
|
+
display: flex;
|
|
33955
|
+
align-items: center;
|
|
33956
|
+
justify-content: center;
|
|
33957
|
+
width: ${GRID_ICON_EDGE_LENGTH}px;
|
|
33958
|
+
height: ${GRID_ICON_EDGE_LENGTH}px;
|
|
33959
|
+
|
|
33960
|
+
&:hover {
|
|
33961
|
+
background: ${FILTERS_COLOR};
|
|
33962
|
+
color: #fff;
|
|
33963
|
+
}
|
|
33964
|
+
|
|
33965
|
+
&.o-high-contrast {
|
|
33966
|
+
color: #defade;
|
|
33967
|
+
}
|
|
33968
|
+
&.o-high-contrast:hover {
|
|
33969
|
+
color: ${FILTERS_COLOR};
|
|
33970
|
+
background: #fff;
|
|
33971
|
+
}
|
|
33972
|
+
}
|
|
33973
|
+
.o-filter-icon:hover {
|
|
33974
|
+
background: ${FILTERS_COLOR};
|
|
33975
|
+
color: #fff;
|
|
33976
|
+
}
|
|
33977
|
+
`;
|
|
33978
|
+
class FilterIcon extends Component {
|
|
33979
|
+
static template = "o-spreadsheet-FilterIcon";
|
|
33980
|
+
static props = {
|
|
33981
|
+
cellPosition: Object,
|
|
33982
|
+
};
|
|
33983
|
+
cellPopovers;
|
|
33984
|
+
setup() {
|
|
33985
|
+
this.cellPopovers = useStore(CellPopoverStore);
|
|
33986
|
+
}
|
|
33987
|
+
onClick() {
|
|
33988
|
+
const position = this.props.cellPosition;
|
|
33989
|
+
const activePopover = this.cellPopovers.persistentCellPopover;
|
|
33990
|
+
const { col, row } = position;
|
|
33991
|
+
if (activePopover.isOpen &&
|
|
33992
|
+
activePopover.col === col &&
|
|
33993
|
+
activePopover.row === row &&
|
|
33994
|
+
activePopover.type === "FilterMenu") {
|
|
33995
|
+
this.cellPopovers.close();
|
|
33996
|
+
return;
|
|
33997
|
+
}
|
|
33998
|
+
this.cellPopovers.open({ col, row }, "FilterMenu");
|
|
33999
|
+
}
|
|
34000
|
+
get isFilterActive() {
|
|
34001
|
+
return this.env.model.getters.isFilterActive(this.props.cellPosition);
|
|
34002
|
+
}
|
|
34003
|
+
get iconClass() {
|
|
34004
|
+
const cellStyle = this.env.model.getters.getCellComputedStyle(this.props.cellPosition);
|
|
34005
|
+
const luminance = relativeLuminance(cellStyle.fillColor || "#fff");
|
|
34006
|
+
return luminance < 0.45 ? "o-high-contrast" : "";
|
|
34007
|
+
}
|
|
34008
|
+
}
|
|
34009
|
+
|
|
34010
|
+
class FilterIconsOverlay extends Component {
|
|
34011
|
+
static template = "o-spreadsheet-FilterIconsOverlay";
|
|
34012
|
+
static props = {
|
|
34013
|
+
onMouseDown: Function,
|
|
34014
|
+
};
|
|
34015
|
+
static components = {
|
|
34016
|
+
GridCellIcon,
|
|
34017
|
+
FilterIcon,
|
|
34018
|
+
};
|
|
34019
|
+
getFilterHeadersPositions() {
|
|
34020
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
34021
|
+
return this.env.model.getters.getFilterHeaders(sheetId);
|
|
34022
|
+
}
|
|
34023
|
+
}
|
|
34024
|
+
|
|
33809
34025
|
css /* scss */ `
|
|
33810
34026
|
.o-grid-add-rows {
|
|
33811
34027
|
input {
|
|
@@ -34019,7 +34235,12 @@ class GridOverlay extends Component {
|
|
|
34019
34235
|
onGridMoved: Function,
|
|
34020
34236
|
gridOverlayDimensions: String,
|
|
34021
34237
|
};
|
|
34022
|
-
static components = {
|
|
34238
|
+
static components = {
|
|
34239
|
+
FiguresContainer,
|
|
34240
|
+
DataValidationOverlay,
|
|
34241
|
+
GridAddRowsFooter,
|
|
34242
|
+
FilterIconsOverlay,
|
|
34243
|
+
};
|
|
34023
34244
|
static defaultProps = {
|
|
34024
34245
|
onCellHovered: () => { },
|
|
34025
34246
|
onCellDoubleClicked: () => { },
|
|
@@ -34064,7 +34285,7 @@ class GridOverlay extends Component {
|
|
|
34064
34285
|
get isPaintingFormat() {
|
|
34065
34286
|
return this.env.model.getters.isPaintingFormat();
|
|
34066
34287
|
}
|
|
34067
|
-
onMouseDown(ev) {
|
|
34288
|
+
onMouseDown(ev, modifiers) {
|
|
34068
34289
|
if (ev.button > 0) {
|
|
34069
34290
|
// not main button, probably a context menu
|
|
34070
34291
|
return;
|
|
@@ -34073,6 +34294,7 @@ class GridOverlay extends Component {
|
|
|
34073
34294
|
this.props.onCellClicked(col, row, {
|
|
34074
34295
|
expandZone: ev.shiftKey,
|
|
34075
34296
|
addZone: isCtrlKey(ev),
|
|
34297
|
+
closePopover: modifiers?.closePopover ?? true,
|
|
34076
34298
|
});
|
|
34077
34299
|
}
|
|
34078
34300
|
onDoubleClick(ev) {
|
|
@@ -35838,7 +36060,6 @@ class Grid extends Component {
|
|
|
35838
36060
|
Popover,
|
|
35839
36061
|
VerticalScrollBar,
|
|
35840
36062
|
HorizontalScrollBar,
|
|
35841
|
-
FilterIconsOverlay,
|
|
35842
36063
|
};
|
|
35843
36064
|
HEADER_HEIGHT = HEADER_HEIGHT;
|
|
35844
36065
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
@@ -36139,17 +36360,17 @@ class Grid extends Component {
|
|
|
36139
36360
|
// ---------------------------------------------------------------------------
|
|
36140
36361
|
// Zone selection with mouse
|
|
36141
36362
|
// ---------------------------------------------------------------------------
|
|
36142
|
-
onCellClicked(col, row,
|
|
36143
|
-
if (this.cellPopovers.isOpen) {
|
|
36363
|
+
onCellClicked(col, row, modifiers) {
|
|
36364
|
+
if (modifiers.closePopover && this.cellPopovers.isOpen) {
|
|
36144
36365
|
this.cellPopovers.close();
|
|
36145
36366
|
}
|
|
36146
36367
|
if (this.composerStore.editionMode === "editing") {
|
|
36147
36368
|
this.composerStore.stopEdition();
|
|
36148
36369
|
}
|
|
36149
|
-
if (expandZone) {
|
|
36370
|
+
if (modifiers.expandZone) {
|
|
36150
36371
|
this.env.model.selection.setAnchorCorner(col, row);
|
|
36151
36372
|
}
|
|
36152
|
-
else if (addZone) {
|
|
36373
|
+
else if (modifiers.addZone) {
|
|
36153
36374
|
this.env.model.selection.addCellToSelection(col, row);
|
|
36154
36375
|
}
|
|
36155
36376
|
else {
|
|
@@ -36871,7 +37092,7 @@ const CHART_TYPE_CONVERSION_MAP = {
|
|
|
36871
37092
|
line3DChart: undefined,
|
|
36872
37093
|
stockChart: undefined,
|
|
36873
37094
|
radarChart: undefined,
|
|
36874
|
-
scatterChart:
|
|
37095
|
+
scatterChart: "scatter",
|
|
36875
37096
|
pieChart: "pie",
|
|
36876
37097
|
pie3DChart: undefined,
|
|
36877
37098
|
doughnutChart: "pie",
|
|
@@ -37635,29 +37856,12 @@ function convertWidthFromExcel(width) {
|
|
|
37635
37856
|
return width;
|
|
37636
37857
|
return Math.round((width / WIDTH_FACTOR) * 100) / 100;
|
|
37637
37858
|
}
|
|
37638
|
-
function convertBorderDescr(descr) {
|
|
37639
|
-
if (!descr) {
|
|
37640
|
-
return undefined;
|
|
37641
|
-
}
|
|
37642
|
-
return {
|
|
37643
|
-
style: descr.style,
|
|
37644
|
-
color: { rgb: descr.color },
|
|
37645
|
-
};
|
|
37646
|
-
}
|
|
37647
37859
|
function extractStyle(cell, data) {
|
|
37648
37860
|
let style = {};
|
|
37649
37861
|
if (cell.style) {
|
|
37650
37862
|
style = data.styles[cell.style];
|
|
37651
37863
|
}
|
|
37652
37864
|
const format = extractFormat(cell, data);
|
|
37653
|
-
const exportedBorder = {};
|
|
37654
|
-
if (cell.border) {
|
|
37655
|
-
const border = data.borders[cell.border];
|
|
37656
|
-
exportedBorder.left = convertBorderDescr(border.left);
|
|
37657
|
-
exportedBorder.right = convertBorderDescr(border.right);
|
|
37658
|
-
exportedBorder.bottom = convertBorderDescr(border.bottom);
|
|
37659
|
-
exportedBorder.top = convertBorderDescr(border.top);
|
|
37660
|
-
}
|
|
37661
37865
|
const styles = {
|
|
37662
37866
|
font: {
|
|
37663
37867
|
size: style?.fontSize || DEFAULT_FONT_SIZE,
|
|
@@ -37671,7 +37875,7 @@ function extractStyle(cell, data) {
|
|
|
37671
37875
|
}
|
|
37672
37876
|
: { reservedAttribute: "none" },
|
|
37673
37877
|
numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
|
|
37674
|
-
border:
|
|
37878
|
+
border: cell.border || 0,
|
|
37675
37879
|
alignment: {
|
|
37676
37880
|
horizontal: style.align,
|
|
37677
37881
|
vertical: style.verticalAlign
|
|
@@ -37693,15 +37897,12 @@ function extractFormat(cell, data) {
|
|
|
37693
37897
|
return undefined;
|
|
37694
37898
|
}
|
|
37695
37899
|
function normalizeStyle(construct, styles) {
|
|
37696
|
-
const { id: fontId } = pushElement(styles["font"], construct.fonts);
|
|
37697
|
-
const { id: fillId } = pushElement(styles["fill"], construct.fills);
|
|
37698
|
-
const { id: borderId } = pushElement(styles["border"], construct.borders);
|
|
37699
37900
|
// Normalize this
|
|
37700
37901
|
const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
|
|
37701
37902
|
const style = {
|
|
37702
|
-
fontId,
|
|
37703
|
-
fillId,
|
|
37704
|
-
borderId,
|
|
37903
|
+
fontId: pushElement(styles.font, construct.fonts),
|
|
37904
|
+
fillId: pushElement(styles.fill, construct.fills),
|
|
37905
|
+
borderId: styles.border,
|
|
37705
37906
|
numFmtId,
|
|
37706
37907
|
alignment: {
|
|
37707
37908
|
vertical: styles.alignment.vertical,
|
|
@@ -37709,8 +37910,7 @@ function normalizeStyle(construct, styles) {
|
|
|
37709
37910
|
wrapText: styles.alignment.wrapText,
|
|
37710
37911
|
},
|
|
37711
37912
|
};
|
|
37712
|
-
|
|
37713
|
-
return id;
|
|
37913
|
+
return pushElement(style, construct.styles);
|
|
37714
37914
|
}
|
|
37715
37915
|
function convertFormat(format, numFmtStructure) {
|
|
37716
37916
|
if (!format) {
|
|
@@ -37718,8 +37918,7 @@ function convertFormat(format, numFmtStructure) {
|
|
|
37718
37918
|
}
|
|
37719
37919
|
let formatId = XLSX_FORMAT_MAP[format.format];
|
|
37720
37920
|
if (!formatId) {
|
|
37721
|
-
|
|
37722
|
-
formatId = id + FIRST_NUMFMT_ID;
|
|
37921
|
+
formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
|
|
37723
37922
|
}
|
|
37724
37923
|
return formatId;
|
|
37725
37924
|
}
|
|
@@ -37744,20 +37943,15 @@ function addRelsToFile(relsFiles, path, rel) {
|
|
|
37744
37943
|
return id;
|
|
37745
37944
|
}
|
|
37746
37945
|
function pushElement(property, propertyList) {
|
|
37747
|
-
|
|
37748
|
-
|
|
37749
|
-
|
|
37946
|
+
let len = propertyList.length;
|
|
37947
|
+
const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
|
|
37948
|
+
for (let i = 0; i < len; i++) {
|
|
37949
|
+
if (operator(property, propertyList[i])) {
|
|
37950
|
+
return i;
|
|
37750
37951
|
}
|
|
37751
37952
|
}
|
|
37752
|
-
|
|
37753
|
-
|
|
37754
|
-
propertyList.push(property);
|
|
37755
|
-
elemId = propertyList.length - 1;
|
|
37756
|
-
}
|
|
37757
|
-
return {
|
|
37758
|
-
id: elemId,
|
|
37759
|
-
list: propertyList,
|
|
37760
|
-
};
|
|
37953
|
+
propertyList[propertyList.length] = property;
|
|
37954
|
+
return propertyList.length - 1;
|
|
37761
37955
|
}
|
|
37762
37956
|
const chartIds = [];
|
|
37763
37957
|
/**
|
|
@@ -38552,7 +38746,25 @@ function parseXML(xmlString, mimeType = "text/xml") {
|
|
|
38552
38746
|
}
|
|
38553
38747
|
return document;
|
|
38554
38748
|
}
|
|
38555
|
-
function
|
|
38749
|
+
function convertBorderDescr(descr) {
|
|
38750
|
+
if (!descr) {
|
|
38751
|
+
return undefined;
|
|
38752
|
+
}
|
|
38753
|
+
return {
|
|
38754
|
+
style: descr.style,
|
|
38755
|
+
color: { rgb: descr.color },
|
|
38756
|
+
};
|
|
38757
|
+
}
|
|
38758
|
+
function getDefaultXLSXStructure(data) {
|
|
38759
|
+
const xlsxBorders = Object.values(data.borders).map((border) => {
|
|
38760
|
+
return {
|
|
38761
|
+
left: convertBorderDescr(border.left),
|
|
38762
|
+
right: convertBorderDescr(border.right),
|
|
38763
|
+
bottom: convertBorderDescr(border.bottom),
|
|
38764
|
+
top: convertBorderDescr(border.top),
|
|
38765
|
+
};
|
|
38766
|
+
});
|
|
38767
|
+
const borders = [{}, ...xlsxBorders];
|
|
38556
38768
|
return {
|
|
38557
38769
|
relsFiles: [],
|
|
38558
38770
|
sharedStrings: [],
|
|
@@ -38575,7 +38787,7 @@ function getDefaultXLSXStructure() {
|
|
|
38575
38787
|
},
|
|
38576
38788
|
],
|
|
38577
38789
|
fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
|
|
38578
|
-
borders
|
|
38790
|
+
borders,
|
|
38579
38791
|
numFmts: [],
|
|
38580
38792
|
dxfs: [],
|
|
38581
38793
|
};
|
|
@@ -39111,8 +39323,8 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
39111
39323
|
return {
|
|
39112
39324
|
title: chartTitle,
|
|
39113
39325
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
39114
|
-
dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`)),
|
|
39115
|
-
labelRange: this.extractChildTextContent(rootChartElement,
|
|
39326
|
+
dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`), chartType),
|
|
39327
|
+
labelRange: this.extractChildTextContent(rootChartElement, `c:ser ${chartType === "scatterChart" ? "c:numRef" : "c:cat"} c:f`),
|
|
39116
39328
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
39117
39329
|
default: "ffffff",
|
|
39118
39330
|
}).asString(),
|
|
@@ -39141,8 +39353,8 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
39141
39353
|
title: chartTitle,
|
|
39142
39354
|
type: "combo",
|
|
39143
39355
|
dataSets: [
|
|
39144
|
-
...this.extractChartDatasets(this.querySelector(chartElement, `c:barChart`)),
|
|
39145
|
-
...this.extractChartDatasets(this.querySelector(chartElement, `c:lineChart`)),
|
|
39356
|
+
...this.extractChartDatasets(this.querySelector(chartElement, `c:barChart`), "comboChart"),
|
|
39357
|
+
...this.extractChartDatasets(this.querySelector(chartElement, `c:lineChart`), "comboChart"),
|
|
39146
39358
|
],
|
|
39147
39359
|
labelRange: this.extractChildTextContent(chartElement, "c:ser c:cat c:f"),
|
|
39148
39360
|
backgroundColor: this.extractChildAttr(chartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
@@ -39160,7 +39372,10 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
39160
39372
|
fontColor: "000000",
|
|
39161
39373
|
};
|
|
39162
39374
|
}
|
|
39163
|
-
extractChartDatasets(chartElement) {
|
|
39375
|
+
extractChartDatasets(chartElement, chartType) {
|
|
39376
|
+
if (chartType === "scatterChart") {
|
|
39377
|
+
return this.extractScatterChartDatasets(chartElement);
|
|
39378
|
+
}
|
|
39164
39379
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
39165
39380
|
return {
|
|
39166
39381
|
label: this.extractChildTextContent(chartDataElement, "c:tx c:f"),
|
|
@@ -39168,6 +39383,14 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
39168
39383
|
};
|
|
39169
39384
|
});
|
|
39170
39385
|
}
|
|
39386
|
+
extractScatterChartDatasets(chartElement) {
|
|
39387
|
+
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
39388
|
+
return {
|
|
39389
|
+
label: this.extractChildTextContent(chartDataElement, "c:xVal c:f", { required: false }),
|
|
39390
|
+
range: this.extractChildTextContent(chartDataElement, "c:yVal c:f", { required: true }),
|
|
39391
|
+
};
|
|
39392
|
+
});
|
|
39393
|
+
}
|
|
39171
39394
|
/**
|
|
39172
39395
|
* The chart type in the XML isn't explicitly defined, but there is an XML element that define the
|
|
39173
39396
|
* chart, and this element tag name tells us which type of chart it is. We just need to find this XML element.
|
|
@@ -40561,12 +40784,14 @@ class BasePlugin {
|
|
|
40561
40784
|
static getters = [];
|
|
40562
40785
|
history;
|
|
40563
40786
|
dispatch;
|
|
40564
|
-
|
|
40787
|
+
canDispatch;
|
|
40788
|
+
constructor(stateObserver, dispatch, canDispatch) {
|
|
40565
40789
|
this.history = Object.assign(Object.create(stateObserver), {
|
|
40566
40790
|
update: stateObserver.addChange.bind(stateObserver, this),
|
|
40567
40791
|
selectCell: () => { },
|
|
40568
40792
|
});
|
|
40569
40793
|
this.dispatch = dispatch;
|
|
40794
|
+
this.canDispatch = canDispatch;
|
|
40570
40795
|
}
|
|
40571
40796
|
/**
|
|
40572
40797
|
* Export for excel should be available for all plugins, even for the UI.
|
|
@@ -40645,8 +40870,8 @@ class BasePlugin {
|
|
|
40645
40870
|
class CorePlugin extends BasePlugin {
|
|
40646
40871
|
getters;
|
|
40647
40872
|
uuidGenerator;
|
|
40648
|
-
constructor({ getters, stateObserver, range, dispatch, uuidGenerator }) {
|
|
40649
|
-
super(stateObserver, dispatch);
|
|
40873
|
+
constructor({ getters, stateObserver, range, dispatch, canDispatch, uuidGenerator, }) {
|
|
40874
|
+
super(stateObserver, dispatch, canDispatch);
|
|
40650
40875
|
range.addRangeProvider(this.adaptRanges.bind(this));
|
|
40651
40876
|
this.getters = getters;
|
|
40652
40877
|
this.uuidGenerator = uuidGenerator;
|
|
@@ -46143,8 +46368,8 @@ class UIPlugin extends BasePlugin {
|
|
|
46143
46368
|
getters;
|
|
46144
46369
|
ui;
|
|
46145
46370
|
selection;
|
|
46146
|
-
constructor({ getters, stateObserver, dispatch, uiActions, selection }) {
|
|
46147
|
-
super(stateObserver, dispatch);
|
|
46371
|
+
constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
|
|
46372
|
+
super(stateObserver, dispatch, canDispatch);
|
|
46148
46373
|
this.getters = getters;
|
|
46149
46374
|
this.ui = uiActions;
|
|
46150
46375
|
this.selection = selection;
|
|
@@ -47424,7 +47649,9 @@ class Evaluator {
|
|
|
47424
47649
|
this.blockedArrayFormulas = this.createEmptyPositionSet();
|
|
47425
47650
|
this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
|
|
47426
47651
|
this.formulaDependencies = lazy(() => {
|
|
47427
|
-
const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
|
|
47652
|
+
const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
|
|
47653
|
+
.filter((range) => !range.invalidSheetName && !range.invalidXc)
|
|
47654
|
+
.map((range) => ({
|
|
47428
47655
|
data: position,
|
|
47429
47656
|
boundingBox: {
|
|
47430
47657
|
zone: range.zone,
|
|
@@ -51508,6 +51735,7 @@ const invalidateTableStyleCommands = [
|
|
|
51508
51735
|
"CREATE_TABLE",
|
|
51509
51736
|
"UPDATE_TABLE",
|
|
51510
51737
|
"UPDATE_FILTER",
|
|
51738
|
+
"REMOVE_TABLE",
|
|
51511
51739
|
];
|
|
51512
51740
|
const invalidateTableStyleCommandsSet = new Set(invalidateTableStyleCommands);
|
|
51513
51741
|
function doesCommandInvalidatesTableStyle(cmd) {
|
|
@@ -51535,6 +51763,10 @@ class CellComputedStylePlugin extends UIPlugin {
|
|
|
51535
51763
|
this.styles = {};
|
|
51536
51764
|
return;
|
|
51537
51765
|
}
|
|
51766
|
+
if (invalidateBordersCommands.has(cmd.type)) {
|
|
51767
|
+
this.borders = {};
|
|
51768
|
+
return;
|
|
51769
|
+
}
|
|
51538
51770
|
}
|
|
51539
51771
|
getCellComputedBorder(position) {
|
|
51540
51772
|
const { sheetId, row, col } = position;
|
|
@@ -55475,7 +55707,6 @@ class SpreadsheetDashboard extends Component {
|
|
|
55475
55707
|
Popover,
|
|
55476
55708
|
VerticalScrollBar,
|
|
55477
55709
|
HorizontalScrollBar,
|
|
55478
|
-
FilterIconsOverlay,
|
|
55479
55710
|
};
|
|
55480
55711
|
cellPopovers;
|
|
55481
55712
|
onMouseWheel;
|
|
@@ -56362,6 +56593,13 @@ class TopBarComposer extends Component {
|
|
|
56362
56593
|
"border-color": SELECTION_BORDER_COLOR,
|
|
56363
56594
|
});
|
|
56364
56595
|
}
|
|
56596
|
+
get delimitation() {
|
|
56597
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
56598
|
+
return {
|
|
56599
|
+
width,
|
|
56600
|
+
height,
|
|
56601
|
+
};
|
|
56602
|
+
}
|
|
56365
56603
|
onFocus(selection) {
|
|
56366
56604
|
this.composerFocusStore.focusTopBarComposer(selection);
|
|
56367
56605
|
}
|
|
@@ -58645,6 +58883,9 @@ function createChart(chart, chartSheetIndex, data) {
|
|
|
58645
58883
|
case "line":
|
|
58646
58884
|
plot = addLineChart(chart.data);
|
|
58647
58885
|
break;
|
|
58886
|
+
case "scatter":
|
|
58887
|
+
plot = addScatterChart(chart.data);
|
|
58888
|
+
break;
|
|
58648
58889
|
case "pie":
|
|
58649
58890
|
plot = addDoughnutChart(chart.data, chartSheetIndex, data, { holeSize: 0 });
|
|
58650
58891
|
break;
|
|
@@ -58922,6 +59163,52 @@ function addLineChart(chart) {
|
|
|
58922
59163
|
${addAx(axisPos, "c:valAx", valAxId, catAxId, { fontColor: chart.fontColor })}
|
|
58923
59164
|
`;
|
|
58924
59165
|
}
|
|
59166
|
+
function addScatterChart(chart) {
|
|
59167
|
+
const colors = new ChartColors();
|
|
59168
|
+
const dataSetsNodes = [];
|
|
59169
|
+
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
59170
|
+
dataSetsNodes.push(escapeXml /*xml*/ `
|
|
59171
|
+
<c:ser>
|
|
59172
|
+
<c:idx val="${dsIndex}"/>
|
|
59173
|
+
<c:order val="${dsIndex}"/>
|
|
59174
|
+
<c:smooth val="0"/>
|
|
59175
|
+
<c:spPr>
|
|
59176
|
+
<a:ln w="19050" cap="rnd">
|
|
59177
|
+
<a:noFill/>
|
|
59178
|
+
<a:round/>
|
|
59179
|
+
</a:ln>
|
|
59180
|
+
<a:effectLst/>
|
|
59181
|
+
</c:spPr>
|
|
59182
|
+
<c:marker>
|
|
59183
|
+
<c:symbol val="circle" />
|
|
59184
|
+
<c:size val="5"/>
|
|
59185
|
+
${shapeProperty({ backgroundColor: toXlsxHexColor(colors.next()) })}
|
|
59186
|
+
</c:marker>
|
|
59187
|
+
${chart.labelRange
|
|
59188
|
+
? escapeXml /*xml*/ `<c:xVal> <!-- x-coordinate values -->
|
|
59189
|
+
${numberRef(chart.labelRange)}
|
|
59190
|
+
</c:xVal>`
|
|
59191
|
+
: ""}
|
|
59192
|
+
<c:yVal> <!-- y-coordinate values -->
|
|
59193
|
+
${numberRef(dataset.range)}
|
|
59194
|
+
</c:yVal>
|
|
59195
|
+
</c:ser>
|
|
59196
|
+
`);
|
|
59197
|
+
}
|
|
59198
|
+
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
59199
|
+
return escapeXml /*xml*/ `
|
|
59200
|
+
<c:scatterChart>
|
|
59201
|
+
<!-- each data marker in the series does not have a different color -->
|
|
59202
|
+
<c:varyColors val="0"/>
|
|
59203
|
+
<c:scatterStyle val="lineMarker"/>
|
|
59204
|
+
${joinXmlNodes(dataSetsNodes)}
|
|
59205
|
+
<c:axId val="${catAxId}" />
|
|
59206
|
+
<c:axId val="${valAxId}" />
|
|
59207
|
+
</c:scatterChart>
|
|
59208
|
+
${addAx("b", "c:valAx", catAxId, valAxId, { fontColor: chart.fontColor })}
|
|
59209
|
+
${addAx(axisPos, "c:valAx", valAxId, catAxId, { fontColor: chart.fontColor })}
|
|
59210
|
+
`;
|
|
59211
|
+
}
|
|
58925
59212
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
58926
59213
|
const colors = new ChartColors();
|
|
58927
59214
|
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
@@ -59062,8 +59349,7 @@ function addContent(content, sharedStrings, forceString = false) {
|
|
|
59062
59349
|
attrs.push(["t", "b"]);
|
|
59063
59350
|
}
|
|
59064
59351
|
else if (forceString || !isNumber(value, DEFAULT_LOCALE)) {
|
|
59065
|
-
|
|
59066
|
-
value = id.toString();
|
|
59352
|
+
value = pushElement(content, sharedStrings);
|
|
59067
59353
|
attrs.push(["t", "s"]);
|
|
59068
59354
|
}
|
|
59069
59355
|
return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
|
|
@@ -59188,8 +59474,7 @@ function addCellIsRule(cf, rule, dxfs) {
|
|
|
59188
59474
|
if (rule.style.fillColor) {
|
|
59189
59475
|
dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
|
|
59190
59476
|
}
|
|
59191
|
-
|
|
59192
|
-
ruleAttributes.push(["dxfId", id]);
|
|
59477
|
+
ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
|
|
59193
59478
|
return escapeXml /*xml*/ `
|
|
59194
59479
|
<conditionalFormatting sqref="${cf.ranges.join(" ")}">
|
|
59195
59480
|
<cfRule ${formatAttributes(ruleAttributes)}>
|
|
@@ -60019,8 +60304,9 @@ function addSheetViews(sheet) {
|
|
|
60019
60304
|
*/
|
|
60020
60305
|
function getXLSX(data) {
|
|
60021
60306
|
data = fixLengthySheetNames(data);
|
|
60307
|
+
data = purgeSingleRowTables(data);
|
|
60022
60308
|
const files = [];
|
|
60023
|
-
const construct = getDefaultXLSXStructure();
|
|
60309
|
+
const construct = getDefaultXLSXStructure(data);
|
|
60024
60310
|
files.push(createWorkbook(data, construct));
|
|
60025
60311
|
files.push(...createWorksheets(data, construct));
|
|
60026
60312
|
files.push(createStylesSheet(construct));
|
|
@@ -60300,6 +60586,16 @@ function fixLengthySheetNames(data) {
|
|
|
60300
60586
|
}
|
|
60301
60587
|
return JSON.parse(stringifiedData);
|
|
60302
60588
|
}
|
|
60589
|
+
/** Excel files do not support tables with a single row the defined range
|
|
60590
|
+
* Since those tables are not really useful (no filtering/limited styling)
|
|
60591
|
+
* This function filters out all tables with a single row.
|
|
60592
|
+
*/
|
|
60593
|
+
function purgeSingleRowTables(data) {
|
|
60594
|
+
for (const sheet of data.sheets) {
|
|
60595
|
+
sheet.tables = sheet.tables.filter((table) => zoneToDimension(toZone(table.range)).numberOfRows > 1);
|
|
60596
|
+
}
|
|
60597
|
+
return data;
|
|
60598
|
+
}
|
|
60303
60599
|
|
|
60304
60600
|
var Status;
|
|
60305
60601
|
(function (Status) {
|
|
@@ -60553,6 +60849,7 @@ class Model extends EventBus {
|
|
|
60553
60849
|
stateObserver: this.state,
|
|
60554
60850
|
range: this.range,
|
|
60555
60851
|
dispatch: this.dispatchFromCorePlugin,
|
|
60852
|
+
canDispatch: this.canDispatch,
|
|
60556
60853
|
uuidGenerator: this.uuidGenerator,
|
|
60557
60854
|
custom: this.config.custom,
|
|
60558
60855
|
external: this.config.external,
|
|
@@ -60563,6 +60860,7 @@ class Model extends EventBus {
|
|
|
60563
60860
|
getters: this.getters,
|
|
60564
60861
|
stateObserver: this.state,
|
|
60565
60862
|
dispatch: this.dispatch,
|
|
60863
|
+
canDispatch: this.canDispatch,
|
|
60566
60864
|
selection: this.selection,
|
|
60567
60865
|
moveClient: this.session.move.bind(this.session),
|
|
60568
60866
|
custom: this.config.custom,
|
|
@@ -60886,7 +61184,7 @@ const links = {
|
|
|
60886
61184
|
const components = {
|
|
60887
61185
|
Checkbox,
|
|
60888
61186
|
Section,
|
|
60889
|
-
|
|
61187
|
+
RoundColorPicker,
|
|
60890
61188
|
ChartDataSeries,
|
|
60891
61189
|
ChartErrorSection,
|
|
60892
61190
|
ChartLabelRange,
|
|
@@ -60948,6 +61246,6 @@ const constants = {
|
|
|
60948
61246
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
60949
61247
|
|
|
60950
61248
|
|
|
60951
|
-
__info__.version = "17.3.0-alpha.
|
|
60952
|
-
__info__.date = "2024-04-
|
|
60953
|
-
__info__.hash = "
|
|
61249
|
+
__info__.version = "17.3.0-alpha.3";
|
|
61250
|
+
__info__.date = "2024-04-10T12:28:23.658Z";
|
|
61251
|
+
__info__.hash = "80b5056";
|