render-tag 0.1.8 → 0.1.9
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 +60 -192
- package/lib/css-resolver.d.ts.map +1 -1
- package/lib/css-resolver.js +16 -0
- package/lib/css-resolver.js.map +1 -1
- package/lib/layout.d.ts.map +1 -1
- package/lib/layout.js +90 -0
- package/lib/layout.js.map +1 -1
- package/lib/path/glyph-layout.d.ts +63 -14
- package/lib/path/glyph-layout.d.ts.map +1 -1
- package/lib/path/glyph-layout.js +224 -42
- package/lib/path/glyph-layout.js.map +1 -1
- package/lib/path/index.d.ts +52 -17
- package/lib/path/index.d.ts.map +1 -1
- package/lib/path/index.js +314 -38
- package/lib/path/index.js.map +1 -1
- package/lib/render-tag.umd.js +4 -4
- package/lib/render-tag.umd.js.map +1 -1
- package/lib/render.d.ts +18 -0
- package/lib/render.d.ts.map +1 -1
- package/lib/render.js +3 -3
- package/lib/render.js.map +1 -1
- package/lib/types.d.ts +6 -0
- package/lib/types.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/path/glyph-layout.js
CHANGED
|
@@ -2,9 +2,32 @@
|
|
|
2
2
|
* Pure layout: walks styled segments and lays each grapheme along a path.
|
|
3
3
|
* No canvas rendering happens here — that's the caller's job. Reusable
|
|
4
4
|
* for hit-testing, debugging, alternate renderers (SVG, GPU).
|
|
5
|
+
*
|
|
6
|
+
* Joining-script support: graphemes from Arabic, Hebrew, Indic, Thai, Khmer,
|
|
7
|
+
* Myanmar and related scripts within a single segment are grouped into one
|
|
8
|
+
* "shaped run" placement. The browser's fillText/measureText then shapes the
|
|
9
|
+
* run as a unit (cursive joining, reordering, conjuncts) — something
|
|
10
|
+
* per-grapheme drawing cannot do.
|
|
5
11
|
*/
|
|
6
|
-
import { applyFont } from '../layout.js';
|
|
12
|
+
import { applyFont, getFontMetrics } from '../layout.js';
|
|
7
13
|
import { stringToArray } from './grapheme.js';
|
|
14
|
+
/**
|
|
15
|
+
* Returns the local-y of the alphabetic baseline given a textBaseline
|
|
16
|
+
* choice and a glyph's ascent/descent. All baseline-relative computations
|
|
17
|
+
* (decoration positions, background polygons, bounds cells) ADD this offset
|
|
18
|
+
* to their local-y so the path line through (0,0) corresponds to the
|
|
19
|
+
* requested baseline anchor.
|
|
20
|
+
*/
|
|
21
|
+
export function baselineLocalY(tb, ascent, descent) {
|
|
22
|
+
switch (tb) {
|
|
23
|
+
case 'alphabetic': return 0;
|
|
24
|
+
case 'middle': return (ascent - descent) / 2;
|
|
25
|
+
case 'top': return ascent;
|
|
26
|
+
case 'bottom': return -descent;
|
|
27
|
+
case 'hanging': return ascent * 0.8;
|
|
28
|
+
case 'ideographic': return -descent * 0.5;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
8
31
|
/**
|
|
9
32
|
* Flatten a styled tree into a flat sequence of styled text segments.
|
|
10
33
|
* Walks in document order; concatenates text under nested inline elements.
|
|
@@ -24,27 +47,131 @@ export function flattenSegments(root) {
|
|
|
24
47
|
walk(root, false);
|
|
25
48
|
return out;
|
|
26
49
|
}
|
|
50
|
+
// Unicode ranges where graphemes need shape-aware rendering. The browser's
|
|
51
|
+
// fillText handles these correctly only when given the whole run at once,
|
|
52
|
+
// not one grapheme at a time:
|
|
53
|
+
// - Hebrew (no joining, but RTL+BiDi)
|
|
54
|
+
// - Arabic + presentation forms (cursive joining)
|
|
55
|
+
// - N'Ko, Mandaic, Syriac, Thaana (joining/RTL)
|
|
56
|
+
// - Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
|
|
57
|
+
// Malayalam, Sinhala (Indic reordering + conjuncts)
|
|
58
|
+
// - Thai, Lao (combining marks + word break)
|
|
59
|
+
// - Tibetan (stacking)
|
|
60
|
+
// - Myanmar (reordering + stacking)
|
|
61
|
+
// - Khmer (reordering + subscript consonants)
|
|
62
|
+
// IMPORTANT: written with `\u` escapes only. Mixing literal RTL characters
|
|
63
|
+
// confuses the regex parser at parse time — e.g. the precomposed `יִ` is
|
|
64
|
+
// actually two code points (U+05D9 + U+05B4) and a literal range starting
|
|
65
|
+
// at the second code point engulfs CJK / Hangul / Hiragana / Katakana,
|
|
66
|
+
// causing `needsShaping('中')` to return true.
|
|
67
|
+
const SHAPING_RE = new RegExp('[' +
|
|
68
|
+
'\\u0590-\\u05FF' + // Hebrew
|
|
69
|
+
'\\u0600-\\u06FF' + // Arabic
|
|
70
|
+
'\\u0700-\\u074F' + // Syriac
|
|
71
|
+
'\\u0750-\\u077F' + // Arabic Supplement
|
|
72
|
+
'\\u0780-\\u07BF' + // Thaana
|
|
73
|
+
'\\u07C0-\\u07FF' + // NKo
|
|
74
|
+
'\\u0800-\\u083F' + // Samaritan
|
|
75
|
+
'\\u0840-\\u085F' + // Mandaic
|
|
76
|
+
'\\u0860-\\u086F' + // Syriac Supplement
|
|
77
|
+
'\\u08A0-\\u08FF' + // Arabic Extended-A
|
|
78
|
+
'\\u0900-\\u097F' + // Devanagari
|
|
79
|
+
'\\u0980-\\u09FF' + // Bengali
|
|
80
|
+
'\\u0A00-\\u0A7F' + // Gurmukhi
|
|
81
|
+
'\\u0A80-\\u0AFF' + // Gujarati
|
|
82
|
+
'\\u0B00-\\u0B7F' + // Oriya
|
|
83
|
+
'\\u0B80-\\u0BFF' + // Tamil
|
|
84
|
+
'\\u0C00-\\u0C7F' + // Telugu
|
|
85
|
+
'\\u0C80-\\u0CFF' + // Kannada
|
|
86
|
+
'\\u0D00-\\u0D7F' + // Malayalam
|
|
87
|
+
'\\u0D80-\\u0DFF' + // Sinhala
|
|
88
|
+
'\\u0E00-\\u0E7F' + // Thai
|
|
89
|
+
'\\u0E80-\\u0EFF' + // Lao
|
|
90
|
+
'\\u0F00-\\u0FFF' + // Tibetan
|
|
91
|
+
'\\u1000-\\u109F' + // Myanmar
|
|
92
|
+
'\\u1780-\\u17FF' + // Khmer
|
|
93
|
+
'\\u1800-\\u18AF' + // Mongolian
|
|
94
|
+
'\\uFB1D-\\uFB4F' + // Hebrew Presentation Forms
|
|
95
|
+
'\\uFB50-\\uFDFF' + // Arabic Presentation Forms-A
|
|
96
|
+
'\\uFE70-\\uFEFF' + // Arabic Presentation Forms-B
|
|
97
|
+
']');
|
|
98
|
+
function needsShaping(s) {
|
|
99
|
+
return SHAPING_RE.test(s);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Split a single styled segment into PreGlyphs.
|
|
103
|
+
*
|
|
104
|
+
* Non-joining graphemes (Latin, CJK, …) emit one PreGlyph per grapheme so the
|
|
105
|
+
* curve can drive per-glyph rotation. Joining-script graphemes are grouped
|
|
106
|
+
* into runs (split at whitespace + style boundaries) so the browser can shape
|
|
107
|
+
* them correctly when we later call fillText on the run as a whole.
|
|
108
|
+
*
|
|
109
|
+
* For RTL segments, the RUN ORDER is reversed (not the graphemes inside a
|
|
110
|
+
* shaped run) — that way Arabic words still shape correctly while flowing in
|
|
111
|
+
* visual right-to-left order along an LTR path walk.
|
|
112
|
+
*/
|
|
113
|
+
function preGlyphsForSegment(ctx, seg) {
|
|
114
|
+
const graphemes = stringToArray(seg.text);
|
|
115
|
+
if (graphemes.length === 0)
|
|
116
|
+
return [];
|
|
117
|
+
applyFont(ctx, seg.style);
|
|
118
|
+
// Always assign — when the current segment's letterSpacing is 0/unset,
|
|
119
|
+
// we still need to reset the previous segment's value.
|
|
120
|
+
ctx.letterSpacing = `${seg.style.letterSpacing || 0}px`;
|
|
121
|
+
const { ascent, descent } = getFontMetrics(ctx, seg.style);
|
|
122
|
+
// Group graphemes into (shaped run | single non-shaped grapheme).
|
|
123
|
+
// Boundaries: shape-status change, ASCII whitespace.
|
|
124
|
+
const runs = [];
|
|
125
|
+
let currentShapedRun = '';
|
|
126
|
+
for (const g of graphemes) {
|
|
127
|
+
const isSpace = g === ' ';
|
|
128
|
+
if (needsShaping(g) && !isSpace) {
|
|
129
|
+
currentShapedRun += g;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
if (currentShapedRun) {
|
|
133
|
+
runs.push({ text: currentShapedRun, shaped: true, isSpace: false });
|
|
134
|
+
currentShapedRun = '';
|
|
135
|
+
}
|
|
136
|
+
runs.push({ text: g, shaped: false, isSpace });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (currentShapedRun) {
|
|
140
|
+
runs.push({ text: currentShapedRun, shaped: true, isSpace: false });
|
|
141
|
+
}
|
|
142
|
+
// RTL: reverse run order. Don't reverse graphemes inside a shaped run —
|
|
143
|
+
// the browser will lay them out right-to-left during fillText.
|
|
144
|
+
if (seg.rtl)
|
|
145
|
+
runs.reverse();
|
|
146
|
+
// Measure each run with the current ctx font/letterSpacing.
|
|
147
|
+
const out = [];
|
|
148
|
+
for (const r of runs) {
|
|
149
|
+
const width = ctx.measureText(r.text).width;
|
|
150
|
+
out.push({
|
|
151
|
+
text: r.text,
|
|
152
|
+
width,
|
|
153
|
+
style: seg.style,
|
|
154
|
+
isSpace: r.isSpace,
|
|
155
|
+
ascent,
|
|
156
|
+
descent,
|
|
157
|
+
shaped: r.shaped,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
27
162
|
/**
|
|
28
163
|
* Lay out graphemes along a path. Pure: does not call ctx.fillText.
|
|
29
164
|
*
|
|
30
165
|
* Algorithm:
|
|
31
|
-
* 1. Per segment, split into graphemes and measure each
|
|
32
|
-
* RTL segments have their grapheme order reversed before walking the path
|
|
33
|
-
* (so a left-to-right path walk produces correct visual order).
|
|
166
|
+
* 1. Per segment, split into graphemes and shaped runs, measure each.
|
|
34
167
|
* 2. Compute total natural width.
|
|
35
168
|
* 3. Pick a starting offset along the path based on `align`.
|
|
36
|
-
* 4. For each
|
|
37
|
-
*
|
|
38
|
-
* p1 = path.getPointAtLength(offset + width)
|
|
39
|
-
* rotation = atan2(p1.y - p0.y, p1.x - p0.x)
|
|
40
|
-
* A trailing kerning slack (sum-of-glyph-widths > whole-string width)
|
|
41
|
-
* can push the last glyph 1–2px past pathLength; clamp the end point
|
|
42
|
-
* to pathLength in that narrow case to avoid dropping the last glyph.
|
|
43
|
-
* 5. If a glyph would extend past the path entirely, stop emitting.
|
|
169
|
+
* 4. For each placement: get p0 / p1 from the path, rotation = atan2(p1-p0).
|
|
170
|
+
* If a placement would overshoot, only allow it within kerning slack.
|
|
44
171
|
*/
|
|
45
172
|
export function layoutGlyphsOnPath(input) {
|
|
46
|
-
const { segments, path, ctx, align } = input;
|
|
47
|
-
// 1. Pre-measure all
|
|
173
|
+
const { segments, path, ctx, align, textBaseline } = input;
|
|
174
|
+
// 1. Pre-measure all placements (one per grapheme or shaped run).
|
|
48
175
|
// Caller's ctx state is mutated here (font, fontKerning, letterSpacing).
|
|
49
176
|
// The outer drawTextOnPath/drawTextOnPathLayout calls ctx.save before this
|
|
50
177
|
// and ctx.restore after, so the leak doesn't reach the caller.
|
|
@@ -54,37 +181,17 @@ export function layoutGlyphsOnPath(input) {
|
|
|
54
181
|
for (const seg of segments) {
|
|
55
182
|
if (!seg.text)
|
|
56
183
|
continue;
|
|
57
|
-
const graphemes = stringToArray(seg.text);
|
|
58
|
-
if (graphemes.length === 0)
|
|
59
|
-
continue;
|
|
60
|
-
if (seg.rtl)
|
|
61
|
-
graphemes.reverse();
|
|
62
|
-
applyFont(ctx, seg.style);
|
|
63
|
-
// Always assign — when the current segment's letterSpacing is 0/unset,
|
|
64
|
-
// we still need to reset the previous segment's value.
|
|
65
|
-
ctx.letterSpacing = `${seg.style.letterSpacing || 0}px`;
|
|
66
|
-
// Track ribbon thickness: CSS line-height in px when set, else font size.
|
|
67
184
|
const lh = seg.style.lineHeight > 0 ? seg.style.lineHeight : seg.style.fontSize;
|
|
68
185
|
if (lh > maxLineHeight)
|
|
69
186
|
maxLineHeight = lh;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
char: g,
|
|
75
|
-
width: m.width,
|
|
76
|
-
style: seg.style,
|
|
77
|
-
// Only ASCII space (U+0020) is justify-eligible. \n/\t/ and
|
|
78
|
-
// other Unicode whitespace must NOT expand — that would break
|
|
79
|
-
// no-break-space contract and treat <br>-synthesized newlines as
|
|
80
|
-
// expansible spaces.
|
|
81
|
-
isSpace: g === ' ',
|
|
82
|
-
});
|
|
83
|
-
}
|
|
187
|
+
const segGlyphs = preGlyphsForSegment(ctx, seg);
|
|
188
|
+
if (segGlyphs.length === 0)
|
|
189
|
+
continue;
|
|
190
|
+
preGlyphs.push(...segGlyphs);
|
|
84
191
|
// Whole-segment width — kerning makes this < sum of per-glyph widths.
|
|
85
192
|
measuredWholeWidth += ctx.measureText(seg.text).width;
|
|
86
193
|
}
|
|
87
|
-
// 2. Sum natural width (sum of
|
|
194
|
+
// 2. Sum natural width (sum of placement widths + letterSpacing per item).
|
|
88
195
|
let textWidth = 0;
|
|
89
196
|
for (const g of preGlyphs) {
|
|
90
197
|
textWidth += g.width + (g.style.letterSpacing || 0);
|
|
@@ -114,8 +221,16 @@ export function layoutGlyphsOnPath(input) {
|
|
|
114
221
|
}
|
|
115
222
|
}
|
|
116
223
|
// 4. Walk the path.
|
|
224
|
+
// We track two cumulative offsets:
|
|
225
|
+
// - `offset` is the path arc-length (used for path.getPointAtLength), and
|
|
226
|
+
// advances by `effectiveWidth` (incl. justify extraPerSpace).
|
|
227
|
+
// - `naturalOffset` is the glyph's position in NATURAL text-space
|
|
228
|
+
// [0, textWidth]. Used as `pathOffset` for gradient slicing — must NOT
|
|
229
|
+
// include extraPerSpace, otherwise late justified glyphs map past the
|
|
230
|
+
// gradient's last stop.
|
|
117
231
|
const glyphs = [];
|
|
118
232
|
let offset = startOffset;
|
|
233
|
+
let naturalOffset = 0;
|
|
119
234
|
for (let i = 0; i < preGlyphs.length; i++) {
|
|
120
235
|
const g = preGlyphs[i];
|
|
121
236
|
const effectiveWidth = g.width + (g.isSpace ? extraPerSpace : 0);
|
|
@@ -126,7 +241,7 @@ export function layoutGlyphsOnPath(input) {
|
|
|
126
241
|
let p1;
|
|
127
242
|
if (endLen > pathLength) {
|
|
128
243
|
// Clamp to pathLength only if the overshoot is within the kerning slack —
|
|
129
|
-
//
|
|
244
|
+
// keeps the last glyph from getting dropped to a sub-px rounding miss.
|
|
130
245
|
if (endLen - pathLength <= kerningSlack + 0.5) {
|
|
131
246
|
p1 = path.getPointAtLength(pathLength);
|
|
132
247
|
}
|
|
@@ -141,15 +256,82 @@ export function layoutGlyphsOnPath(input) {
|
|
|
141
256
|
break;
|
|
142
257
|
const rotation = Math.atan2(p1.y - p0.y, p1.x - p0.x);
|
|
143
258
|
glyphs.push({
|
|
144
|
-
char: g.
|
|
259
|
+
char: g.text,
|
|
145
260
|
x: p0.x,
|
|
146
261
|
y: p0.y,
|
|
147
262
|
rotation,
|
|
148
263
|
width: g.width,
|
|
149
264
|
style: g.style,
|
|
265
|
+
ascent: g.ascent,
|
|
266
|
+
descent: g.descent,
|
|
267
|
+
pathOffset: naturalOffset,
|
|
268
|
+
shaped: g.shaped,
|
|
150
269
|
});
|
|
151
270
|
offset = endLen + (g.style.letterSpacing || 0);
|
|
271
|
+
naturalOffset += g.width + (g.style.letterSpacing || 0);
|
|
272
|
+
}
|
|
273
|
+
const bounds = computeBounds(glyphs, textBaseline);
|
|
274
|
+
return {
|
|
275
|
+
glyphs,
|
|
276
|
+
textWidth,
|
|
277
|
+
pathLength,
|
|
278
|
+
lineHeight: maxLineHeight,
|
|
279
|
+
bounds,
|
|
280
|
+
textBaseline,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Bounding box of the rendered text: union of each glyph's
|
|
285
|
+
* `width × per-glyph line-height` cell, rotated by the glyph's tangent.
|
|
286
|
+
*
|
|
287
|
+
* The cell height is the per-glyph line-height (CSS line-height when set,
|
|
288
|
+
* else font-size — Polotno's chosen metric). It is distributed
|
|
289
|
+
* ASYMMETRICALLY above/below the baseline using the font's natural
|
|
290
|
+
* ascent/descent ratio, so cap-height + ascender area is covered and the
|
|
291
|
+
* cell doesn't waste pixels below an empty descender. For a typical font
|
|
292
|
+
* with ascent ~25 / descent ~7 / lineHeight 32, the cell extends ~25px
|
|
293
|
+
* above and ~7px below the baseline, matching the painted glyph extent.
|
|
294
|
+
*
|
|
295
|
+
* Empty layouts return `{ x: 0, y: 0, width: 0, height: 0 }`.
|
|
296
|
+
*/
|
|
297
|
+
function computeBounds(glyphs, textBaseline) {
|
|
298
|
+
if (glyphs.length === 0)
|
|
299
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
300
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
301
|
+
for (const g of glyphs) {
|
|
302
|
+
const lh = g.style.lineHeight > 0 ? g.style.lineHeight : g.style.fontSize;
|
|
303
|
+
// Distribute the lineHeight above/below the baseline by the font's
|
|
304
|
+
// natural ascent/descent ratio (CSS line-box half-leading semantics).
|
|
305
|
+
const fontHeight = g.ascent + g.descent;
|
|
306
|
+
const ascentShare = fontHeight > 0 ? g.ascent / fontHeight : 0.75;
|
|
307
|
+
const topFromBaseline = lh * ascentShare; // above baseline
|
|
308
|
+
const bottomFromBaseline = lh * (1 - ascentShare); // below baseline
|
|
309
|
+
// Shift by the local-y of the baseline so the cell stays correct under
|
|
310
|
+
// any textBaseline (e.g. 'middle' places the cell vertically centred
|
|
311
|
+
// on the path; 'top' moves the entire cell down).
|
|
312
|
+
const baseY = baselineLocalY(textBaseline, g.ascent, g.descent);
|
|
313
|
+
const top = baseY - topFromBaseline;
|
|
314
|
+
const bottom = baseY + bottomFromBaseline;
|
|
315
|
+
const c = Math.cos(g.rotation);
|
|
316
|
+
const s = Math.sin(g.rotation);
|
|
317
|
+
// Local cell: x in [0, width], y in [top, bottom]. Rotate + translate.
|
|
318
|
+
const corners = [
|
|
319
|
+
{ x: g.x + (-s) * top, y: g.y + c * top },
|
|
320
|
+
{ x: g.x + c * g.width + (-s) * top, y: g.y + s * g.width + c * top },
|
|
321
|
+
{ x: g.x + c * g.width + (-s) * bottom, y: g.y + s * g.width + c * bottom },
|
|
322
|
+
{ x: g.x + (-s) * bottom, y: g.y + c * bottom },
|
|
323
|
+
];
|
|
324
|
+
for (const p of corners) {
|
|
325
|
+
if (p.x < minX)
|
|
326
|
+
minX = p.x;
|
|
327
|
+
if (p.y < minY)
|
|
328
|
+
minY = p.y;
|
|
329
|
+
if (p.x > maxX)
|
|
330
|
+
maxX = p.x;
|
|
331
|
+
if (p.y > maxY)
|
|
332
|
+
maxY = p.y;
|
|
333
|
+
}
|
|
152
334
|
}
|
|
153
|
-
return {
|
|
335
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
154
336
|
}
|
|
155
337
|
//# sourceMappingURL=glyph-layout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyph-layout.js","sourceRoot":"","sources":["../../src/path/glyph-layout.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"glyph-layout.js","sourceRoot":"","sources":["../../src/path/glyph-layout.ts"],"names":[],"mappings":"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"}
|
package/lib/path/index.d.ts
CHANGED
|
@@ -13,20 +13,25 @@
|
|
|
13
13
|
* align: 'center',
|
|
14
14
|
* });
|
|
15
15
|
*
|
|
16
|
-
* For finer control
|
|
16
|
+
* For finer control:
|
|
17
17
|
* const result = layoutTextOnPath({ html, path, align });
|
|
18
18
|
* drawTextOnPathLayout({ layout: result, ctx });
|
|
19
|
-
* Use the split when you want to inspect / hit-test glyphs before drawing,
|
|
20
|
-
* or render the same layout onto multiple targets.
|
|
21
19
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
20
|
+
* Supported styles (matches the main renderer):
|
|
21
|
+
* font-family / size / weight / style / kerning
|
|
22
|
+
* color, -webkit-text-fill-color, -webkit-text-stroke (width + color), paint-order
|
|
23
|
+
* background-color (span backgrounds drawn as curve-following polygons)
|
|
24
|
+
* text-shadow (rotates with glyphs; multi-shadow supported)
|
|
25
|
+
* text-decoration: underline / line-through / overline (solid/dotted/dashed/double/wavy)
|
|
26
|
+
* text-decoration-color, text-decoration-style
|
|
27
|
+
* background-clip:text + background-image:linear-gradient (gradient flows along the path)
|
|
28
|
+
* letter-spacing, direction: rtl, dir="rtl"
|
|
29
|
+
* Arabic / Hebrew / Indic / Thai / Khmer / Myanmar — shaped runs are
|
|
30
|
+
* rendered as a unit so cursive joining and reordering work correctly.
|
|
26
31
|
*/
|
|
27
32
|
import { type PathLike } from './svg-path.js';
|
|
28
|
-
import { type AlignMode, type GlyphPlacement } from './glyph-layout.js';
|
|
29
|
-
export type { PathLike, GlyphPlacement, AlignMode };
|
|
33
|
+
import { type AlignMode, type GlyphPlacement, type TextBaseline } from './glyph-layout.js';
|
|
34
|
+
export type { PathLike, GlyphPlacement, AlignMode, TextBaseline };
|
|
30
35
|
export interface LayoutTextOnPathConfig {
|
|
31
36
|
/** Rich-text HTML (same dialect as render-tag's main API). */
|
|
32
37
|
html: string;
|
|
@@ -34,6 +39,13 @@ export interface LayoutTextOnPathConfig {
|
|
|
34
39
|
path: string | PathLike;
|
|
35
40
|
/** Alignment of text along the path (default 'left'). */
|
|
36
41
|
align?: AlignMode;
|
|
42
|
+
/**
|
|
43
|
+
* Where the path runs relative to the rendered text. Default
|
|
44
|
+
* `'alphabetic'` (path = baseline, descenders drop below). Use `'middle'`
|
|
45
|
+
* for design-tool style "text centered on path" rendering. The choice
|
|
46
|
+
* also affects `bounds`.
|
|
47
|
+
*/
|
|
48
|
+
textBaseline?: TextBaseline;
|
|
37
49
|
/**
|
|
38
50
|
* Optional measurement context. If omitted, an offscreen canvas is created.
|
|
39
51
|
* Pass one to share font measurement caches with other render-tag calls.
|
|
@@ -41,23 +53,39 @@ export interface LayoutTextOnPathConfig {
|
|
|
41
53
|
ctx?: CanvasRenderingContext2D;
|
|
42
54
|
}
|
|
43
55
|
export interface TextOnPathLayout {
|
|
44
|
-
/** Per-glyph
|
|
56
|
+
/** Per-glyph (or per-shaped-run) placement records. */
|
|
45
57
|
glyphs: GlyphPlacement[];
|
|
46
58
|
/** Sum of per-glyph advances (the natural width of the rendered text). */
|
|
47
59
|
textWidth: number;
|
|
48
60
|
/** Total arc length of the path. */
|
|
49
61
|
pathLength: number;
|
|
50
62
|
/**
|
|
51
|
-
* Max line height across all segments
|
|
52
|
-
*
|
|
53
|
-
* ribbon polygon around curved text.
|
|
63
|
+
* Max line height across all segments. Useful as the thickness for a
|
|
64
|
+
* background ribbon polygon around curved text.
|
|
54
65
|
*/
|
|
55
66
|
lineHeight: number;
|
|
67
|
+
/**
|
|
68
|
+
* Visible bounding box of the rendered text in the layout's coordinate
|
|
69
|
+
* system (same shape as `DOMRect`). Computed as the union of each glyph's
|
|
70
|
+
* `width × per-glyph line-height` cell, rotated by the glyph's tangent.
|
|
71
|
+
*
|
|
72
|
+
* Consumer-facing: render-tag does not consume `bounds` itself. Use it to
|
|
73
|
+
* keep a parent element's width/height in sync with the rendered curved
|
|
74
|
+
* text without re-walking the glyphs.
|
|
75
|
+
*/
|
|
76
|
+
bounds: {
|
|
77
|
+
x: number;
|
|
78
|
+
y: number;
|
|
79
|
+
width: number;
|
|
80
|
+
height: number;
|
|
81
|
+
};
|
|
82
|
+
/** The textBaseline mode the layout was computed with. */
|
|
83
|
+
textBaseline: TextBaseline;
|
|
56
84
|
}
|
|
57
85
|
export interface DrawTextOnPathLayoutConfig {
|
|
58
86
|
/** Result from layoutTextOnPath(). */
|
|
59
87
|
layout: TextOnPathLayout;
|
|
60
|
-
/** Destination 2D context.
|
|
88
|
+
/** Destination 2D context. Saved+restored around the whole batch. */
|
|
61
89
|
ctx: CanvasRenderingContext2D;
|
|
62
90
|
}
|
|
63
91
|
export interface DrawTextOnPathConfig {
|
|
@@ -69,6 +97,8 @@ export interface DrawTextOnPathConfig {
|
|
|
69
97
|
ctx: CanvasRenderingContext2D;
|
|
70
98
|
/** Alignment of text along the path (default 'left'). */
|
|
71
99
|
align?: AlignMode;
|
|
100
|
+
/** Where the path runs relative to the text (default 'alphabetic'). */
|
|
101
|
+
textBaseline?: TextBaseline;
|
|
72
102
|
}
|
|
73
103
|
export type DrawTextOnPathResult = TextOnPathLayout;
|
|
74
104
|
/**
|
|
@@ -84,13 +114,18 @@ export type DrawTextOnPathResult = TextOnPathLayout;
|
|
|
84
114
|
export declare function layoutTextOnPath(config: LayoutTextOnPathConfig): TextOnPathLayout;
|
|
85
115
|
/**
|
|
86
116
|
* Draw a pre-computed layout onto a canvas context.
|
|
87
|
-
*
|
|
88
|
-
*
|
|
117
|
+
*
|
|
118
|
+
* Rendering passes (matching CSS painting order):
|
|
119
|
+
* 1. Span backgrounds (background-color, curve-following polygons)
|
|
120
|
+
* 2. Text shadows (per glyph, multi-shadow supported, rotates with glyph)
|
|
121
|
+
* 3. Glyph fill + stroke (paint-order aware; gradient text via slicing)
|
|
122
|
+
* 4. Text decoration (underline / line-through / overline)
|
|
123
|
+
*
|
|
124
|
+
* ctx state is saved+restored around the entire batch — nothing leaks.
|
|
89
125
|
*/
|
|
90
126
|
export declare function drawTextOnPathLayout(config: DrawTextOnPathLayoutConfig): void;
|
|
91
127
|
/**
|
|
92
128
|
* Convenience: compute layout and draw in a single call.
|
|
93
|
-
* Equivalent to `drawTextOnPathLayout({ layout: layoutTextOnPath(...), ctx })`.
|
|
94
129
|
*/
|
|
95
130
|
export declare function drawTextOnPath(config: DrawTextOnPathConfig): DrawTextOnPathResult;
|
|
96
131
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/path/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/path/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/path/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAWH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AAElE,MAAM,WAAW,sBAAsB;IACrC,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,yDAAyD;IACzD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;OAGG;IACH,GAAG,CAAC,EAAE,wBAAwB,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,0DAA0D;IAC1D,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,sCAAsC;IACtC,MAAM,EAAE,gBAAgB,CAAC;IACzB,qEAAqE;IACrE,GAAG,EAAE,wBAAwB,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,8BAA8B;IAC9B,GAAG,EAAE,wBAAwB,CAAC;IAC9B,yDAAyD;IACzD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uEAAuE;IACvE,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAEpD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,gBAAgB,CAkBjF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,0BAA0B,GAAG,IAAI,CAa7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,oBAAoB,CAUjF"}
|