@trebco/treb 31.3.4 → 31.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/treb-export-worker.mjs +2 -2
- package/dist/treb-spreadsheet.mjs +12 -11
- package/dist/treb.d.ts +7 -1
- package/package.json +1 -1
- package/treb-base-types/src/color.ts +38 -5
- package/treb-base-types/src/font-stack.ts +1 -1
- package/treb-calculator/src/dag/state_leaf_vertex.ts +16 -39
- package/treb-data-model/src/annotation.ts +5 -0
- package/treb-embed/src/embedded-spreadsheet.ts +65 -15
- package/treb-embed/src/toolbar-message.ts +1 -1
- package/treb-grid/src/types/grid.ts +109 -30
- package/treb-grid/src/types/grid_base.ts +70 -2
- package/treb-grid/src/types/grid_command.ts +32 -2
- package/treb-grid/src/types/grid_events.ts +7 -1
- package/treb-grid/src/types/grid_options.ts +4 -0
- package/treb-grid/src/types/tab_bar.ts +2 -0
- package/treb-grid/src/types/update_flags.ts +6 -0
- package/treb-parser/src/md-parser.ts +23 -7
- package/test/parser.ts +0 -13
package/dist/treb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! API v31.
|
|
1
|
+
/*! API v31.7. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* add our tag to the map
|
|
@@ -498,6 +498,7 @@ export declare class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
498
498
|
InsertTable(range?: RangeReference, options?: InsertTableOptions): void;
|
|
499
499
|
RemoveTable(range?: RangeReference): void;
|
|
500
500
|
UpdateTableStyle(range?: RangeReference, theme?: TableTheme | number): void;
|
|
501
|
+
SetTabColor(sheet?: number | string, color?: Color): void;
|
|
501
502
|
|
|
502
503
|
/**
|
|
503
504
|
* Add a sheet, optionally named.
|
|
@@ -2153,6 +2154,11 @@ export interface AnnotationChartData extends AnnotationDataBase {
|
|
|
2153
2154
|
}
|
|
2154
2155
|
export interface AnnotationTextBoxData extends AnnotationDataBase {
|
|
2155
2156
|
type: 'textbox';
|
|
2157
|
+
|
|
2158
|
+
/**
|
|
2159
|
+
* @internalRemarks
|
|
2160
|
+
* what's with this weird structure? did we inherit it? can we clean it up?
|
|
2161
|
+
*/
|
|
2156
2162
|
data: {
|
|
2157
2163
|
style?: CellStyle;
|
|
2158
2164
|
paragraphs: {
|
package/package.json
CHANGED
|
@@ -125,14 +125,22 @@ export const ColorFunctions = {
|
|
|
125
125
|
////////////////
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
GetLuminance: (r
|
|
128
|
+
GetLuminance: ([r, g, b]: number[],): number => {
|
|
129
129
|
const a = [r, g, b].map(v => {
|
|
130
130
|
v /= 255;
|
|
131
131
|
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
132
132
|
});
|
|
133
133
|
return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
|
|
134
134
|
},
|
|
135
|
-
|
|
135
|
+
|
|
136
|
+
WeightedLuminance: ([r, g, b]: number[], weights: number[] = [1,1,1]): number => {
|
|
137
|
+
const a = [r, g, b].map(v => {
|
|
138
|
+
v /= 255;
|
|
139
|
+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
140
|
+
});
|
|
141
|
+
return 0.2126 * a[0] * weights[0] + 0.7152 * a[1] * weights[1] + 0.0722 * a[2] * weights[2];
|
|
142
|
+
},
|
|
143
|
+
|
|
136
144
|
GetContrastRatio: (data: [number, number]): number => {
|
|
137
145
|
data.sort((a, b) => b - a);
|
|
138
146
|
return (data[0] + 0.05) / (data[1] + 0.05);
|
|
@@ -140,14 +148,39 @@ export const ColorFunctions = {
|
|
|
140
148
|
|
|
141
149
|
GetTextColor: (background: [number, number, number], a: [number, number, number], b: [number, number, number]) => {
|
|
142
150
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
151
|
+
// weighted contrast ratio: assign more weight to the r channel.
|
|
152
|
+
|
|
153
|
+
const weights = [0.4, 0.3, 0.3];
|
|
154
|
+
|
|
155
|
+
const luminance = ColorFunctions.WeightedLuminance(background, weights);
|
|
156
|
+
const luminance_a = ColorFunctions.WeightedLuminance(a, weights);
|
|
157
|
+
const luminance_b = ColorFunctions.WeightedLuminance(b, weights);
|
|
146
158
|
|
|
147
159
|
const contrast_a = ColorFunctions.GetContrastRatio([luminance_a, luminance]);
|
|
148
160
|
const contrast_b = ColorFunctions.GetContrastRatio([luminance_b, luminance]);
|
|
149
161
|
|
|
150
162
|
return contrast_a > contrast_b ? a : b;
|
|
163
|
+
|
|
164
|
+
// perceptual lightness (actually I like this one)
|
|
165
|
+
|
|
166
|
+
/*
|
|
167
|
+
const background_lightness = ColorFunctions.RGBToHSL(...background).l;
|
|
168
|
+
const a_lightness = ColorFunctions.RGBToHSL(...a).l;
|
|
169
|
+
const b_lightness = ColorFunctions.RGBToHSL(...b).l;
|
|
170
|
+
|
|
171
|
+
console.info("background", background_lightness, "a", a_lightness, "b", b_lightness);
|
|
172
|
+
|
|
173
|
+
const lighter = a_lightness > b_lightness ? a : b;
|
|
174
|
+
const darker = a_lightness > b_lightness ? b : a;
|
|
175
|
+
|
|
176
|
+
if (background_lightness < .6) {
|
|
177
|
+
return lighter;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
return darker;
|
|
181
|
+
}
|
|
182
|
+
*/
|
|
183
|
+
|
|
151
184
|
},
|
|
152
185
|
|
|
153
186
|
};
|
|
@@ -37,6 +37,15 @@ import { Color } from './vertex';
|
|
|
37
37
|
* FIXME: it might be better to have an intermediate class/interface and
|
|
38
38
|
* have both leaf- and spreadsheet-vertex extend that.
|
|
39
39
|
*
|
|
40
|
+
* UPDATE: we're removing the internal "state" representation because (1)
|
|
41
|
+
* it should be unnecessary, if we are only updating when dependencies
|
|
42
|
+
* change, and (2) it was broken anyway.
|
|
43
|
+
*
|
|
44
|
+
* Now we rely on the calculation graph to indicate when the leaf is
|
|
45
|
+
* dirty and needs to update. This will result in extra calculation when
|
|
46
|
+
* you do a hard recalc, but that seems reasonable (and we could possibly
|
|
47
|
+
* work around that).
|
|
48
|
+
*
|
|
40
49
|
*/
|
|
41
50
|
export class StateLeafVertex extends SpreadsheetVertex {
|
|
42
51
|
|
|
@@ -54,42 +63,6 @@ export class StateLeafVertex extends SpreadsheetVertex {
|
|
|
54
63
|
*/
|
|
55
64
|
public color = Color.black;
|
|
56
65
|
|
|
57
|
-
protected state_representation = '';
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* construct the state, compare, and increment the state id if
|
|
61
|
-
* it changes. this is expected to be called from Calculate(), but
|
|
62
|
-
* we can also call it on init if we already know the state.
|
|
63
|
-
*
|
|
64
|
-
* FIXME: what's more expensive, generating this state field or
|
|
65
|
-
* re-rendering a chart with the same data? (...?)
|
|
66
|
-
* especially since it's only called on dirty...
|
|
67
|
-
*
|
|
68
|
-
* what is the case where the depenendency is dirty but state
|
|
69
|
-
* does not change? you type in the same value? (...) or maybe
|
|
70
|
-
* there's a volatile function that doesn't change value (e.g. Today())
|
|
71
|
-
*
|
|
72
|
-
* still, it seems like a waste here. let's test without the state.
|
|
73
|
-
* (meaning just update the flag anytime it's dirty)
|
|
74
|
-
*
|
|
75
|
-
* Actually I think the case is manual recalc, when values don't change
|
|
76
|
-
* (especially true for MC charts).
|
|
77
|
-
*
|
|
78
|
-
* TODO: perf
|
|
79
|
-
*/
|
|
80
|
-
public UpdateState(): void {
|
|
81
|
-
|
|
82
|
-
// FIXME: hash!
|
|
83
|
-
//const state = JSON.stringify(this.edges_in.map((edge) => (edge as SpreadsheetVertex).result));
|
|
84
|
-
const state = JSON.stringify(Array.from(this.edges_in).map((edge) => (edge as SpreadsheetVertex).result));
|
|
85
|
-
|
|
86
|
-
if (state !== this.state_representation) {
|
|
87
|
-
this.state_representation = state;
|
|
88
|
-
this.state_id++;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
66
|
/** overrides calculate function */
|
|
94
67
|
public Calculate(): void {
|
|
95
68
|
|
|
@@ -103,11 +76,15 @@ export class StateLeafVertex extends SpreadsheetVertex {
|
|
|
103
76
|
}
|
|
104
77
|
}
|
|
105
78
|
|
|
106
|
-
// ok
|
|
107
|
-
|
|
79
|
+
// ok update state so clients know they need to refresh
|
|
80
|
+
// (see note above re: internal state)
|
|
81
|
+
|
|
82
|
+
this.state_id++;
|
|
83
|
+
|
|
84
|
+
// and we're clean
|
|
85
|
+
|
|
108
86
|
this.dirty = false;
|
|
109
87
|
|
|
110
|
-
// we are not allowed to have edges out, so nothing to do
|
|
111
88
|
}
|
|
112
89
|
|
|
113
90
|
public AddDependent(): void {
|
|
@@ -190,6 +190,11 @@ export interface AnnotationChartData extends AnnotationDataBase {
|
|
|
190
190
|
|
|
191
191
|
export interface AnnotationTextBoxData extends AnnotationDataBase {
|
|
192
192
|
type: 'textbox';
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @internalRemarks
|
|
196
|
+
* what's with this weird structure? did we inherit it? can we clean it up?
|
|
197
|
+
*/
|
|
193
198
|
data: {
|
|
194
199
|
style?: CellStyle;
|
|
195
200
|
paragraphs: {
|
|
@@ -1411,18 +1411,25 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1411
1411
|
if (event.type === 'structure') {
|
|
1412
1412
|
this.grid.EnsureActiveSheet();
|
|
1413
1413
|
this.grid.UpdateLayout();
|
|
1414
|
-
// (this.grid as any).tab_bar?.Update();
|
|
1415
1414
|
this.grid.UpdateTabBar();
|
|
1415
|
+
|
|
1416
|
+
if (event.update_annotations) {
|
|
1417
|
+
this.grid.RefreshAnnotations();
|
|
1418
|
+
this.InflateAnnotations();
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1416
1421
|
}
|
|
1417
1422
|
});
|
|
1418
1423
|
|
|
1419
1424
|
view.Subscribe(event => {
|
|
1425
|
+
|
|
1420
1426
|
switch (event.type) {
|
|
1421
1427
|
case 'selection':
|
|
1422
1428
|
break;
|
|
1423
1429
|
default:
|
|
1424
1430
|
view.UpdateAnnotations();
|
|
1425
1431
|
this.grid.Update(true);
|
|
1432
|
+
this.grid.UpdateAnnotations();
|
|
1426
1433
|
}
|
|
1427
1434
|
});
|
|
1428
1435
|
|
|
@@ -1430,8 +1437,13 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1430
1437
|
if (event.type === 'structure') {
|
|
1431
1438
|
view.grid.EnsureActiveSheet();
|
|
1432
1439
|
view.grid.UpdateLayout();
|
|
1433
|
-
// (view.grid as any).tab_bar?.Update();
|
|
1434
1440
|
view.grid.UpdateTabBar();
|
|
1441
|
+
|
|
1442
|
+
if (event.update_annotations) {
|
|
1443
|
+
view.grid.RefreshAnnotations();
|
|
1444
|
+
view.InflateAnnotations();
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1435
1447
|
}
|
|
1436
1448
|
});
|
|
1437
1449
|
|
|
@@ -1444,12 +1456,14 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1444
1456
|
case 'reset':
|
|
1445
1457
|
view.grid.EnsureActiveSheet(true); // force update of annotations
|
|
1446
1458
|
view.UpdateAnnotations();
|
|
1459
|
+
view.grid.UpdateAnnotations();
|
|
1447
1460
|
view.grid.Update(true);
|
|
1448
1461
|
break;
|
|
1449
1462
|
|
|
1450
1463
|
default:
|
|
1451
1464
|
view.UpdateAnnotations();
|
|
1452
1465
|
view.grid.Update(true);
|
|
1466
|
+
view.grid.UpdateAnnotations();
|
|
1453
1467
|
}
|
|
1454
1468
|
});
|
|
1455
1469
|
|
|
@@ -1651,7 +1665,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1651
1665
|
if (selection && !selection.empty) {
|
|
1652
1666
|
const label = selection.area.spreadsheet_label;
|
|
1653
1667
|
|
|
1654
|
-
if (func === 'Scatter.Plot' || func === 'Scatter.Line') {
|
|
1668
|
+
if (func === 'Scatter.Plot' || func === 'Scatter.Line' || func === 'Box.Plot') {
|
|
1655
1669
|
this.InsertAnnotation(`=${func}(Series(,,${label}),"${label}")`, undefined, undefined, ',');
|
|
1656
1670
|
}
|
|
1657
1671
|
else {
|
|
@@ -1758,8 +1772,6 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1758
1772
|
|
|
1759
1773
|
if (scale && !isNaN(scale)) {
|
|
1760
1774
|
|
|
1761
|
-
console.info("FS", scale);
|
|
1762
|
-
|
|
1763
1775
|
this.grid.ApplyStyle(undefined, {
|
|
1764
1776
|
//font_size_unit: 'em', font_size_value: scale
|
|
1765
1777
|
font_size: {
|
|
@@ -1843,6 +1855,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1843
1855
|
case 'insert-bar-chart': insert_annotation('Bar.Chart'); break;
|
|
1844
1856
|
case 'insert-line-chart': insert_annotation('Line.Chart'); break;
|
|
1845
1857
|
case 'insert-scatter-plot': insert_annotation('Scatter.Plot'); break;
|
|
1858
|
+
case 'insert-box-plot': insert_annotation('Box.Plot'); break;
|
|
1846
1859
|
|
|
1847
1860
|
case 'increase-precision':
|
|
1848
1861
|
case 'decrease-precision':
|
|
@@ -2230,12 +2243,22 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2230
2243
|
// FIXME: sheet change events (affects annotations)
|
|
2231
2244
|
// TODO: sheet change events (affects annotations)
|
|
2232
2245
|
|
|
2246
|
+
// console.info({events});
|
|
2247
|
+
|
|
2233
2248
|
for (const event of events) {
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2249
|
+
switch (event.type) {
|
|
2250
|
+
case 'data':
|
|
2251
|
+
recalc = true;
|
|
2252
|
+
break;
|
|
2253
|
+
|
|
2254
|
+
case 'structure':
|
|
2255
|
+
if (event.rebuild_required) {
|
|
2256
|
+
reset = true;
|
|
2257
|
+
}
|
|
2258
|
+
break;
|
|
2259
|
+
|
|
2260
|
+
default:
|
|
2261
|
+
// console.info('unhandled event:', event.type, { event });
|
|
2239
2262
|
}
|
|
2240
2263
|
}
|
|
2241
2264
|
|
|
@@ -2417,6 +2440,17 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2417
2440
|
|
|
2418
2441
|
}
|
|
2419
2442
|
|
|
2443
|
+
public SetTabColor(sheet?: number|string, color?: Color) {
|
|
2444
|
+
const target = (typeof sheet === 'undefined') ?
|
|
2445
|
+
this.grid.active_sheet :
|
|
2446
|
+
this.model.sheets.Find(sheet);
|
|
2447
|
+
|
|
2448
|
+
if (target) {
|
|
2449
|
+
this.grid.TabColor(target, color);
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2420
2454
|
/**
|
|
2421
2455
|
* Add a sheet, optionally named.
|
|
2422
2456
|
*/
|
|
@@ -2585,9 +2619,13 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2585
2619
|
* the argument separator, we allow that to be passed directly, but this
|
|
2586
2620
|
* is deprecated. new code should use the options object.
|
|
2587
2621
|
*/
|
|
2588
|
-
public InsertAnnotation(
|
|
2622
|
+
public InsertAnnotation(
|
|
2623
|
+
formula: string,
|
|
2624
|
+
type: AnnotationType = 'treb-chart',
|
|
2625
|
+
rect?: IRectangle|RangeReference,
|
|
2626
|
+
options?: EvaluateOptions|','|';'): void {
|
|
2589
2627
|
|
|
2590
|
-
let target: IRectangle |
|
|
2628
|
+
let target: IRectangle | IArea | undefined;
|
|
2591
2629
|
let argument_separator: ','|';'|undefined = undefined;
|
|
2592
2630
|
let r1c1 = false;
|
|
2593
2631
|
|
|
@@ -2664,7 +2702,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2664
2702
|
type,
|
|
2665
2703
|
formula,
|
|
2666
2704
|
// class_name,
|
|
2667
|
-
}, undefined, undefined, target || { top: y / scale + 30, left: x / scale + 30, ...auto_size });
|
|
2705
|
+
}, undefined, undefined, undefined, target || { top: y / scale + 30, left: x / scale + 30, ...auto_size });
|
|
2668
2706
|
|
|
2669
2707
|
}
|
|
2670
2708
|
|
|
@@ -5353,7 +5391,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
5353
5391
|
src: contents,
|
|
5354
5392
|
original_size: { width: img.width || 300, height: img.height || 300 },
|
|
5355
5393
|
},
|
|
5356
|
-
}, undefined, undefined, {
|
|
5394
|
+
}, undefined, undefined, undefined, {
|
|
5357
5395
|
top: 30,
|
|
5358
5396
|
left: 30,
|
|
5359
5397
|
width: img.width || 300,
|
|
@@ -5488,7 +5526,17 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
5488
5526
|
|
|
5489
5527
|
// set all views dirty in this case
|
|
5490
5528
|
for (const view of annotation.view) {
|
|
5491
|
-
|
|
5529
|
+
|
|
5530
|
+
// if !view, that usually means it was just created. it should
|
|
5531
|
+
// get taken care of soon, so don't worry about it.
|
|
5532
|
+
|
|
5533
|
+
if (view) {
|
|
5534
|
+
view.dirty = true;
|
|
5535
|
+
}
|
|
5536
|
+
// else {
|
|
5537
|
+
// console.info("empty view")
|
|
5538
|
+
// }
|
|
5539
|
+
|
|
5492
5540
|
}
|
|
5493
5541
|
}
|
|
5494
5542
|
|
|
@@ -5508,6 +5556,8 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
5508
5556
|
// either we just set this dirty for all views, or another
|
|
5509
5557
|
// view set it dirty for us: in either case, update
|
|
5510
5558
|
|
|
5559
|
+
view.dirty = false;
|
|
5560
|
+
|
|
5511
5561
|
if (view.update_callback) {
|
|
5512
5562
|
view.update_callback();
|
|
5513
5563
|
}
|
|
@@ -23,7 +23,7 @@ export interface BorderToolbarMessage {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export interface AnnotationToolbarMessage {
|
|
26
|
-
command: 'insert-image'|'insert-donut-chart'|'insert-line-chart'|'insert-column-chart'|'insert-bar-chart'|'insert-scatter-plot';
|
|
26
|
+
command: 'insert-image'|'insert-donut-chart'|'insert-line-chart'|'insert-column-chart'|'insert-bar-chart'|'insert-scatter-plot'|'insert-box-plot';
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export interface LayoutToolbarMessage {
|
|
@@ -104,7 +104,9 @@ import type {
|
|
|
104
104
|
InsertRowsCommand, InsertColumnsCommand, SetNameCommand,
|
|
105
105
|
ActivateSheetCommand, DataValidationCommand,
|
|
106
106
|
ResizeRowsCommand, ResizeColumnsCommand,
|
|
107
|
-
SelectCommand
|
|
107
|
+
SelectCommand,
|
|
108
|
+
CreateAnnotationCommand,
|
|
109
|
+
RemoveAnnotationCommand
|
|
108
110
|
} from './grid_command';
|
|
109
111
|
import { CommandKey
|
|
110
112
|
} from './grid_command';
|
|
@@ -705,6 +707,26 @@ export class Grid extends GridBase {
|
|
|
705
707
|
return undefined;
|
|
706
708
|
}
|
|
707
709
|
|
|
710
|
+
public CreateAnnotation(
|
|
711
|
+
properties: Partial<AnnotationData> = {},
|
|
712
|
+
sheet: Sheet = this.active_sheet,
|
|
713
|
+
add_to_sheet = true,
|
|
714
|
+
offset = false,
|
|
715
|
+
target?: IArea|IRectangle,
|
|
716
|
+
focus?: boolean ) {
|
|
717
|
+
|
|
718
|
+
this.ExecCommand({
|
|
719
|
+
key: CommandKey.CreateAnnotation,
|
|
720
|
+
properties,
|
|
721
|
+
add_to_sheet,
|
|
722
|
+
offset,
|
|
723
|
+
target,
|
|
724
|
+
focus,
|
|
725
|
+
sheet,
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
}
|
|
729
|
+
|
|
708
730
|
/**
|
|
709
731
|
* create an annotation, with properties, without an original object.
|
|
710
732
|
* optionally (and by default) add to sheet.
|
|
@@ -716,10 +738,11 @@ export class Grid extends GridBase {
|
|
|
716
738
|
* @param target new parameter allows setting annotation as rect or as
|
|
717
739
|
* cell range
|
|
718
740
|
*/
|
|
719
|
-
|
|
720
|
-
const annotation = new Annotation(properties);
|
|
741
|
+
protected CreateAnnotationInternal(command: CreateAnnotationCommand) {
|
|
721
742
|
|
|
722
|
-
|
|
743
|
+
const annotation = new Annotation(command.properties);
|
|
744
|
+
|
|
745
|
+
if (command.offset) {
|
|
723
746
|
|
|
724
747
|
// to offset, we have to have layout (or at least scaled rect)
|
|
725
748
|
if (!annotation.data.layout && annotation.scaled_rect) {
|
|
@@ -734,7 +757,7 @@ export class Grid extends GridBase {
|
|
|
734
757
|
let recheck = true;
|
|
735
758
|
while (recheck) {
|
|
736
759
|
recheck = false;
|
|
737
|
-
for (const test of
|
|
760
|
+
for (const test of command.sheet.annotations) {
|
|
738
761
|
if (test === annotation) { continue; }
|
|
739
762
|
if (test.scaled_rect && test.scaled_rect.top === target_rect.top && test.scaled_rect.left === target_rect.left) {
|
|
740
763
|
target_rect = target_rect.Shift(20, 20);
|
|
@@ -747,28 +770,44 @@ export class Grid extends GridBase {
|
|
|
747
770
|
}
|
|
748
771
|
}
|
|
749
772
|
|
|
750
|
-
if (target) {
|
|
751
|
-
if (Rectangle.IsRectangle(target)) {
|
|
773
|
+
if (command.target) {
|
|
774
|
+
if (Rectangle.IsRectangle(command.target)) {
|
|
752
775
|
// console.info('creating from rectangle,', target);
|
|
753
776
|
annotation.data.layout = undefined;
|
|
754
|
-
annotation.rect = Rectangle.Create(target);
|
|
777
|
+
annotation.rect = Rectangle.Create(command.target);
|
|
755
778
|
}
|
|
756
|
-
else if (target.start) {
|
|
779
|
+
else if (command.target.start) {
|
|
757
780
|
annotation.rect = undefined;
|
|
758
|
-
annotation.data.layout = this.layout.AddressToAnnotationLayout(target.start, target.end||target.start);
|
|
781
|
+
annotation.data.layout = this.layout.AddressToAnnotationLayout(command.target.start, command.target.end||command.target.start);
|
|
759
782
|
}
|
|
760
783
|
}
|
|
761
784
|
|
|
762
|
-
if (add_to_sheet) {
|
|
785
|
+
if (command.add_to_sheet) {
|
|
763
786
|
|
|
764
787
|
// ensure we haven't already added this
|
|
765
|
-
if (!
|
|
766
|
-
|
|
788
|
+
if (!command.sheet.annotations.some((test) => test === annotation)) {
|
|
789
|
+
command.sheet.annotations.push(annotation);
|
|
767
790
|
}
|
|
768
791
|
|
|
769
792
|
this.AddAnnotation(annotation);
|
|
770
793
|
}
|
|
771
|
-
|
|
794
|
+
|
|
795
|
+
if (command.focus) {
|
|
796
|
+
|
|
797
|
+
// pending... we need to know which view it was pasted in. maybe this
|
|
798
|
+
// should be the index?
|
|
799
|
+
|
|
800
|
+
const view = annotation.view[this.view_index];
|
|
801
|
+
if (view && view.node) {
|
|
802
|
+
const node = view.node;
|
|
803
|
+
setTimeout(() => {
|
|
804
|
+
node.focus();
|
|
805
|
+
}, 1);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// return annotation;
|
|
772
811
|
}
|
|
773
812
|
|
|
774
813
|
/** placeholder */
|
|
@@ -1060,21 +1099,17 @@ export class Grid extends GridBase {
|
|
|
1060
1099
|
* the parent (although the node still exists in the annotation, if
|
|
1061
1100
|
* it existed before).
|
|
1062
1101
|
*/
|
|
1063
|
-
public RemoveAnnotation(annotation: Annotation): void {
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1102
|
+
public RemoveAnnotation(annotation: Annotation, sheet = this.active_sheet): void {
|
|
1103
|
+
this.ExecCommand({
|
|
1104
|
+
key: CommandKey.RemoveAnnotation,
|
|
1105
|
+
annotation,
|
|
1106
|
+
sheet,
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1069
1109
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
event: 'delete',
|
|
1074
|
-
});
|
|
1075
|
-
return;
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1110
|
+
protected RemoveAnnotationInternal(command: RemoveAnnotationCommand) {
|
|
1111
|
+
super.RemoveAnnotationInternal(command);
|
|
1112
|
+
this.layout.RemoveAnnotation(command.annotation);
|
|
1078
1113
|
}
|
|
1079
1114
|
|
|
1080
1115
|
/**
|
|
@@ -1474,6 +1509,18 @@ export class Grid extends GridBase {
|
|
|
1474
1509
|
|
|
1475
1510
|
}
|
|
1476
1511
|
|
|
1512
|
+
/** set scale directly */
|
|
1513
|
+
public SetScale(scale: number) {
|
|
1514
|
+
scale = Math.round(scale * 1000) / 1000;
|
|
1515
|
+
scale = Math.min(2, Math.max(scale, .5));
|
|
1516
|
+
|
|
1517
|
+
if (this.options.persist_scale_key) {
|
|
1518
|
+
localStorage.setItem(this.options.persist_scale_key, JSON.stringify({scale}));
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
this.scale = scale;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1477
1524
|
/**
|
|
1478
1525
|
* @param container html container element
|
|
1479
1526
|
*/
|
|
@@ -2430,6 +2477,15 @@ export class Grid extends GridBase {
|
|
|
2430
2477
|
this.DelayedRender(force, area);
|
|
2431
2478
|
}
|
|
2432
2479
|
|
|
2480
|
+
/**
|
|
2481
|
+
* update annotation layouts (not content)
|
|
2482
|
+
*/
|
|
2483
|
+
public UpdateAnnotations() {
|
|
2484
|
+
if (this.active_sheet.annotations.length) {
|
|
2485
|
+
this.layout.UpdateAnnotation(this.active_sheet.annotations, this.theme);
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2433
2489
|
/* *
|
|
2434
2490
|
* API method
|
|
2435
2491
|
*
|
|
@@ -2676,6 +2732,18 @@ export class Grid extends GridBase {
|
|
|
2676
2732
|
|
|
2677
2733
|
}
|
|
2678
2734
|
|
|
2735
|
+
/**
|
|
2736
|
+
* this is intended to synchronize views when annotations are added/removed.
|
|
2737
|
+
* there should be no need to call it if there's only one view.
|
|
2738
|
+
*/
|
|
2739
|
+
public RefreshAnnotations() {
|
|
2740
|
+
|
|
2741
|
+
this.RemoveAnnotationNodes();
|
|
2742
|
+
for (const element of this.active_sheet.annotations) {
|
|
2743
|
+
this.AddAnnotation(element, true, true);
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
}
|
|
2679
2747
|
|
|
2680
2748
|
/**
|
|
2681
2749
|
* specialization for grid. note that we don't call superclass,
|
|
@@ -3934,7 +4002,14 @@ export class Grid extends GridBase {
|
|
|
3934
4002
|
if (cell?.note) {
|
|
3935
4003
|
|
|
3936
4004
|
// optional MD formatting
|
|
3937
|
-
|
|
4005
|
+
|
|
4006
|
+
// UPDATE: we should allow MD in notes irrespective of the cell
|
|
4007
|
+
// markdown setting. or maybe split the two settings? it makes
|
|
4008
|
+
// a lot of sense in comments, even if you don't want it in cells.
|
|
4009
|
+
|
|
4010
|
+
const parsed = MDParser.instance.Parse(cell.note);
|
|
4011
|
+
|
|
4012
|
+
const md = this.options.comment_markdown ? MDParser.instance.HTML(parsed, { br: false }) : undefined;
|
|
3938
4013
|
this.layout.ShowNote(cell.note, address, event, md);
|
|
3939
4014
|
|
|
3940
4015
|
this.hover_data.note = true;
|
|
@@ -5399,7 +5474,7 @@ export class Grid extends GridBase {
|
|
|
5399
5474
|
*/
|
|
5400
5475
|
private SetInferredType(selection: GridSelection, value: string|undefined, array = false, exec = true, apply_style?: CellStyle) {
|
|
5401
5476
|
|
|
5402
|
-
console.info("SIT", {apply_style});
|
|
5477
|
+
// console.info("SIT", {apply_style});
|
|
5403
5478
|
|
|
5404
5479
|
// validation: cannot change part of an array without changing the
|
|
5405
5480
|
// whole array. so check the array. separately, if you are entering
|
|
@@ -7285,6 +7360,9 @@ export class Grid extends GridBase {
|
|
|
7285
7360
|
}
|
|
7286
7361
|
}
|
|
7287
7362
|
}
|
|
7363
|
+
|
|
7364
|
+
this.CreateAnnotation(composite.data, undefined, true, true, undefined, true);
|
|
7365
|
+
/*
|
|
7288
7366
|
const annotation = this.CreateAnnotation(composite.data, true, true);
|
|
7289
7367
|
const view = annotation.view[this.view_index];
|
|
7290
7368
|
if (view && view.node) {
|
|
@@ -7293,6 +7371,7 @@ export class Grid extends GridBase {
|
|
|
7293
7371
|
node.focus();
|
|
7294
7372
|
}, 1);
|
|
7295
7373
|
}
|
|
7374
|
+
*/
|
|
7296
7375
|
}
|
|
7297
7376
|
catch (e) {
|
|
7298
7377
|
console.error(e);
|