@thi.ng/text-canvas 2.6.37 → 3.0.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/CHANGELOG.md +23 -1
- package/README.md +88 -68
- package/api.d.ts +1 -0
- package/bars.d.ts +38 -4
- package/bars.js +4 -4
- package/canvas.d.ts +4 -2
- package/canvas.js +6 -0
- package/image.d.ts +31 -6
- package/image.js +218 -23
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/line.d.ts +0 -2
- package/line.js +1 -41
- package/package.json +16 -8
- package/plot.d.ts +17 -0
- package/plot.js +64 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-02-
|
|
3
|
+
- **Last updated**: 2024-02-19T15:50:26Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,28 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
# [3.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/text-canvas@3.0.0) (2024-02-19)
|
|
13
|
+
|
|
14
|
+
#### 🛑 Breaking changes
|
|
15
|
+
|
|
16
|
+
- add plotting, additive blending/blitting, refactor bar chart fns ([7cd6d41](https://github.com/thi-ng/umbrella/commit/7cd6d41))
|
|
17
|
+
- BREAKING CHANGE: swap naming of barChartH/V fns, update args for blit()/blitMask()
|
|
18
|
+
- swap naming of barChartH/V fns:
|
|
19
|
+
- barChartHLines/Str() <=> barChartVLines/Str()
|
|
20
|
+
- add plotBarsV() multi-plot function
|
|
21
|
+
- add blitBarsV() fn w/ support for custom blending fns
|
|
22
|
+
- add blendBarsVAdd() additive blending fn
|
|
23
|
+
- add BLEND_ADD lookup table for additive blending using ANSI16 colors
|
|
24
|
+
- update arg order of blit()/blitMask() fns
|
|
25
|
+
- add Canvas.empty(), Canvas.clear() fns
|
|
26
|
+
|
|
27
|
+
#### ♻️ Refactoring
|
|
28
|
+
|
|
29
|
+
- unify plotting function naming ([cb275ae](https://github.com/thi-ng/umbrella/commit/cb275ae))
|
|
30
|
+
- plotBarsV() => plotBarChartV()
|
|
31
|
+
- lineChart() => plotLineChart()
|
|
32
|
+
- migrate line chart fns to plot.ts
|
|
33
|
+
|
|
12
34
|
### [2.6.17](https://github.com/thi-ng/umbrella/tree/@thi.ng/text-canvas@2.6.17) (2023-11-09)
|
|
13
35
|
|
|
14
36
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -46,12 +46,15 @@
|
|
|
46
46
|
- [Bars & bar charts](#bars--bar-charts)
|
|
47
47
|
- [Tables](#tables)
|
|
48
48
|
- [3D wireframe cube example](#3d-wireframe-cube-example)
|
|
49
|
+
- [Multiple bar plots with additive blending](#multiple-bar-plots-with-additive-blending)
|
|
49
50
|
- [Authors](#authors)
|
|
50
51
|
- [License](#license)
|
|
51
52
|
|
|
52
53
|
## About
|
|
53
54
|
|
|
54
|
-
Text based canvas, drawing, tables with arbitrary formatting (incl. ANSI/HTML).
|
|
55
|
+
Text based canvas, drawing, plotting, tables with arbitrary formatting (incl. ANSI/HTML).
|
|
56
|
+
|
|
57
|
+

|
|
55
58
|
|
|
56
59
|
## Status
|
|
57
60
|
|
|
@@ -83,7 +86,7 @@ For Node.js REPL:
|
|
|
83
86
|
const textCanvas = await import("@thi.ng/text-canvas");
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
89
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 6.27 KB
|
|
87
90
|
|
|
88
91
|
## Dependencies
|
|
89
92
|
|
|
@@ -205,9 +208,9 @@ package):
|
|
|
205
208
|
|
|
206
209
|
```ts
|
|
207
210
|
// Terminal
|
|
208
|
-
|
|
211
|
+
process.stdout.write(formatCanvas(canvas, FMT_ANSI16));
|
|
209
212
|
// or
|
|
210
|
-
console.log(formatCanvas(canvas,
|
|
213
|
+
console.log(formatCanvas(canvas, FMT_ANSI16));
|
|
211
214
|
|
|
212
215
|
// Browser
|
|
213
216
|
const el = document.createElement("pre");
|
|
@@ -253,23 +256,22 @@ each newly pushed one being intersected with the previous top-of-stack rect:
|
|
|
253
256
|
|
|
254
257
|
### Drawing functions
|
|
255
258
|
|
|
256
|
-
- `line`
|
|
257
|
-
- `hline`
|
|
258
|
-
- `vline`
|
|
259
|
-
- `circle`
|
|
259
|
+
- `line()`
|
|
260
|
+
- `hline()`
|
|
261
|
+
- `vline()`
|
|
262
|
+
- `circle()`
|
|
260
263
|
|
|
261
|
-
- `clear`
|
|
262
|
-
- `fillRect`
|
|
263
|
-
- `strokeRect`
|
|
264
|
+
- `clear()`
|
|
265
|
+
- `fillRect()`
|
|
266
|
+
- `strokeRect()`
|
|
264
267
|
|
|
265
268
|
### Image functions
|
|
266
269
|
|
|
267
|
-
- `blit`
|
|
268
|
-
- `
|
|
269
|
-
- `
|
|
270
|
-
- `
|
|
271
|
-
- `
|
|
272
|
-
- `imageBraille` / `imageCanvasBraille` / `imageStringBraille`
|
|
270
|
+
- `blit()` / `blitMask()` / `blitBarsV()`
|
|
271
|
+
- `image()` / `imageRaw()` / `imageCanvas565()` / `imageString565()`
|
|
272
|
+
- `imageBraille()` / `imageCanvasBraille()` / `imageStringBraille()`
|
|
273
|
+
- `resize()` / `extract()`
|
|
274
|
+
- `scrollV()`
|
|
273
275
|
|
|
274
276
|
```ts
|
|
275
277
|
import { RGB565 } from "@thi.ng/pixel";
|
|
@@ -289,19 +291,19 @@ console.log(imageString565(img));
|
|
|
289
291
|
|
|
290
292
|
### Text functions
|
|
291
293
|
|
|
292
|
-
- `textLine`
|
|
293
|
-
- `textLines`
|
|
294
|
-
- `textColumn` (word wrapped)
|
|
295
|
-
- `textBox` (word wrapped)
|
|
294
|
+
- `textLine()`
|
|
295
|
+
- `textLines()`
|
|
296
|
+
- `textColumn()` (word wrapped)
|
|
297
|
+
- `textBox()` (word wrapped)
|
|
296
298
|
|
|
297
299
|
### Bars & bar charts
|
|
298
300
|
|
|
299
|
-
The following are string builders only, draw result via text functions:
|
|
301
|
+
The following are string builders only, draw result via [text functions](#text-functions):
|
|
300
302
|
|
|
301
|
-
- `barHorizontal`
|
|
302
|
-
- `barVertical`
|
|
303
|
-
- `barChartHStr`
|
|
304
|
-
- `barChartVStr`
|
|
303
|
+
- `barHorizontal()`
|
|
304
|
+
- `barVertical()`
|
|
305
|
+
- `barChartHStr()`
|
|
306
|
+
- `barChartVStr()`
|
|
305
307
|
|
|
306
308
|
### Tables
|
|
307
309
|
|
|
@@ -323,7 +325,7 @@ Table cell contents will be word-wrapped. By default, individual words longer
|
|
|
323
325
|
than the configured cell width will be truncated, but can be forced to wrap by
|
|
324
326
|
enabling the `hard` option (see example below).
|
|
325
327
|
|
|
326
|
-
```ts
|
|
328
|
+
```ts tangle:export/readme-table.ts
|
|
327
329
|
import { repeatedly } from "@thi.ng/transducers";
|
|
328
330
|
import * as tc from "@thi.ng/text-canvas";
|
|
329
331
|
import * as tf from "@thi.ng/text-format";
|
|
@@ -331,7 +333,7 @@ import * as tf from "@thi.ng/text-format";
|
|
|
331
333
|
// generate 20 random values
|
|
332
334
|
const data = repeatedly(() => Math.random(), 20)
|
|
333
335
|
// format as bar chart string
|
|
334
|
-
const chart = tc.
|
|
336
|
+
const chart = tc.barChartVStr(4, data, 0, 1);
|
|
335
337
|
|
|
336
338
|
// create text canvas
|
|
337
339
|
const canvas = new tc.Canvas(64, 20);
|
|
@@ -390,44 +392,11 @@ as content.
|
|
|
390
392
|
|
|
391
393
|
### 3D wireframe cube example
|
|
392
394
|
|
|
393
|
-
|
|
394
|
-
┌───┐
|
|
395
|
-
┌──────────────────────┐
|
|
396
|
-
│ @thi.ng/text-canvas │
|
|
397
|
-
│ wireframe cube │++++++++++
|
|
398
|
-
│ │ +++++++++++ ┌───┐
|
|
399
|
-
│ x: 0.42 │ ++++│ 6 │
|
|
400
|
-
│ y: 0.30 │ ┌───┐ ++++++++ └───┘
|
|
401
|
-
└──────────────────────┘++++++++│ 7 │+ +
|
|
402
|
-
+ └───┘ └───┘ +
|
|
403
|
-
+ + + +
|
|
404
|
-
+ + + +
|
|
405
|
-
+ + + +
|
|
406
|
-
+ + + +
|
|
407
|
-
+ + + +
|
|
408
|
-
+ + + +
|
|
409
|
-
+ + + +
|
|
410
|
-
+ + ┌───┐ +
|
|
411
|
-
+ + +│ 3 │ +
|
|
412
|
-
+ ┌───┐+++ └───┘ +
|
|
413
|
-
+ │ 0 │ + +
|
|
414
|
-
+ └───┘ + +
|
|
415
|
-
+ + + +
|
|
416
|
-
+ + + +
|
|
417
|
-
+ + + +
|
|
418
|
-
+ + + +
|
|
419
|
-
+ + ┌───┐
|
|
420
|
-
+ + │ 2 │
|
|
421
|
-
+ + ++└───┘
|
|
422
|
-
+ + +++
|
|
423
|
-
+ + ++
|
|
424
|
-
+ + +++
|
|
425
|
-
++ ++
|
|
426
|
-
````
|
|
395
|
+

|
|
427
396
|
|
|
428
397
|
Code for this above example output (CLI version):
|
|
429
398
|
|
|
430
|
-
```ts
|
|
399
|
+
```ts tangle:export/readme-cube.ts
|
|
431
400
|
import * as geom from "@thi.ng/geom";
|
|
432
401
|
import * as mat from "@thi.ng/matrices";
|
|
433
402
|
import * as tc from "@thi.ng/text-canvas";
|
|
@@ -491,13 +460,64 @@ setInterval(() => {
|
|
|
491
460
|
padding: [1, 0]
|
|
492
461
|
}
|
|
493
462
|
);
|
|
494
|
-
// draw canvas
|
|
495
|
-
console.clear();
|
|
496
463
|
// output as ANSI formatted string
|
|
497
|
-
|
|
498
|
-
|
|
464
|
+
process.stdout.write(
|
|
465
|
+
tf.ANSI_SYNC_START +
|
|
466
|
+
tf.ANSI_CLEAR_SCREEN +
|
|
467
|
+
tf.ANSI_HOME +
|
|
468
|
+
tc.formatCanvas(canvas, tf.FMT_ANSI16) +
|
|
469
|
+
tf.ANSI_SYNC_END
|
|
470
|
+
);
|
|
471
|
+
// ...our output as plain text
|
|
499
472
|
// console.log(tc.formatCanvas(canvas));
|
|
500
|
-
},
|
|
473
|
+
}, 16);
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Multiple bar plots with additive blending
|
|
477
|
+
|
|
478
|
+
```ts tangle:export/readme-barplot.ts
|
|
479
|
+
import { HERMITE_V, VEC4, ramp } from "@thi.ng/ramp";
|
|
480
|
+
import { canvas, formatCanvas, plotBarChartV } from "@thi.ng/text-canvas";
|
|
481
|
+
import { FG_BLUE, FG_GRAY, FG_GREEN, FG_RED, FMT_ANSI16 } from "@thi.ng/text-format";
|
|
482
|
+
|
|
483
|
+
// define curves for 4 params which will be computed via
|
|
484
|
+
// cubic hermite interpolation
|
|
485
|
+
const curves = ramp(
|
|
486
|
+
// use VEC4 interpolation preset
|
|
487
|
+
HERMITE_V(VEC4),
|
|
488
|
+
// keyframes
|
|
489
|
+
[
|
|
490
|
+
[0.0, [1, 0, 0.33, 0]],
|
|
491
|
+
[0.5, [0, 1, 0.06, -0.3]],
|
|
492
|
+
[1.0, [0, 0, 1, 0.5]],
|
|
493
|
+
]
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
const W = 100;
|
|
497
|
+
const H = 24;
|
|
498
|
+
const samples: number[][] = [];
|
|
499
|
+
|
|
500
|
+
// sample curves
|
|
501
|
+
for (let i = 0; i < W; i++) {
|
|
502
|
+
samples.push(<number[]>curves.at(i / (W - 1)));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// create empty canvas
|
|
506
|
+
const plot = canvas(W, H);
|
|
507
|
+
|
|
508
|
+
// create all 4 bar plots in the same canvas, by default uses additive blending
|
|
509
|
+
// to composite each plot layer
|
|
510
|
+
plotBarChartV(
|
|
511
|
+
plot,
|
|
512
|
+
{ min: 0, max: 1 },
|
|
513
|
+
{ data: samples.map((x) => x[0]), color: FG_RED },
|
|
514
|
+
{ data: samples.map((x) => x[1]), color: FG_GREEN },
|
|
515
|
+
{ data: samples.map((x) => x[2]), color: FG_BLUE },
|
|
516
|
+
{ data: samples.map((x) => x[3]), color: FG_GRAY }
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
// format & print canvas using ANSI colors
|
|
520
|
+
console.log(formatCanvas(plot, FMT_ANSI16));
|
|
501
521
|
```
|
|
502
522
|
|
|
503
523
|
## Authors
|
package/api.d.ts
CHANGED
package/bars.d.ts
CHANGED
|
@@ -1,7 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Visualizes given values (in `[min..max]`interval) as vertical bar chart.
|
|
3
|
+
* Returns array of line strings.
|
|
4
|
+
*
|
|
5
|
+
* @param height
|
|
6
|
+
* @param vals
|
|
7
|
+
* @param min
|
|
8
|
+
* @param max
|
|
9
|
+
*/
|
|
10
|
+
export declare const barChartVLines: (height: number, vals: Iterable<number>, min?: number, max?: number) => string[];
|
|
11
|
+
/**
|
|
12
|
+
* Same as {@link barChartVLines}, but returns result as single string.
|
|
13
|
+
*
|
|
14
|
+
* @param height
|
|
15
|
+
* @param vals
|
|
16
|
+
* @param min
|
|
17
|
+
* @param max
|
|
18
|
+
*/
|
|
19
|
+
export declare const barChartVStr: (height: number, vals: Iterable<number>, min?: number, max?: number) => string;
|
|
20
|
+
/**
|
|
21
|
+
* Visualizes given values (in `[min..max]`interval) as horizontal bar chart.
|
|
22
|
+
* Returns array of line strings.
|
|
23
|
+
*
|
|
24
|
+
* @param height
|
|
25
|
+
* @param vals
|
|
26
|
+
* @param min
|
|
27
|
+
* @param max
|
|
28
|
+
*/
|
|
29
|
+
export declare const barChartHLines: (width: number, vals: Iterable<number>, min?: number, max?: number) => string[];
|
|
30
|
+
/**
|
|
31
|
+
* Same as {@link barChartVLines}, but returns result as single string.
|
|
32
|
+
*
|
|
33
|
+
* @param height
|
|
34
|
+
* @param vals
|
|
35
|
+
* @param min
|
|
36
|
+
* @param max
|
|
37
|
+
*/
|
|
38
|
+
export declare const barChartHStr: (width: number, vals: Iterable<number>, min?: number, max?: number) => string;
|
|
5
39
|
export declare const barHorizontal: (width: number, x: number, min?: number, max?: number) => string;
|
|
6
40
|
export declare const barVertical: (height: number, x: number, min?: number, max?: number, delim?: string) => string;
|
|
7
41
|
//# sourceMappingURL=bars.d.ts.map
|
package/bars.js
CHANGED
|
@@ -8,7 +8,7 @@ import { map } from "@thi.ng/transducers/map";
|
|
|
8
8
|
import { max as $max } from "@thi.ng/transducers/max";
|
|
9
9
|
import { min as $min } from "@thi.ng/transducers/min";
|
|
10
10
|
import { BARS_H, BARS_V } from "./api.js";
|
|
11
|
-
const
|
|
11
|
+
const barChartVLines = (height, vals, min, max) => {
|
|
12
12
|
const $vals = ensureArray(vals);
|
|
13
13
|
min = min !== void 0 ? min : $min($vals);
|
|
14
14
|
max = max !== void 0 ? max : $max($vals);
|
|
@@ -24,14 +24,14 @@ const barChartHLines = (height, vals, min, max) => {
|
|
|
24
24
|
}
|
|
25
25
|
return res;
|
|
26
26
|
};
|
|
27
|
-
const
|
|
28
|
-
const
|
|
27
|
+
const barChartVStr = (height, vals, min, max) => barChartVLines(height, vals, min, max).join("\n");
|
|
28
|
+
const barChartHLines = (width, vals, min, max) => {
|
|
29
29
|
const $vals = ensureArray(vals);
|
|
30
30
|
min = min !== void 0 ? min : $min($vals);
|
|
31
31
|
max = max !== void 0 ? max : $max($vals);
|
|
32
32
|
return [...map((x) => barHorizontal(width, x, min, max), $vals)];
|
|
33
33
|
};
|
|
34
|
-
const
|
|
34
|
+
const barChartHStr = (width, vals, min, max) => barChartHLines(width, vals, min, max).join("\n");
|
|
35
35
|
const barHorizontal = (width, x, min = 0, max = 1) => bar(BARS_H, width, false, x, min, max, "");
|
|
36
36
|
const barVertical = (height, x, min = 0, max = 1, delim = "\n") => bar(BARS_V, height, true, x, min, max, delim);
|
|
37
37
|
const bar = (chars, size, left, x, min, max, delim) => {
|
package/canvas.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type Fn0, type ICopy, type IGrid2D, type NumOrString } from "@thi.ng/api";
|
|
1
|
+
import { type Fn0, type ICopy, type IGrid2D, type NumOrString, type IEmpty, type IClear } from "@thi.ng/api";
|
|
2
2
|
import { type ClipRect, type StrokeStyle } from "./api.js";
|
|
3
|
-
export declare class Canvas implements ICopy<Canvas>, IGrid2D<Uint32Array, number> {
|
|
3
|
+
export declare class Canvas implements IClear, ICopy<Canvas>, IEmpty<Canvas>, IGrid2D<Uint32Array, number> {
|
|
4
4
|
data: Uint32Array;
|
|
5
5
|
size: [number, number];
|
|
6
6
|
stride: [number, number];
|
|
@@ -14,6 +14,8 @@ export declare class Canvas implements ICopy<Canvas>, IGrid2D<Uint32Array, numbe
|
|
|
14
14
|
get offset(): number;
|
|
15
15
|
get dim(): 2;
|
|
16
16
|
copy(): Canvas;
|
|
17
|
+
empty(): Canvas;
|
|
18
|
+
clear(): void;
|
|
17
19
|
order(): number[];
|
|
18
20
|
includes(d0: number, d1: number): boolean;
|
|
19
21
|
indexAt(d0: number, d1: number): number;
|
package/canvas.js
CHANGED
package/image.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type { NumOrString, UIntArray } from "@thi.ng/api";
|
|
2
|
-
import { type ImageOpts } from "./api.js";
|
|
1
|
+
import type { FnN4, NumOrString, UIntArray } from "@thi.ng/api";
|
|
2
|
+
import { type BlendFn, type ImageOpts } from "./api.js";
|
|
3
3
|
import { Canvas } from "./canvas.js";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param dest
|
|
7
|
+
* @param src
|
|
8
|
+
* @param x
|
|
9
|
+
* @param y
|
|
10
|
+
*/
|
|
11
|
+
export declare const blit: (dest: Canvas, src: Canvas, x?: number, y?: number) => void;
|
|
5
12
|
/**
|
|
6
13
|
* Similar to {@link blit}. Pastes `src` {@link Canvas} into `dest` at given
|
|
7
14
|
* position and uses `mask` to exclude pixels from being copied (and therefore
|
|
8
|
-
* achieve a form of
|
|
15
|
+
* achieve a form of on/off transparency, similar to GIFs), i.e. only non-`mask`
|
|
9
16
|
* pixels/chars will be copied. Supports region clipping.
|
|
10
17
|
*
|
|
11
18
|
* @example
|
|
@@ -40,12 +47,30 @@ export declare const blit: (dest: Canvas, x: number, y: number, src: Canvas) =>
|
|
|
40
47
|
* ```
|
|
41
48
|
*
|
|
42
49
|
* @param dest
|
|
50
|
+
* @param src
|
|
43
51
|
* @param x
|
|
44
52
|
* @param y
|
|
45
|
-
* @param src
|
|
46
53
|
* @param mask
|
|
47
54
|
*/
|
|
48
|
-
export declare const blitMask: (dest: Canvas,
|
|
55
|
+
export declare const blitMask: (dest: Canvas, src: Canvas, x?: number, y?: number, mask?: NumOrString) => void;
|
|
56
|
+
export declare const blitBarsV: (dest: Canvas, src: Canvas, x?: number, y?: number, blend?: BlendFn) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Blending function for {@link blendBarsVAdd}. Additive blending for vertical
|
|
59
|
+
* box drawing characters.
|
|
60
|
+
*
|
|
61
|
+
* @param a
|
|
62
|
+
* @param b
|
|
63
|
+
*/
|
|
64
|
+
export declare const blendBarsVAdd: FnN4;
|
|
65
|
+
/**
|
|
66
|
+
* @remarks
|
|
67
|
+
* Lookups in this index are symmetrical (see {@link __blend}). Grays are
|
|
68
|
+
* handled via the last group of entries.
|
|
69
|
+
*
|
|
70
|
+
* The order of entries in each group should be B,G,R,C,M,Y, followed by light
|
|
71
|
+
* versions (in same order)
|
|
72
|
+
*/
|
|
73
|
+
export declare const BLEND_ADD: Record<number, Record<number, number>>;
|
|
49
74
|
export declare const resize: (canvas: Canvas, newWidth: number, newHeight: number) => void;
|
|
50
75
|
export declare const extract: (canvas: Canvas, x: number, y: number, w: number, h: number) => Canvas;
|
|
51
76
|
/**
|
package/image.js
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
import { blit1d } from "@thi.ng/arrays/blit";
|
|
1
|
+
import { blit1d, blitPred1d } from "@thi.ng/arrays/blit";
|
|
2
2
|
import { peek } from "@thi.ng/arrays/peek";
|
|
3
3
|
import { isNumber } from "@thi.ng/checks/is-number";
|
|
4
4
|
import { clamp0 } from "@thi.ng/math/interval";
|
|
5
|
+
import {
|
|
6
|
+
FG_BLUE,
|
|
7
|
+
FG_CYAN,
|
|
8
|
+
FG_GRAY,
|
|
9
|
+
FG_GREEN,
|
|
10
|
+
FG_LIGHT_BLUE,
|
|
11
|
+
FG_LIGHT_CYAN,
|
|
12
|
+
FG_LIGHT_GRAY,
|
|
13
|
+
FG_LIGHT_GREEN,
|
|
14
|
+
FG_LIGHT_MAGENTA,
|
|
15
|
+
FG_LIGHT_RED,
|
|
16
|
+
FG_LIGHT_YELLOW,
|
|
17
|
+
FG_MAGENTA,
|
|
18
|
+
FG_RED,
|
|
19
|
+
FG_YELLOW,
|
|
20
|
+
FG_WHITE
|
|
21
|
+
} from "@thi.ng/text-format";
|
|
5
22
|
import { FMT_ANSI565 } from "@thi.ng/text-format/ansi";
|
|
6
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
SHADES_BLOCK
|
|
25
|
+
} from "./api.js";
|
|
7
26
|
import { Canvas, canvas } from "./canvas.js";
|
|
8
27
|
import { formatCanvas } from "./format.js";
|
|
9
28
|
import { charCode, intersectRect } from "./utils.js";
|
|
10
|
-
const
|
|
29
|
+
const __initBlit = (dest, x, y, src) => {
|
|
11
30
|
x |= 0;
|
|
12
31
|
y |= 0;
|
|
13
32
|
const { data: sbuf, width: sw, height: sh } = src;
|
|
@@ -26,31 +45,24 @@ const blit = (dest, x, y, src) => {
|
|
|
26
45
|
return;
|
|
27
46
|
const sx = clamp0(x1 - x);
|
|
28
47
|
const sy = clamp0(y1 - y);
|
|
48
|
+
return { sbuf, dbuf, sw, dw, x, y, x1, y1, y2, iw, ih, sx, sy };
|
|
49
|
+
};
|
|
50
|
+
const blit = (dest, src, x = 0, y = 0) => {
|
|
51
|
+
const state = __initBlit(dest, x, y, src);
|
|
52
|
+
if (!state)
|
|
53
|
+
return;
|
|
54
|
+
const { sbuf, dbuf, x1, y1, y2, sx, sy, iw, sw, dw } = state;
|
|
29
55
|
for (let yy = sy, dy = y1; dy < y2; yy++, dy++) {
|
|
30
56
|
let sidx = sx + yy * sw;
|
|
31
57
|
let didx = x1 + dy * dw;
|
|
32
58
|
dbuf.set(sbuf.subarray(sidx, sidx + iw), didx);
|
|
33
59
|
}
|
|
34
60
|
};
|
|
35
|
-
const blitMask = (dest, x, y
|
|
36
|
-
x
|
|
37
|
-
|
|
38
|
-
const { data: sbuf, width: sw, height: sh } = src;
|
|
39
|
-
const { data: dbuf, width: dw } = dest;
|
|
40
|
-
const {
|
|
41
|
-
x1,
|
|
42
|
-
y1,
|
|
43
|
-
y2,
|
|
44
|
-
w: iw,
|
|
45
|
-
h: ih
|
|
46
|
-
} = intersectRect(
|
|
47
|
-
{ x1: x, y1: y, x2: x + sw, y2: y + sh, w: sw, h: sh },
|
|
48
|
-
peek(dest.clipRects)
|
|
49
|
-
);
|
|
50
|
-
if (!iw || !ih)
|
|
61
|
+
const blitMask = (dest, src, x = 0, y = 0, mask = 32) => {
|
|
62
|
+
const state = __initBlit(dest, x, y, src);
|
|
63
|
+
if (!state)
|
|
51
64
|
return;
|
|
52
|
-
const
|
|
53
|
-
const sy = clamp0(y1 - y);
|
|
65
|
+
const { sbuf, dbuf, x1, y1, y2, sx, sy, iw, sw, dw } = state;
|
|
54
66
|
mask = charCode(mask, 0);
|
|
55
67
|
for (let yy = sy, dy = y1; dy < y2; yy++, dy++) {
|
|
56
68
|
let sidx = sx + yy * sw;
|
|
@@ -58,12 +70,192 @@ const blitMask = (dest, x, y, src, mask = 32) => {
|
|
|
58
70
|
blit1d(dbuf, didx, sbuf.subarray(sidx, sidx + iw), mask);
|
|
59
71
|
}
|
|
60
72
|
};
|
|
73
|
+
const blitBarsV = (dest, src, x = 0, y = 0, blend = blendBarsVAdd) => {
|
|
74
|
+
const state = __initBlit(dest, x, y, src);
|
|
75
|
+
if (!state)
|
|
76
|
+
return;
|
|
77
|
+
const { sbuf, dbuf, x1, y1, y2, sx, sy, iw, sw, dw } = state;
|
|
78
|
+
for (let yy = sy, dy = y1; dy < y2; yy++, dy++) {
|
|
79
|
+
let sidx = sx + yy * sw;
|
|
80
|
+
let didx = x1 + dy * dw;
|
|
81
|
+
blitPred1d(dbuf, didx, sbuf.subarray(sidx, sidx + iw), (a, b, x2) => {
|
|
82
|
+
const ac = a & 65535;
|
|
83
|
+
return ac === 32 ? void 0 : ac > 9600 && ac < 9609 ? blend(a, b, x2, yy) : a;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const blendBarsVAdd = (a, b) => {
|
|
88
|
+
const ac = a & 65535;
|
|
89
|
+
const fmtA = a >> 16 & 31;
|
|
90
|
+
const fgA = fmtA & 31;
|
|
91
|
+
const bc = b & 65535;
|
|
92
|
+
const fmtB = b >> 16;
|
|
93
|
+
const bgB = fmtB >> 5;
|
|
94
|
+
const fgB = fmtB & 31;
|
|
95
|
+
let col;
|
|
96
|
+
let col2;
|
|
97
|
+
if (bc === 32) {
|
|
98
|
+
col = __blend(fgA, bgB) || fgA;
|
|
99
|
+
return ac == 9608 ? col << 21 | 32 : bgB << 21 | col << 16 | ac;
|
|
100
|
+
}
|
|
101
|
+
if (ac <= bc) {
|
|
102
|
+
col2 = bc > 9604 ? fgB : bgB;
|
|
103
|
+
col = __blend(fgA, col2);
|
|
104
|
+
return col2 << 21 | col << 16 | ac + bc >> 1;
|
|
105
|
+
} else {
|
|
106
|
+
col = __blend(fgA, fgB) || fgA;
|
|
107
|
+
col2 = __blend(fgA, bgB) || fgA;
|
|
108
|
+
return col2 << 21 | col << 16 | bc;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const __blend = (a, b) => BLEND_ADD[b]?.[a] || BLEND_ADD[a]?.[b] || 0;
|
|
112
|
+
const BLEND_ADD = {
|
|
113
|
+
// primary
|
|
114
|
+
[FG_BLUE]: {
|
|
115
|
+
[FG_BLUE]: FG_LIGHT_BLUE,
|
|
116
|
+
[FG_GREEN]: FG_CYAN,
|
|
117
|
+
[FG_RED]: FG_MAGENTA,
|
|
118
|
+
[FG_CYAN]: FG_LIGHT_CYAN,
|
|
119
|
+
[FG_MAGENTA]: FG_LIGHT_MAGENTA,
|
|
120
|
+
[FG_YELLOW]: FG_LIGHT_GRAY,
|
|
121
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_CYAN,
|
|
122
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_CYAN,
|
|
123
|
+
[FG_LIGHT_RED]: FG_LIGHT_MAGENTA,
|
|
124
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY,
|
|
125
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY,
|
|
126
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
127
|
+
},
|
|
128
|
+
[FG_GREEN]: {
|
|
129
|
+
[FG_GREEN]: FG_LIGHT_GREEN,
|
|
130
|
+
[FG_RED]: FG_YELLOW,
|
|
131
|
+
[FG_CYAN]: FG_LIGHT_CYAN,
|
|
132
|
+
[FG_MAGENTA]: FG_LIGHT_GRAY,
|
|
133
|
+
[FG_YELLOW]: FG_LIGHT_YELLOW,
|
|
134
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_CYAN,
|
|
135
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_GRAY,
|
|
136
|
+
[FG_LIGHT_RED]: FG_LIGHT_YELLOW,
|
|
137
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY,
|
|
138
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY,
|
|
139
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
140
|
+
},
|
|
141
|
+
[FG_RED]: {
|
|
142
|
+
[FG_RED]: FG_LIGHT_RED,
|
|
143
|
+
[FG_CYAN]: FG_LIGHT_GRAY,
|
|
144
|
+
[FG_MAGENTA]: FG_LIGHT_MAGENTA,
|
|
145
|
+
[FG_YELLOW]: FG_LIGHT_YELLOW,
|
|
146
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_MAGENTA,
|
|
147
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_YELLOW,
|
|
148
|
+
[FG_LIGHT_RED]: FG_LIGHT_GRAY,
|
|
149
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY,
|
|
150
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY,
|
|
151
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
152
|
+
},
|
|
153
|
+
// secondary
|
|
154
|
+
[FG_CYAN]: {
|
|
155
|
+
[FG_CYAN]: FG_LIGHT_CYAN,
|
|
156
|
+
[FG_MAGENTA]: FG_LIGHT_GRAY,
|
|
157
|
+
[FG_YELLOW]: FG_LIGHT_GRAY,
|
|
158
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_CYAN,
|
|
159
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_CYAN,
|
|
160
|
+
[FG_LIGHT_RED]: FG_LIGHT_GRAY,
|
|
161
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY,
|
|
162
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY,
|
|
163
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
164
|
+
},
|
|
165
|
+
[FG_MAGENTA]: {
|
|
166
|
+
[FG_MAGENTA]: FG_LIGHT_MAGENTA,
|
|
167
|
+
[FG_YELLOW]: FG_LIGHT_GRAY,
|
|
168
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_MAGENTA,
|
|
169
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_GRAY,
|
|
170
|
+
[FG_LIGHT_RED]: FG_LIGHT_GRAY,
|
|
171
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY,
|
|
172
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY,
|
|
173
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
174
|
+
},
|
|
175
|
+
[FG_YELLOW]: {
|
|
176
|
+
[FG_YELLOW]: FG_LIGHT_YELLOW,
|
|
177
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_GRAY,
|
|
178
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_GRAY,
|
|
179
|
+
[FG_LIGHT_RED]: FG_LIGHT_GRAY,
|
|
180
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY,
|
|
181
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY,
|
|
182
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
183
|
+
},
|
|
184
|
+
// light primary
|
|
185
|
+
[FG_LIGHT_BLUE]: {
|
|
186
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_GRAY
|
|
187
|
+
},
|
|
188
|
+
[FG_LIGHT_GREEN]: {
|
|
189
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_GRAY
|
|
190
|
+
},
|
|
191
|
+
[FG_LIGHT_RED]: {
|
|
192
|
+
[FG_LIGHT_RED]: FG_LIGHT_GRAY
|
|
193
|
+
},
|
|
194
|
+
// light secondary
|
|
195
|
+
[FG_LIGHT_CYAN]: {
|
|
196
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY
|
|
197
|
+
},
|
|
198
|
+
[FG_LIGHT_MAGENTA]: {
|
|
199
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY
|
|
200
|
+
},
|
|
201
|
+
[FG_LIGHT_YELLOW]: {
|
|
202
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
203
|
+
},
|
|
204
|
+
// grays
|
|
205
|
+
[FG_GRAY]: {
|
|
206
|
+
[FG_BLUE]: FG_LIGHT_BLUE,
|
|
207
|
+
[FG_GREEN]: FG_LIGHT_GREEN,
|
|
208
|
+
[FG_RED]: FG_LIGHT_RED,
|
|
209
|
+
[FG_CYAN]: FG_LIGHT_CYAN,
|
|
210
|
+
[FG_MAGENTA]: FG_LIGHT_MAGENTA,
|
|
211
|
+
[FG_YELLOW]: FG_LIGHT_YELLOW,
|
|
212
|
+
[FG_GRAY]: FG_LIGHT_GRAY,
|
|
213
|
+
[FG_LIGHT_BLUE]: FG_LIGHT_GRAY,
|
|
214
|
+
[FG_LIGHT_GREEN]: FG_LIGHT_GRAY,
|
|
215
|
+
[FG_LIGHT_RED]: FG_LIGHT_GRAY,
|
|
216
|
+
[FG_LIGHT_CYAN]: FG_LIGHT_GRAY,
|
|
217
|
+
[FG_LIGHT_MAGENTA]: FG_LIGHT_GRAY,
|
|
218
|
+
[FG_LIGHT_YELLOW]: FG_LIGHT_GRAY
|
|
219
|
+
},
|
|
220
|
+
[FG_LIGHT_GRAY]: {
|
|
221
|
+
[FG_BLUE]: FG_WHITE,
|
|
222
|
+
[FG_GREEN]: FG_WHITE,
|
|
223
|
+
[FG_RED]: FG_WHITE,
|
|
224
|
+
[FG_CYAN]: FG_WHITE,
|
|
225
|
+
[FG_MAGENTA]: FG_WHITE,
|
|
226
|
+
[FG_YELLOW]: FG_WHITE,
|
|
227
|
+
[FG_GRAY]: FG_WHITE,
|
|
228
|
+
[FG_LIGHT_BLUE]: FG_WHITE,
|
|
229
|
+
[FG_LIGHT_GREEN]: FG_WHITE,
|
|
230
|
+
[FG_LIGHT_RED]: FG_WHITE,
|
|
231
|
+
[FG_LIGHT_CYAN]: FG_WHITE,
|
|
232
|
+
[FG_LIGHT_MAGENTA]: FG_WHITE,
|
|
233
|
+
[FG_LIGHT_YELLOW]: FG_WHITE,
|
|
234
|
+
[FG_LIGHT_GRAY]: FG_WHITE
|
|
235
|
+
},
|
|
236
|
+
[FG_WHITE]: {
|
|
237
|
+
[FG_BLUE]: FG_WHITE,
|
|
238
|
+
[FG_CYAN]: FG_WHITE,
|
|
239
|
+
[FG_GRAY]: FG_WHITE,
|
|
240
|
+
[FG_GREEN]: FG_WHITE,
|
|
241
|
+
[FG_RED]: FG_WHITE,
|
|
242
|
+
[FG_MAGENTA]: FG_WHITE,
|
|
243
|
+
[FG_YELLOW]: FG_WHITE,
|
|
244
|
+
[FG_LIGHT_BLUE]: FG_WHITE,
|
|
245
|
+
[FG_LIGHT_CYAN]: FG_WHITE,
|
|
246
|
+
[FG_LIGHT_GRAY]: FG_WHITE,
|
|
247
|
+
[FG_LIGHT_GREEN]: FG_WHITE,
|
|
248
|
+
[FG_LIGHT_MAGENTA]: FG_WHITE,
|
|
249
|
+
[FG_LIGHT_RED]: FG_WHITE,
|
|
250
|
+
[FG_LIGHT_YELLOW]: FG_WHITE
|
|
251
|
+
}
|
|
252
|
+
};
|
|
61
253
|
const resize = (canvas2, newWidth, newHeight) => {
|
|
62
254
|
if (canvas2.width === newWidth && canvas2.height === newHeight)
|
|
63
255
|
return;
|
|
64
256
|
const dest = new Canvas(newWidth, newHeight);
|
|
65
257
|
dest.data.fill(charCode(32, canvas2.format));
|
|
66
|
-
blit(dest,
|
|
258
|
+
blit(dest, canvas2);
|
|
67
259
|
canvas2.data = dest.data;
|
|
68
260
|
canvas2.size[0] = newWidth;
|
|
69
261
|
canvas2.size[1] = newHeight;
|
|
@@ -80,7 +272,7 @@ const resize = (canvas2, newWidth, newHeight) => {
|
|
|
80
272
|
};
|
|
81
273
|
const extract = (canvas2, x, y, w, h) => {
|
|
82
274
|
const dest = new Canvas(w, h, canvas2.format, peek(canvas2.styles));
|
|
83
|
-
blit(dest, -x, -y
|
|
275
|
+
blit(dest, canvas2, -x, -y);
|
|
84
276
|
return dest;
|
|
85
277
|
};
|
|
86
278
|
const scrollV = (canvas2, dy, clear = 32) => {
|
|
@@ -241,7 +433,10 @@ const imgRect = (canvas2, x, y, w, h) => {
|
|
|
241
433
|
return rect;
|
|
242
434
|
};
|
|
243
435
|
export {
|
|
436
|
+
BLEND_ADD,
|
|
437
|
+
blendBarsVAdd,
|
|
244
438
|
blit,
|
|
439
|
+
blitBarsV,
|
|
245
440
|
blitMask,
|
|
246
441
|
extract,
|
|
247
442
|
image,
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
package/line.d.ts
CHANGED
|
@@ -13,6 +13,4 @@ import { Canvas } from "./canvas.js";
|
|
|
13
13
|
* @param char -
|
|
14
14
|
*/
|
|
15
15
|
export declare const line: (canvas: Canvas, ax: number, ay: number, bx: number, by: number, char?: NumOrString, format?: number) => void;
|
|
16
|
-
export declare const lineChart: (canvas: Canvas, x: number, y: number, height: number, vals: Iterable<number>, min?: number, max?: number, format?: number) => void;
|
|
17
|
-
export declare const lineChartStr: (height: number, vals: Iterable<number>, min?: number, max?: number) => string;
|
|
18
16
|
//# sourceMappingURL=line.d.ts.map
|
package/line.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import { ensureArray } from "@thi.ng/arrays/ensure-array";
|
|
2
1
|
import { peek } from "@thi.ng/arrays/peek";
|
|
3
2
|
import { liangBarsky2Raw } from "@thi.ng/geom-clip-line/liang-barsky";
|
|
4
|
-
import { fitClamped } from "@thi.ng/math/fit";
|
|
5
|
-
import { minMax } from "@thi.ng/math/interval";
|
|
6
|
-
import { max as $max } from "@thi.ng/transducers/max";
|
|
7
|
-
import { min as $min } from "@thi.ng/transducers/min";
|
|
8
3
|
import { Canvas } from "./canvas.js";
|
|
9
|
-
import { formatCanvas } from "./format.js";
|
|
10
4
|
import { charCode } from "./utils.js";
|
|
11
5
|
const line = (canvas, ax, ay, bx, by, char, format = canvas.format) => {
|
|
12
6
|
const { x1, y1, x2, y2 } = peek(canvas.clipRects);
|
|
@@ -42,40 +36,6 @@ const line = (canvas, ax, ay, bx, by, char, format = canvas.format) => {
|
|
|
42
36
|
}
|
|
43
37
|
}
|
|
44
38
|
};
|
|
45
|
-
const lineChart = (canvas, x, y, height, vals, min, max, format = canvas.format) => {
|
|
46
|
-
const $vals = ensureArray(vals);
|
|
47
|
-
min = min !== void 0 ? min : $min($vals);
|
|
48
|
-
max = max !== void 0 ? max : $max($vals);
|
|
49
|
-
height--;
|
|
50
|
-
format <<= 16;
|
|
51
|
-
const { x1, x2 } = peek(canvas.clipRects);
|
|
52
|
-
for (let i = 0, n = $vals.length - 1; i < n; i++) {
|
|
53
|
-
const xx = x + i;
|
|
54
|
-
if (xx < x1)
|
|
55
|
-
continue;
|
|
56
|
-
if (xx > x2)
|
|
57
|
-
break;
|
|
58
|
-
const ya = Math.round(fitClamped($vals[i], min, max, height, 0)) + y;
|
|
59
|
-
const yb = Math.round(fitClamped($vals[i + 1], min, max, height, 0)) + y;
|
|
60
|
-
if (ya === yb) {
|
|
61
|
-
canvas.setAt(xx, ya, 9472 | format);
|
|
62
|
-
} else {
|
|
63
|
-
let [y1, y2] = minMax(ya, yb);
|
|
64
|
-
while (++y1 < y2)
|
|
65
|
-
canvas.setAt(xx, y1, 9474 | format);
|
|
66
|
-
canvas.setAt(xx, ya, (ya < yb ? 9582 : 9583) | format);
|
|
67
|
-
canvas.setAt(xx, yb, (ya < yb ? 9584 : 9581) | format);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
const lineChartStr = (height, vals, min, max) => {
|
|
72
|
-
const $vals = ensureArray(vals);
|
|
73
|
-
const surf = new Canvas($vals.length, height);
|
|
74
|
-
lineChart(surf, 0, 0, height, $vals, min, max);
|
|
75
|
-
return formatCanvas(surf);
|
|
76
|
-
};
|
|
77
39
|
export {
|
|
78
|
-
line
|
|
79
|
-
lineChart,
|
|
80
|
-
lineChartStr
|
|
40
|
+
line
|
|
81
41
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/text-canvas",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Text based canvas, drawing, tables with arbitrary formatting (incl. ANSI/HTML)",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Text based canvas, drawing, plotting, tables with arbitrary formatting (incl. ANSI/HTML)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
7
7
|
"typings": "./index.d.ts",
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@thi.ng/api": "^8.9.23",
|
|
39
|
-
"@thi.ng/arrays": "^2.
|
|
39
|
+
"@thi.ng/arrays": "^2.8.0",
|
|
40
40
|
"@thi.ng/checks": "^3.4.23",
|
|
41
41
|
"@thi.ng/errors": "^2.4.16",
|
|
42
|
-
"@thi.ng/geom-clip-line": "^2.3.
|
|
43
|
-
"@thi.ng/math": "^5.
|
|
42
|
+
"@thi.ng/geom-clip-line": "^2.3.66",
|
|
43
|
+
"@thi.ng/math": "^5.10.0",
|
|
44
44
|
"@thi.ng/strings": "^3.7.14",
|
|
45
|
-
"@thi.ng/text-format": "^2.0
|
|
46
|
-
"@thi.ng/transducers": "^8.9.
|
|
45
|
+
"@thi.ng/text-format": "^2.1.0",
|
|
46
|
+
"@thi.ng/transducers": "^8.9.3"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@microsoft/api-extractor": "^7.40.1",
|
|
@@ -68,18 +68,23 @@
|
|
|
68
68
|
"braille",
|
|
69
69
|
"canvas",
|
|
70
70
|
"circle",
|
|
71
|
+
"clipping",
|
|
71
72
|
"color",
|
|
72
73
|
"datastructure",
|
|
74
|
+
"dataviz",
|
|
73
75
|
"drawing",
|
|
74
76
|
"format",
|
|
75
77
|
"image",
|
|
76
78
|
"line",
|
|
79
|
+
"plot",
|
|
77
80
|
"rect",
|
|
78
81
|
"rgb",
|
|
82
|
+
"shape",
|
|
79
83
|
"table",
|
|
80
84
|
"text",
|
|
81
85
|
"theme",
|
|
82
86
|
"typescript",
|
|
87
|
+
"visualization",
|
|
83
88
|
"wordwrap"
|
|
84
89
|
],
|
|
85
90
|
"publishConfig": {
|
|
@@ -120,6 +125,9 @@
|
|
|
120
125
|
"./line": {
|
|
121
126
|
"default": "./line.js"
|
|
122
127
|
},
|
|
128
|
+
"./plot": {
|
|
129
|
+
"default": "./plot.js"
|
|
130
|
+
},
|
|
123
131
|
"./rect": {
|
|
124
132
|
"default": "./rect.js"
|
|
125
133
|
},
|
|
@@ -139,5 +147,5 @@
|
|
|
139
147
|
],
|
|
140
148
|
"year": 2020
|
|
141
149
|
},
|
|
142
|
-
"gitHead": "
|
|
150
|
+
"gitHead": "ea2ec2e4f14c572bbfac00c43953a6c4033da09e\n"
|
|
143
151
|
}
|
package/plot.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { NumericArray } from "@thi.ng/api";
|
|
2
|
+
import type { BlendFn } from "./api.js";
|
|
3
|
+
import { Canvas } from "./canvas.js";
|
|
4
|
+
export interface PlotBarsVOpts {
|
|
5
|
+
min: number;
|
|
6
|
+
max: number;
|
|
7
|
+
blend?: BlendFn;
|
|
8
|
+
}
|
|
9
|
+
interface PlotSpec {
|
|
10
|
+
data: NumericArray;
|
|
11
|
+
color: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const plotBarChartV: (canv: Canvas, opts: PlotBarsVOpts, ...plots: PlotSpec[]) => Canvas;
|
|
14
|
+
export declare const plotLineChart: (canvas: Canvas, x: number, y: number, height: number, vals: Iterable<number>, min?: number, max?: number, format?: number) => void;
|
|
15
|
+
export declare const lineChartStr: (height: number, vals: Iterable<number>, min?: number, max?: number) => string;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=plot.d.ts.map
|
package/plot.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ensureArray } from "@thi.ng/arrays/ensure-array";
|
|
2
|
+
import { peek } from "@thi.ng/arrays/peek";
|
|
3
|
+
import { fitClamped } from "@thi.ng/math/fit";
|
|
4
|
+
import { minMax } from "@thi.ng/math/interval";
|
|
5
|
+
import { max as $max } from "@thi.ng/transducers/max";
|
|
6
|
+
import { min as $min } from "@thi.ng/transducers/min";
|
|
7
|
+
import { barChartVLines } from "./bars.js";
|
|
8
|
+
import { Canvas } from "./canvas.js";
|
|
9
|
+
import { formatCanvas } from "./format.js";
|
|
10
|
+
import { blendBarsVAdd, blitBarsV } from "./image.js";
|
|
11
|
+
import { textLines } from "./text.js";
|
|
12
|
+
const plotBarChartV = (canv, opts, ...plots) => {
|
|
13
|
+
const channel = canv.empty();
|
|
14
|
+
const blend = opts.blend || blendBarsVAdd;
|
|
15
|
+
for (let plot of plots) {
|
|
16
|
+
channel.clear();
|
|
17
|
+
textLines(
|
|
18
|
+
channel,
|
|
19
|
+
0,
|
|
20
|
+
0,
|
|
21
|
+
barChartVLines(channel.height, plot.data, opts.min, opts.max),
|
|
22
|
+
plot.color
|
|
23
|
+
);
|
|
24
|
+
blitBarsV(canv, channel, 0, 0, blend);
|
|
25
|
+
}
|
|
26
|
+
return canv;
|
|
27
|
+
};
|
|
28
|
+
const plotLineChart = (canvas, x, y, height, vals, min, max, format = canvas.format) => {
|
|
29
|
+
const $vals = ensureArray(vals);
|
|
30
|
+
min = min !== void 0 ? min : $min($vals);
|
|
31
|
+
max = max !== void 0 ? max : $max($vals);
|
|
32
|
+
height--;
|
|
33
|
+
format <<= 16;
|
|
34
|
+
const { x1, x2 } = peek(canvas.clipRects);
|
|
35
|
+
for (let i = 0, n = $vals.length - 1; i < n; i++) {
|
|
36
|
+
const xx = x + i;
|
|
37
|
+
if (xx < x1)
|
|
38
|
+
continue;
|
|
39
|
+
if (xx > x2)
|
|
40
|
+
break;
|
|
41
|
+
const ya = Math.round(fitClamped($vals[i], min, max, height, 0)) + y;
|
|
42
|
+
const yb = Math.round(fitClamped($vals[i + 1], min, max, height, 0)) + y;
|
|
43
|
+
if (ya === yb) {
|
|
44
|
+
canvas.setAt(xx, ya, 9472 | format);
|
|
45
|
+
} else {
|
|
46
|
+
let [y1, y2] = minMax(ya, yb);
|
|
47
|
+
while (++y1 < y2)
|
|
48
|
+
canvas.setAt(xx, y1, 9474 | format);
|
|
49
|
+
canvas.setAt(xx, ya, (ya < yb ? 9582 : 9583) | format);
|
|
50
|
+
canvas.setAt(xx, yb, (ya < yb ? 9584 : 9581) | format);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const lineChartStr = (height, vals, min, max) => {
|
|
55
|
+
const $vals = ensureArray(vals);
|
|
56
|
+
const surf = new Canvas($vals.length, height);
|
|
57
|
+
plotLineChart(surf, 0, 0, height, $vals, min, max);
|
|
58
|
+
return formatCanvas(surf);
|
|
59
|
+
};
|
|
60
|
+
export {
|
|
61
|
+
lineChartStr,
|
|
62
|
+
plotBarChartV,
|
|
63
|
+
plotLineChart
|
|
64
|
+
};
|