@trebco/treb 25.5.0 → 25.6.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-spreadsheet.mjs +7 -7
- package/dist/treb.d.ts +3 -2
- package/package.json +1 -1
- package/treb-base-types/src/import.ts +23 -22
- package/treb-base-types/src/table.ts +0 -4
- package/treb-calculator/src/calculator.ts +2 -2
- package/treb-embed/src/embedded-spreadsheet.ts +25 -16
- package/treb-export/src/export2.ts +16 -10
- package/treb-export/src/import2.ts +2 -1
- package/treb-grid/src/index.ts +2 -1
- package/treb-grid/src/layout/base_layout.ts +16 -13
- package/treb-grid/src/types/annotation.ts +110 -82
- package/treb-grid/src/types/grid.ts +29 -29
- package/treb-grid/src/types/grid_base.ts +47 -47
- package/treb-grid/src/types/sheet.ts +9 -9
- package/treb-grid/src/types/sheet_types.ts +2 -2
package/dist/treb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! API v25.
|
|
1
|
+
/*! API v25.6. Copyright 2018-2023 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* add our tag to the map
|
|
@@ -367,7 +367,7 @@ export declare class EmbeddedSpreadsheet {
|
|
|
367
367
|
* @param argument_separator - the argument separator to use when evaluating
|
|
368
368
|
* the function. defaults to current locale.
|
|
369
369
|
*/
|
|
370
|
-
InsertAnnotation(formula: string, type?:
|
|
370
|
+
InsertAnnotation(formula: string, type?: AnnotationType, rect?: IRectangle | RangeReference, argument_separator?: ',' | ';'): void;
|
|
371
371
|
|
|
372
372
|
/**
|
|
373
373
|
* Insert an image. This method will open a file chooser and (if an image
|
|
@@ -952,6 +952,7 @@ export interface FreezePane {
|
|
|
952
952
|
rows: number;
|
|
953
953
|
columns: number;
|
|
954
954
|
}
|
|
955
|
+
export type AnnotationType = 'treb-chart' | 'image' | 'external';
|
|
955
956
|
export declare type BorderConstants = "none" | "all" | "outside" | "top" | "bottom" | "left" | "right";
|
|
956
957
|
|
|
957
958
|
/**
|
package/package.json
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of TREB.
|
|
3
|
-
*
|
|
4
|
-
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
-
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
-
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
-
* later version.
|
|
8
|
-
*
|
|
9
|
-
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
-
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
-
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
-
* details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License along
|
|
15
|
-
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
*
|
|
17
|
-
* Copyright 2022-2023 trebco, llc.
|
|
18
|
-
* info@treb.app
|
|
19
|
-
*
|
|
20
|
-
*/
|
|
21
|
-
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
22
|
import type { Style } from './style';
|
|
23
23
|
import type { ValueType } from './value-type';
|
|
24
24
|
import type { IArea } from './area';
|
|
25
25
|
import type { AnnotationLayout } from './layout';
|
|
26
26
|
import type { DataValidation } from './cell';
|
|
27
27
|
import type { Table } from './table';
|
|
28
|
+
import type { AnnotationType } from 'treb-grid';
|
|
28
29
|
|
|
29
30
|
export interface CellParseResult {
|
|
30
31
|
row: number,
|
|
@@ -43,7 +44,7 @@ export interface CellParseResult {
|
|
|
43
44
|
|
|
44
45
|
export interface AnchoredAnnotation {
|
|
45
46
|
layout: AnnotationLayout;
|
|
46
|
-
type?:
|
|
47
|
+
type?: AnnotationType;
|
|
47
48
|
formula?: string;
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -1774,13 +1774,13 @@ export class Calculator extends Graph {
|
|
|
1774
1774
|
}
|
|
1775
1775
|
|
|
1776
1776
|
for (const entry of list) {
|
|
1777
|
-
if (entry.formula) {
|
|
1777
|
+
if (entry.data.formula) {
|
|
1778
1778
|
if (!entry.temp.vertex) {
|
|
1779
1779
|
entry.temp.vertex = new LeafVertex();
|
|
1780
1780
|
}
|
|
1781
1781
|
const vertex = entry.temp.vertex as LeafVertex;
|
|
1782
1782
|
this.AddLeafVertex(vertex);
|
|
1783
|
-
this.UpdateLeafVertex(vertex, entry.formula, context);
|
|
1783
|
+
this.UpdateLeafVertex(vertex, entry.data.formula, context);
|
|
1784
1784
|
}
|
|
1785
1785
|
}
|
|
1786
1786
|
|
|
@@ -29,7 +29,8 @@ import type {
|
|
|
29
29
|
SerializedModel, FreezePane, SerializedSheet,
|
|
30
30
|
SheetChangeEvent, GridOptions,
|
|
31
31
|
GridSelection, CellEvent, FunctionDescriptor,
|
|
32
|
-
AnnotationViewData,
|
|
32
|
+
AnnotationViewData,
|
|
33
|
+
AnnotationType,
|
|
33
34
|
} from 'treb-grid';
|
|
34
35
|
|
|
35
36
|
import {
|
|
@@ -1891,7 +1892,7 @@ export class EmbeddedSpreadsheet {
|
|
|
1891
1892
|
* @param argument_separator - the argument separator to use when evaluating
|
|
1892
1893
|
* the function. defaults to current locale.
|
|
1893
1894
|
*/
|
|
1894
|
-
public InsertAnnotation(formula: string, type = 'treb-chart', rect?: IRectangle|RangeReference, argument_separator?: ','|';'): void {
|
|
1895
|
+
public InsertAnnotation(formula: string, type: AnnotationType = 'treb-chart', rect?: IRectangle|RangeReference, argument_separator?: ','|';'): void {
|
|
1895
1896
|
|
|
1896
1897
|
let target: IRectangle | Partial<Area> | undefined;
|
|
1897
1898
|
|
|
@@ -3171,7 +3172,7 @@ export class EmbeddedSpreadsheet {
|
|
|
3171
3172
|
}
|
|
3172
3173
|
|
|
3173
3174
|
for (const annotation of sheet.annotations || []) {
|
|
3174
|
-
if (annotation.type === 'image' && annotation.data
|
|
3175
|
+
if (annotation.type === 'image' && annotation.data?.src) {
|
|
3175
3176
|
annotation.data.src = Store(annotation.data.src);
|
|
3176
3177
|
}
|
|
3177
3178
|
}
|
|
@@ -4350,15 +4351,20 @@ export class EmbeddedSpreadsheet {
|
|
|
4350
4351
|
const annotation = this.grid.CreateAnnotation({
|
|
4351
4352
|
type: 'image',
|
|
4352
4353
|
formula: '',
|
|
4354
|
+
data: {
|
|
4355
|
+
scale: '',
|
|
4356
|
+
src: contents,
|
|
4357
|
+
original_size: { width: img.width || 300, height: img.height || 300 },
|
|
4358
|
+
},
|
|
4353
4359
|
}, undefined, undefined, {
|
|
4354
4360
|
top: 30,
|
|
4355
4361
|
left: 30,
|
|
4356
4362
|
width: img.width || 300,
|
|
4357
|
-
height: img.height || 300
|
|
4363
|
+
height: img.height || 300,
|
|
4358
4364
|
});
|
|
4359
4365
|
|
|
4360
|
-
annotation.data.src = contents;
|
|
4361
|
-
annotation.data.original_size = { width: img.width || 300, height: img.height || 300 };
|
|
4366
|
+
// annotation.data.src = contents;
|
|
4367
|
+
// annotation.data.original_size = { width: img.width || 300, height: img.height || 300 };
|
|
4362
4368
|
|
|
4363
4369
|
}
|
|
4364
4370
|
|
|
@@ -4613,9 +4619,12 @@ export class EmbeddedSpreadsheet {
|
|
|
4613
4619
|
annotation.dirty = false;
|
|
4614
4620
|
}
|
|
4615
4621
|
|
|
4616
|
-
|
|
4622
|
+
// why was this testing for data? that would always exist on an annotation
|
|
4623
|
+
// instance (but not in our new data type). maybe some legacy thing?
|
|
4617
4624
|
|
|
4618
|
-
|
|
4625
|
+
if (view.content_node ) { // && annotation.annotation_data.data) {
|
|
4626
|
+
|
|
4627
|
+
if (annotation.data.type === 'treb-chart') {
|
|
4619
4628
|
|
|
4620
4629
|
// if (!(self as any).TREB || !(self as any).TREB.CreateChart2) {
|
|
4621
4630
|
// console.warn('missing chart library');
|
|
@@ -4633,8 +4642,8 @@ export class EmbeddedSpreadsheet {
|
|
|
4633
4642
|
|
|
4634
4643
|
const update_chart = () => {
|
|
4635
4644
|
|
|
4636
|
-
if (annotation.formula) {
|
|
4637
|
-
const parse_result = this.parser.Parse(annotation.formula);
|
|
4645
|
+
if (annotation.data.formula) {
|
|
4646
|
+
const parse_result = this.parser.Parse(annotation.data.formula);
|
|
4638
4647
|
if (parse_result &&
|
|
4639
4648
|
parse_result.expression &&
|
|
4640
4649
|
parse_result.expression.type === 'call') {
|
|
@@ -4686,16 +4695,16 @@ export class EmbeddedSpreadsheet {
|
|
|
4686
4695
|
}
|
|
4687
4696
|
|
|
4688
4697
|
}
|
|
4689
|
-
else if (annotation.type === 'image') {
|
|
4690
|
-
if (typeof annotation.data.src === 'string') {
|
|
4698
|
+
else if (annotation.data.type === 'image') {
|
|
4699
|
+
if (typeof annotation.data.data?.src === 'string') {
|
|
4691
4700
|
|
|
4692
|
-
const reference = ValidateURI(annotation.data.src);
|
|
4701
|
+
const reference = ValidateURI(annotation.data.data.src);
|
|
4693
4702
|
if (reference) {
|
|
4694
4703
|
|
|
4695
4704
|
const img = document.createElement('img');
|
|
4696
4705
|
img.src = reference;
|
|
4697
4706
|
|
|
4698
|
-
if (annotation.data.scale === 'fixed') {
|
|
4707
|
+
if (annotation.data.data.scale === 'fixed') {
|
|
4699
4708
|
img.style.position = 'relative';
|
|
4700
4709
|
img.style.left = '50%';
|
|
4701
4710
|
img.style.top = '50%';
|
|
@@ -5044,7 +5053,7 @@ export class EmbeddedSpreadsheet {
|
|
|
5044
5053
|
for (const sheet_data of sheets) {
|
|
5045
5054
|
|
|
5046
5055
|
if (sheet_data.annotations) {
|
|
5047
|
-
for (const annotation of (sheet_data.annotations
|
|
5056
|
+
for (const annotation of (sheet_data.annotations)) {
|
|
5048
5057
|
if (annotation.formula) {
|
|
5049
5058
|
const translated = translate(annotation.formula);
|
|
5050
5059
|
if (translated) {
|
|
@@ -5161,7 +5170,7 @@ export class EmbeddedSpreadsheet {
|
|
|
5161
5170
|
sheet.background_image = Unshare(sheet.background_image);
|
|
5162
5171
|
}
|
|
5163
5172
|
for (const annotation of sheet.annotations || []) {
|
|
5164
|
-
if (annotation.type === 'image' && annotation.data
|
|
5173
|
+
if (annotation.type === 'image' && annotation.data?.src) {
|
|
5165
5174
|
annotation.data.src = Unshare(annotation.data.src);
|
|
5166
5175
|
}
|
|
5167
5176
|
}
|
|
@@ -35,7 +35,7 @@ import { template } from './template-2';
|
|
|
35
35
|
import type { SerializedSheet } from 'treb-grid';
|
|
36
36
|
|
|
37
37
|
import type { IArea, ICellAddress, CellValue, DataValidation,
|
|
38
|
-
AnnotationLayout, Corner as LayoutCorner, Cell } from 'treb-base-types';
|
|
38
|
+
AnnotationLayout, Corner as LayoutCorner, Cell, Rectangle } from 'treb-base-types';
|
|
39
39
|
import { Area, Cells, ValueType, Style, ValidationType } from 'treb-base-types';
|
|
40
40
|
|
|
41
41
|
// import * as xmlparser from 'fast-xml-parser';
|
|
@@ -61,6 +61,7 @@ import type { ImageOptions } from './drawing2/embedded-image';
|
|
|
61
61
|
import type { TwoCellAnchor } from './drawing2/drawing2';
|
|
62
62
|
import { Drawing } from './drawing2/drawing2';
|
|
63
63
|
import type { TableDescription, TableFooterType } from './workbook2';
|
|
64
|
+
import type { AnnotationData } from 'treb-grid/src/types/annotation';
|
|
64
65
|
|
|
65
66
|
export class Exporter {
|
|
66
67
|
|
|
@@ -651,12 +652,7 @@ export class Exporter {
|
|
|
651
652
|
* the target units are.
|
|
652
653
|
*/
|
|
653
654
|
public AnnotationRectToAnchor(
|
|
654
|
-
|
|
655
|
-
left: number;
|
|
656
|
-
top: number;
|
|
657
|
-
width: number;
|
|
658
|
-
height: number;
|
|
659
|
-
},
|
|
655
|
+
src_rect: Partial<Rectangle>,
|
|
660
656
|
sheet: SerializedSheet): TwoCellAnchor {
|
|
661
657
|
|
|
662
658
|
const anchor: TwoCellAnchor = {
|
|
@@ -664,6 +660,11 @@ export class Exporter {
|
|
|
664
660
|
to: {row: -1, column: -1},
|
|
665
661
|
};
|
|
666
662
|
|
|
663
|
+
const annotation_rect = {
|
|
664
|
+
top: 0, left: 0, width: 301, height: 301,
|
|
665
|
+
...src_rect,
|
|
666
|
+
};
|
|
667
|
+
|
|
667
668
|
const rect = {
|
|
668
669
|
...annotation_rect, // {top, left, width, height}
|
|
669
670
|
right: annotation_rect.left + annotation_rect.width,
|
|
@@ -706,7 +707,7 @@ export class Exporter {
|
|
|
706
707
|
|
|
707
708
|
const images: Array<{ anchor: TwoCellAnchor, options: ImageOptions }> = [];
|
|
708
709
|
|
|
709
|
-
for (const annotation of sheet_source.annotations || []) {
|
|
710
|
+
for (const annotation of (sheet_source.annotations as Array<AnnotationData & {rect?: Partial<Rectangle>}>) || []) {
|
|
710
711
|
if (annotation.type === 'image' && annotation.data?.src) {
|
|
711
712
|
|
|
712
713
|
// this is (should be) a data URI in base64. at least (atm)
|
|
@@ -940,9 +941,14 @@ export class Exporter {
|
|
|
940
941
|
}
|
|
941
942
|
}
|
|
942
943
|
|
|
943
|
-
|
|
944
|
+
// FIXME: fix this type (this happened when we switched from annotation
|
|
945
|
+
// class to a data interface)
|
|
946
|
+
|
|
947
|
+
const rect = (annotation as AnnotationData & { rect?: Partial<Rectangle>}).rect;
|
|
948
|
+
|
|
949
|
+
if (rect) {
|
|
944
950
|
charts.push({
|
|
945
|
-
anchor: this.AnnotationRectToAnchor(
|
|
951
|
+
anchor: this.AnnotationRectToAnchor(rect, sheet_source), options});
|
|
946
952
|
// sheet.AddChart(this.AnnotationRectToAnchor(annotation.rect, sheet_source), options);
|
|
947
953
|
}
|
|
948
954
|
else if (annotation.layout) {
|
|
@@ -37,6 +37,7 @@ import { XMLUtils } from './xml-utils';
|
|
|
37
37
|
|
|
38
38
|
// import { one_hundred_pixels } from './constants';
|
|
39
39
|
import { ColumnWidthToPixels } from './column-width';
|
|
40
|
+
import type { AnnotationType } from 'treb-grid';
|
|
40
41
|
|
|
41
42
|
interface SharedFormula {
|
|
42
43
|
row: number;
|
|
@@ -697,7 +698,7 @@ export class Importer {
|
|
|
697
698
|
br: AnchorToCorner(descriptor.anchor.to),
|
|
698
699
|
};
|
|
699
700
|
|
|
700
|
-
let type:
|
|
701
|
+
let type: AnnotationType|undefined;
|
|
701
702
|
const args: Array<string|undefined> = [];
|
|
702
703
|
let func = '';
|
|
703
704
|
const series = descriptor.chart?.series;
|
package/treb-grid/src/index.ts
CHANGED
|
@@ -37,4 +37,5 @@ export { BorderConstants } from './types/border_constants';
|
|
|
37
37
|
export type { SerializeOptions } from './types/serialize_options';
|
|
38
38
|
export type { FunctionDescriptor, ArgumentDescriptor } from './editors/autocomplete_matcher';
|
|
39
39
|
export { UA } from './util/ua';
|
|
40
|
-
export type { SetRangeOptions } from './types/set_range_options';
|
|
40
|
+
export type { SetRangeOptions } from './types/set_range_options';
|
|
41
|
+
export type { AnnotationData, AnnotationType } from './types/annotation';
|
|
@@ -672,21 +672,21 @@ export abstract class BaseLayout {
|
|
|
672
672
|
// be persisted (assuming it's saved). eventually this should
|
|
673
673
|
// be superfluous...
|
|
674
674
|
|
|
675
|
-
if (annotation.rect && !annotation.layout) {
|
|
675
|
+
if (annotation.rect && !annotation.data.layout) {
|
|
676
676
|
|
|
677
677
|
// this is breaking on freeze when the spreadsheet is scrolled because
|
|
678
678
|
// the top-left uses the freeze panes. stop doing that.
|
|
679
679
|
|
|
680
680
|
annotation.scaled_rect = annotation.rect.Scale(this.scale);
|
|
681
|
-
annotation.layout = this.RectToAnnotationLayout(annotation.scaled_rect);
|
|
681
|
+
annotation.data.layout = this.RectToAnnotationLayout(annotation.scaled_rect);
|
|
682
682
|
}
|
|
683
683
|
|
|
684
684
|
|
|
685
685
|
// FIXME: merge cells? [...]
|
|
686
686
|
|
|
687
|
-
if (annotation.layout) {
|
|
687
|
+
if (annotation.data.layout) {
|
|
688
688
|
|
|
689
|
-
const rect = this.AnnotationLayoutToRect(annotation.layout);
|
|
689
|
+
const rect = this.AnnotationLayoutToRect(annotation.data.layout);
|
|
690
690
|
rect.ApplyStyle(view.node);
|
|
691
691
|
|
|
692
692
|
// NOTE: we still set the scaled rect, because that's used in
|
|
@@ -949,9 +949,9 @@ export abstract class BaseLayout {
|
|
|
949
949
|
}
|
|
950
950
|
|
|
951
951
|
}, () => {
|
|
952
|
-
annotation.extent = undefined; // reset
|
|
952
|
+
annotation.data.extent = undefined; // reset
|
|
953
953
|
// annotation.rect = rect.Scale(1/this.scale);
|
|
954
|
-
annotation.layout = this.RectToAnnotationLayout(rect);
|
|
954
|
+
annotation.data.layout = this.RectToAnnotationLayout(rect);
|
|
955
955
|
// this.grid_events.Publish({ type: 'annotation', annotation, event: 'move' });
|
|
956
956
|
resolve({ type: 'annotation', annotation, event: 'move' })
|
|
957
957
|
});
|
|
@@ -969,11 +969,14 @@ export abstract class BaseLayout {
|
|
|
969
969
|
node.focus();
|
|
970
970
|
|
|
971
971
|
let aspect = 0;
|
|
972
|
-
if (annotation.data
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
annotation.data.original_size.height
|
|
972
|
+
if (annotation.data.type === 'image') {
|
|
973
|
+
if (annotation.data.data
|
|
974
|
+
&& annotation.data.data.original_size
|
|
975
|
+
&& annotation.data.data.original_size.width
|
|
976
|
+
&& annotation.data.data.original_size.height) {
|
|
977
|
+
aspect = annotation.data.data.original_size.width /
|
|
978
|
+
annotation.data.data.original_size.height;
|
|
979
|
+
}
|
|
977
980
|
}
|
|
978
981
|
|
|
979
982
|
const bounds = node.getBoundingClientRect();
|
|
@@ -1029,9 +1032,9 @@ export abstract class BaseLayout {
|
|
|
1029
1032
|
}
|
|
1030
1033
|
|
|
1031
1034
|
}, () => {
|
|
1032
|
-
annotation.extent = undefined; // reset
|
|
1035
|
+
annotation.data.extent = undefined; // reset
|
|
1033
1036
|
// annotation.rect = rect.Scale(1/this.scale);
|
|
1034
|
-
annotation.layout = this.RectToAnnotationLayout(rect);
|
|
1037
|
+
annotation.data.layout = this.RectToAnnotationLayout(rect);
|
|
1035
1038
|
|
|
1036
1039
|
// this.grid_events.Publish({ type: 'annotation', annotation, event: 'resize' });
|
|
1037
1040
|
resolve({ type: 'annotation', annotation, event: 'resize' });
|
|
@@ -79,74 +79,66 @@ export interface ViewData {
|
|
|
79
79
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
* have freeze panes. when an annotation crosses a freeze pane, we need
|
|
91
|
-
* two copies of the rendered node so that we can scroll. we use the key
|
|
92
|
-
* to match the frozen/unfrozen instances.
|
|
93
|
-
*/
|
|
94
|
-
public get key(): number { return this.key_; }
|
|
95
|
-
|
|
96
|
-
/** coordinates, in sheet space */
|
|
97
|
-
public rect?: Rectangle;
|
|
82
|
+
export interface ImageAnnotationData {
|
|
83
|
+
src: string;
|
|
84
|
+
scale: string;
|
|
85
|
+
original_size: {
|
|
86
|
+
width: number;
|
|
87
|
+
height: number;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
98
90
|
|
|
99
|
-
|
|
91
|
+
export type AnnotationType = 'treb-chart'|'image'|'external';
|
|
100
92
|
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
/**
|
|
94
|
+
* splitting persisted data from the annotation class. that class might
|
|
95
|
+
* disappear in the future in favor of just a type. this interface should
|
|
96
|
+
* fully match the old Partial<Annotation> we used before. note that we
|
|
97
|
+
* used to define values for all members, but they may now be undefined
|
|
98
|
+
* because the Annotation class as a Partial instance of this data.
|
|
99
|
+
*
|
|
100
|
+
* conceptually annotation was originally intended to support types other
|
|
101
|
+
* than our own charts and images, but no one ever used it. so we could
|
|
102
|
+
* lock down the `type` field if we wanted to. or perhaps have an `external`
|
|
103
|
+
* type with opaque data. TODO.
|
|
104
|
+
*
|
|
105
|
+
*/
|
|
106
|
+
export interface AnnotationDataBase {
|
|
103
107
|
|
|
104
108
|
/** the new layout, persisted and takes preference over the old one */
|
|
105
|
-
|
|
109
|
+
layout?: AnnotationLayout;
|
|
106
110
|
|
|
107
|
-
/**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
public type = '';
|
|
115
|
-
|
|
116
|
-
/** also opaque data, but not serialized. */
|
|
117
|
-
public temp: any = {};
|
|
111
|
+
/**
|
|
112
|
+
* the old layout used rectangles, and we need to keep support for
|
|
113
|
+
* that. this is not the layout rectangle. this rectangle is just
|
|
114
|
+
* for serialization/deserialization. the actual rectangle is maintained
|
|
115
|
+
* in the Annotation class.
|
|
116
|
+
*/
|
|
117
|
+
rect?: Partial<Rectangle>;
|
|
118
118
|
|
|
119
119
|
/** annotation can be resized. this is advisory, for UI */
|
|
120
|
-
|
|
120
|
+
resizable: boolean;
|
|
121
121
|
|
|
122
122
|
/** annotation can be moved. this is advisory, for UI */
|
|
123
|
-
|
|
123
|
+
movable: boolean;
|
|
124
124
|
|
|
125
125
|
/** annotation can be removed/deleted. this is advisory, for UI */
|
|
126
|
-
|
|
126
|
+
removable: boolean;
|
|
127
127
|
|
|
128
128
|
/** annotation can be selected. this is advisory, for UI */
|
|
129
|
-
|
|
129
|
+
selectable: boolean;
|
|
130
130
|
|
|
131
131
|
/** move when resizing/inserting rows/columns */
|
|
132
|
-
|
|
132
|
+
move_with_cells: boolean;
|
|
133
133
|
|
|
134
134
|
/** resize when resizing/inserting rows/columns */
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
public view: ViewData[] = [];
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* advisory, meaning we probably need an update if there's an opportunity.
|
|
141
|
-
* only advisory and not persisted.
|
|
142
|
-
*/
|
|
143
|
-
public dirty?: boolean;
|
|
135
|
+
resize_with_cells: boolean;
|
|
144
136
|
|
|
145
137
|
/**
|
|
146
138
|
* optional formula. the formula will be updated on structure events
|
|
147
139
|
* (insert/delete row/column).
|
|
148
140
|
*/
|
|
149
|
-
|
|
141
|
+
formula: string;
|
|
150
142
|
|
|
151
143
|
/**
|
|
152
144
|
* extent, useful for exporting. we could probably serialize this,
|
|
@@ -159,54 +151,90 @@ export class Annotation {
|
|
|
159
151
|
* dynamically but since it won't change all that often, we might
|
|
160
152
|
* as well precalculate.
|
|
161
153
|
*/
|
|
162
|
-
|
|
154
|
+
extent: ICellAddress;
|
|
163
155
|
|
|
164
|
-
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface AnnotationImageData extends AnnotationDataBase {
|
|
159
|
+
type: 'image';
|
|
160
|
+
data: ImageAnnotationData;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface AnnotationChartData extends AnnotationDataBase {
|
|
164
|
+
type: 'treb-chart';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface AnnotationExternalData extends AnnotationDataBase {
|
|
168
|
+
type: 'external';
|
|
169
|
+
data: Record<string, string>;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export type AnnotationData = AnnotationChartData | AnnotationImageData | AnnotationExternalData;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* why is this a class? it doesn't do anything.
|
|
176
|
+
* FIXME: -> interface
|
|
177
|
+
*/
|
|
178
|
+
export class Annotation {
|
|
179
|
+
|
|
180
|
+
public data: Partial<AnnotationData> = {};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* the key field is used to identify and coordinate annotations when we
|
|
184
|
+
* have freeze panes. when an annotation crosses a freeze pane, we need
|
|
185
|
+
* two copies of the rendered node so that we can scroll. we use the key
|
|
186
|
+
* to match the frozen/unfrozen instances.
|
|
187
|
+
*/
|
|
188
|
+
public get key(): number { return this.key_; }
|
|
189
|
+
|
|
190
|
+
/** coordinates, in sheet space */
|
|
191
|
+
public rect?: Rectangle;
|
|
192
|
+
|
|
193
|
+
// public get rect(): Rectangle|undefined { return this.rect_; }
|
|
194
|
+
|
|
195
|
+
/** display coordinates, possibly scaled. not persisted. */
|
|
196
|
+
public scaled_rect?: Rectangle;
|
|
197
|
+
|
|
198
|
+
/** also opaque data, but not serialized. */
|
|
199
|
+
public temp: any = {};
|
|
200
|
+
|
|
201
|
+
public view: ViewData[] = [];
|
|
165
202
|
|
|
166
203
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* or the key won't exist.
|
|
204
|
+
* advisory, meaning we probably need an update if there's an opportunity.
|
|
205
|
+
* only advisory and not persisted.
|
|
170
206
|
*/
|
|
171
|
-
|
|
172
|
-
for (const key of Object.keys(this) as Array<keyof Annotation>){
|
|
173
|
-
if (key !== 'layout' // && key !== 'rect'
|
|
174
|
-
&& opts[key]) { // key !== 'cell_address' && opts[key]) {
|
|
175
|
-
(this as any)[key] = opts[key];
|
|
176
|
-
}
|
|
177
|
-
}
|
|
207
|
+
public dirty?: boolean;
|
|
178
208
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
209
|
+
private key_ = (key_generator++);
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* constructor takes persisted data
|
|
213
|
+
*/
|
|
214
|
+
constructor(opts: Partial<AnnotationData> = {}) {
|
|
215
|
+
this.data = JSON.parse(JSON.stringify(opts)); // why clone?
|
|
182
216
|
if (opts.rect) {
|
|
183
217
|
this.rect = Rectangle.Create(opts.rect);
|
|
184
218
|
}
|
|
185
219
|
}
|
|
186
220
|
|
|
187
221
|
/**
|
|
188
|
-
* serialization
|
|
222
|
+
* serialization just returns persisted data, plus we update the
|
|
223
|
+
* rectangle.
|
|
224
|
+
*
|
|
225
|
+
* anyone serializing annotations should just be fetching the data
|
|
226
|
+
* object, but we're leaving this in place because we can't trace
|
|
227
|
+
* it back using tooling. that's a real drawback of toJSON, we
|
|
228
|
+
* should stop using it.
|
|
229
|
+
*
|
|
230
|
+
* although as long as we need to support `rect` here, it's not bad
|
|
231
|
+
* that we do it this way. perhaps change the function name, and
|
|
232
|
+
* call it directly?
|
|
233
|
+
*
|
|
189
234
|
*/
|
|
190
|
-
public toJSON(): Partial<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (this.data) result.data = this.data;
|
|
194
|
-
if (this.formula) result.formula = this.formula;
|
|
195
|
-
if (this.type) result.type = this.type;
|
|
196
|
-
// if (this.class_name) result.class_name = this.class_name;
|
|
197
|
-
|
|
198
|
-
if (!this.resizable) result.resizable = this.resizable;
|
|
199
|
-
if (!this.movable) result.movable = this.movable;
|
|
200
|
-
if (!this.removable) result.removable = this.removable;
|
|
201
|
-
if (!this.selectable) result.selectable = this.selectable;
|
|
202
|
-
|
|
203
|
-
if (!this.move_with_cells) result.move_with_cells = this.move_with_cells;
|
|
204
|
-
if (!this.resize_with_cells) result.resize_with_cells = this.resize_with_cells;
|
|
205
|
-
|
|
206
|
-
if (this.layout) result.layout = this.layout;
|
|
207
|
-
if (this.extent) result.extent = this.extent;
|
|
208
|
-
|
|
209
|
-
return result;
|
|
235
|
+
public toJSON(): Partial<AnnotationData> {
|
|
236
|
+
return {
|
|
237
|
+
...this.data, rect: this.rect };
|
|
210
238
|
}
|
|
211
239
|
|
|
212
240
|
}
|