@trebco/treb 30.16.0 → 31.0.2
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/api-generator/api-generator.ts +3 -1
- package/api-generator/package.json +2 -1
- package/dist/treb-export-worker.mjs +2 -2
- package/dist/treb-spreadsheet.mjs +13 -13
- package/dist/treb.d.ts +19 -2
- package/package.json +8 -7
- package/treb-base-types/src/font-stack.ts +144 -0
- package/treb-base-types/src/style.ts +121 -11
- package/treb-base-types/src/theme.ts +53 -8
- package/treb-calculator/src/calculator.ts +13 -13
- package/treb-calculator/src/descriptors.ts +12 -4
- package/treb-calculator/src/expression-calculator.ts +17 -4
- package/treb-calculator/src/functions/base-functions.ts +57 -4
- package/treb-calculator/src/functions/statistics-functions.ts +9 -6
- package/treb-calculator/tsconfig.json +11 -0
- package/treb-charts/style/charts.scss +7 -1
- package/treb-data-model/src/annotation.ts +6 -0
- package/treb-data-model/src/data_model.ts +14 -3
- package/treb-data-model/src/sheet.ts +57 -56
- package/treb-embed/markup/toolbar.html +15 -1
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +38 -0
- package/treb-embed/src/embedded-spreadsheet.ts +119 -29
- package/treb-embed/src/options.ts +3 -0
- package/treb-embed/src/selection-state.ts +1 -0
- package/treb-embed/src/toolbar-message.ts +6 -0
- package/treb-embed/src/types.ts +9 -0
- package/treb-embed/style/defaults.scss +12 -1
- package/treb-embed/style/font-stacks.scss +105 -0
- package/treb-embed/style/layout.scss +1 -0
- package/treb-embed/style/theme-defaults.scss +12 -2
- package/treb-embed/style/toolbar.scss +16 -0
- package/treb-grid/src/editors/overlay_editor.ts +36 -3
- package/treb-grid/src/layout/base_layout.ts +52 -37
- package/treb-grid/src/layout/grid_layout.ts +7 -0
- package/treb-grid/src/render/tile_renderer.ts +154 -148
- package/treb-grid/src/types/grid.ts +188 -54
- package/treb-grid/src/types/grid_events.ts +1 -1
- package/treb-grid/src/types/grid_options.ts +3 -0
- package/treb-grid/src/util/fontmetrics.ts +134 -0
- package/treb-parser/src/parser.ts +12 -3
- package/treb-utils/src/measurement.ts +2 -3
- package/tsproject.json +1 -1
- package/treb-calculator/modern.tsconfig.json +0 -11
- package/treb-grid/src/util/fontmetrics2.ts +0 -182
- package/treb-parser/src/parser.test.ts +0 -298
- /package/treb-embed/{modern.tsconfig.json → tsconfig.json} +0 -0
- /package/treb-export/{modern.tsconfig.json → tsconfig.json} +0 -0
|
@@ -99,6 +99,13 @@ export class GridLayout extends BaseLayout {
|
|
|
99
99
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
public FocusInLayout(target?: EventTarget): boolean {
|
|
103
|
+
if (target && target instanceof Element && this.container?.contains(target)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
public ResizeCursor(resize?: 'row'|'column'): void {
|
|
103
110
|
switch (resize) {
|
|
104
111
|
case 'row':
|
|
@@ -28,16 +28,18 @@ import type { ICellAddress,
|
|
|
28
28
|
import { TextPartFlag, Style, ValueType, Area, Rectangle, ResolveThemeColor, IsDefinedColor } from 'treb-base-types';
|
|
29
29
|
|
|
30
30
|
import type { Tile } from '../types/tile';
|
|
31
|
-
import { FontMetricsCache as FontMetricsCache2 } from '../util/fontmetrics2';
|
|
31
|
+
// import { FontMetricsCache as FontMetricsCache2 } from '../util/fontmetrics2';
|
|
32
32
|
import type { FormattedString} from 'treb-parser';
|
|
33
33
|
import { MDParser } from 'treb-parser';
|
|
34
|
-
import
|
|
34
|
+
import { BaseLayout, TileRange } from '../layout/base_layout';
|
|
35
35
|
import type { DataModel, ViewModel } from 'treb-data-model';
|
|
36
36
|
import type { GridOptions } from '../types/grid_options';
|
|
37
37
|
|
|
38
|
+
import { Get as GetFontMetrics } from '../util/fontmetrics';
|
|
39
|
+
|
|
38
40
|
const DEFAULT_INDENT = ' '; // two spaces in the current font
|
|
39
|
-
const BASELINE = 'bottom';
|
|
40
|
-
const WK = /webkit/i.test(typeof navigator === 'undefined' ? '' : navigator?.userAgent || '') ? 1 : 0;
|
|
41
|
+
// const BASELINE = 'bottom';
|
|
42
|
+
// const WK = /webkit/i.test(typeof navigator === 'undefined' ? '' : navigator?.userAgent || '') ? 1 : 0;
|
|
41
43
|
|
|
42
44
|
interface FontSet {
|
|
43
45
|
base: string,
|
|
@@ -118,7 +120,8 @@ export class TileRenderer {
|
|
|
118
120
|
this.buffer_context = context;
|
|
119
121
|
this.buffer_context.setTransform(scale, 0, 0, scale, 0, 0);
|
|
120
122
|
this.buffer_context.textAlign = 'left';
|
|
121
|
-
this.buffer_context.textBaseline = BASELINE; //
|
|
123
|
+
this.buffer_context.textBaseline = // BASELINE; //
|
|
124
|
+
'alphabetic';
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
// this.UpdateTheme();
|
|
@@ -173,6 +176,52 @@ export class TileRenderer {
|
|
|
173
176
|
}
|
|
174
177
|
|
|
175
178
|
/**
|
|
179
|
+
* new method for measuring text, intended to take into account
|
|
180
|
+
* indentation and wrapping, scale, and all the other stuff.
|
|
181
|
+
*/
|
|
182
|
+
public MeasureText(cell: Cell, current_width: number, override_scale?: number) {
|
|
183
|
+
|
|
184
|
+
// we need a canvas. I guess we can just randomly use one?
|
|
185
|
+
|
|
186
|
+
const tile = this.layout.grid_tiles[0][0];
|
|
187
|
+
|
|
188
|
+
// we need fonts, and check if we need variants
|
|
189
|
+
|
|
190
|
+
const scale = override_scale ?? this.layout.scale;
|
|
191
|
+
const style: CellStyle = cell.style || {};
|
|
192
|
+
const base_font = Style.CompositeFont(this.theme.grid_cell_font_size, style, scale, this.theme);
|
|
193
|
+
const metrics = GetFontMetrics(base_font.font, base_font.variants);
|
|
194
|
+
|
|
195
|
+
const fonts: FontSet = {
|
|
196
|
+
base: base_font.font,
|
|
197
|
+
strong: Style.CompositeFont(this.theme.grid_cell_font_size, {...style, bold: true}, scale, this.theme).font,
|
|
198
|
+
emphasis: Style.CompositeFont(this.theme.grid_cell_font_size, {...style, italic: true}, scale, this.theme).font,
|
|
199
|
+
strong_emphasis: Style.CompositeFont(this.theme.grid_cell_font_size, {...style, bold: true, italic: true }, scale, this.theme).font,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
if (base_font.variants) {
|
|
203
|
+
tile.style.fontVariant = base_font.variants;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
tile.style.fontVariant = '';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const context = tile.getContext('2d', { alpha: false });
|
|
210
|
+
|
|
211
|
+
if (!context) {
|
|
212
|
+
throw new Error('context failed');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const prepped = this.PrepText(context, fonts, cell, current_width);
|
|
216
|
+
|
|
217
|
+
const width = prepped.width;
|
|
218
|
+
const height = metrics.height * prepped.strings.length;
|
|
219
|
+
|
|
220
|
+
return { width, height };
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* *
|
|
176
225
|
* use one of the tile contexts to measure text. we are using the tile
|
|
177
226
|
* context because it's attached to the DOM, and style is applied. we need
|
|
178
227
|
* that for the root font size, in case font size in the style is relative
|
|
@@ -188,7 +237,7 @@ export class TileRenderer {
|
|
|
188
237
|
*
|
|
189
238
|
* @param text
|
|
190
239
|
* @param font
|
|
191
|
-
|
|
240
|
+
* /
|
|
192
241
|
public MeasureText(text: string, font?: string): TextMetrics {
|
|
193
242
|
|
|
194
243
|
const context = this.layout.grid_tiles[0][0].getContext('2d', { alpha: false });
|
|
@@ -203,6 +252,7 @@ export class TileRenderer {
|
|
|
203
252
|
|
|
204
253
|
return context.measureText(text);
|
|
205
254
|
}
|
|
255
|
+
*/
|
|
206
256
|
|
|
207
257
|
/**
|
|
208
258
|
* when drawing to the buffered canvas, (1) ensure it's large enough,
|
|
@@ -233,7 +283,8 @@ export class TileRenderer {
|
|
|
233
283
|
if (context) {
|
|
234
284
|
this.buffer_context = context;
|
|
235
285
|
this.buffer_context.textAlign = 'left';
|
|
236
|
-
this.buffer_context.textBaseline = BASELINE;
|
|
286
|
+
this.buffer_context.textBaseline = // BASELINE;
|
|
287
|
+
'alphabetic';
|
|
237
288
|
}
|
|
238
289
|
|
|
239
290
|
}
|
|
@@ -291,7 +342,8 @@ export class TileRenderer {
|
|
|
291
342
|
throw new Error('invalid context');
|
|
292
343
|
}
|
|
293
344
|
|
|
294
|
-
const
|
|
345
|
+
const font_info = Style.CompositeFont(this.theme.grid_cell_font_size, this.theme.headers||{}, this.layout.scale, this.theme);
|
|
346
|
+
const m2 = GetFontMetrics(font_info.font, font_info.variants);
|
|
295
347
|
|
|
296
348
|
const scale = this.layout.dpr;
|
|
297
349
|
const header_size = this.layout.header_offset;
|
|
@@ -351,8 +403,8 @@ export class TileRenderer {
|
|
|
351
403
|
// 0 or 1 pixel) we don't want to render them here.
|
|
352
404
|
|
|
353
405
|
context.textAlign = 'center';
|
|
354
|
-
context.textBaseline = 'middle';
|
|
355
|
-
context.font = Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
406
|
+
context.textBaseline = 'middle'; // FUXME
|
|
407
|
+
context.font = font_info.font; // Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
356
408
|
|
|
357
409
|
context.fillStyle = ResolveThemeColor(this.theme, this.theme.headers?.text);
|
|
358
410
|
|
|
@@ -365,7 +417,8 @@ export class TileRenderer {
|
|
|
365
417
|
context.lineTo(header_size.x, 0 - 0.5);
|
|
366
418
|
context.stroke();
|
|
367
419
|
|
|
368
|
-
this.RenderRowLabels(context, 0, this.view.active_sheet.freeze.rows - 1, m2.block);
|
|
420
|
+
this.RenderRowLabels(context, 0, this.view.active_sheet.freeze.rows - 1, // m2.block);
|
|
421
|
+
m2.height);
|
|
369
422
|
|
|
370
423
|
}
|
|
371
424
|
|
|
@@ -458,7 +511,10 @@ export class TileRenderer {
|
|
|
458
511
|
|
|
459
512
|
const scale = this.layout.dpr;
|
|
460
513
|
const header_size = this.layout.header_offset;
|
|
461
|
-
|
|
514
|
+
|
|
515
|
+
const font_info = Style.CompositeFont(this.theme.grid_cell_font_size, this.theme.headers||{}, this.layout.scale, this.theme);
|
|
516
|
+
const m2 = GetFontMetrics(font_info.font, font_info.variants);
|
|
517
|
+
|
|
462
518
|
|
|
463
519
|
for (let column = tiles.start.column; column <= tiles.end.column; column++) {
|
|
464
520
|
|
|
@@ -470,8 +526,15 @@ export class TileRenderer {
|
|
|
470
526
|
context.setTransform(scale, 0, 0, scale, 0, 0);
|
|
471
527
|
|
|
472
528
|
context.textAlign = 'center';
|
|
473
|
-
context.textBaseline = 'middle';
|
|
474
|
-
|
|
529
|
+
context.textBaseline = 'middle'; // FIXME
|
|
530
|
+
|
|
531
|
+
context.font = font_info.font; // Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
532
|
+
if (font_info.variants) {
|
|
533
|
+
tile.style.fontVariant = font_info.variants;
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
tile.style.fontVariant = '';
|
|
537
|
+
}
|
|
475
538
|
|
|
476
539
|
context.fillStyle = this.theme.headers?.fill ? ResolveThemeColor(this.theme, this.theme.headers.fill) : '';
|
|
477
540
|
context.fillRect(0, 0, tile.logical_size.width, this.layout.header_offset.y);
|
|
@@ -512,8 +575,16 @@ export class TileRenderer {
|
|
|
512
575
|
context.setTransform(scale, 0, 0, scale, 0, 0);
|
|
513
576
|
|
|
514
577
|
context.textAlign = 'center';
|
|
515
|
-
context.textBaseline = 'middle';
|
|
516
|
-
context.font = Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
578
|
+
context.textBaseline = 'middle'; // FIXME
|
|
579
|
+
// context.font = Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
580
|
+
|
|
581
|
+
context.font = font_info.font; // Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
582
|
+
if (font_info.variants) {
|
|
583
|
+
tile.style.fontVariant = font_info.variants;
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
tile.style.fontVariant = '';
|
|
587
|
+
}
|
|
517
588
|
|
|
518
589
|
context.fillRect(0, 0, this.layout.header_offset.x, tile.logical_size.height);
|
|
519
590
|
|
|
@@ -527,7 +598,8 @@ export class TileRenderer {
|
|
|
527
598
|
|
|
528
599
|
context.strokeStyle = this.theme.headers_grid_color || '';
|
|
529
600
|
|
|
530
|
-
this.RenderRowLabels(context, tile.first_cell.row, tile.last_cell.row, m2.block);
|
|
601
|
+
this.RenderRowLabels(context, tile.first_cell.row, tile.last_cell.row, // m2.block);
|
|
602
|
+
m2.height);
|
|
531
603
|
|
|
532
604
|
tile.dirty = false;
|
|
533
605
|
}
|
|
@@ -587,10 +659,18 @@ export class TileRenderer {
|
|
|
587
659
|
/** render a tile */
|
|
588
660
|
public Render(tile: Tile): void {
|
|
589
661
|
|
|
662
|
+
// can we assume this is always set? this feels sloppy, and
|
|
663
|
+
// it feels like something we'd like to turn off... can we
|
|
664
|
+
// fetch the canvas more than once? not sure what the impact of
|
|
665
|
+
// that would be.
|
|
666
|
+
|
|
667
|
+
// tile.style.fontVariantNumeric = 'lining-nums tabular-nums';
|
|
668
|
+
|
|
590
669
|
const context = tile.getContext('2d', { alpha: false });
|
|
591
670
|
if (!context) { return; } // should throw
|
|
592
671
|
|
|
593
|
-
context.textBaseline = BASELINE;
|
|
672
|
+
context.textBaseline = // BASELINE;
|
|
673
|
+
'alphabetic';
|
|
594
674
|
|
|
595
675
|
const scale = this.layout.dpr;
|
|
596
676
|
|
|
@@ -1654,13 +1734,28 @@ export class TileRenderer {
|
|
|
1654
1734
|
// (eventually) painting to the buffer context. just remember to set
|
|
1655
1735
|
// font in the buffer context.
|
|
1656
1736
|
|
|
1737
|
+
const base_font = Style.CompositeFont(this.theme.grid_cell_font_size, style, this.layout.scale, this.theme);
|
|
1738
|
+
|
|
1739
|
+
/*
|
|
1740
|
+
if (cell.value) {
|
|
1741
|
+
console.info(base_font);
|
|
1742
|
+
}
|
|
1743
|
+
*/
|
|
1744
|
+
|
|
1657
1745
|
const fonts: FontSet = {
|
|
1658
|
-
base:
|
|
1659
|
-
strong: Style.
|
|
1660
|
-
emphasis: Style.
|
|
1661
|
-
strong_emphasis: Style.
|
|
1746
|
+
base: base_font.font,
|
|
1747
|
+
strong: Style.CompositeFont(this.theme.grid_cell_font_size, {...style, bold: true}, this.layout.scale, this.theme).font,
|
|
1748
|
+
emphasis: Style.CompositeFont(this.theme.grid_cell_font_size, {...style, italic: true}, this.layout.scale, this.theme).font,
|
|
1749
|
+
strong_emphasis: Style.CompositeFont(this.theme.grid_cell_font_size, {...style, bold: true, italic: true }, this.layout.scale, this.theme).font,
|
|
1662
1750
|
};
|
|
1663
1751
|
|
|
1752
|
+
if (base_font.variants) {
|
|
1753
|
+
tile.style.fontVariant = base_font.variants;
|
|
1754
|
+
}
|
|
1755
|
+
else {
|
|
1756
|
+
tile.style.fontVariant = '';
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1664
1759
|
context.font = fonts.base;
|
|
1665
1760
|
|
|
1666
1761
|
//
|
|
@@ -1927,16 +2022,23 @@ export class TileRenderer {
|
|
|
1927
2022
|
// and bold variants). this should be OK because we use it for height, mostly.
|
|
1928
2023
|
// not sure about invisible text (FIXME)
|
|
1929
2024
|
|
|
1930
|
-
const m2 = FontMetricsCache2.Get(fonts.base, this.theme.grid_cell?.font_size?.value);
|
|
1931
|
-
//
|
|
2025
|
+
// const m2 = FontMetricsCache2.Get(fonts.base, // this.theme.grid_cell?.font_size?.value);
|
|
2026
|
+
// this.theme.grid_cell_font_size);
|
|
2027
|
+
|
|
2028
|
+
|
|
2029
|
+
const m2 = GetFontMetrics(fonts.base, base_font.variants);
|
|
1932
2030
|
|
|
2031
|
+
if (cell.value) {
|
|
2032
|
+
console.info(fonts.base, {m2});
|
|
2033
|
+
}
|
|
2034
|
+
|
|
1933
2035
|
// set stroke for underline
|
|
1934
2036
|
|
|
1935
2037
|
// FIXME: color here should default to style, not ''. it's working only
|
|
1936
2038
|
// because our default style happens to be the default color. that applies
|
|
1937
2039
|
// to text color, background color and border color.
|
|
1938
2040
|
|
|
1939
|
-
context.lineWidth = 1;
|
|
2041
|
+
context.lineWidth = 1; // 1.5; // FIXME: scale? font scale?
|
|
1940
2042
|
|
|
1941
2043
|
context.strokeStyle = context.fillStyle =
|
|
1942
2044
|
text_data.format ? text_data.format : ResolveThemeColor(this.theme, style.text, 1);
|
|
@@ -1945,11 +2047,12 @@ export class TileRenderer {
|
|
|
1945
2047
|
|
|
1946
2048
|
let left = this.cell_edge_buffer;
|
|
1947
2049
|
|
|
1948
|
-
const line_height = 1.25;
|
|
2050
|
+
const line_height = 1; // 1.25;
|
|
1949
2051
|
|
|
1950
2052
|
//const line_count = text_data.single ? 1 : text_data.strings.length;
|
|
1951
2053
|
const line_count = text_data.strings.length;
|
|
1952
|
-
const text_height = (line_count * m2.block * line_height);
|
|
2054
|
+
// const text_height = (line_count * m2.block * line_height);
|
|
2055
|
+
const text_height = (line_count * m2.height * line_height);
|
|
1953
2056
|
|
|
1954
2057
|
// we stopped clipping initially because it was expensive -- but then
|
|
1955
2058
|
// we were doing it on every cell. it's hard to imagine that clipping
|
|
@@ -1970,20 +2073,23 @@ export class TileRenderer {
|
|
|
1970
2073
|
context.clip();
|
|
1971
2074
|
}
|
|
1972
2075
|
|
|
1973
|
-
// path for underline. if there's no underline
|
|
2076
|
+
// path for underline (and strike). if there's no underline (or strike),
|
|
2077
|
+
// it won't do anything.
|
|
1974
2078
|
|
|
1975
2079
|
context.beginPath();
|
|
1976
2080
|
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2081
|
+
let original_baseline = Math.round(
|
|
2082
|
+
(height - m2.descent - 2) + // baseline for first line of text
|
|
2083
|
+
(-line_height * m2.height * (line_count - 1))); // adjust for multiple lines
|
|
1980
2084
|
|
|
1981
2085
|
switch (style.vertical_align) {
|
|
1982
|
-
case 'top':
|
|
1983
|
-
original_baseline = Math.round(m2.
|
|
2086
|
+
case 'top':
|
|
2087
|
+
original_baseline = Math.round(2 + m2.ascent);
|
|
1984
2088
|
break;
|
|
1985
|
-
|
|
1986
|
-
|
|
2089
|
+
|
|
2090
|
+
case 'middle':
|
|
2091
|
+
original_baseline = Math.round((height - text_height) / 2 + m2.ascent) - 1.5;
|
|
2092
|
+
|
|
1987
2093
|
break;
|
|
1988
2094
|
}
|
|
1989
2095
|
|
|
@@ -2017,7 +2123,7 @@ export class TileRenderer {
|
|
|
2017
2123
|
// may have different formatting.
|
|
2018
2124
|
|
|
2019
2125
|
let baseline = original_baseline;
|
|
2020
|
-
let index = 0;
|
|
2126
|
+
// let index = 0;
|
|
2021
2127
|
|
|
2022
2128
|
for (const line of text_data.strings) {
|
|
2023
2129
|
|
|
@@ -2026,29 +2132,17 @@ export class TileRenderer {
|
|
|
2026
2132
|
let line_width = 0;
|
|
2027
2133
|
for (const part of line) { line_width += part.width; }
|
|
2028
2134
|
|
|
2029
|
-
if (horizontal_align === 'center'
|
|
2135
|
+
if (horizontal_align === 'center') {
|
|
2030
2136
|
left = Math.round((width - line_width) / 2);
|
|
2031
2137
|
}
|
|
2032
|
-
else if (horizontal_align === 'right'
|
|
2138
|
+
else if (horizontal_align === 'right') {
|
|
2033
2139
|
left = width - this.cell_edge_buffer - line_width;
|
|
2034
2140
|
}
|
|
2035
2141
|
|
|
2036
|
-
|
|
2037
|
-
if (style.font_underline) {
|
|
2038
|
-
const underline_y = Math.floor(baseline + 1.5 - m2.descender - WK) + .5; // metrics.block - 3.5 - metrics.ascent - 3;
|
|
2039
|
-
context.moveTo(left, underline_y);
|
|
2040
|
-
context.lineTo(left + line_width, underline_y);
|
|
2041
|
-
}
|
|
2042
|
-
|
|
2043
|
-
if (style.font_strike) {
|
|
2044
|
-
const strike_y = Math.floor(baseline - m2.descender - m2.ascender / 2) + .5;
|
|
2045
|
-
context.moveTo(left, strike_y);
|
|
2046
|
-
context.lineTo(left + line_width, strike_y);
|
|
2047
|
-
}
|
|
2048
|
-
*/
|
|
2142
|
+
// still tinkering with these. surely we need to apply scale? FIXME
|
|
2049
2143
|
|
|
2050
|
-
const underline_y =
|
|
2051
|
-
const strike_y = Math.floor(baseline - m2.
|
|
2144
|
+
const underline_y = baseline + 2.5;
|
|
2145
|
+
const strike_y = Math.floor(baseline - m2.ascent * 1 / 3) + .5;
|
|
2052
2146
|
|
|
2053
2147
|
let x = left;
|
|
2054
2148
|
for (const part of line) {
|
|
@@ -2089,8 +2183,10 @@ export class TileRenderer {
|
|
|
2089
2183
|
|
|
2090
2184
|
if (preserve_layout_info) {
|
|
2091
2185
|
part.left = x;
|
|
2092
|
-
part.top = baseline - m2.block;
|
|
2093
|
-
|
|
2186
|
+
part.top = baseline - // m2.block;
|
|
2187
|
+
m2.ascent;
|
|
2188
|
+
part.height = // m2.block;
|
|
2189
|
+
m2.height;
|
|
2094
2190
|
}
|
|
2095
2191
|
|
|
2096
2192
|
}
|
|
@@ -2099,106 +2195,16 @@ export class TileRenderer {
|
|
|
2099
2195
|
|
|
2100
2196
|
}
|
|
2101
2197
|
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
}
|
|
2198
|
+
// height tends to be an integer, or maybe at worst 1/2 integer,
|
|
2199
|
+
// so stepping is probably ok (we used to index and multiply).
|
|
2106
2200
|
|
|
2201
|
+
baseline += line_height * m2.height;
|
|
2107
2202
|
|
|
2108
|
-
}
|
|
2109
2203
|
|
|
2110
|
-
/*
|
|
2111
|
-
else if (text_data.single) {
|
|
2112
|
-
|
|
2113
|
-
// const cached_font = context.font;
|
|
2114
|
-
// const italic_font = /italic/i.test(cached_font) ? cached_font : 'italic ' + cached_font;
|
|
2115
|
-
|
|
2116
|
-
// single refers to single-line text that has multiple components,
|
|
2117
|
-
// including spacing or hidden text. single line text (not formatted)
|
|
2118
|
-
// probably doesn't have this flag set, it will use the next block.
|
|
2119
|
-
// these could (should?) be consolidated
|
|
2120
|
-
|
|
2121
|
-
if (horizontal_align === Style.HorizontalAlign.Center) {
|
|
2122
|
-
left = Math.round((width - text_data.width) / 2);
|
|
2123
|
-
}
|
|
2124
|
-
else if (horizontal_align === Style.HorizontalAlign.Right) {
|
|
2125
|
-
left = width - this.cell_edge_buffer - text_data.width;
|
|
2126
2204
|
}
|
|
2127
2205
|
|
|
2128
|
-
const underline_y = Math.floor(original_baseline + 1.5 - m2.descender - WK) + .5; // metrics.block - 3.5 - metrics.ascent - 3;
|
|
2129
|
-
const strike_y = Math.floor(original_baseline - m2.descender - m2.ascender / 2) + .5;
|
|
2130
|
-
|
|
2131
|
-
// we want a single underline, possibly spanning hidden elements,
|
|
2132
|
-
// but not starting or stopping on a hidden element (usually invisible
|
|
2133
|
-
// parentheses).
|
|
2134
|
-
|
|
2135
|
-
for (const part of text_data.strings) {
|
|
2136
|
-
if (!part.hidden) {
|
|
2137
|
-
|
|
2138
|
-
context.fillText(part.text, left, original_baseline);
|
|
2139
|
-
|
|
2140
|
-
if (style.font_underline) {
|
|
2141
|
-
context.moveTo(left, underline_y);
|
|
2142
|
-
context.lineTo(left + part.width, underline_y);
|
|
2143
|
-
}
|
|
2144
|
-
if (style.font_strike) {
|
|
2145
|
-
context.moveTo(left, strike_y);
|
|
2146
|
-
context.lineTo(left + part.width, strike_y);
|
|
2147
|
-
}
|
|
2148
|
-
}
|
|
2149
|
-
|
|
2150
|
-
if (preserve_layout_info) {
|
|
2151
|
-
part.left = left;
|
|
2152
|
-
part.top = original_baseline - m2.block;
|
|
2153
|
-
part.height = m2.block;
|
|
2154
|
-
}
|
|
2155
|
-
|
|
2156
|
-
left += part.width;
|
|
2157
|
-
}
|
|
2158
|
-
|
|
2159
|
-
}
|
|
2160
|
-
else {
|
|
2161
|
-
|
|
2162
|
-
let baseline = original_baseline;
|
|
2163
|
-
let index = 0;
|
|
2164
|
-
|
|
2165
|
-
for (const part of text_data.strings) {
|
|
2166
|
-
|
|
2167
|
-
// here we justify based on part, each line might have different width
|
|
2168
|
-
|
|
2169
|
-
if (horizontal_align === Style.HorizontalAlign.Center) {
|
|
2170
|
-
left = Math.round((width - part.width) / 2);
|
|
2171
|
-
}
|
|
2172
|
-
else if (horizontal_align === Style.HorizontalAlign.Right) {
|
|
2173
|
-
left = width - this.cell_edge_buffer - part.width;
|
|
2174
|
-
}
|
|
2175
|
-
|
|
2176
|
-
if (style.font_underline) {
|
|
2177
|
-
const underline_y = Math.floor(baseline + 1.5 - m2.descender - WK) + .5; // metrics.block - 3.5 - metrics.ascent - 3;
|
|
2178
|
-
context.moveTo(left, underline_y);
|
|
2179
|
-
context.lineTo(left + part.width, underline_y);
|
|
2180
|
-
}
|
|
2181
|
-
|
|
2182
|
-
if (style.font_strike) {
|
|
2183
|
-
const strike_y = Math.floor(baseline - m2.descender - m2.ascender / 2) + .5;
|
|
2184
|
-
context.moveTo(left, strike_y);
|
|
2185
|
-
context.lineTo(left + part.width, strike_y);
|
|
2186
|
-
}
|
|
2187
|
-
|
|
2188
|
-
context.fillText(part.text, left, baseline);
|
|
2189
|
-
|
|
2190
|
-
if (preserve_layout_info) {
|
|
2191
|
-
part.left = left;
|
|
2192
|
-
part.top = baseline - m2.block;
|
|
2193
|
-
part.height = m2.block;
|
|
2194
|
-
}
|
|
2195
|
-
|
|
2196
|
-
index++;
|
|
2197
|
-
baseline = Math.round(original_baseline + index * m2.block * line_height);
|
|
2198
|
-
}
|
|
2199
2206
|
|
|
2200
2207
|
}
|
|
2201
|
-
*/
|
|
2202
2208
|
|
|
2203
2209
|
context.stroke();
|
|
2204
2210
|
|