modern-text 0.2.5 → 0.2.6
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/dist/index.cjs +123 -88
- package/dist/index.d.cts +15 -17
- package/dist/index.d.mts +15 -17
- package/dist/index.d.ts +15 -17
- package/dist/index.js +2 -2
- package/dist/index.mjs +124 -89
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BoundingBox,
|
|
1
|
+
import { BoundingBox, Point2D, Path2D, parseSvgToDom, parseSvg, Matrix3 } from 'modern-path2d';
|
|
2
2
|
import { fonts, Woff, Ttf } from 'modern-font';
|
|
3
3
|
export * from 'modern-font';
|
|
4
4
|
|
|
@@ -170,7 +170,6 @@ class Character {
|
|
|
170
170
|
this.index = index;
|
|
171
171
|
this.parent = parent;
|
|
172
172
|
__publicField$4(this, "boundingBox", new BoundingBox());
|
|
173
|
-
__publicField$4(this, "path", new Path2D());
|
|
174
173
|
__publicField$4(this, "textWidth", 0);
|
|
175
174
|
__publicField$4(this, "textHeight", 0);
|
|
176
175
|
// glyph
|
|
@@ -192,11 +191,14 @@ class Character {
|
|
|
192
191
|
}
|
|
193
192
|
return void 0;
|
|
194
193
|
}
|
|
195
|
-
|
|
194
|
+
updateGlyph(font = this._font()) {
|
|
195
|
+
if (!font) {
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
const { unitsPerEm, ascender, descender, os2, post } = font;
|
|
196
199
|
const { content, computedStyle, boundingBox, isVertical } = this;
|
|
197
200
|
const { left, top, height } = boundingBox;
|
|
198
201
|
const { fontSize } = computedStyle;
|
|
199
|
-
const { unitsPerEm, ascender, descender, os2, post } = font;
|
|
200
202
|
const rate = unitsPerEm / fontSize;
|
|
201
203
|
const glyphWidth = font.getAdvanceWidth(content, fontSize);
|
|
202
204
|
const glyphHeight = (ascender + Math.abs(descender)) / rate;
|
|
@@ -217,84 +219,7 @@ class Character {
|
|
|
217
219
|
this.centerPoint = this.glyphBox.getCenterPoint();
|
|
218
220
|
return this;
|
|
219
221
|
}
|
|
220
|
-
|
|
221
|
-
const { isVertical, underlinePosition, yStrikeoutPosition } = this;
|
|
222
|
-
const { textDecoration, fontSize } = this.computedStyle;
|
|
223
|
-
const { left, top, width, height } = this.boundingBox;
|
|
224
|
-
const lineWidth = 0.1 * fontSize;
|
|
225
|
-
let start;
|
|
226
|
-
switch (textDecoration) {
|
|
227
|
-
case "underline":
|
|
228
|
-
if (isVertical) {
|
|
229
|
-
start = left;
|
|
230
|
-
} else {
|
|
231
|
-
start = top + underlinePosition;
|
|
232
|
-
}
|
|
233
|
-
break;
|
|
234
|
-
case "line-through":
|
|
235
|
-
if (isVertical) {
|
|
236
|
-
start = left + width / 2;
|
|
237
|
-
} else {
|
|
238
|
-
start = top + yStrikeoutPosition;
|
|
239
|
-
}
|
|
240
|
-
break;
|
|
241
|
-
case "none":
|
|
242
|
-
default:
|
|
243
|
-
return [];
|
|
244
|
-
}
|
|
245
|
-
if (isVertical) {
|
|
246
|
-
return [
|
|
247
|
-
{ type: "M", x: start, y: top },
|
|
248
|
-
{ type: "L", x: start, y: top + height },
|
|
249
|
-
{ type: "L", x: start + lineWidth, y: top + height },
|
|
250
|
-
{ type: "L", x: start + lineWidth, y: top },
|
|
251
|
-
{ type: "Z" }
|
|
252
|
-
];
|
|
253
|
-
} else {
|
|
254
|
-
return [
|
|
255
|
-
{ type: "M", x: left, y: start },
|
|
256
|
-
{ type: "L", x: left + width, y: start },
|
|
257
|
-
{ type: "L", x: left + width, y: start + lineWidth },
|
|
258
|
-
{ type: "L", x: left, y: start + lineWidth },
|
|
259
|
-
{ type: "Z" }
|
|
260
|
-
];
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
_transform(commands, cb) {
|
|
264
|
-
return commands.map((rawCmd) => {
|
|
265
|
-
const cmd = { ...rawCmd };
|
|
266
|
-
switch (cmd.type) {
|
|
267
|
-
case "L":
|
|
268
|
-
case "M":
|
|
269
|
-
[cmd.x, cmd.y] = cb(cmd.x, cmd.y);
|
|
270
|
-
break;
|
|
271
|
-
case "Q":
|
|
272
|
-
[cmd.x1, cmd.y1] = cb(cmd.x1, cmd.y1);
|
|
273
|
-
[cmd.x, cmd.y] = cb(cmd.x, cmd.y);
|
|
274
|
-
break;
|
|
275
|
-
}
|
|
276
|
-
return cmd;
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
_italic(commands, startPoint) {
|
|
280
|
-
const { baseline, glyphWidth } = this;
|
|
281
|
-
const { left, top } = this.boundingBox;
|
|
282
|
-
const _startPoint = startPoint || {
|
|
283
|
-
y: top + baseline,
|
|
284
|
-
x: left + glyphWidth / 2
|
|
285
|
-
};
|
|
286
|
-
return this._transform(commands, (x, y) => {
|
|
287
|
-
const p = getSkewPoint({ x, y }, _startPoint, -0.24, 0);
|
|
288
|
-
return [p.x, p.y];
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
_rotation90(commands, point) {
|
|
292
|
-
return this._transform(commands, (x, y) => {
|
|
293
|
-
const p = getPointPosition({ x, y }, point, 90);
|
|
294
|
-
return [p.x, p.y];
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
updatePath() {
|
|
222
|
+
updateCommands() {
|
|
298
223
|
const font = this._font();
|
|
299
224
|
if (!font) {
|
|
300
225
|
return this;
|
|
@@ -309,7 +234,7 @@ class Character {
|
|
|
309
234
|
baseline,
|
|
310
235
|
glyphHeight,
|
|
311
236
|
glyphWidth
|
|
312
|
-
} = this.
|
|
237
|
+
} = this.updateGlyph(font);
|
|
313
238
|
const { os2, ascender, descender } = font;
|
|
314
239
|
const usWinAscent = ascender;
|
|
315
240
|
const usWinDescent = descender;
|
|
@@ -367,11 +292,120 @@ class Character {
|
|
|
367
292
|
}
|
|
368
293
|
commands.push(...this._decoration());
|
|
369
294
|
this.commands = commands;
|
|
370
|
-
this.path = new Path2D(commands);
|
|
371
295
|
return this;
|
|
372
296
|
}
|
|
373
297
|
update() {
|
|
374
|
-
this.
|
|
298
|
+
this.updateCommands();
|
|
299
|
+
return this;
|
|
300
|
+
}
|
|
301
|
+
_decoration() {
|
|
302
|
+
const { isVertical, underlinePosition, yStrikeoutPosition } = this;
|
|
303
|
+
const { textDecoration, fontSize } = this.computedStyle;
|
|
304
|
+
const { left, top, width, height } = this.boundingBox;
|
|
305
|
+
const lineWidth = 0.1 * fontSize;
|
|
306
|
+
let start;
|
|
307
|
+
switch (textDecoration) {
|
|
308
|
+
case "underline":
|
|
309
|
+
if (isVertical) {
|
|
310
|
+
start = left;
|
|
311
|
+
} else {
|
|
312
|
+
start = top + underlinePosition;
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
case "line-through":
|
|
316
|
+
if (isVertical) {
|
|
317
|
+
start = left + width / 2;
|
|
318
|
+
} else {
|
|
319
|
+
start = top + yStrikeoutPosition;
|
|
320
|
+
}
|
|
321
|
+
break;
|
|
322
|
+
case "none":
|
|
323
|
+
default:
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
if (isVertical) {
|
|
327
|
+
return [
|
|
328
|
+
{ type: "M", x: start, y: top },
|
|
329
|
+
{ type: "L", x: start, y: top + height },
|
|
330
|
+
{ type: "L", x: start + lineWidth, y: top + height },
|
|
331
|
+
{ type: "L", x: start + lineWidth, y: top },
|
|
332
|
+
{ type: "Z" }
|
|
333
|
+
];
|
|
334
|
+
} else {
|
|
335
|
+
return [
|
|
336
|
+
{ type: "M", x: left, y: start },
|
|
337
|
+
{ type: "L", x: left + width, y: start },
|
|
338
|
+
{ type: "L", x: left + width, y: start + lineWidth },
|
|
339
|
+
{ type: "L", x: left, y: start + lineWidth },
|
|
340
|
+
{ type: "Z" }
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
_italic(commands, startPoint) {
|
|
345
|
+
const { baseline, glyphWidth } = this;
|
|
346
|
+
const { left, top } = this.boundingBox;
|
|
347
|
+
const _startPoint = startPoint || {
|
|
348
|
+
y: top + baseline,
|
|
349
|
+
x: left + glyphWidth / 2
|
|
350
|
+
};
|
|
351
|
+
return this._transform(commands, (x, y) => {
|
|
352
|
+
const p = getSkewPoint({ x, y }, _startPoint, -0.24, 0);
|
|
353
|
+
return [p.x, p.y];
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
_rotation90(commands, point) {
|
|
357
|
+
return this._transform(commands, (x, y) => {
|
|
358
|
+
const p = getPointPosition({ x, y }, point, 90);
|
|
359
|
+
return [p.x, p.y];
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
_transform(commands, cb) {
|
|
363
|
+
return commands.map((rawCmd) => {
|
|
364
|
+
const cmd = { ...rawCmd };
|
|
365
|
+
switch (cmd.type) {
|
|
366
|
+
case "L":
|
|
367
|
+
case "M":
|
|
368
|
+
[cmd.x, cmd.y] = cb(cmd.x, cmd.y);
|
|
369
|
+
break;
|
|
370
|
+
case "Q":
|
|
371
|
+
[cmd.x1, cmd.y1] = cb(cmd.x1, cmd.y1);
|
|
372
|
+
[cmd.x, cmd.y] = cb(cmd.x, cmd.y);
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
return cmd;
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
forEachCommand(cb) {
|
|
379
|
+
const commands = this.commands;
|
|
380
|
+
const last = { x: 0, y: 0 };
|
|
381
|
+
const first = { x: 0, y: 0 };
|
|
382
|
+
let isFirst = true;
|
|
383
|
+
let doSetFirstPoint = false;
|
|
384
|
+
for (let i = 0, len = commands.length; i < len; i++) {
|
|
385
|
+
if (isFirst) {
|
|
386
|
+
doSetFirstPoint = true;
|
|
387
|
+
isFirst = false;
|
|
388
|
+
}
|
|
389
|
+
let command = commands[i];
|
|
390
|
+
command = cb(command, i, { last, first }) ?? command;
|
|
391
|
+
switch (command.type) {
|
|
392
|
+
case "M":
|
|
393
|
+
case "L":
|
|
394
|
+
case "Q":
|
|
395
|
+
last.x = command.x;
|
|
396
|
+
last.y = command.y;
|
|
397
|
+
if (doSetFirstPoint) {
|
|
398
|
+
first.x = last.x;
|
|
399
|
+
first.y = last.y;
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
case "Z":
|
|
403
|
+
last.x = first.x;
|
|
404
|
+
last.y = first.y;
|
|
405
|
+
isFirst = true;
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
375
409
|
return this;
|
|
376
410
|
}
|
|
377
411
|
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
@@ -405,7 +439,7 @@ class Character {
|
|
|
405
439
|
drawTo(ctx, config = {}) {
|
|
406
440
|
drawPaths({
|
|
407
441
|
ctx,
|
|
408
|
-
paths: [this.
|
|
442
|
+
paths: [new Path2D(this.commands)],
|
|
409
443
|
fontSize: this.computedStyle.fontSize,
|
|
410
444
|
color: this.computedStyle.color,
|
|
411
445
|
...config
|
|
@@ -571,7 +605,7 @@ class Highlighter extends Feature {
|
|
|
571
605
|
this.paths = groups.filter((characters2) => characters2.length).map((characters2) => {
|
|
572
606
|
return {
|
|
573
607
|
url: characters2[0].parent.highlight.url,
|
|
574
|
-
box: BoundingBox.from(...characters2.map((c) => c.
|
|
608
|
+
box: BoundingBox.from(...characters2.map((c) => c.boundingBox)),
|
|
575
609
|
baseline: Math.max(...characters2.map((c) => c.baseline))
|
|
576
610
|
};
|
|
577
611
|
}).map((group2) => this._parseGroup(group2, fontSize)).flat();
|
|
@@ -1040,14 +1074,15 @@ class Text {
|
|
|
1040
1074
|
const { paragraphs, boundingBox } = this.measure();
|
|
1041
1075
|
this.paragraphs = paragraphs;
|
|
1042
1076
|
this.boundingBox = boundingBox;
|
|
1043
|
-
|
|
1077
|
+
const characters = this.characters;
|
|
1078
|
+
characters.forEach((c) => c.update());
|
|
1044
1079
|
if (this.deformation) {
|
|
1045
1080
|
this._deformer.deform();
|
|
1046
1081
|
}
|
|
1047
1082
|
this._highlighter.highlight();
|
|
1048
1083
|
const min = Point2D.MAX;
|
|
1049
1084
|
const max = Point2D.MIN;
|
|
1050
|
-
|
|
1085
|
+
characters.forEach((c) => c.getMinMax(min, max));
|
|
1051
1086
|
this.renderBoundingBox = new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
1052
1087
|
return this;
|
|
1053
1088
|
}
|