@kensio/colophon 2.11.1 → 2.13.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/README.md +4 -1
- package/dist/astro/index.d.ts.map +1 -1
- package/dist/astro/index.js +0 -1
- package/dist/astro/index.js.map +1 -1
- package/dist/config/defaults.d.ts +24 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +29 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/size.d.ts.map +1 -1
- package/dist/config/size.js +3 -0
- package/dist/config/size.js.map +1 -1
- package/dist/layout/fill.d.ts +32 -0
- package/dist/layout/fill.d.ts.map +1 -0
- package/dist/layout/fill.js +34 -0
- package/dist/layout/fill.js.map +1 -0
- package/dist/layout/index.d.ts +4 -2
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +2 -1
- package/dist/layout/index.js.map +1 -1
- package/dist/measure/faces.d.ts.map +1 -1
- package/dist/measure/faces.js.map +1 -1
- package/dist/render/svg.js +1 -1
- package/dist/render/svg.js.map +1 -1
- package/dist/templates/banner/index.js +2 -2
- package/dist/templates/banner/index.js.map +1 -1
- package/dist/templates/card/index.js +2 -2
- package/dist/templates/card/index.js.map +1 -1
- package/dist/templates/code/bar.d.ts +24 -0
- package/dist/templates/code/bar.d.ts.map +1 -0
- package/dist/templates/code/bar.js +31 -0
- package/dist/templates/code/bar.js.map +1 -0
- package/dist/templates/code/gutter.d.ts +30 -0
- package/dist/templates/code/gutter.d.ts.map +1 -0
- package/dist/templates/code/gutter.js +64 -0
- package/dist/templates/code/gutter.js.map +1 -0
- package/dist/templates/code/index.d.ts.map +1 -1
- package/dist/templates/code/index.js +34 -15
- package/dist/templates/code/index.js.map +1 -1
- package/dist/templates/code/layout.d.ts +6 -1
- package/dist/templates/code/layout.d.ts.map +1 -1
- package/dist/templates/code/layout.js +8 -3
- package/dist/templates/code/layout.js.map +1 -1
- package/dist/templates/code/mark/draw.d.ts +26 -0
- package/dist/templates/code/mark/draw.d.ts.map +1 -0
- package/dist/templates/code/mark/draw.js +41 -0
- package/dist/templates/code/mark/draw.js.map +1 -0
- package/dist/templates/code/mark/index.d.ts +16 -0
- package/dist/templates/code/mark/index.d.ts.map +1 -0
- package/dist/templates/code/mark/index.js +34 -0
- package/dist/templates/code/mark/index.js.map +1 -0
- package/dist/templates/code/mark/locate.d.ts +20 -0
- package/dist/templates/code/mark/locate.d.ts.map +1 -0
- package/dist/templates/code/mark/locate.js +56 -0
- package/dist/templates/code/mark/locate.js.map +1 -0
- package/dist/templates/code/mark/read.d.ts +30 -0
- package/dist/templates/code/mark/read.d.ts.map +1 -0
- package/dist/templates/code/mark/read.js +61 -0
- package/dist/templates/code/mark/read.js.map +1 -0
- package/dist/templates/code/plate.d.ts +7 -1
- package/dist/templates/code/plate.d.ts.map +1 -1
- package/dist/templates/code/plate.js +14 -4
- package/dist/templates/code/plate.js.map +1 -1
- package/dist/templates/footer.d.ts +9 -1
- package/dist/templates/footer.d.ts.map +1 -1
- package/dist/templates/footer.js +24 -0
- package/dist/templates/footer.js.map +1 -1
- package/dist/templates/frame.d.ts.map +1 -1
- package/dist/templates/frame.js +5 -7
- package/dist/templates/frame.js.map +1 -1
- package/dist/templates/index.d.ts +1 -0
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +3 -0
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/terminal/index.js +4 -4
- package/dist/templates/terminal/index.js.map +1 -1
- package/dist/templates/thumbnail/index.d.ts +21 -0
- package/dist/templates/thumbnail/index.d.ts.map +1 -0
- package/dist/templates/thumbnail/index.js +68 -0
- package/dist/templates/thumbnail/index.js.map +1 -0
- package/dist/templates/thumbnail/lines.d.ts +38 -0
- package/dist/templates/thumbnail/lines.d.ts.map +1 -0
- package/dist/templates/thumbnail/lines.js +76 -0
- package/dist/templates/thumbnail/lines.js.map +1 -0
- package/dist/templates/window/dots.d.ts +11 -0
- package/dist/templates/window/dots.d.ts.map +1 -0
- package/dist/templates/window/dots.js +32 -0
- package/dist/templates/window/dots.js.map +1 -0
- package/dist/templates/{terminal/window.d.ts → window/index.d.ts} +4 -2
- package/dist/templates/window/index.d.ts.map +1 -0
- package/dist/templates/window/index.js +48 -0
- package/dist/templates/window/index.js.map +1 -0
- package/dist/templates/window/title.d.ts +9 -0
- package/dist/templates/window/title.d.ts.map +1 -0
- package/dist/templates/window/title.js +24 -0
- package/dist/templates/window/title.js.map +1 -0
- package/dist/text/fill.d.ts +34 -0
- package/dist/text/fill.d.ts.map +1 -0
- package/dist/text/fill.js +57 -0
- package/dist/text/fill.js.map +1 -0
- package/dist/text/fit.d.ts.map +1 -1
- package/dist/text/fit.js +2 -6
- package/dist/text/fit.js.map +1 -1
- package/dist/text/index.d.ts +2 -0
- package/dist/text/index.d.ts.map +1 -1
- package/dist/text/index.js +1 -0
- package/dist/text/index.js.map +1 -1
- package/dist/text/step.d.ts +13 -0
- package/dist/text/step.d.ts.map +1 -0
- package/dist/text/step.js +17 -0
- package/dist/text/step.js.map +1 -0
- package/dist/text/unbroken.d.ts +22 -0
- package/dist/text/unbroken.d.ts.map +1 -0
- package/dist/text/unbroken.js +29 -0
- package/dist/text/unbroken.js.map +1 -0
- package/dist/texture/chevrons.d.ts +13 -0
- package/dist/texture/chevrons.d.ts.map +1 -0
- package/dist/texture/chevrons.js +22 -0
- package/dist/texture/chevrons.js.map +1 -0
- package/dist/texture/grid.d.ts +14 -0
- package/dist/texture/grid.d.ts.map +1 -0
- package/dist/texture/grid.js +38 -0
- package/dist/texture/grid.js.map +1 -0
- package/dist/texture/halftone.d.ts +14 -0
- package/dist/texture/halftone.d.ts.map +1 -0
- package/dist/texture/halftone.js +55 -0
- package/dist/texture/halftone.js.map +1 -0
- package/dist/texture/honeycomb.d.ts +14 -0
- package/dist/texture/honeycomb.d.ts.map +1 -0
- package/dist/texture/honeycomb.js +43 -0
- package/dist/texture/honeycomb.js.map +1 -0
- package/dist/texture/index.d.ts +15 -4
- package/dist/texture/index.d.ts.map +1 -1
- package/dist/texture/index.js +64 -14
- package/dist/texture/index.js.map +1 -1
- package/dist/texture/moire.d.ts +18 -0
- package/dist/texture/moire.d.ts.map +1 -0
- package/dist/texture/moire.js +44 -0
- package/dist/texture/moire.js.map +1 -0
- package/dist/texture/pattern.d.ts +10 -0
- package/dist/texture/pattern.d.ts.map +1 -1
- package/dist/texture/pattern.js +36 -13
- package/dist/texture/pattern.js.map +1 -1
- package/dist/texture/rays.d.ts +13 -0
- package/dist/texture/rays.d.ts.map +1 -0
- package/dist/texture/rays.js +36 -0
- package/dist/texture/rays.js.map +1 -0
- package/dist/texture/resolve.d.ts +10 -0
- package/dist/texture/resolve.d.ts.map +1 -1
- package/dist/texture/resolve.js +15 -0
- package/dist/texture/resolve.js.map +1 -1
- package/dist/texture/scallops.d.ts +14 -0
- package/dist/texture/scallops.d.ts.map +1 -0
- package/dist/texture/scallops.js +29 -0
- package/dist/texture/scallops.js.map +1 -0
- package/dist/texture/tile.d.ts +14 -0
- package/dist/texture/tile.d.ts.map +1 -0
- package/dist/texture/tile.js +23 -0
- package/dist/texture/tile.js.map +1 -0
- package/dist/texture/topographic/contours.d.ts +13 -0
- package/dist/texture/topographic/contours.d.ts.map +1 -0
- package/dist/texture/topographic/contours.js +72 -0
- package/dist/texture/topographic/contours.js.map +1 -0
- package/dist/texture/topographic/field.d.ts +8 -0
- package/dist/texture/topographic/field.d.ts.map +1 -0
- package/dist/texture/topographic/field.js +29 -0
- package/dist/texture/topographic/field.js.map +1 -0
- package/dist/texture/topographic/index.d.ts +17 -0
- package/dist/texture/topographic/index.d.ts.map +1 -0
- package/dist/texture/topographic/index.js +48 -0
- package/dist/texture/topographic/index.js.map +1 -0
- package/dist/theme/presets.d.ts +13 -5
- package/dist/theme/presets.d.ts.map +1 -1
- package/dist/theme/presets.js +16 -5
- package/dist/theme/presets.js.map +1 -1
- package/dist/types.d.ts +259 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/validate/collect.d.ts.map +1 -1
- package/dist/validate/collect.js +2 -1
- package/dist/validate/collect.js.map +1 -1
- package/dist/validate/keys.d.ts +37 -0
- package/dist/validate/keys.d.ts.map +1 -1
- package/dist/validate/keys.js +132 -2
- package/dist/validate/keys.js.map +1 -1
- package/dist/validate/texture.d.ts +4 -5
- package/dist/validate/texture.d.ts.map +1 -1
- package/dist/validate/texture.js +11 -20
- package/dist/validate/texture.js.map +1 -1
- package/dist/validate/values.d.ts +6 -0
- package/dist/validate/values.d.ts.map +1 -1
- package/dist/validate/values.js +16 -1
- package/dist/validate/values.js.map +1 -1
- package/package.json +3 -10
- package/dist/templates/terminal/window.d.ts.map +0 -1
- package/dist/templates/terminal/window.js +0 -84
- package/dist/templates/terminal/window.js.map +0 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { nextSize } from "./step.js";
|
|
2
|
+
import { largestUnbroken } from "./unbroken.js";
|
|
3
|
+
import { wrapText } from "./wrap.js";
|
|
4
|
+
/**
|
|
5
|
+
* How many whole lines fit in the box at a given size, and never fewer than one.
|
|
6
|
+
*
|
|
7
|
+
* A box too short for a single line gets that line anyway, running over rather
|
|
8
|
+
* than being left empty. That is the rule `distribute` follows for a group that
|
|
9
|
+
* overflows: a template which has asked for the impossible wants to see it.
|
|
10
|
+
*/
|
|
11
|
+
function linesInBox(maxHeight, advance) {
|
|
12
|
+
return Math.max(1, Math.floor(maxHeight / advance));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The size the search starts from, which is the largest one worth trying: no
|
|
16
|
+
* taller than a single line of the box, no larger than the caller's ceiling,
|
|
17
|
+
* and small enough that no word has to be broken to fit the width.
|
|
18
|
+
*/
|
|
19
|
+
function startingSize(text, measure, options) {
|
|
20
|
+
const ceiling = Math.min(options.maxFontSize, Math.floor(options.maxHeight / options.lineHeight));
|
|
21
|
+
return Math.max(options.minFontSize, largestUnbroken(text, measure, options.maxWidth, ceiling));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Wrap text into a box, at the largest size the whole of it fits at.
|
|
25
|
+
*
|
|
26
|
+
* This is {@link fitText} with the question turned round. `fitText` is given a
|
|
27
|
+
* size and shrinks only when the words need more lines than the layout allows,
|
|
28
|
+
* so a short title is drawn at whatever size the template named and no larger.
|
|
29
|
+
* That is right where the text sits in a group with other things, since a
|
|
30
|
+
* heading that grew to fill the space would stop looking like a heading.
|
|
31
|
+
*
|
|
32
|
+
* It is wrong where the text is the picture. A YouTube thumbnail is looked at
|
|
33
|
+
* in a fraction of the space it was rendered at, so its words have to take the
|
|
34
|
+
* room they are given rather than sit in the middle of it, and how much room
|
|
35
|
+
* that is depends on how many words there are: three of them should be drawn
|
|
36
|
+
* much larger than twelve. So the search comes down from the largest size the
|
|
37
|
+
* box could hold until the wrapped block fits both the width and the height.
|
|
38
|
+
*
|
|
39
|
+
* Text that will not fit even at the floor is cut to the lines there is room
|
|
40
|
+
* for, which is what `fitText` does at its own floor and for the same reason:
|
|
41
|
+
* below a certain size the image has stopped saying anything anybody can read.
|
|
42
|
+
*/
|
|
43
|
+
export function fillText(text, measure, options) {
|
|
44
|
+
const { maxWidth, maxHeight, lineHeight, minFontSize } = options;
|
|
45
|
+
let fontSize = startingSize(text, measure, options);
|
|
46
|
+
let lines = wrapText(text, maxWidth, (line) => measure(line, fontSize));
|
|
47
|
+
while (lines.length * fontSize * lineHeight > maxHeight &&
|
|
48
|
+
fontSize > minFontSize) {
|
|
49
|
+
fontSize = nextSize(fontSize, minFontSize);
|
|
50
|
+
lines = wrapText(text, maxWidth, (line) => measure(line, fontSize));
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
lines: lines.slice(0, linesInBox(maxHeight, fontSize * lineHeight)),
|
|
54
|
+
fontSize,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=fill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fill.js","sourceRoot":"","sources":["../../src/text/fill.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAcrC;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,SAAiB,EAAE,OAAe;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CACnB,IAAY,EACZ,OAAkB,EAClB,OAAoB;IAEpB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CACtB,OAAO,CAAC,WAAW,EACnB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CACnD,CAAC;IAEF,OAAO,IAAI,CAAC,GAAG,CACb,OAAO,CAAC,WAAW,EACnB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAC1D,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,OAAkB,EAClB,OAAoB;IAEpB,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACjE,IAAI,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACpD,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAExE,OACE,KAAK,CAAC,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS;QAChD,QAAQ,GAAG,WAAW,EACtB,CAAC;QACD,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC3C,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;QACnE,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
package/dist/text/fit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fit.d.ts","sourceRoot":"","sources":["../../src/text/fit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fit.d.ts","sourceRoot":"","sources":["../../src/text/fit.ts"],"names":[],"mappings":"AAGA,uEAAuE;AACvE,MAAM,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;AAEnE,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,6DAA6D;AAC7D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,UAAU,GAClB,UAAU,CAWZ"}
|
package/dist/text/fit.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { nextSize } from "./step.js";
|
|
1
2
|
import { wrapText } from "./wrap.js";
|
|
2
|
-
/** How much of the size is given up each time the text does not fit. */
|
|
3
|
-
const shrinkStep = 0.94;
|
|
4
3
|
/**
|
|
5
4
|
* Wrap text into the space it has, shrinking it until it fits.
|
|
6
5
|
*
|
|
@@ -18,10 +17,7 @@ export function fitText(text, measure, options) {
|
|
|
18
17
|
let fontSize = options.fontSize;
|
|
19
18
|
let lines = wrapText(text, maxWidth, (line) => measure(line, fontSize));
|
|
20
19
|
while (lines.length > maxLines && fontSize > minFontSize) {
|
|
21
|
-
|
|
22
|
-
// makes the search short, and the whole pixel is what stops it stalling
|
|
23
|
-
// once the sizes are small enough for rounding to swallow the step.
|
|
24
|
-
fontSize = Math.max(minFontSize, Math.min(fontSize - 1, Math.floor(fontSize * shrinkStep)));
|
|
20
|
+
fontSize = nextSize(fontSize, minFontSize);
|
|
25
21
|
lines = wrapText(text, maxWidth, (line) => measure(line, fontSize));
|
|
26
22
|
}
|
|
27
23
|
return { lines: lines.slice(0, maxLines), fontSize };
|
package/dist/text/fit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fit.js","sourceRoot":"","sources":["../../src/text/fit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"fit.js","sourceRoot":"","sources":["../../src/text/fit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAqBrC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,OAAO,CACrB,IAAY,EACZ,OAAkB,EAClB,OAAmB;IAEnB,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACpD,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAChC,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAExE,OAAO,KAAK,CAAC,MAAM,GAAG,QAAQ,IAAI,QAAQ,GAAG,WAAW,EAAE,CAAC;QACzD,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC3C,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;AACvD,CAAC"}
|
package/dist/text/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type { TextAttributes } from "./element.js";
|
|
|
4
4
|
export { breakWord } from "./break.js";
|
|
5
5
|
export { clampLine } from "./clamp.js";
|
|
6
6
|
export { ellipsis } from "./ellipsis.js";
|
|
7
|
+
export { fillText } from "./fill.js";
|
|
8
|
+
export type { FillOptions } from "./fill.js";
|
|
7
9
|
export { fitText } from "./fit.js";
|
|
8
10
|
export type { FitOptions, FittedText, MeasureAt } from "./fit.js";
|
|
9
11
|
export { wrapText } from "./wrap.js";
|
package/dist/text/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/text/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { textElement } from "./element.js";
|
|
|
3
3
|
export { breakWord } from "./break.js";
|
|
4
4
|
export { clampLine } from "./clamp.js";
|
|
5
5
|
export { ellipsis } from "./ellipsis.js";
|
|
6
|
+
export { fillText } from "./fill.js";
|
|
6
7
|
export { fitText } from "./fit.js";
|
|
7
8
|
export { wrapText } from "./wrap.js";
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
package/dist/text/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The next size down to try, for a search that is shrinking text into a space.
|
|
3
|
+
*
|
|
4
|
+
* Both terms are here to guarantee progress: the proportional step is what
|
|
5
|
+
* makes the search short, and the whole pixel is what stops it stalling once
|
|
6
|
+
* the sizes are small enough for rounding to swallow the step.
|
|
7
|
+
*
|
|
8
|
+
* It is shared by the two searches rather than written out in each, since a
|
|
9
|
+
* step that differed between them would mean two layouts settling on different
|
|
10
|
+
* sizes for the same words with no reason a reader could name.
|
|
11
|
+
*/
|
|
12
|
+
export declare function nextSize(fontSize: number, minFontSize: number): number;
|
|
13
|
+
//# sourceMappingURL=step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/text/step.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAKtE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** How much of the size is given up each time the text does not fit. */
|
|
2
|
+
const shrinkRatio = 0.94;
|
|
3
|
+
/**
|
|
4
|
+
* The next size down to try, for a search that is shrinking text into a space.
|
|
5
|
+
*
|
|
6
|
+
* Both terms are here to guarantee progress: the proportional step is what
|
|
7
|
+
* makes the search short, and the whole pixel is what stops it stalling once
|
|
8
|
+
* the sizes are small enough for rounding to swallow the step.
|
|
9
|
+
*
|
|
10
|
+
* It is shared by the two searches rather than written out in each, since a
|
|
11
|
+
* step that differed between them would mean two layouts settling on different
|
|
12
|
+
* sizes for the same words with no reason a reader could name.
|
|
13
|
+
*/
|
|
14
|
+
export function nextSize(fontSize, minFontSize) {
|
|
15
|
+
return Math.max(minFontSize, Math.min(fontSize - 1, Math.floor(fontSize * shrinkRatio)));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=step.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step.js","sourceRoot":"","sources":["../../src/text/step.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,WAAW,GAAG,IAAI,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB,EAAE,WAAmB;IAC5D,OAAO,IAAI,CAAC,GAAG,CACb,WAAW,EACX,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC,CAC3D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MeasureAt } from "./fit.js";
|
|
2
|
+
/**
|
|
3
|
+
* The largest size, no more than `ceiling`, at which every word fits on a line
|
|
4
|
+
* of its own.
|
|
5
|
+
*
|
|
6
|
+
* Text that is being grown to fill a box is the one case where wrapping is
|
|
7
|
+
* under pressure to break a word in half. `wrapText` breaks a word too wide for
|
|
8
|
+
* its line, which is the right answer when the size is settled and the
|
|
9
|
+
* alternative is a line running off the image, and the wrong one here: two
|
|
10
|
+
* lines of a broken word are shorter than one whole one, so a search measuring
|
|
11
|
+
* only the height it filled would happily settle on `Frontmatte` above `r`.
|
|
12
|
+
*
|
|
13
|
+
* So the search starts below the size where any breaking happens. A word that
|
|
14
|
+
* cannot fit even at the floor is broken as it always was, since by then there
|
|
15
|
+
* is nothing else to be done with it.
|
|
16
|
+
*
|
|
17
|
+
* Measuring at the ceiling and scaling is exact rather than a guess: widths are
|
|
18
|
+
* held per em and multiplied by the size, and the estimate used for a font the
|
|
19
|
+
* build cannot read is linear in the size too.
|
|
20
|
+
*/
|
|
21
|
+
export declare function largestUnbroken(text: string, measure: MeasureAt, maxWidth: number, ceiling: number): number;
|
|
22
|
+
//# sourceMappingURL=unbroken.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unbroken.d.ts","sourceRoot":"","sources":["../../src/text/unbroken.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,MAAM,CAUR"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The largest size, no more than `ceiling`, at which every word fits on a line
|
|
3
|
+
* of its own.
|
|
4
|
+
*
|
|
5
|
+
* Text that is being grown to fill a box is the one case where wrapping is
|
|
6
|
+
* under pressure to break a word in half. `wrapText` breaks a word too wide for
|
|
7
|
+
* its line, which is the right answer when the size is settled and the
|
|
8
|
+
* alternative is a line running off the image, and the wrong one here: two
|
|
9
|
+
* lines of a broken word are shorter than one whole one, so a search measuring
|
|
10
|
+
* only the height it filled would happily settle on `Frontmatte` above `r`.
|
|
11
|
+
*
|
|
12
|
+
* So the search starts below the size where any breaking happens. A word that
|
|
13
|
+
* cannot fit even at the floor is broken as it always was, since by then there
|
|
14
|
+
* is nothing else to be done with it.
|
|
15
|
+
*
|
|
16
|
+
* Measuring at the ceiling and scaling is exact rather than a guess: widths are
|
|
17
|
+
* held per em and multiplied by the size, and the estimate used for a font the
|
|
18
|
+
* build cannot read is linear in the size too.
|
|
19
|
+
*/
|
|
20
|
+
export function largestUnbroken(text, measure, maxWidth, ceiling) {
|
|
21
|
+
const words = text.split(/\s+/).filter((word) => word !== "");
|
|
22
|
+
return words.reduce((size, word) => {
|
|
23
|
+
const width = measure(word, ceiling);
|
|
24
|
+
return width <= maxWidth
|
|
25
|
+
? size
|
|
26
|
+
: Math.min(size, Math.floor((ceiling * maxWidth) / width));
|
|
27
|
+
}, ceiling);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=unbroken.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unbroken.js","sourceRoot":"","sources":["../../src/text/unbroken.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,OAAkB,EAClB,QAAgB,EAChB,OAAe;IAEf,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;IAE9D,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAErC,OAAO,KAAK,IAAI,QAAQ;YACtB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAC/D,CAAC,EAAE,OAAO,CAAC,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Dimensions, Texture } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Rows of chevrons: one V to a tile, meeting its neighbours at the tile edge.
|
|
4
|
+
*
|
|
5
|
+
* The V spans the whole width and stops short of the top and bottom, so the
|
|
6
|
+
* rows have air between them. Its ends sit at the same height on both edges,
|
|
7
|
+
* which is what makes one tile's chevron continue into the next rather than
|
|
8
|
+
* ending in a corner.
|
|
9
|
+
*/
|
|
10
|
+
export declare function chevronsSvg(texture: Extract<Texture, {
|
|
11
|
+
readonly type: "chevrons";
|
|
12
|
+
}>, dimensions: Dimensions, id: string): string;
|
|
13
|
+
//# sourceMappingURL=chevrons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chevrons.d.ts","sourceRoot":"","sources":["../../src/texture/chevrons.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAMvD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,EACxD,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,MAAM,GACT,MAAM,CAkBR"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { fallbackColor } from "./color.js";
|
|
2
|
+
import { tile } from "./tile.js";
|
|
3
|
+
const chevronDefaults = { opacity: 0.07, width: 2, gap: 36 };
|
|
4
|
+
/**
|
|
5
|
+
* Rows of chevrons: one V to a tile, meeting its neighbours at the tile edge.
|
|
6
|
+
*
|
|
7
|
+
* The V spans the whole width and stops short of the top and bottom, so the
|
|
8
|
+
* rows have air between them. Its ends sit at the same height on both edges,
|
|
9
|
+
* which is what makes one tile's chevron continue into the next rather than
|
|
10
|
+
* ending in a corner.
|
|
11
|
+
*/
|
|
12
|
+
export function chevronsSvg(texture, dimensions, id) {
|
|
13
|
+
const gap = texture.gap ?? chevronDefaults.gap;
|
|
14
|
+
const low = String(gap * 0.7);
|
|
15
|
+
const high = String(gap * 0.3);
|
|
16
|
+
const chevron = `<path d="M0 ${low}L${String(gap / 2)} ${high}L${String(gap)} ${low}"` +
|
|
17
|
+
` stroke="${texture.color ?? fallbackColor}"` +
|
|
18
|
+
` stroke-width="${String(texture.width ?? chevronDefaults.width)}"` +
|
|
19
|
+
` fill="none"/>`;
|
|
20
|
+
return tile(id, gap, chevron, "", dimensions, texture.opacity ?? chevronDefaults.opacity);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=chevrons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chevrons.js","sourceRoot":"","sources":["../../src/texture/chevrons.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,eAAe,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,OAAwD,EACxD,UAAsB,EACtB,EAAU;IAEV,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC;IAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IAC/B,MAAM,OAAO,GACX,eAAe,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG;QACtE,YAAY,OAAO,CAAC,KAAK,IAAI,aAAa,GAAG;QAC7C,kBAAkB,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,eAAe,CAAC,KAAK,CAAC,GAAG;QACnE,gBAAgB,CAAC;IAEnB,OAAO,IAAI,CACT,EAAE,EACF,GAAG,EACH,OAAO,EACP,EAAE,EACF,UAAU,EACV,OAAO,CAAC,OAAO,IAAI,eAAe,CAAC,OAAO,CAC3C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Dimensions, Texture } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Squared paper: lines both ways, and a heavier one every so often.
|
|
4
|
+
*
|
|
5
|
+
* The heavy lines are a second tile rather than part of the first, since what
|
|
6
|
+
* makes them heavy is that they repeat at a multiple of the spacing. Drawing
|
|
7
|
+
* both from `<pattern>`s keeps this among the cheap treatments: the tiles are
|
|
8
|
+
* square to the image, so a row of the rendered picture repeats, which is what
|
|
9
|
+
* the compression works on.
|
|
10
|
+
*/
|
|
11
|
+
export declare function gridSvg(texture: Extract<Texture, {
|
|
12
|
+
readonly type: "grid";
|
|
13
|
+
}>, dimensions: Dimensions, id: string): string;
|
|
14
|
+
//# sourceMappingURL=grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../src/texture/grid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AA4BvD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EACpD,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,MAAM,GACT,MAAM,CA8BR"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { fallbackColor } from "./color.js";
|
|
2
|
+
import { tile } from "./tile.js";
|
|
3
|
+
const gridDefaults = { opacity: 0.07, width: 1, gap: 32, major: 5 };
|
|
4
|
+
/** How much heavier the every-so-often line is than the rest. */
|
|
5
|
+
const majorScale = 2;
|
|
6
|
+
/** One square's worth of grid: a line along two of its edges. */
|
|
7
|
+
function square(texture, gap, width) {
|
|
8
|
+
const middle = String(gap / 2);
|
|
9
|
+
const size = String(gap);
|
|
10
|
+
// Down the middle of the tile on both axes rather than along its edges, for
|
|
11
|
+
// the reason `rulesSvg` gives: a stroke centred on the edge would have half
|
|
12
|
+
// of itself outside the tile, where the pattern does not repeat it.
|
|
13
|
+
return (`<path d="M0 ${middle}H${size}M${middle} 0V${size}"` +
|
|
14
|
+
` stroke="${texture.color ?? fallbackColor}"` +
|
|
15
|
+
` stroke-width="${String(width)}" fill="none"/>`);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Squared paper: lines both ways, and a heavier one every so often.
|
|
19
|
+
*
|
|
20
|
+
* The heavy lines are a second tile rather than part of the first, since what
|
|
21
|
+
* makes them heavy is that they repeat at a multiple of the spacing. Drawing
|
|
22
|
+
* both from `<pattern>`s keeps this among the cheap treatments: the tiles are
|
|
23
|
+
* square to the image, so a row of the rendered picture repeats, which is what
|
|
24
|
+
* the compression works on.
|
|
25
|
+
*/
|
|
26
|
+
export function gridSvg(texture, dimensions, id) {
|
|
27
|
+
const gap = texture.gap ?? gridDefaults.gap;
|
|
28
|
+
const width = texture.width ?? gridDefaults.width;
|
|
29
|
+
const opacity = texture.opacity ?? gridDefaults.opacity;
|
|
30
|
+
const major = texture.major ?? gridDefaults.major;
|
|
31
|
+
const fine = tile(`${id}a`, gap, square(texture, gap, width), "", dimensions, opacity);
|
|
32
|
+
if (major < 2) {
|
|
33
|
+
return fine;
|
|
34
|
+
}
|
|
35
|
+
return (fine +
|
|
36
|
+
tile(`${id}b`, gap * major, square(texture, gap * major, width * majorScale), "", dimensions, opacity));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid.js","sourceRoot":"","sources":["../../src/texture/grid.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,YAAY,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAEpE,iEAAiE;AACjE,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,iEAAiE;AACjE,SAAS,MAAM,CACb,OAAoD,EACpD,GAAW,EACX,KAAa;IAEb,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAEzB,4EAA4E;IAC5E,4EAA4E;IAC5E,oEAAoE;IACpE,OAAO,CACL,eAAe,MAAM,IAAI,IAAI,IAAI,MAAM,MAAM,IAAI,GAAG;QACpD,YAAY,OAAO,CAAC,KAAK,IAAI,aAAa,GAAG;QAC7C,kBAAkB,MAAM,CAAC,KAAK,CAAC,iBAAiB,CACjD,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CACrB,OAAoD,EACpD,UAAsB,EACtB,EAAU;IAEV,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC;IAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC;IAElD,MAAM,IAAI,GAAG,IAAI,CACf,GAAG,EAAE,GAAG,EACR,GAAG,EACH,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,EAC3B,EAAE,EACF,UAAU,EACV,OAAO,CACR,CAAC;IAEF,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,IAAI;QACJ,IAAI,CACF,GAAG,EAAE,GAAG,EACR,GAAG,GAAG,KAAK,EACX,MAAM,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK,EAAE,KAAK,GAAG,UAAU,CAAC,EAChD,EAAE,EACF,UAAU,EACV,OAAO,CACR,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Dimensions, Texture } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* A grid of dots that grow across the image, which is a gradient made out of
|
|
4
|
+
* print.
|
|
5
|
+
*
|
|
6
|
+
* It cannot be a tile: every dot is a different size, which is the whole
|
|
7
|
+
* effect. What keeps it affordable is that the size depends on the position
|
|
8
|
+
* rather than on chance, so a run of dots across the image is a smooth ramp
|
|
9
|
+
* and there is nothing noisy for the compression to choke on.
|
|
10
|
+
*/
|
|
11
|
+
export declare function halftoneSvg(texture: Extract<Texture, {
|
|
12
|
+
readonly type: "halftone";
|
|
13
|
+
}>, dimensions: Dimensions): string;
|
|
14
|
+
//# sourceMappingURL=halftone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"halftone.d.ts","sourceRoot":"","sources":["../../src/texture/halftone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAsCvD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,EACxD,UAAU,EAAE,UAAU,GACrB,MAAM,CAuBR"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { fallbackColor } from "./color.js";
|
|
2
|
+
const halftoneDefaults = {
|
|
3
|
+
opacity: 0.12,
|
|
4
|
+
size: 12,
|
|
5
|
+
gap: 30,
|
|
6
|
+
angle: 90,
|
|
7
|
+
from: 0.1,
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* How far along the growth a point is, from 0 at one edge to 1 at the other.
|
|
11
|
+
*
|
|
12
|
+
* It is the point's distance along the direction the dots grow in, measured
|
|
13
|
+
* from whichever corner is furthest back along it, so the ramp covers the
|
|
14
|
+
* whole image whatever angle it runs at.
|
|
15
|
+
*/
|
|
16
|
+
function ramp(dimensions, angle) {
|
|
17
|
+
const radians = (angle * Math.PI) / 180;
|
|
18
|
+
const dx = Math.cos(radians);
|
|
19
|
+
const dy = Math.sin(radians);
|
|
20
|
+
const { width, height } = dimensions;
|
|
21
|
+
// The four corners projected onto the direction give its full span, so the
|
|
22
|
+
// ends of the ramp land on the image rather than somewhere outside it.
|
|
23
|
+
const corners = [0, width].flatMap((cx) => [0, height].map((cy) => cx * dx + cy * dy));
|
|
24
|
+
const low = Math.min(...corners);
|
|
25
|
+
const span = Math.max(...corners) - low || 1;
|
|
26
|
+
return (px, py) => (px * dx + py * dy - low) / span;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A grid of dots that grow across the image, which is a gradient made out of
|
|
30
|
+
* print.
|
|
31
|
+
*
|
|
32
|
+
* It cannot be a tile: every dot is a different size, which is the whole
|
|
33
|
+
* effect. What keeps it affordable is that the size depends on the position
|
|
34
|
+
* rather than on chance, so a run of dots across the image is a smooth ramp
|
|
35
|
+
* and there is nothing noisy for the compression to choke on.
|
|
36
|
+
*/
|
|
37
|
+
export function halftoneSvg(texture, dimensions) {
|
|
38
|
+
const gap = texture.gap ?? halftoneDefaults.gap;
|
|
39
|
+
const size = texture.size ?? halftoneDefaults.size;
|
|
40
|
+
const from = texture.from ?? halftoneDefaults.from;
|
|
41
|
+
const at = ramp(dimensions, texture.angle ?? halftoneDefaults.angle);
|
|
42
|
+
let dots = "";
|
|
43
|
+
for (let y = gap / 2; y < dimensions.height + gap; y += gap) {
|
|
44
|
+
for (let x = gap / 2; x < dimensions.width + gap; x += gap) {
|
|
45
|
+
const radius = (size / 2) * (from + (1 - from) * at(x, y));
|
|
46
|
+
dots +=
|
|
47
|
+
`<circle cx="${String(Math.round(x))}" cy="${String(Math.round(y))}"` +
|
|
48
|
+
` r="${String(Math.round(radius * 100) / 100)}"/>`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return (`<g fill="${texture.color ?? fallbackColor}"` +
|
|
52
|
+
` opacity="${String(texture.opacity ?? halftoneDefaults.opacity)}">` +
|
|
53
|
+
`${dots}</g>`);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=halftone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"halftone.js","sourceRoot":"","sources":["../../src/texture/halftone.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,gBAAgB,GAAG;IACvB,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,EAAE;IACR,GAAG,EAAE,EAAE;IACP,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,GAAG;CACV,CAAC;AAEF;;;;;;GAMG;AACH,SAAS,IAAI,CACX,UAAsB,EACtB,KAAa;IAEb,MAAM,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;IACxC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IAErC,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CACxC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAC3C,CAAC;IACF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAE7C,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CACzB,OAAwD,EACxD,UAAsB;IAEtB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,gBAAgB,CAAC,GAAG,CAAC;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,gBAAgB,CAAC,IAAI,CAAC;IACnD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,gBAAgB,CAAC,IAAI,CAAC;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAErE,IAAI,IAAI,GAAG,EAAE,CAAC;IAEd,KAAK,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC;QAC5D,KAAK,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC;YAC3D,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAE3D,IAAI;gBACF,eAAe,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG;oBACrE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;QACvD,CAAC;IACH,CAAC;IAED,OAAO,CACL,YAAY,OAAO,CAAC,KAAK,IAAI,aAAa,GAAG;QAC7C,aAAa,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,IAAI;QACpE,GAAG,IAAI,MAAM,CACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Dimensions, Texture } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* A honeycomb of hexagon outlines.
|
|
4
|
+
*
|
|
5
|
+
* The grid repeats every three sides across and every `side * sqrt(3)` down,
|
|
6
|
+
* which is the smallest rectangle a honeycomb fits in. Two hexagons go in it,
|
|
7
|
+
* the second offset by half of each, and the ones that fall outside are drawn
|
|
8
|
+
* anyway so that the tile joins its neighbours: the pattern clips them, and a
|
|
9
|
+
* hexagon cut in half by the tile edge meets its other half in the next tile.
|
|
10
|
+
*/
|
|
11
|
+
export declare function honeycombSvg(texture: Extract<Texture, {
|
|
12
|
+
readonly type: "honeycomb";
|
|
13
|
+
}>, dimensions: Dimensions, id: string): string;
|
|
14
|
+
//# sourceMappingURL=honeycomb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"honeycomb.d.ts","sourceRoot":"","sources":["../../src/texture/honeycomb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AA8BvD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,EACzD,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,MAAM,GACT,MAAM,CAwBR"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { fallbackColor } from "./color.js";
|
|
2
|
+
import { tile } from "./tile.js";
|
|
3
|
+
const combDefaults = { opacity: 0.07, width: 1.5, size: 26 };
|
|
4
|
+
/** Rounded to keep the path short, since it is written out twice a tile. */
|
|
5
|
+
function at(value) {
|
|
6
|
+
return String(Math.round(value * 100) / 100);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* One flat-topped hexagon, from its centre and the length of a side.
|
|
10
|
+
*
|
|
11
|
+
* A hexagon of side `s` is `2s` across the points and `s * sqrt(3)` across the
|
|
12
|
+
* flats, which is where every number below comes from.
|
|
13
|
+
*/
|
|
14
|
+
function hexagon(cx, cy, side) {
|
|
15
|
+
const half = (side * Math.sqrt(3)) / 2;
|
|
16
|
+
return (`M${at(cx - side)} ${at(cy)}` +
|
|
17
|
+
`L${at(cx - side / 2)} ${at(cy - half)}` +
|
|
18
|
+
`L${at(cx + side / 2)} ${at(cy - half)}` +
|
|
19
|
+
`L${at(cx + side)} ${at(cy)}` +
|
|
20
|
+
`L${at(cx + side / 2)} ${at(cy + half)}` +
|
|
21
|
+
`L${at(cx - side / 2)} ${at(cy + half)}Z`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A honeycomb of hexagon outlines.
|
|
25
|
+
*
|
|
26
|
+
* The grid repeats every three sides across and every `side * sqrt(3)` down,
|
|
27
|
+
* which is the smallest rectangle a honeycomb fits in. Two hexagons go in it,
|
|
28
|
+
* the second offset by half of each, and the ones that fall outside are drawn
|
|
29
|
+
* anyway so that the tile joins its neighbours: the pattern clips them, and a
|
|
30
|
+
* hexagon cut in half by the tile edge meets its other half in the next tile.
|
|
31
|
+
*/
|
|
32
|
+
export function honeycombSvg(texture, dimensions, id) {
|
|
33
|
+
const side = texture.size ?? combDefaults.size;
|
|
34
|
+
const height = side * Math.sqrt(3);
|
|
35
|
+
const width = side * 3;
|
|
36
|
+
const comb = `<path d="${hexagon(side, height / 2, side)}${hexagon(side * 2.5, 0, side)}${hexagon(side * 2.5, height, side)}" stroke="${texture.color ?? fallbackColor}"` +
|
|
37
|
+
` stroke-width="${String(texture.width ?? combDefaults.width)}"` +
|
|
38
|
+
` fill="none"/>`;
|
|
39
|
+
// Not the square tile the others use: a honeycomb's repeat is wider than it
|
|
40
|
+
// is tall, so `tile` takes the two separately here.
|
|
41
|
+
return tile(id, { width, height }, comb, "", dimensions, texture.opacity ?? combDefaults.opacity);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=honeycomb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"honeycomb.js","sourceRoot":"","sources":["../../src/texture/honeycomb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,YAAY,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AAE7D,4EAA4E;AAC5E,SAAS,EAAE,CAAC,KAAa;IACvB,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,SAAS,OAAO,CAAC,EAAU,EAAE,EAAU,EAAE,IAAY;IACnD,MAAM,IAAI,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEvC,OAAO,CACL,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE;QAC7B,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE;QACxC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE;QACxC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE;QAC7B,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE;QACxC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAC1C,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAyD,EACzD,UAAsB,EACtB,EAAU;IAEV,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;IAEvB,MAAM,IAAI,GACR,YAAY,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,OAAO,CACnD,IAAI,GAAG,GAAG,EACV,CAAC,EACD,IAAI,CACL,GAAG,OAAO,CAAC,IAAI,GAAG,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,OAAO,CAAC,KAAK,IAAI,aAAa,GAAG;QACnF,kBAAkB,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG;QAChE,gBAAgB,CAAC;IAEnB,4EAA4E;IAC5E,oDAAoD;IACpD,OAAO,IAAI,CACT,EAAE,EACF,EAAE,KAAK,EAAE,MAAM,EAAE,EACjB,IAAI,EACJ,EAAE,EACF,UAAU,EACV,OAAO,CAAC,OAAO,IAAI,YAAY,CAAC,OAAO,CACxC,CAAC;AACJ,CAAC"}
|
package/dist/texture/index.d.ts
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import type { Dimensions, Texture } from "../types.js";
|
|
2
|
-
export { resolveTexture } from "./resolve.js";
|
|
2
|
+
export { resolveTexture, resolveTextureScale } from "./resolve.js";
|
|
3
3
|
/**
|
|
4
4
|
* Render the treatment laid over a background as SVG, naming whatever it needs
|
|
5
|
-
* in `<defs>` after the given `id`.
|
|
6
|
-
* plain elements and names nothing.
|
|
5
|
+
* in `<defs>` after the given `id`.
|
|
7
6
|
*
|
|
8
7
|
* It is drawn between the background and whatever a template draws, so a
|
|
9
8
|
* texture never comes between a headline and the reader.
|
|
9
|
+
*
|
|
10
|
+
* `scale` draws the same picture larger, for an image that will be looked at
|
|
11
|
+
* much smaller than it was rendered. It is done here, once, rather than by
|
|
12
|
+
* every treatment reading it: the thirteen of them describe their geometry in
|
|
13
|
+
* a dozen different fields, and there is no arithmetic they could share except
|
|
14
|
+
* this. So the texture is drawn into a smaller image and that image is scaled
|
|
15
|
+
* back up, which is exactly what a magnifier over the corner of it would show.
|
|
16
|
+
* The dimensions are rounded up so the treatment still covers the last row of
|
|
17
|
+
* pixels, and the viewport is what trims the overhang.
|
|
18
|
+
*
|
|
19
|
+
* A scale of `1` writes what it always wrote, down to the byte, which is what
|
|
20
|
+
* leaves every image that does not ask for this alone.
|
|
10
21
|
*/
|
|
11
|
-
export declare function textureSvg(texture: Texture, dimensions: Dimensions, id: string): string;
|
|
22
|
+
export declare function textureSvg(texture: Texture, dimensions: Dimensions, id: string, scale?: number): string;
|
|
12
23
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/texture/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/texture/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAavD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAuCnE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,MAAM,EACV,KAAK,SAAI,GACR,MAAM,CAgBR"}
|
package/dist/texture/index.js
CHANGED
|
@@ -1,25 +1,75 @@
|
|
|
1
|
+
import { chevronsSvg } from "./chevrons.js";
|
|
1
2
|
import { grainSvg } from "./grain.js";
|
|
2
|
-
import {
|
|
3
|
+
import { halftoneSvg } from "./halftone.js";
|
|
4
|
+
import { gridSvg } from "./grid.js";
|
|
5
|
+
import { honeycombSvg } from "./honeycomb.js";
|
|
6
|
+
import { moireSvg } from "./moire.js";
|
|
7
|
+
import { crossesSvg, dotsSvg, rulesSvg } from "./pattern.js";
|
|
8
|
+
import { raysSvg } from "./rays.js";
|
|
9
|
+
import { scallopsSvg } from "./scallops.js";
|
|
10
|
+
import { topographicSvg } from "./topographic/index.js";
|
|
3
11
|
import { wavesSvg } from "./waves.js";
|
|
4
|
-
export { resolveTexture } from "./resolve.js";
|
|
12
|
+
export { resolveTexture, resolveTextureScale } from "./resolve.js";
|
|
13
|
+
/**
|
|
14
|
+
* Which function draws which treatment.
|
|
15
|
+
*
|
|
16
|
+
* A table rather than a chain of `if`s, because the chain had a branch per
|
|
17
|
+
* texture and there are ten of them: the file was close to the complexity
|
|
18
|
+
* threshold and every new treatment made it worse. The type is what keeps this
|
|
19
|
+
* honest, and it does the job the chain's final `return` used to do badly: a
|
|
20
|
+
* variant added to `Texture` with no entry here fails to compile, where before
|
|
21
|
+
* it silently came out as ruled lines.
|
|
22
|
+
*
|
|
23
|
+
* `waves` and `rays` name nothing in `<defs>` and take no id. They are wrapped
|
|
24
|
+
* rather than given a parameter to ignore, so each one's own signature still
|
|
25
|
+
* says what it uses.
|
|
26
|
+
*/
|
|
27
|
+
const drawers = {
|
|
28
|
+
grain: grainSvg,
|
|
29
|
+
dots: dotsSvg,
|
|
30
|
+
rules: rulesSvg,
|
|
31
|
+
grid: gridSvg,
|
|
32
|
+
crosses: crossesSvg,
|
|
33
|
+
chevrons: chevronsSvg,
|
|
34
|
+
honeycomb: honeycombSvg,
|
|
35
|
+
moire: moireSvg,
|
|
36
|
+
scallops: scallopsSvg,
|
|
37
|
+
waves: (texture, dimensions) => wavesSvg(texture, dimensions),
|
|
38
|
+
rays: (texture, dimensions) => raysSvg(texture, dimensions),
|
|
39
|
+
halftone: (texture, dimensions) => halftoneSvg(texture, dimensions),
|
|
40
|
+
topographic: (texture, dimensions) => topographicSvg(texture, dimensions),
|
|
41
|
+
};
|
|
5
42
|
/**
|
|
6
43
|
* Render the treatment laid over a background as SVG, naming whatever it needs
|
|
7
|
-
* in `<defs>` after the given `id`.
|
|
8
|
-
* plain elements and names nothing.
|
|
44
|
+
* in `<defs>` after the given `id`.
|
|
9
45
|
*
|
|
10
46
|
* It is drawn between the background and whatever a template draws, so a
|
|
11
47
|
* texture never comes between a headline and the reader.
|
|
48
|
+
*
|
|
49
|
+
* `scale` draws the same picture larger, for an image that will be looked at
|
|
50
|
+
* much smaller than it was rendered. It is done here, once, rather than by
|
|
51
|
+
* every treatment reading it: the thirteen of them describe their geometry in
|
|
52
|
+
* a dozen different fields, and there is no arithmetic they could share except
|
|
53
|
+
* this. So the texture is drawn into a smaller image and that image is scaled
|
|
54
|
+
* back up, which is exactly what a magnifier over the corner of it would show.
|
|
55
|
+
* The dimensions are rounded up so the treatment still covers the last row of
|
|
56
|
+
* pixels, and the viewport is what trims the overhang.
|
|
57
|
+
*
|
|
58
|
+
* A scale of `1` writes what it always wrote, down to the byte, which is what
|
|
59
|
+
* leaves every image that does not ask for this alone.
|
|
12
60
|
*/
|
|
13
|
-
export function textureSvg(texture, dimensions, id) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (texture.type === "waves") {
|
|
21
|
-
return wavesSvg(texture, dimensions);
|
|
61
|
+
export function textureSvg(texture, dimensions, id, scale = 1) {
|
|
62
|
+
// The value and the lookup narrow separately, so the compiler cannot see
|
|
63
|
+
// that they are the same variant, though the table's type is what makes them
|
|
64
|
+
// so. This is the one line that knows better than the checker.
|
|
65
|
+
const draw = drawers[texture.type];
|
|
66
|
+
if (scale === 1) {
|
|
67
|
+
return draw(texture, dimensions, id);
|
|
22
68
|
}
|
|
23
|
-
|
|
69
|
+
const reduced = {
|
|
70
|
+
width: Math.ceil(dimensions.width / scale),
|
|
71
|
+
height: Math.ceil(dimensions.height / scale),
|
|
72
|
+
};
|
|
73
|
+
return `<g transform="scale(${String(scale)})">${draw(texture, reduced, id)}</g>`;
|
|
24
74
|
}
|
|
25
75
|
//# sourceMappingURL=index.js.map
|