@thi.ng/text-canvas 2.6.22 → 2.6.24

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/table.js CHANGED
@@ -2,132 +2,147 @@ import { peek } from "@thi.ng/arrays/peek";
2
2
  import { isString } from "@thi.ng/checks/is-string";
3
3
  import { wordWrapLines } from "@thi.ng/strings/word-wrap";
4
4
  import { Border } from "./api.js";
5
- import { beginClip, beginStyle, canvas, endClip, endStyle, setAt, } from "./canvas.js";
5
+ import {
6
+ beginClip,
7
+ beginStyle,
8
+ canvas,
9
+ endClip,
10
+ endStyle,
11
+ setAt
12
+ } from "./canvas.js";
6
13
  import { hline, vline } from "./hvline.js";
7
14
  import { fillRect, strokeRect } from "./rect.js";
8
15
  import { horizontalOnly, verticalOnly } from "./style.js";
9
16
  import { textLines } from "./text.js";
10
- export const initTable = (opts, cells) => {
11
- const b = opts.border !== undefined ? opts.border : Border.ALL;
12
- const bH = b & Border.H ? 1 : 0;
13
- const bV = b & Border.V ? 1 : 0;
14
- const bF = (bH && bV) || b & Border.FRAME ? 1 : 0;
15
- const bFH = bF | bH;
16
- const bFV = bF | bV;
17
- const [padH, padV] = (opts.padding || [0, 0]).map((x) => x << 1);
18
- const cols = opts.cols;
19
- const numCols = cols.length - 1;
20
- const numRows = cells.length - 1;
21
- const rowHeights = new Array(numRows + 1).fill(0);
22
- const wrapped = [];
23
- for (let i = 0; i <= numRows; i++) {
24
- const row = cells[i];
25
- const wrappedRow = [];
26
- for (let j = 0; j <= numCols; j++) {
27
- const cell = isString(row[j])
28
- ? { body: row[j] }
29
- : row[j];
30
- const lines = cell.wrap !== false
31
- ? wordWrapLines(cell.body, {
32
- width: cols[j].width,
33
- hard: cell.hard || opts.hard,
34
- }).map((l) => l.toString())
35
- : cell.body.split(/\r?\n/g);
36
- wrappedRow.push({
37
- body: lines,
38
- format: cell.format,
39
- });
40
- rowHeights[i] = Math.max(rowHeights[i], lines.length, cell.height || 0);
41
- }
42
- wrapped.push(wrappedRow);
17
+ const initTable = (opts, cells) => {
18
+ const b = opts.border !== void 0 ? opts.border : Border.ALL;
19
+ const bH = b & Border.H ? 1 : 0;
20
+ const bV = b & Border.V ? 1 : 0;
21
+ const bF = bH && bV || b & Border.FRAME ? 1 : 0;
22
+ const bFH = bF | bH;
23
+ const bFV = bF | bV;
24
+ const [padH, padV] = (opts.padding || [0, 0]).map((x) => x << 1);
25
+ const cols = opts.cols;
26
+ const numCols = cols.length - 1;
27
+ const numRows = cells.length - 1;
28
+ const rowHeights = new Array(numRows + 1).fill(0);
29
+ const wrapped = [];
30
+ for (let i = 0; i <= numRows; i++) {
31
+ const row = cells[i];
32
+ const wrappedRow = [];
33
+ for (let j = 0; j <= numCols; j++) {
34
+ const cell = isString(row[j]) ? { body: row[j] } : row[j];
35
+ const lines = cell.wrap !== false ? wordWrapLines(cell.body, {
36
+ width: cols[j].width,
37
+ hard: cell.hard || opts.hard
38
+ }).map((l) => l.toString()) : cell.body.split(/\r?\n/g);
39
+ wrappedRow.push({
40
+ body: lines,
41
+ format: cell.format
42
+ });
43
+ rowHeights[i] = Math.max(
44
+ rowHeights[i],
45
+ lines.length,
46
+ cell.height || 0
47
+ );
43
48
  }
44
- return {
45
- style: opts.style,
46
- format: opts.format,
47
- formatHead: opts.formatHead,
48
- width: cols.reduce((acc, x) => acc + x.width, 0) +
49
- 2 * bFV +
50
- numCols * bV +
51
- (numCols + 1) * padH,
52
- height: rowHeights.reduce((acc, x) => acc + x, 0) +
53
- 2 * bFH +
54
- numRows * bH +
55
- (numRows + 1) * padV,
56
- cells: wrapped,
57
- rowHeights,
58
- cols,
59
- numCols,
60
- numRows,
61
- padH,
62
- padV,
63
- b,
64
- bH,
65
- bV,
66
- bFH,
67
- bFV,
68
- };
49
+ wrapped.push(wrappedRow);
50
+ }
51
+ return {
52
+ style: opts.style,
53
+ format: opts.format,
54
+ formatHead: opts.formatHead,
55
+ width: cols.reduce((acc, x) => acc + x.width, 0) + 2 * bFV + numCols * bV + (numCols + 1) * padH,
56
+ height: rowHeights.reduce((acc, x) => acc + x, 0) + 2 * bFH + numRows * bH + (numRows + 1) * padV,
57
+ cells: wrapped,
58
+ rowHeights,
59
+ cols,
60
+ numCols,
61
+ numRows,
62
+ padH,
63
+ padV,
64
+ b,
65
+ bH,
66
+ bV,
67
+ bFH,
68
+ bFV
69
+ };
69
70
  };
70
- export const drawTable = (canvas, x, y, opts) => {
71
- const { cells, cols, numCols, numRows, rowHeights, width, height, padH, padV, bH, bV, bFH, bFV, } = opts;
72
- const fmt = opts.format !== undefined ? opts.format : canvas.format;
73
- const fmtHd = opts.formatHead !== undefined ? opts.formatHead : fmt;
74
- const currFormat = canvas.format;
75
- canvas.format = fmt;
76
- let style = opts.style || peek(canvas.styles);
77
- style =
78
- opts.b === Border.H
79
- ? horizontalOnly(style)
80
- : opts.b === Border.V
81
- ? verticalOnly(style)
82
- : style;
83
- beginStyle(canvas, style);
84
- fillRect(canvas, x + bFV, y + bFH, width - 2 * bFV, height - 2 * bFH, " ");
85
- opts.b && strokeRect(canvas, x, y, width, height);
86
- if (bV) {
87
- for (let i = 1, xx = x + cols[0].width + padH + 1; i <= numCols; xx += cols[i].width + padH + 1, i++) {
88
- vline(canvas, xx, y, height, style.tjt, style.tjb, style.vl);
89
- }
71
+ const drawTable = (canvas2, x, y, opts) => {
72
+ const {
73
+ cells,
74
+ cols,
75
+ numCols,
76
+ numRows,
77
+ rowHeights,
78
+ width,
79
+ height,
80
+ padH,
81
+ padV,
82
+ bH,
83
+ bV,
84
+ bFH,
85
+ bFV
86
+ } = opts;
87
+ const fmt = opts.format !== void 0 ? opts.format : canvas2.format;
88
+ const fmtHd = opts.formatHead !== void 0 ? opts.formatHead : fmt;
89
+ const currFormat = canvas2.format;
90
+ canvas2.format = fmt;
91
+ let style = opts.style || peek(canvas2.styles);
92
+ style = opts.b === Border.H ? horizontalOnly(style) : opts.b === Border.V ? verticalOnly(style) : style;
93
+ beginStyle(canvas2, style);
94
+ fillRect(canvas2, x + bFV, y + bFH, width - 2 * bFV, height - 2 * bFH, " ");
95
+ opts.b && strokeRect(canvas2, x, y, width, height);
96
+ if (bV) {
97
+ for (let i = 1, xx = x + cols[0].width + padH + 1; i <= numCols; xx += cols[i].width + padH + 1, i++) {
98
+ vline(canvas2, xx, y, height, style.tjt, style.tjb, style.vl);
90
99
  }
91
- for (let i = 0, yy = y + bFH; i <= numRows; i++) {
92
- const row = cells[i];
93
- const rowH = rowHeights[i];
94
- const y2 = yy + rowH + padV;
95
- if (bH && i < numRows) {
96
- hline(canvas, x, y2, width, style.tjl, style.tjr, style.hl);
97
- }
98
- for (let j = 0, xx = x + bFV; j <= numCols; j++) {
99
- const col = cols[j];
100
- const curr = row[j];
101
- if (curr.body) {
102
- beginClip(canvas, xx, yy, col.width + padH, rowH + padV);
103
- textLines(canvas, xx + padH / 2, yy + padV / 2, curr.body, curr.format || (i ? fmt : fmtHd));
104
- endClip(canvas);
105
- }
106
- if (bH && bV && j > 0 && i < numRows) {
107
- setAt(canvas, xx - 1, y2, style.jct);
108
- }
109
- xx += col.width + bV + padH;
110
- }
111
- yy = y2 + bH;
100
+ }
101
+ for (let i = 0, yy = y + bFH; i <= numRows; i++) {
102
+ const row = cells[i];
103
+ const rowH = rowHeights[i];
104
+ const y2 = yy + rowH + padV;
105
+ if (bH && i < numRows) {
106
+ hline(canvas2, x, y2, width, style.tjl, style.tjr, style.hl);
112
107
  }
113
- endStyle(canvas);
114
- canvas.format = currFormat;
108
+ for (let j = 0, xx = x + bFV; j <= numCols; j++) {
109
+ const col = cols[j];
110
+ const curr = row[j];
111
+ if (curr.body) {
112
+ beginClip(canvas2, xx, yy, col.width + padH, rowH + padV);
113
+ textLines(
114
+ canvas2,
115
+ xx + padH / 2,
116
+ yy + padV / 2,
117
+ curr.body,
118
+ curr.format || (i ? fmt : fmtHd)
119
+ );
120
+ endClip(canvas2);
121
+ }
122
+ if (bH && bV && j > 0 && i < numRows) {
123
+ setAt(canvas2, xx - 1, y2, style.jct);
124
+ }
125
+ xx += col.width + bV + padH;
126
+ }
127
+ yy = y2 + bH;
128
+ }
129
+ endStyle(canvas2);
130
+ canvas2.format = currFormat;
131
+ };
132
+ const table = (canvas2, x, y, opts, cells) => {
133
+ const spec = initTable(opts, cells);
134
+ drawTable(canvas2, x, y, spec);
135
+ return [spec.width, spec.height];
115
136
  };
116
- export const table = (canvas, x, y, opts, cells) => {
117
- const spec = initTable(opts, cells);
118
- drawTable(canvas, x, y, spec);
119
- return [spec.width, spec.height];
137
+ const tableCanvas = (opts, cells) => {
138
+ const tbl = initTable(opts, cells);
139
+ const result = canvas(tbl.width, tbl.height);
140
+ drawTable(result, 0, 0, tbl);
141
+ return result;
120
142
  };
121
- /**
122
- * Initializes table with given options and contents. Then creates
123
- * auto-sized canvas for it, renders table and returns canvas.
124
- *
125
- * @param opts - table config
126
- * @param cells - table cells (row major)
127
- */
128
- export const tableCanvas = (opts, cells) => {
129
- const tbl = initTable(opts, cells);
130
- const result = canvas(tbl.width, tbl.height);
131
- drawTable(result, 0, 0, tbl);
132
- return result;
143
+ export {
144
+ drawTable,
145
+ initTable,
146
+ table,
147
+ tableCanvas
133
148
  };
package/text.js CHANGED
@@ -1,116 +1,94 @@
1
1
  import { peek } from "@thi.ng/arrays/peek";
2
2
  import { clamp0 } from "@thi.ng/math/interval";
3
3
  import { wordWrapLines } from "@thi.ng/strings/word-wrap";
4
- import { beginClip, beginStyle, endClip, endStyle, } from "./canvas.js";
4
+ import {
5
+ beginClip,
6
+ beginStyle,
7
+ endClip,
8
+ endStyle
9
+ } from "./canvas.js";
5
10
  import { fillRect, strokeRect } from "./rect.js";
6
- /**
7
- * Writes given string at position `x`,`y`, taking the current clip rect
8
- * and format into account. The string MUST not include linebreaks or
9
- * other control chars.
10
- *
11
- * @param canvas -
12
- * @param x -
13
- * @param y -
14
- * @param line -
15
- */
16
- export const textLine = (canvas, x, y, line, format = canvas.format) => {
17
- x |= 0;
18
- y |= 0;
19
- const { x1, y1, x2, y2 } = peek(canvas.clipRects);
20
- if (y < y1 || y >= y2 || x >= x2)
21
- return;
22
- let i = 0;
23
- if (x < x1) {
24
- i = x1 - x;
25
- x = x1;
26
- }
27
- const { data, width } = canvas;
28
- const n = line.length;
29
- format <<= 16;
30
- for (let idx = x + y * width; i < n && x < x2; i++, x++, idx++) {
31
- data[idx] = line.charCodeAt(i) | format;
32
- }
11
+ const textLine = (canvas, x, y, line, format = canvas.format) => {
12
+ x |= 0;
13
+ y |= 0;
14
+ const { x1, y1, x2, y2 } = peek(canvas.clipRects);
15
+ if (y < y1 || y >= y2 || x >= x2)
16
+ return;
17
+ let i = 0;
18
+ if (x < x1) {
19
+ i = x1 - x;
20
+ x = x1;
21
+ }
22
+ const { data, width } = canvas;
23
+ const n = line.length;
24
+ format <<= 16;
25
+ for (let idx = x + y * width; i < n && x < x2; i++, x++, idx++) {
26
+ data[idx] = line.charCodeAt(i) | format;
27
+ }
33
28
  };
34
- export const textLines = (canvas, x, y, lines, format = canvas.format) => {
35
- for (let line of lines) {
36
- textLine(canvas, x, y, line, format);
37
- y++;
38
- }
39
- return y;
29
+ const textLines = (canvas, x, y, lines, format = canvas.format) => {
30
+ for (let line of lines) {
31
+ textLine(canvas, x, y, line, format);
32
+ y++;
33
+ }
34
+ return y;
40
35
  };
41
- /**
42
- * Writes multiline string at position `x`,`y` and using column `width`,
43
- * also taking the current clip rect and format into account. Applies
44
- * word wrapping.
45
- *
46
- * @param canvas -
47
- * @param x -
48
- * @param y -
49
- * @param width -
50
- * @param txt -
51
- * @param format -
52
- * @param hardWrap -
53
- */
54
- export const textColumn = (canvas, x, y, width, txt, format = canvas.format, hard = false) => {
55
- x |= 0;
56
- y |= 0;
57
- width |= 0;
58
- const height = canvas.height;
59
- for (let line of wordWrapLines(txt, { width, hard })) {
60
- textLine(canvas, x, y, line.toString(), format);
61
- y++;
62
- if (y >= height)
63
- break;
64
- }
65
- return y;
36
+ const textColumn = (canvas, x, y, width, txt, format = canvas.format, hard = false) => {
37
+ x |= 0;
38
+ y |= 0;
39
+ width |= 0;
40
+ const height = canvas.height;
41
+ for (let line of wordWrapLines(txt, { width, hard })) {
42
+ textLine(canvas, x, y, line.toString(), format);
43
+ y++;
44
+ if (y >= height)
45
+ break;
46
+ }
47
+ return y;
66
48
  };
67
- /**
68
- * Draws a text box at given position and dimension. If `height < 0`, the inner
69
- * box height will be set to the number of lines required to fit the given (word
70
- * wrapped) text.
71
- *
72
- * @remarks
73
- * The width and height will include any configured padding and the box frame.
74
- *
75
- * @param canvas -
76
- * @param x -
77
- * @param y -
78
- * @param width -
79
- * @param height -
80
- * @param txt -
81
- * @param opts -
82
- */
83
- export const textBox = (canvas, x, y, width, height, txt, opts) => {
84
- const { format, style, padding: [padX, padY], hard, } = {
85
- format: canvas.format,
86
- padding: [0, 0],
87
- hard: false,
88
- ...opts,
89
- };
90
- const currFmt = canvas.format;
91
- canvas.format = format;
92
- style && beginStyle(canvas, style);
93
- x |= 0;
94
- y |= 0;
95
- width |= 0;
96
- let innerW = width - 2 - 2 * padX;
97
- let innerH = 0;
98
- const lines = wordWrapLines(txt, { width: innerW, hard }).map((l) => l.toString());
99
- if (height < 0) {
100
- innerH = lines.length + 2;
101
- height = innerH + 2 * padY;
102
- }
103
- else {
104
- innerH = clamp0(height - 2);
105
- }
106
- strokeRect(canvas, x, y, width, height);
107
- fillRect(canvas, x + 1, y + 1, width - 2, height - 2, " ");
108
- x += 1 + padX;
109
- y += 1 + padY;
110
- beginClip(canvas, x, y, innerW, innerH);
111
- y = textLines(canvas, x, y, lines);
112
- endClip(canvas);
113
- style && endStyle(canvas);
114
- canvas.format = currFmt;
115
- return y + height;
49
+ const textBox = (canvas, x, y, width, height, txt, opts) => {
50
+ const {
51
+ format,
52
+ style,
53
+ padding: [padX, padY],
54
+ hard
55
+ } = {
56
+ format: canvas.format,
57
+ padding: [0, 0],
58
+ hard: false,
59
+ ...opts
60
+ };
61
+ const currFmt = canvas.format;
62
+ canvas.format = format;
63
+ style && beginStyle(canvas, style);
64
+ x |= 0;
65
+ y |= 0;
66
+ width |= 0;
67
+ let innerW = width - 2 - 2 * padX;
68
+ let innerH = 0;
69
+ const lines = wordWrapLines(txt, { width: innerW, hard }).map(
70
+ (l) => l.toString()
71
+ );
72
+ if (height < 0) {
73
+ innerH = lines.length + 2;
74
+ height = innerH + 2 * padY;
75
+ } else {
76
+ innerH = clamp0(height - 2);
77
+ }
78
+ strokeRect(canvas, x, y, width, height);
79
+ fillRect(canvas, x + 1, y + 1, width - 2, height - 2, " ");
80
+ x += 1 + padX;
81
+ y += 1 + padY;
82
+ beginClip(canvas, x, y, innerW, innerH);
83
+ y = textLines(canvas, x, y, lines);
84
+ endClip(canvas);
85
+ style && endStyle(canvas);
86
+ canvas.format = currFmt;
87
+ return y + height;
88
+ };
89
+ export {
90
+ textBox,
91
+ textColumn,
92
+ textLine,
93
+ textLines
116
94
  };
package/utils.js CHANGED
@@ -1,10 +1,15 @@
1
- export const charCode = (x, format) => (typeof x === "string" ? x.charCodeAt(0) : x) | (format << 16);
2
- export const intersectRect = (a, b) => {
3
- const x1 = Math.max(a.x1, b.x1);
4
- const y1 = Math.max(a.y1, b.y1);
5
- const x2 = Math.min(a.x2, b.x2);
6
- const y2 = Math.min(a.y2, b.y2);
7
- return { x1, y1, x2, y2, w: Math.max(x2 - x1, 0), h: Math.max(y2 - y1, 0) };
1
+ const charCode = (x, format) => (typeof x === "string" ? x.charCodeAt(0) : x) | format << 16;
2
+ const intersectRect = (a, b) => {
3
+ const x1 = Math.max(a.x1, b.x1);
4
+ const y1 = Math.max(a.y1, b.y1);
5
+ const x2 = Math.min(a.x2, b.x2);
6
+ const y2 = Math.min(a.y2, b.y2);
7
+ return { x1, y1, x2, y2, w: Math.max(x2 - x1, 0), h: Math.max(y2 - y1, 0) };
8
8
  };
9
9
  const axis = (a, b, c) => (a < b ? a - b : a > b + c ? a - b - c : 0) ** 2;
10
- export const intersectRectCircle = (x, y, w, h, cx, cy, r) => axis(cx, x, w) + axis(cy, y, h) <= r * r;
10
+ const intersectRectCircle = (x, y, w, h, cx, cy, r) => axis(cx, x, w) + axis(cy, y, h) <= r * r;
11
+ export {
12
+ charCode,
13
+ intersectRect,
14
+ intersectRectCircle
15
+ };