@trebco/treb 28.17.5 → 29.1.4

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.
Files changed (88) hide show
  1. package/dist/treb-spreadsheet-light.mjs +12 -12
  2. package/dist/treb-spreadsheet.mjs +12 -12
  3. package/dist/treb.d.ts +121 -82
  4. package/eslint.config.js +21 -0
  5. package/package.json +6 -6
  6. package/treb-base-types/src/area.ts +4 -2
  7. package/treb-base-types/src/cell.ts +1 -1
  8. package/treb-base-types/src/cells.ts +16 -7
  9. package/treb-base-types/src/dom-utilities.ts +4 -2
  10. package/treb-base-types/src/import.ts +2 -2
  11. package/treb-base-types/src/rectangle.ts +5 -5
  12. package/treb-base-types/src/text_part.ts +7 -0
  13. package/treb-base-types/src/union.ts +6 -1
  14. package/treb-base-types/src/value-type.ts +1 -1
  15. package/treb-calculator/src/calculator.ts +114 -165
  16. package/treb-calculator/src/dag/calculation_leaf_vertex.ts +1 -2
  17. package/treb-calculator/src/dag/graph.ts +3 -3
  18. package/treb-calculator/src/dag/spreadsheet_vertex.ts +2 -2
  19. package/treb-calculator/src/dag/state_leaf_vertex.ts +2 -4
  20. package/treb-calculator/src/descriptors.ts +28 -2
  21. package/treb-calculator/src/expression-calculator.ts +25 -34
  22. package/treb-calculator/src/function-error.ts +2 -2
  23. package/treb-calculator/src/function-library.ts +16 -0
  24. package/treb-calculator/src/functions/base-functions.ts +185 -211
  25. package/treb-calculator/src/functions/checkbox.ts +0 -1
  26. package/treb-calculator/src/functions/complex-functions.ts +49 -47
  27. package/treb-calculator/src/functions/finance-functions.ts +10 -10
  28. package/treb-calculator/src/functions/function-utilities.ts +26 -0
  29. package/treb-calculator/src/functions/information-functions.ts +21 -41
  30. package/treb-calculator/src/functions/matrix-functions.ts +8 -1
  31. package/treb-calculator/src/functions/sparkline.ts +6 -4
  32. package/treb-calculator/src/functions/statistics-functions.ts +21 -17
  33. package/treb-calculator/src/functions/text-functions.ts +14 -13
  34. package/treb-calculator/src/primitives.ts +48 -37
  35. package/treb-calculator/src/utilities.ts +117 -134
  36. package/treb-charts/src/chart-functions.ts +3 -3
  37. package/treb-charts/src/chart-types.ts +42 -1
  38. package/treb-charts/src/chart-utils.ts +155 -113
  39. package/treb-charts/src/chart.ts +6 -5
  40. package/treb-charts/src/default-chart-renderer.ts +6 -5
  41. package/treb-charts/src/renderer.ts +12 -11
  42. package/treb-charts/src/util.ts +25 -36
  43. package/treb-data-model/package.json +5 -0
  44. package/{treb-grid/src/types → treb-data-model/src}/annotation.ts +2 -2
  45. package/{treb-grid/src/types → treb-data-model/src}/conditional_format.ts +20 -0
  46. package/{treb-grid/src/types → treb-data-model/src}/data_model.ts +231 -133
  47. package/treb-data-model/src/index.ts +45 -0
  48. package/{treb-grid/src/types/named_range.ts → treb-data-model/src/named.ts} +459 -376
  49. package/{treb-grid/src/types → treb-data-model/src}/sheet.ts +13 -5
  50. package/treb-data-model/src/sheet_collection.ts +114 -0
  51. package/{treb-grid/src/types → treb-data-model/src}/sheet_types.ts +6 -3
  52. package/treb-embed/modern.tsconfig.json +1 -0
  53. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +2 -2
  54. package/treb-embed/src/embedded-spreadsheet.ts +125 -270
  55. package/treb-embed/src/selection-state.ts +1 -1
  56. package/treb-embed/src/toolbar-message.ts +1 -1
  57. package/treb-embed/src/types.ts +13 -5
  58. package/treb-export/src/export-worker/export-worker.ts +22 -7
  59. package/treb-export/src/export2.ts +110 -41
  60. package/treb-export/src/import2.ts +6 -5
  61. package/treb-export/src/workbook2.ts +31 -13
  62. package/treb-export/src/xml-utils.ts +5 -1
  63. package/treb-format/src/format.ts +8 -6
  64. package/treb-grid/src/editors/autocomplete.ts +2 -2
  65. package/treb-grid/src/editors/autocomplete_matcher.ts +57 -19
  66. package/treb-grid/src/editors/editor.ts +27 -25
  67. package/treb-grid/src/editors/formula_bar.ts +5 -5
  68. package/treb-grid/src/editors/overlay_editor.ts +1 -2
  69. package/treb-grid/src/index.ts +0 -11
  70. package/treb-grid/src/layout/base_layout.ts +20 -8
  71. package/treb-grid/src/layout/grid_layout.ts +2 -2
  72. package/treb-grid/src/layout/mock-layout.ts +5 -6
  73. package/treb-grid/src/render/selection-renderer.ts +2 -3
  74. package/treb-grid/src/render/tile_renderer.ts +18 -8
  75. package/treb-grid/src/types/grid.ts +96 -67
  76. package/treb-grid/src/types/grid_base.ts +76 -60
  77. package/treb-grid/src/types/grid_command.ts +3 -2
  78. package/treb-grid/src/types/grid_events.ts +12 -6
  79. package/treb-grid/src/types/tab_bar.ts +1 -2
  80. package/treb-parser/src/parser-types.ts +2 -1
  81. package/treb-parser/src/parser.ts +7 -5
  82. package/treb-utils/src/event_source.ts +1 -1
  83. package/treb-utils/src/serialize_html.ts +31 -6
  84. package/.eslintignore +0 -8
  85. package/.eslintrc.cjs +0 -168
  86. package/treb-grid/src/layout/rectangle_cache.ts +0 -86
  87. /package/{treb-grid/src/types → treb-data-model/src}/serialize_options.ts +0 -0
  88. /package/{treb-grid/src/types/grid_selection.ts → treb-data-model/src/sheet_selection.ts} +0 -0
@@ -1,9 +1,10 @@
1
1
 
2
- import { type UnionValue, ValueType, type ArrayUnion } from 'treb-base-types';
3
- import { LegendStyle } from './chart-types';
4
- import type { SubSeries, SeriesType, BarData, ChartDataBaseType, ChartData, ScatterData2, LineData, DonutSlice, BubbleChartData } from './chart-types';
2
+ import { type UnionValue, ValueType, type ArrayUnion, IsComplex, type CellValue } from 'treb-base-types';
3
+ import { IsArrayUnion, IsMetadata, IsSeries, LegendStyle } from './chart-types';
4
+ import type { SubSeries, SeriesType, BarData, ChartDataBaseType, ChartData, ScatterData2, DonutSlice, BubbleChartData } from './chart-types';
5
5
  import { NumberFormatCache } from 'treb-format';
6
6
  import { Util } from './util';
7
+ import type { ReferenceSeries } from './chart-types';
7
8
 
8
9
  /**
9
10
  * this file is the concrete translation from function arguments
@@ -15,7 +16,9 @@ import { Util } from './util';
15
16
 
16
17
  const DEFAULT_FORMAT = '#,##0.00'; // why not use "general", or whatever the usual default is?
17
18
 
18
- export const ReadSeries = (data: Array<any>): SeriesType => {
19
+ export const ReadSeries = (data: ReferenceSeries['value']): SeriesType => {
20
+
21
+ const [label, x, y, z, index, subtype, data_labels] = data;
19
22
 
20
23
  // series type is (now)
21
24
  //
@@ -33,80 +36,74 @@ export const ReadSeries = (data: Array<any>): SeriesType => {
33
36
  y: { data: [] },
34
37
  };
35
38
 
36
- if (data[4] && typeof data[4] === 'number') {
37
- series.index = data[4];
39
+ if (typeof index === 'number') {
40
+ series.index = index;
38
41
  }
39
42
 
40
- if (data[5]) {
41
- series.subtype = data[5].toString();
43
+ if (subtype) {
44
+ series.subtype = subtype.toString();
42
45
  }
43
46
 
44
- if (data[6]) {
45
- const labels = Util.Flatten(Array.isArray(data[6]) ? data[6] : [data[6]]);
47
+ if (data_labels) {
48
+ const labels = Util.Flatten<CellValue>(Array.isArray(data_labels) ? data_labels : [data_labels]);
46
49
  series.labels = labels.map(value => (typeof value === 'undefined') ? '' : value.toString());
47
50
  }
48
51
 
49
- if (data[0]) {
52
+ if (label) {
53
+ series.label = label.toString();
54
+ }
55
+
56
+ const ParseSubseries = (source?: UnionValue, apply_labels = false) => {
50
57
 
51
- const flat = Util.Flatten(data[0]);
58
+ let subseries: SubSeries|undefined;
52
59
 
53
- // this could be a string, if it's a literal, or metadata
54
- // [why would we want metadata?]
55
- //
56
- // OK, check that, should be a string (or other literal)
60
+ // convert single values -> array (is this still necessary?)
57
61
 
58
- if (typeof flat[0] === 'object') {
59
- series.label = flat[0]?.value?.toString() || '';
60
- }
61
- else {
62
- series.label = flat[0].toString();
62
+ if (IsMetadata(source)) {
63
+ source = {
64
+ type: ValueType.array,
65
+ value: [[source]],
66
+ };
63
67
  }
64
- }
65
68
 
66
- // convert single value series to arrays so we can just use the old routine
69
+ if (IsArrayUnion(source)) {
67
70
 
68
- for (let i = 1; i < 4; i++) {
69
- if (data[i] && typeof data[i] === 'object' && data[i].key === 'metadata') {
70
- data[i] = {
71
- type: ValueType.array,
72
- value: [data[i]],
71
+ subseries = { data: [] };
72
+
73
+ const flat = Util.Flatten<UnionValue>(source.value);
74
+
75
+ subseries.data = flat.map(item => {
76
+ if (IsMetadata(item)) {
77
+ if (typeof item.value.value === 'number') {
78
+ return item.value.value;
79
+ }
80
+ }
81
+ else if (item.type === ValueType.number) {
82
+ return item.value;
83
+ }
84
+ return undefined;
85
+ });
86
+
87
+ if (IsMetadata(flat[0]) && flat[0].value?.format) {
88
+ subseries.format = (flat[0].value.format);
89
+ if (apply_labels) {
90
+ const format = NumberFormatCache.Get(subseries.format);
91
+ subseries.labels = subseries.data.map(value => (value === undefined) ? undefined : format.Format(value));
92
+ }
73
93
  }
74
- }
75
- }
76
94
 
77
- // read [2] first, so we can default for [1] if necessary
78
-
79
- if (!!data[2] && (typeof data[2] === 'object') && data[2].type === ValueType.array) {
80
- const flat = Util.Flatten(data[2].value);
81
- series.y.data = flat.map(item => typeof item.value.value === 'number' ? item.value.value : undefined);
82
- if (flat[0].value?.format) {
83
- series.y.format = flat[0].value?.format as string;
84
- const format = NumberFormatCache.Get(series.y.format);
85
- series.y.labels = series.y.data.map(value => (value === undefined) ? undefined : format.Format(value));
86
95
  }
87
- }
88
-
89
- if (!!data[1] && (typeof data[1] === 'object') && data[1].type === ValueType.array) {
90
- const flat = Util.Flatten(data[1].value);
91
- series.x.data = flat.map(item => typeof item.value.value === 'number' ? item.value.value : undefined);
92
- if (flat[0].value.format) {
93
- series.x.format = flat[0].value.format;
94
- }
95
- }
96
+ return subseries;
96
97
 
97
- const entries = [series.x, series.y]
98
+ };
98
99
 
99
- // try reading [3]
100
+ // read [2] first, so we can default for [1] if necessary
100
101
 
101
- if (!!data[3] && (typeof data[3] === 'object') && data[3].type === ValueType.array) {
102
- const flat = Util.Flatten(data[3].value);
103
- series.z = { data: [] };
104
- series.z.data = flat.map(item => typeof item.value.value === 'number' ? item.value.value : undefined);
105
- if (flat[0].value.format) {
106
- series.z.format = flat[0].value.format;
107
- }
108
- }
102
+ series.y = ParseSubseries(y, true) || { data: [] };
103
+ series.x = ParseSubseries(x) || { data: [] };
104
+ series.z = ParseSubseries(z);
109
105
 
106
+ const entries = [series.x, series.y]
110
107
 
111
108
  for (const subseries of entries) {
112
109
 
@@ -129,7 +126,7 @@ export const ArrayToSeries = (array_data: ArrayUnion): SeriesType => {
129
126
  // this is an array of Y, X not provided
130
127
 
131
128
  const series: SeriesType = { x: { data: [] }, y: { data: [] }, };
132
- const flat = Util.Flatten(array_data.value);
129
+ const flat = Util.Flatten<UnionValue>(array_data.value);
133
130
 
134
131
  // series.y.data = flat.map(item => typeof item.value === 'number' ? item.value : undefined);
135
132
 
@@ -142,20 +139,35 @@ export const ArrayToSeries = (array_data: ArrayUnion): SeriesType => {
142
139
 
143
140
  // ... ok, it's metadata (why not just test?) ...
144
141
 
145
- // experimenting with complex... put real in X axis and imaginary in Y axis
146
- // note should also function w/ complex not in a metadata structure
142
+ if (IsMetadata(item)) {
143
+
144
+ // experimenting with complex... put real in X axis and imaginary in Y axis
145
+ // note should also function w/ complex not in a metadata structure
146
+
147
+ // if (typeof item.value.value?.real === 'number') {
148
+ if (IsComplex(item.value.value)) {
149
+ series.x.data[index] = item.value.value.real;
150
+ return item.value.value.imaginary;
151
+ }
152
+ if (typeof item.value.value === 'number') {
153
+ return item.value.value;
154
+ }
147
155
 
148
- if (typeof item.value.value?.real === 'number') {
149
- series.x.data[index] = item.value.value.real;
150
- return item.value.value.imaginary;
151
156
  }
152
157
 
153
- return typeof item.value.value === 'number' ? item.value.value : undefined;
158
+ // return typeof item.value.value === 'number' ? item.value.value : undefined;
159
+
160
+ return undefined;
154
161
 
155
162
  });
156
163
 
157
- if (flat[0].value.format) {
158
- series.y.format = flat[0].value.format || '';
164
+ let first_format = '';
165
+ if (IsMetadata(flat[0])) {
166
+ first_format = flat[0].value.format || '';
167
+ }
168
+
169
+ if (first_format) {
170
+ series.y.format = first_format;
159
171
  const format = NumberFormatCache.Get(series.y.format || '');
160
172
  series.y.labels = series.y.data.map(value => (value === undefined) ? undefined : format.Format(value));
161
173
  }
@@ -177,8 +189,8 @@ export const ArrayToSeries = (array_data: ArrayUnion): SeriesType => {
177
189
  max: Math.max.apply(0, filtered),
178
190
  }
179
191
 
180
- if (flat[0].value.format) {
181
- series.x.format = flat[0].value.format || '';
192
+ if (first_format) {
193
+ series.x.format = first_format;
182
194
  const format = NumberFormatCache.Get(series.x.format || '');
183
195
  series.x.labels = series.x.data.map(value => (value === undefined) ? undefined : format.Format(value));
184
196
  }
@@ -212,7 +224,7 @@ export const TransformSeriesData = (raw_data?: UnionValue, default_x?: UnionValu
212
224
  if (Array.isArray(raw_data.value)) {
213
225
  for (const [series_index, entry] of raw_data.value.entries()) {
214
226
  if (!!entry && (typeof entry === 'object')) {
215
- if (entry.key === 'series') {
227
+ if (IsSeries(entry)) {
216
228
  const series = ReadSeries(entry.value);
217
229
  if (typeof series.index === 'undefined') {
218
230
  series.index = series_index + 1;
@@ -226,7 +238,7 @@ export const TransformSeriesData = (raw_data?: UnionValue, default_x?: UnionValu
226
238
  }
227
239
  }
228
240
  }
229
- else if (raw_data.key === 'series') {
241
+ else if (IsSeries(raw_data)) {
230
242
  const series = ReadSeries(raw_data.value);
231
243
  list.push(series);
232
244
  }
@@ -247,18 +259,17 @@ export const TransformSeriesData = (raw_data?: UnionValue, default_x?: UnionValu
247
259
 
248
260
  if (default_x?.type === ValueType.array) {
249
261
 
250
- const values = Util.Flatten(default_x.value);
262
+ const values = Util.Flatten<UnionValue>(default_x.value);
251
263
 
252
264
  let format = '0.00###';
253
265
 
254
- if (values[0] && values[0].type === ValueType.object) { // UnionIs.Extended(values[0])) {
266
+ if (IsMetadata(values[0]) && values[0].value.format) {
255
267
  format = values[0].value.format;
256
268
  }
257
269
 
258
270
  const data = values.map(x => {
259
271
  if (x.type === ValueType.number) { return x.value; }
260
- if (x.type === ValueType.object) { // ??
261
- // if (UnionIs.Extended(x)) { // ?
272
+ if (IsMetadata(x) && typeof x.value.value === 'number') {
262
273
  return x.value.value;
263
274
  }
264
275
  return undefined;
@@ -332,7 +343,7 @@ export const CommonData = (series: SeriesType[], y_floor?: number, y_ceiling?: n
332
343
  let x_min = Math.min.apply(0, x.map(test => test.x.range?.min || 0));
333
344
  let x_max = Math.max.apply(0, x.map(test => test.x.range?.max || 0));
334
345
 
335
- const y = series.filter(test => test.y.range);
346
+ // const y = series.filter(test => test.y.range);
336
347
  let y_min = Math.min.apply(0, x.map(test => test.y.range?.min || 0));
337
348
  let y_max = Math.max.apply(0, x.map(test => test.y.range?.max || 0));
338
349
 
@@ -461,7 +472,7 @@ export const CreateBubbleChart = (args: UnionValue[]): ChartData => {
461
472
 
462
473
  const common = CommonData(series, y_floor, undefined, x_floor);
463
474
  const title = args[1]?.toString() || undefined;
464
- const options = args[2]?.toString() || undefined;
475
+ // const options = args[2]?.toString() || undefined;
465
476
 
466
477
  // console.info({ series, common, title, options });
467
478
 
@@ -583,7 +594,7 @@ export const CreateBubbleChart = (args: UnionValue[]): ChartData => {
583
594
  *
584
595
  * @param args
585
596
  */
586
- export const CreateScatterChart = (args: any[], style: 'plot' | 'line' = 'plot'): ChartData => {
597
+ export const CreateScatterChart = (args: [UnionValue, string, string], style: 'plot' | 'line' = 'plot'): ChartData => {
587
598
 
588
599
  // FIXME: transform the data, then have this function
589
600
  // operate on clean data. that way the transform can
@@ -650,32 +661,40 @@ export const CreateScatterChart = (args: any[], style: 'plot' | 'line' = 'plot')
650
661
  * @param args arguments: data, categories, title, options
651
662
  * @param type
652
663
  */
653
- export const CreateColumnChart = (args: [UnionValue?, UnionValue?, string?, string?], type: 'bar' | 'column'): ChartData => {
664
+ export const CreateColumnChart = (
665
+ args: [UnionValue?, UnionValue?, string?, string?],
666
+ type: 'bar' | 'column'): ChartData => {
654
667
 
655
- const series: SeriesType[] = TransformSeriesData(args[0]);
668
+ const [data, labels, args_title, args_options] = args;
669
+
670
+ const series: SeriesType[] = TransformSeriesData(data);
656
671
  const common = CommonData(series);
657
672
 
658
673
  let category_labels: string[] | undefined;
659
674
 
660
- if (args[1]) {
675
+ if (labels) {
676
+
677
+ const values = labels.type === ValueType.array ? Util.Flatten<UnionValue>(labels.value) : Util.Flatten<UnionValue>(labels);
661
678
 
662
- const values = args[1].type === ValueType.array ? Util.Flatten(args[1].value) : Util.Flatten(args[1]);
663
679
  category_labels = values.map((cell) => {
664
- if (!cell) { return ''; }
665
680
 
666
- if (cell.type === ValueType.object && cell.value.type === 'metadata') {
681
+ if (!cell || !cell.value) { return ''; }
682
+
683
+ if (IsMetadata(cell)) {
667
684
  if (typeof cell.value.value === 'number') {
668
685
  const format = NumberFormatCache.Get(cell.value.format || DEFAULT_FORMAT);
669
686
  return format.Format(cell.value.value);
670
687
  }
671
- return cell.value.value;
688
+ return cell.value.value?.toString() || '';
672
689
  }
673
690
 
674
691
  if (typeof cell.value === 'number') {
675
- const format = NumberFormatCache.Get(cell.format || DEFAULT_FORMAT);
692
+ const format = NumberFormatCache.Get(DEFAULT_FORMAT);
676
693
  return format.Format(cell.value);
677
694
  }
678
- return cell.value;
695
+
696
+ return cell.value.toString();
697
+
679
698
  });
680
699
 
681
700
  const count = series.reduce((a, entry) => Math.max(a, entry.y.data.length), 0);
@@ -688,8 +707,8 @@ export const CreateColumnChart = (args: [UnionValue?, UnionValue?, string?, stri
688
707
 
689
708
  }
690
709
 
691
- const title = args[2]?.toString() || undefined;
692
- const options = args[3]?.toString() || undefined;
710
+ const title = args_title?.toString() || undefined;
711
+ const options = args_options?.toString() || undefined;
693
712
 
694
713
  const chart_data = {
695
714
  type,
@@ -734,7 +753,7 @@ export const CreateColumnChart = (args: [UnionValue?, UnionValue?, string?, stri
734
753
  /**
735
754
  * args: data, labels, title, callouts, "smooth"
736
755
  */
737
- export const CreateLineChart = (args: any[], type: 'line' | 'area'): ChartData => {
756
+ export const CreateLineChart = (args: [UnionValue, UnionValue, string, string], type: 'line' | 'area'): ChartData => {
738
757
 
739
758
  const series: SeriesType[] = TransformSeriesData(args[0], args[1]);
740
759
  const common = CommonData(series, 0, 0);
@@ -781,14 +800,23 @@ export const CreateLineChart = (args: any[], type: 'line' | 'area'): ChartData =
781
800
  */
782
801
  export const CreateDonut = (args: [UnionValue?, UnionValue?, string?, string?, string?], pie_chart = false): ChartData => {
783
802
 
803
+ const [_a, _c, title, _options, _slice_title] = args;
804
+
784
805
  const raw_data = args[0]?.type === ValueType.array ? args[0].value : args[0];
785
806
 
786
- // we're now expecting this to be metadata (including value).
787
- // so we need to unpack. could be an array... could be deep...
788
- const flat = Util.Flatten(raw_data);
807
+ const flat = raw_data ? Util.Flatten<UnionValue>(raw_data) : [];
789
808
 
790
809
  // we still need the aggregate for range, scale
791
- let data = flat.map((x) => (typeof x.value.value === 'number') ? x.value.value : undefined) as number[];
810
+ // let data = flat.map((x) => (typeof x.value.value === 'number') ? x.value.value : undefined) as number[];
811
+
812
+ let data: (number|undefined)[] = flat.map(cell => {
813
+ if (IsMetadata(cell)) {
814
+ if (typeof cell.value.value === 'number') {
815
+ return cell.value.value;
816
+ }
817
+ }
818
+ return undefined;
819
+ })
792
820
 
793
821
 
794
822
  // if labels are strings, just pass them in. if they're numbers then
@@ -796,34 +824,40 @@ export const CreateDonut = (args: [UnionValue?, UnionValue?, string?, string?, s
796
824
 
797
825
  const raw_labels = args[1]?.type === ValueType.array ? args[1].value : args[1];
798
826
 
799
- const labels = Util.Flatten(raw_labels).map((label) => {
800
- if (label && typeof label === 'object') {
801
- const value = label.value?.value;
802
- if (typeof value === 'number' && label.value?.format) {
803
- return NumberFormatCache.Get(label.value?.format).Format(value);
827
+ const labels = Util.Flatten<UnionValue>(raw_labels||[]).map(label => {
828
+ if (IsMetadata(label)) {
829
+ if (typeof label.value.value === 'number' && label.value.format) {
830
+ return NumberFormatCache.Get(label.value.format).Format(label.value.value);
804
831
  }
805
- else return value ? value.toString() : '';
832
+ else return label.value.value?.toString() || '';
806
833
  }
807
- else return label ? label.toString() : '';
834
+ return label.value?.toString() || '';
808
835
  });
809
836
 
810
837
  // no negative numbers
811
838
 
839
+ let warned = false;
812
840
  data = data.map((check) => {
813
- if (check < 0) {
814
- console.warn('pie/donut chart does not support negative values (omitted)');
841
+ if (check && check < 0) {
842
+ if (!warned) {
843
+ console.warn('pie/donut chart does not support negative values (omitted)');
844
+ warned = true;
845
+ }
815
846
  return 0;
816
847
  }
817
848
  return check;
818
849
  });
819
850
 
820
- const title = args[2] || '';
821
-
822
851
  let sum = 0;
823
852
 
824
853
  const slices: DonutSlice[] = data.map((value, i) => {
825
854
  if (typeof value !== 'undefined') sum += value;
826
- return { value, label: labels[i] || '', index: i + 1, percent: 0 };
855
+ return {
856
+ value: value || 0,
857
+ label: labels[i] || '',
858
+ index: i + 1,
859
+ percent: 0,
860
+ };
827
861
  });
828
862
 
829
863
  if (sum) {
@@ -835,7 +869,16 @@ export const CreateDonut = (args: [UnionValue?, UnionValue?, string?, string?, s
835
869
  // titles? label/value/percent
836
870
  // FIXME: number format(s)
837
871
 
838
- const format_pattern = (flat.length && flat[0].value?.format) ? flat[0].value.format : '';
872
+ let format_pattern = '';
873
+ for (const value of flat) {
874
+ if (IsMetadata(value)) {
875
+ format_pattern = value.value.format || '';
876
+ break;
877
+ }
878
+ }
879
+
880
+ // const format_pattern = (flat.length && flat[0].value?.format) ? flat[0].value.format : '';
881
+
839
882
  const format = NumberFormatCache.Get(format_pattern || DEFAULT_FORMAT);
840
883
  const percent_format = NumberFormatCache.Get('percent');
841
884
 
@@ -861,11 +904,10 @@ export const CreateDonut = (args: [UnionValue?, UnionValue?, string?, string?, s
861
904
 
862
905
  // optionally sort...
863
906
 
864
- const options = (args[3] || '').toString().trim();
865
907
 
866
908
  // old-style...
867
909
 
868
- let sort = options.toUpperCase();
910
+ let sort = (_options||'').toUpperCase();
869
911
  if (sort === 'ASC' || sort === 'ASCENDING' || sort === 'INC') {
870
912
  slices.sort((a, b) => { return (a.value || 0) - (b.value || 0); });
871
913
  }
@@ -873,7 +915,7 @@ export const CreateDonut = (args: [UnionValue?, UnionValue?, string?, string?, s
873
915
  slices.sort((a, b) => { return (b.value || 0) - (a.value || 0); });
874
916
  }
875
917
  else {
876
- const match = options.match(/sort=([\w]+)(?:\W|$)/i);
918
+ const match = (_options||'').match(/sort=([\w]+)(?:\W|$)/i);
877
919
  if (match) {
878
920
  sort = match[1];
879
921
  if (/^(asc|inc)/i.test(sort)) {
@@ -888,11 +930,11 @@ export const CreateDonut = (args: [UnionValue?, UnionValue?, string?, string?, s
888
930
  const chart_data: ChartData = {
889
931
  type: pie_chart ? 'pie' : 'donut',
890
932
  slices,
891
- title,
933
+ title: title || '',
892
934
  };
893
935
 
894
- if (options) {
895
- const match = options.match(/class=([_-\w]+)(?:\W|$)/);
936
+ if (_options) {
937
+ const match = _options.match(/class=([_-\w]+)(?:\W|$)/);
896
938
  if (match) {
897
939
  chart_data.class_name = match[1];
898
940
  }
@@ -31,7 +31,8 @@ export class Chart {
31
31
 
32
32
  public Exec(func: string, union: ExtendedUnion) {
33
33
 
34
- const args: any[] = union?.value || [];
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ const args: any[] = (union?.value as any[]) || [];
35
36
 
36
37
  switch (func.toLowerCase()) {
37
38
 
@@ -44,11 +45,11 @@ export class Chart {
44
45
  break;
45
46
 
46
47
  case 'line.chart':
47
- this.chart_data = ChartUtils.CreateLineChart(args, 'line');
48
+ this.chart_data = ChartUtils.CreateLineChart(args as Parameters<typeof ChartUtils.CreateLineChart>[0], 'line');
48
49
  break;
49
50
 
50
51
  case 'area.chart':
51
- this.chart_data = ChartUtils.CreateLineChart(args, 'area');
52
+ this.chart_data = ChartUtils.CreateLineChart(args as Parameters<typeof ChartUtils.CreateLineChart>[0], 'area');
52
53
  break;
53
54
 
54
55
  case 'donut.chart':
@@ -57,11 +58,11 @@ export class Chart {
57
58
  break;
58
59
 
59
60
  case 'scatter.plot':
60
- this.chart_data = ChartUtils.CreateScatterChart(args, 'plot');
61
+ this.chart_data = ChartUtils.CreateScatterChart(args as Parameters<typeof ChartUtils.CreateScatterChart>[0], 'plot');
61
62
  break;
62
63
 
63
64
  case 'scatter.line':
64
- this.chart_data = ChartUtils.CreateScatterChart(args, 'line');
65
+ this.chart_data = ChartUtils.CreateScatterChart(args as Parameters<typeof ChartUtils.CreateScatterChart>[0], 'line');
65
66
  break;
66
67
 
67
68
  case 'bubble.chart':
@@ -23,6 +23,7 @@ export class DefaultChartRenderer implements ChartRendererType {
23
23
 
24
24
  private margin = { top: 0.025, left: 0.05, bottom: 0.025, right: 0.075 };
25
25
 
26
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
26
27
  public Resize(target: HTMLElement, data: ChartData) {
27
28
  this.renderer.Resize();
28
29
  }
@@ -196,7 +197,7 @@ export class DefaultChartRenderer implements ChartRendererType {
196
197
 
197
198
  // now do type-specific rendering
198
199
 
199
- let zeros: number[]|undefined = [];
200
+ const zeros: number[] = [];
200
201
 
201
202
  switch (chart_data.type) {
202
203
  case 'scatter':
@@ -384,7 +385,7 @@ export class DefaultChartRenderer implements ChartRendererType {
384
385
 
385
386
  let x = 0;
386
387
  let width = 0;
387
- let negative = false;
388
+ // let negative = false;
388
389
 
389
390
  if (zero) {
390
391
  if (value > 0) {
@@ -394,7 +395,7 @@ export class DefaultChartRenderer implements ChartRendererType {
394
395
  else {
395
396
  width = Util.ApplyScale(chart_data.scale.min - value, area.width, chart_data.scale);
396
397
  x = area.left + zero - width;
397
- negative = true;
398
+ // negative = true;
398
399
  }
399
400
  }
400
401
  else {
@@ -484,7 +485,7 @@ export class DefaultChartRenderer implements ChartRendererType {
484
485
 
485
486
  let height = 0;
486
487
  let y = 0;
487
- let negative = false;
488
+ // let negative = false;
488
489
 
489
490
  if (zero) {
490
491
  if (value > 0) {
@@ -494,7 +495,7 @@ export class DefaultChartRenderer implements ChartRendererType {
494
495
  else {
495
496
  height = Util.ApplyScale(chart_data.scale.min - value, area.height, chart_data.scale);
496
497
  y = area.bottom - zero; // // area.bottom - height - zero;
497
- negative = true;
498
+ // negative = true;
498
499
  }
499
500
  }
500
501
  else {
@@ -33,11 +33,11 @@ export interface Metrics {
33
33
  y_offset: number;
34
34
  }
35
35
 
36
- const SVGNode = (tag: string, attribute_map: {[index: string]: any} = {}, text?: string): SVGElement => {
36
+ const SVGNode = (tag: string, attribute_map: {[index: string]: string|number|unknown} = {}, text?: string): SVGElement => {
37
37
  const node = document.createElementNS(SVGNS, tag);
38
38
  for (const key of Object.keys(attribute_map)) {
39
39
  if (attribute_map[key] !== undefined) {
40
- const value = attribute_map[key];
40
+ const value = attribute_map[key] ?? '';
41
41
  node.setAttribute(key, Array.isArray(value) ? value.join(' ') : value.toString());
42
42
  }
43
43
  }
@@ -836,10 +836,10 @@ export class ChartRenderer {
836
836
 
837
837
  const shape = SVGNode('circle', {cx: circle.x, cy: circle.y, r: step});
838
838
 
839
- shape.addEventListener('mouseenter', (event) => {
839
+ shape.addEventListener('mouseenter', () => {
840
840
  this.parent.setAttribute('title', titles[circle.i] || '');
841
841
  });
842
- shape.addEventListener('mouseleave', (event) => {
842
+ shape.addEventListener('mouseleave', () => {
843
843
  this.parent.setAttribute('title', '');
844
844
  });
845
845
 
@@ -934,10 +934,10 @@ export class ChartRenderer {
934
934
 
935
935
  const shape = SVGNode('circle', { cx: circle.x, cy: circle.y, r: step });
936
936
 
937
- shape.addEventListener('mouseenter', (event) => {
937
+ shape.addEventListener('mouseenter', () => {
938
938
  this.parent.setAttribute('title', titles[circle.i] || '');
939
939
  });
940
- shape.addEventListener('mouseleave', (event) => {
940
+ shape.addEventListener('mouseleave', () => {
941
941
  this.parent.setAttribute('title', '');
942
942
  });
943
943
 
@@ -1251,8 +1251,8 @@ export class ChartRenderer {
1251
1251
  offset: number,
1252
1252
  }> = [];
1253
1253
 
1254
- const d: string[] = [];
1255
- const areas: string[] = [];
1254
+ // const d: string[] = [];
1255
+ // const areas: string[] = [];
1256
1256
 
1257
1257
  const group = SVGNode('g', {class: classes});
1258
1258
 
@@ -1652,10 +1652,10 @@ export class ChartRenderer {
1652
1652
  });
1653
1653
 
1654
1654
  if (title) {
1655
- node.addEventListener('mouseenter', (event) => {
1655
+ node.addEventListener('mouseenter', () => {
1656
1656
  this.parent.setAttribute('title', title);
1657
1657
  });
1658
- node.addEventListener('mouseleave', (event) => {
1658
+ node.addEventListener('mouseleave', () => {
1659
1659
  this.parent.setAttribute('title', '');
1660
1660
  });
1661
1661
  }
@@ -1894,7 +1894,8 @@ export class ChartRenderer {
1894
1894
  let break_index = -1;
1895
1895
  let break_value = 1;
1896
1896
 
1897
- const indices: number[] = [];
1897
+ // const indices: number[] = [];
1898
+
1898
1899
  for (let i = 0; i < text.length; i++) {
1899
1900
  if (break_regex.test(text[i])) {
1900
1901
  const index_value = Math.abs(0.5 - (i / text.length));