modern-text 0.2.30 → 0.2.32
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 +423 -369
- package/dist/index.d.cts +141 -155
- package/dist/index.d.mts +141 -155
- package/dist/index.d.ts +141 -155
- package/dist/index.js +4 -2
- package/dist/index.mjs +414 -365
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -76,10 +76,58 @@ function drawPath(options) {
|
|
|
76
76
|
ctx.restore();
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
function fillBackground(ctx, text) {
|
|
80
|
+
const { computedStyle: style, paragraphs } = text;
|
|
81
|
+
function fillBackground2(color, x, y, width, height) {
|
|
82
|
+
ctx.fillStyle = color;
|
|
83
|
+
ctx.fillRect(x, y, width, height);
|
|
84
|
+
}
|
|
85
|
+
if (style?.backgroundColor) {
|
|
86
|
+
fillBackground2(style.backgroundColor, 0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
87
|
+
}
|
|
88
|
+
paragraphs.forEach((paragraph) => {
|
|
89
|
+
if (paragraph.style?.backgroundColor) {
|
|
90
|
+
fillBackground2(paragraph.computedStyle.backgroundColor, ...paragraph.boundingBox.toArray());
|
|
91
|
+
}
|
|
92
|
+
paragraph.fragments.forEach((fragment) => {
|
|
93
|
+
if (fragment.style?.backgroundColor) {
|
|
94
|
+
fillBackground2(fragment.computedStyle.backgroundColor, ...fragment.boundingBox.toArray());
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function setupView(ctx, pixelRatio, boundingBox) {
|
|
101
|
+
const { left, top, width, height } = boundingBox;
|
|
102
|
+
const view = ctx.canvas;
|
|
103
|
+
view.dataset.viewbox = String(`${left} ${top} ${width} ${height}`);
|
|
104
|
+
view.dataset.pixelRatio = String(pixelRatio);
|
|
105
|
+
view.width = Math.max(1, Math.ceil(width * pixelRatio));
|
|
106
|
+
view.height = Math.max(1, Math.ceil(height * pixelRatio));
|
|
107
|
+
view.style.marginTop = `${top}px`;
|
|
108
|
+
view.style.marginLeft = `${left}px`;
|
|
109
|
+
view.style.width = `${width}px`;
|
|
110
|
+
view.style.height = `${height}px`;
|
|
111
|
+
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
112
|
+
ctx.scale(pixelRatio, pixelRatio);
|
|
113
|
+
ctx.translate(-left, -top);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function uploadColors(ctx, text) {
|
|
117
|
+
const { paragraphs, computedStyle: style, renderBoundingBox } = text;
|
|
118
|
+
uploadColor(style, renderBoundingBox, ctx);
|
|
119
|
+
paragraphs.forEach((paragraph) => {
|
|
120
|
+
uploadColor(paragraph.computedStyle, paragraph.boundingBox, ctx);
|
|
121
|
+
paragraph.fragments.forEach((fragment) => {
|
|
122
|
+
uploadColor(fragment.computedStyle, fragment.boundingBox, ctx);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
var __defProp$3 = Object.defineProperty;
|
|
128
|
+
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
129
|
+
var __publicField$3 = (obj, key, value) => {
|
|
130
|
+
__defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
83
131
|
return value;
|
|
84
132
|
};
|
|
85
133
|
const set1 = /* @__PURE__ */ new Set(["\xA9", "\xAE", "\xF7"]);
|
|
@@ -114,21 +162,21 @@ class Character {
|
|
|
114
162
|
this.index = index;
|
|
115
163
|
this.parent = parent;
|
|
116
164
|
// measure dom
|
|
117
|
-
__publicField$
|
|
118
|
-
__publicField$
|
|
119
|
-
__publicField$
|
|
165
|
+
__publicField$3(this, "boundingBox", new modernPath2d.BoundingBox());
|
|
166
|
+
__publicField$3(this, "textWidth", 0);
|
|
167
|
+
__publicField$3(this, "textHeight", 0);
|
|
120
168
|
// font glyph
|
|
121
|
-
__publicField$
|
|
122
|
-
__publicField$
|
|
123
|
-
__publicField$
|
|
124
|
-
__publicField$
|
|
125
|
-
__publicField$
|
|
126
|
-
__publicField$
|
|
127
|
-
__publicField$
|
|
128
|
-
__publicField$
|
|
129
|
-
__publicField$
|
|
130
|
-
__publicField$
|
|
131
|
-
__publicField$
|
|
169
|
+
__publicField$3(this, "glyphHeight", 0);
|
|
170
|
+
__publicField$3(this, "glyphWidth", 0);
|
|
171
|
+
__publicField$3(this, "underlinePosition", 0);
|
|
172
|
+
__publicField$3(this, "underlineThickness", 0);
|
|
173
|
+
__publicField$3(this, "yStrikeoutPosition", 0);
|
|
174
|
+
__publicField$3(this, "yStrikeoutSize", 0);
|
|
175
|
+
__publicField$3(this, "baseline", 0);
|
|
176
|
+
__publicField$3(this, "centerDiviation", 0);
|
|
177
|
+
__publicField$3(this, "path", new modernPath2d.Path2D());
|
|
178
|
+
__publicField$3(this, "glyphBox", new modernPath2d.BoundingBox());
|
|
179
|
+
__publicField$3(this, "center", new modernPath2d.Vector2());
|
|
132
180
|
}
|
|
133
181
|
get computedStyle() {
|
|
134
182
|
return this.parent.computedStyle;
|
|
@@ -320,10 +368,6 @@ class Character {
|
|
|
320
368
|
} else {
|
|
321
369
|
min ?? (min = modernPath2d.Vector2.MAX);
|
|
322
370
|
max ?? (max = modernPath2d.Vector2.MIN);
|
|
323
|
-
min.x = Math.min(min.x, this.boundingBox.left);
|
|
324
|
-
min.y = Math.min(min.y, this.boundingBox.top);
|
|
325
|
-
max.x = Math.max(max.x, this.boundingBox.right);
|
|
326
|
-
max.y = Math.max(max.y, this.boundingBox.bottom);
|
|
327
371
|
return { min, max };
|
|
328
372
|
}
|
|
329
373
|
}
|
|
@@ -342,6 +386,9 @@ class Character {
|
|
|
342
386
|
}
|
|
343
387
|
}
|
|
344
388
|
|
|
389
|
+
function isNone(val) {
|
|
390
|
+
return !val || val === "none";
|
|
391
|
+
}
|
|
345
392
|
function filterEmpty(val) {
|
|
346
393
|
if (!val)
|
|
347
394
|
return val;
|
|
@@ -354,10 +401,10 @@ function filterEmpty(val) {
|
|
|
354
401
|
return res;
|
|
355
402
|
}
|
|
356
403
|
|
|
357
|
-
var __defProp$
|
|
358
|
-
var __defNormalProp$
|
|
359
|
-
var __publicField$
|
|
360
|
-
__defNormalProp$
|
|
404
|
+
var __defProp$2 = Object.defineProperty;
|
|
405
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
406
|
+
var __publicField$2 = (obj, key, value) => {
|
|
407
|
+
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
361
408
|
return value;
|
|
362
409
|
};
|
|
363
410
|
class Fragment {
|
|
@@ -365,8 +412,7 @@ class Fragment {
|
|
|
365
412
|
this.content = content;
|
|
366
413
|
this.style = style;
|
|
367
414
|
this.parent = parent;
|
|
368
|
-
__publicField$
|
|
369
|
-
__publicField$3(this, "highlight");
|
|
415
|
+
__publicField$2(this, "boundingBox", new modernPath2d.BoundingBox());
|
|
370
416
|
this.updateComputedStyle().initCharacters();
|
|
371
417
|
}
|
|
372
418
|
get computedContent() {
|
|
@@ -391,18 +437,18 @@ class Fragment {
|
|
|
391
437
|
}
|
|
392
438
|
}
|
|
393
439
|
|
|
394
|
-
var __defProp$
|
|
395
|
-
var __defNormalProp$
|
|
396
|
-
var __publicField$
|
|
397
|
-
__defNormalProp$
|
|
440
|
+
var __defProp$1 = Object.defineProperty;
|
|
441
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
442
|
+
var __publicField$1 = (obj, key, value) => {
|
|
443
|
+
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
398
444
|
return value;
|
|
399
445
|
};
|
|
400
446
|
class Paragraph {
|
|
401
447
|
constructor(style, parentStyle) {
|
|
402
448
|
this.style = style;
|
|
403
449
|
this.parentStyle = parentStyle;
|
|
404
|
-
__publicField$
|
|
405
|
-
__publicField$
|
|
450
|
+
__publicField$1(this, "boundingBox", new modernPath2d.BoundingBox());
|
|
451
|
+
__publicField$1(this, "fragments", []);
|
|
406
452
|
this.updateComputedStyle();
|
|
407
453
|
}
|
|
408
454
|
updateComputedStyle() {
|
|
@@ -419,231 +465,10 @@ class Paragraph {
|
|
|
419
465
|
}
|
|
420
466
|
}
|
|
421
467
|
|
|
422
|
-
class
|
|
468
|
+
class Measurer {
|
|
423
469
|
constructor(_text) {
|
|
424
470
|
this._text = _text;
|
|
425
471
|
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
class Deformer extends Feature {
|
|
429
|
-
deform() {
|
|
430
|
-
this._text.deformation?.();
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const tempM1 = new modernPath2d.Matrix3();
|
|
435
|
-
const tempM2 = new modernPath2d.Matrix3();
|
|
436
|
-
const tempV1 = new modernPath2d.Vector2();
|
|
437
|
-
class Effector extends Feature {
|
|
438
|
-
getTransform2D(style) {
|
|
439
|
-
const { fontSize, renderBoundingBox } = this._text;
|
|
440
|
-
const offsetX = (style.offsetX ?? 0) * fontSize;
|
|
441
|
-
const offsetY = (style.offsetY ?? 0) * fontSize;
|
|
442
|
-
const PI_2 = Math.PI * 2;
|
|
443
|
-
const skewX = (style.skewX ?? 0) / 360 * PI_2;
|
|
444
|
-
const skewY = (style.skewY ?? 0) / 360 * PI_2;
|
|
445
|
-
const { left, top, width, height } = renderBoundingBox;
|
|
446
|
-
const centerX = left + width / 2;
|
|
447
|
-
const centerY = top + height / 2;
|
|
448
|
-
tempM1.identity();
|
|
449
|
-
tempM2.makeTranslation(offsetX, offsetY);
|
|
450
|
-
tempM1.multiply(tempM2);
|
|
451
|
-
tempM2.makeTranslation(centerX, centerY);
|
|
452
|
-
tempM1.multiply(tempM2);
|
|
453
|
-
tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
|
|
454
|
-
tempM1.multiply(tempM2);
|
|
455
|
-
tempM2.makeTranslation(-centerX, -centerY);
|
|
456
|
-
tempM1.multiply(tempM2);
|
|
457
|
-
return tempM1.clone();
|
|
458
|
-
}
|
|
459
|
-
getBoundingBox() {
|
|
460
|
-
const { characters, effects, fontSize } = this._text;
|
|
461
|
-
const boxes = [];
|
|
462
|
-
characters.forEach((character) => {
|
|
463
|
-
effects?.forEach((style) => {
|
|
464
|
-
const aabb = character.glyphBox.clone();
|
|
465
|
-
const m = this.getTransform2D(style);
|
|
466
|
-
tempV1.set(aabb.left, aabb.top);
|
|
467
|
-
tempV1.applyMatrix3(m);
|
|
468
|
-
aabb.left = tempV1.x;
|
|
469
|
-
aabb.top = tempV1.y;
|
|
470
|
-
tempV1.set(aabb.right, aabb.bottom);
|
|
471
|
-
tempV1.applyMatrix3(m);
|
|
472
|
-
aabb.width = tempV1.x - aabb.left;
|
|
473
|
-
aabb.height = tempV1.y - aabb.top;
|
|
474
|
-
const shadowOffsetX = (style.shadowOffsetX ?? 0) * fontSize;
|
|
475
|
-
const shadowOffsetY = (style.shadowOffsetY ?? 0) * fontSize;
|
|
476
|
-
const textStrokeWidth = Math.max(0.1, style.textStrokeWidth ?? 0) * fontSize;
|
|
477
|
-
aabb.left += shadowOffsetX - textStrokeWidth;
|
|
478
|
-
aabb.top += shadowOffsetY - textStrokeWidth;
|
|
479
|
-
aabb.width += textStrokeWidth * 2;
|
|
480
|
-
aabb.height += textStrokeWidth * 2;
|
|
481
|
-
boxes.push(aabb);
|
|
482
|
-
});
|
|
483
|
-
});
|
|
484
|
-
return modernPath2d.BoundingBox.from(...boxes);
|
|
485
|
-
}
|
|
486
|
-
draw(options) {
|
|
487
|
-
const { ctx } = options;
|
|
488
|
-
const { effects, characters, renderBoundingBox } = this._text;
|
|
489
|
-
if (effects) {
|
|
490
|
-
effects.forEach((style) => {
|
|
491
|
-
uploadColor(style, renderBoundingBox, ctx);
|
|
492
|
-
ctx.save();
|
|
493
|
-
const [a, c, e, b, d, f] = this.getTransform2D(style).transpose().elements;
|
|
494
|
-
ctx.transform(a, b, c, d, e, f);
|
|
495
|
-
characters.forEach((character) => {
|
|
496
|
-
character.drawTo(ctx, style);
|
|
497
|
-
});
|
|
498
|
-
ctx.restore();
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
return this;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
var __defProp$1 = Object.defineProperty;
|
|
506
|
-
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
507
|
-
var __publicField$1 = (obj, key, value) => {
|
|
508
|
-
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
509
|
-
return value;
|
|
510
|
-
};
|
|
511
|
-
const defaultHighlightRefer = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIiBmaWxsPSJub25lIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMyLjQwMjkgMjhIMzUuMTU5NFYzMy4xNzcxQzM1Ljk4MjEgMzIuMzExNSAzNi45NzEgMzEuODczNyAzOC4wOTQ4IDMxLjg3MzdDMzkuNjY3NiAzMS44NzM3IDQwLjkxNjYgMzIuNDI5NSA0MS44MzkgMzMuNTQzN0w0MS44NDAzIDMzLjU0NTNDNDIuNjcxNyAzNC41NzA1IDQzLjA5MTUgMzUuODU1OSA0My4wOTE1IDM3LjM4NzdDNDMuMDkxNSAzOC45NzYxIDQyLjY3MjkgNDAuMzAyOCA0MS44MTgzIDQxLjMzMDRMNDEuODE3MSA0MS4zMzE4QzQwLjg3MzEgNDIuNDQ2MSAzOS41ODMyIDQzIDM3Ljk3MjEgNDNDMzYuNzQ3NyA0MyAzNS43NDg4IDQyLjY1OTkgMzQuOTk1OCA0MS45NjkzVjQyLjcyNDdIMzIuNDAyOVYyOFpNMzcuNTQyOCAzNC4wOTI0QzM2Ljg1NDkgMzQuMDkyNCAzNi4zMDE0IDM0LjM1NjEgMzUuODQ4NyAzNC45MDA0TDM1Ljg0NTIgMzQuOTA0NkMzNS4zMzU4IDM1LjQ4NTMgMzUuMDc3NiAzNi4yOTc2IDM1LjA3NzYgMzcuMzQ4NFYzNy41MDU3QzM1LjA3NzYgMzguNDY0IDM1LjI3NzIgMzkuMjQ0MyAzNS42OTQzIDM5LjgyNzlDMzYuMTQ0MSA0MC40NTg3IDM2Ljc3MjYgNDAuNzgxMyAzNy42MjQ1IDQwLjc4MTNDMzguNTg3NCA0MC43ODEzIDM5LjI3MDcgNDAuNDUyNyAzOS43MTUyIDM5LjgxMjdDNDAuMDcyOCAzOS4yNjg0IDQwLjI3MzcgMzguNDY3MyA0MC4yNzM3IDM3LjM4NzdDNDAuMjczNyAzNi4zMTA1IDQwLjA1MzMgMzUuNTMxMyAzOS42NzgzIDM1LjAwNzdDMzkuMjM3MSAzNC40MDcxIDM4LjUzNDIgMzQuMDkyNCAzNy41NDI4IDM0LjA5MjRaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZD0iTTQ5Ljg2MTQgMzEuODczN0M0OC4xNTM1IDMxLjg3MzcgNDYuODAxNiAzMi40MjM5IDQ1LjgzNDggMzMuNTM5MkM0NC45MzcgMzQuNTQ3MiA0NC40OTY2IDM1Ljg1NiA0NC40OTY2IDM3LjQyN0M0NC40OTY2IDM5LjAzNjggNDQuOTM2NyA0MC4zNjU5IDQ1Ljg1NTkgNDEuMzk0M0M0Ni44MDMxIDQyLjQ3MDYgNDguMTM0OCA0MyA0OS44MjA1IDQzQzUxLjIyNiA0MyA1Mi4zODI2IDQyLjY1NjMgNTMuMjQ3OSA0MS45Njk3QzU0LjEzNTkgNDEuMjYxNCA1NC43MDYxIDQwLjE4ODcgNTQuOTU3MyAzOC43NzkxTDU1IDM4LjUzOTdINTIuMjQ4NEw1Mi4yMjU5IDM4LjcyMDFDNTIuMTM3OSAzOS40MjUxIDUxLjg5MjUgMzkuOTI3OCA1MS41MTA5IDQwLjI1NThDNTEuMTI5NSA0MC41ODM1IDUwLjU4MzEgNDAuNzYxNiA0OS44NDA5IDQwLjc2MTZDNDkuMDAwMSA0MC43NjE2IDQ4LjM5NDkgNDAuNDcxNSA0Ny45OTA3IDM5LjkyMzdMNDcuOTg3NCAzOS45MTk0QzQ3LjUzNTYgMzkuMzQwMSA0Ny4zMTQ0IDM4LjUwNjIgNDcuMzE0NCAzNy40MDc0QzQ3LjMxNDQgMzYuMzMyMiA0Ny41NTQ0IDM1LjUxNzcgNDguMDA1OCAzNC45NTY4TDQ4LjAwNzggMzQuOTU0M0M0OC40NTM3IDM0LjM4MjUgNDkuMDYxOCAzNC4xMTIxIDQ5Ljg2MTQgMzQuMTEyMUM1MC41MjMgMzQuMTEyMSA1MS4wNDUxIDM0LjI2MTUgNTEuNDI3MiAzNC41NDA3QzUxLjc4ODQgMzQuODE5NCA1Mi4wNTMgMzUuMjQ0NyA1Mi4xODgxIDM1Ljg1NzFMNTIuMjIzOSAzNi4wMTk0SDU0Ljk1NDhMNTQuOTE3IDM1Ljc4MzVDNTQuNzA2MyAzNC40NjYgNTQuMTUzNiAzMy40NzAxIDUzLjI2MzQgMzIuODAxOUw1My4yNjAyIDMyLjc5OTVDNTIuMzk1MSAzMi4xNzU1IDUxLjI2MjEgMzEuODczNyA0OS44NjE0IDMxLjg3MzdaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNS43NTYxIDI4LjI3NTNIMjIuNzQ0TDE3IDQyLjcyNDdIMjAuMDE0MUwyMS4zNDI5IDM5LjIwNDlIMjcuMTU3MkwyOC40ODYgNDIuNzI0N0gzMS41MDAxTDI1Ljc1NjEgMjguMjc1M1pNMjIuMjEyNSAzNi45MDc2TDI0LjI1OTYgMzEuNDUzOUwyNi4yODg1IDM2LjkwNzZIMjIuMjEyNVoiIGZpbGw9IiMyMjI1MjkiLz48L3N2Zz4=";
|
|
512
|
-
const _Highlighter = class _Highlighter extends Feature {
|
|
513
|
-
constructor() {
|
|
514
|
-
super(...arguments);
|
|
515
|
-
__publicField$1(this, "paths", []);
|
|
516
|
-
}
|
|
517
|
-
static get refer() {
|
|
518
|
-
return this._refer;
|
|
519
|
-
}
|
|
520
|
-
static set refer(refer) {
|
|
521
|
-
this._refer = refer;
|
|
522
|
-
this.parsedRefer = modernPath2d.parseSvg(refer);
|
|
523
|
-
}
|
|
524
|
-
getReferBoundingBox() {
|
|
525
|
-
const max = modernPath2d.Vector2.MIN;
|
|
526
|
-
const min = modernPath2d.Vector2.MAX;
|
|
527
|
-
_Highlighter.parsedRefer.forEach((path) => {
|
|
528
|
-
path.getMinMax(min, max);
|
|
529
|
-
});
|
|
530
|
-
return new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
531
|
-
}
|
|
532
|
-
getBoundingBox() {
|
|
533
|
-
if (!this.paths.length) {
|
|
534
|
-
return void 0;
|
|
535
|
-
}
|
|
536
|
-
const min = modernPath2d.Vector2.MAX;
|
|
537
|
-
const max = modernPath2d.Vector2.MIN;
|
|
538
|
-
this.paths.forEach((v) => v.path.getMinMax(min, max));
|
|
539
|
-
return new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
540
|
-
}
|
|
541
|
-
highlight(perChar = false) {
|
|
542
|
-
const { characters } = this._text;
|
|
543
|
-
let group;
|
|
544
|
-
const groups = [];
|
|
545
|
-
let prevHighlight;
|
|
546
|
-
characters.forEach((character) => {
|
|
547
|
-
const highlight = character.parent.highlight;
|
|
548
|
-
if (highlight?.url) {
|
|
549
|
-
if (!perChar && prevHighlight?.url === highlight.url && prevHighlight?.strokeWidth === highlight.strokeWidth && prevHighlight?.repeatXByFontsize === highlight.repeatXByFontsize && prevHighlight?.overflowXHidden === highlight.overflowXHidden && group.length && group[0].boundingBox.top === character.boundingBox.top && group[0].fontSize === character.fontSize) {
|
|
550
|
-
group.push(character);
|
|
551
|
-
} else {
|
|
552
|
-
group = [];
|
|
553
|
-
group.push(character);
|
|
554
|
-
groups.push(group);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
prevHighlight = highlight;
|
|
558
|
-
});
|
|
559
|
-
this.paths = groups.filter((characters2) => characters2.length).map((characters2) => {
|
|
560
|
-
return {
|
|
561
|
-
highlight: characters2[0].parent.highlight,
|
|
562
|
-
box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.glyphBox)),
|
|
563
|
-
baseline: Math.max(...characters2.map((c) => c.baseline)),
|
|
564
|
-
fontSize: characters2[0].fontSize
|
|
565
|
-
};
|
|
566
|
-
}).map((group2) => this._parseGroup(group2)).flat();
|
|
567
|
-
}
|
|
568
|
-
_parseSvg(url) {
|
|
569
|
-
const svg = modernPath2d.parseSvgToDom(url);
|
|
570
|
-
const paths = modernPath2d.parseSvg(svg);
|
|
571
|
-
const min = modernPath2d.Vector2.MAX;
|
|
572
|
-
const max = modernPath2d.Vector2.MIN;
|
|
573
|
-
paths.forEach((path) => path.getMinMax(min, max));
|
|
574
|
-
return {
|
|
575
|
-
paths,
|
|
576
|
-
box: new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y)
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
_parseGroup(group) {
|
|
580
|
-
const { highlight, box: groupBox, fontSize } = group;
|
|
581
|
-
const {
|
|
582
|
-
strokeWidth = 1,
|
|
583
|
-
repeatXByFontsize = 0,
|
|
584
|
-
overflowXHidden = Boolean(repeatXByFontsize)
|
|
585
|
-
} = highlight;
|
|
586
|
-
const { box, paths } = this._parseSvg(highlight.url);
|
|
587
|
-
const result = [];
|
|
588
|
-
const referBoundingBox = this.getReferBoundingBox();
|
|
589
|
-
const scale = {
|
|
590
|
-
x: repeatXByFontsize ? fontSize * repeatXByFontsize * (box.width / referBoundingBox.width) / box.width : groupBox.width * (box.width / referBoundingBox.width) / box.width,
|
|
591
|
-
y: groupBox.height * (box.height / referBoundingBox.height) / box.height
|
|
592
|
-
};
|
|
593
|
-
const styleScale = fontSize / box.width * 2;
|
|
594
|
-
const unitWidth = box.width * scale.x;
|
|
595
|
-
const total = Math.ceil(groupBox.width / unitWidth);
|
|
596
|
-
const offset = {
|
|
597
|
-
x: (box.left - referBoundingBox.left) * scale.x,
|
|
598
|
-
y: (box.top - referBoundingBox.top) * scale.y
|
|
599
|
-
};
|
|
600
|
-
const transform = new modernPath2d.Matrix3().translate(-box.left, -box.top).scale(scale.x, scale.y).translate(groupBox.left, groupBox.top).translate(offset.x, offset.y);
|
|
601
|
-
for (let i = 0; i < total; i++) {
|
|
602
|
-
const _transform = transform.clone().translate(i * unitWidth, 0);
|
|
603
|
-
paths.forEach((original) => {
|
|
604
|
-
const path = original.clone().matrix(_transform);
|
|
605
|
-
if (path.style.strokeWidth) {
|
|
606
|
-
path.style.strokeWidth *= styleScale * strokeWidth;
|
|
607
|
-
}
|
|
608
|
-
if (path.style.strokeMiterlimit) {
|
|
609
|
-
path.style.strokeMiterlimit *= styleScale;
|
|
610
|
-
}
|
|
611
|
-
if (path.style.strokeDashoffset) {
|
|
612
|
-
path.style.strokeDashoffset *= styleScale;
|
|
613
|
-
}
|
|
614
|
-
if (path.style.strokeDasharray) {
|
|
615
|
-
path.style.strokeDasharray = path.style.strokeDasharray.map((v) => v * styleScale);
|
|
616
|
-
}
|
|
617
|
-
result.push({
|
|
618
|
-
clipRect: overflowXHidden ? new modernPath2d.BoundingBox(
|
|
619
|
-
groupBox.left + offset.x * 2,
|
|
620
|
-
groupBox.top - groupBox.height,
|
|
621
|
-
groupBox.width - offset.x * 2,
|
|
622
|
-
groupBox.height * 3
|
|
623
|
-
) : void 0,
|
|
624
|
-
path
|
|
625
|
-
});
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
return result;
|
|
629
|
-
}
|
|
630
|
-
draw({ ctx }) {
|
|
631
|
-
this.paths.forEach((v) => {
|
|
632
|
-
drawPath({
|
|
633
|
-
ctx,
|
|
634
|
-
path: v.path,
|
|
635
|
-
clipRect: v.clipRect,
|
|
636
|
-
fontSize: this._text.computedStyle.fontSize
|
|
637
|
-
});
|
|
638
|
-
});
|
|
639
|
-
return this;
|
|
640
|
-
}
|
|
641
|
-
};
|
|
642
|
-
__publicField$1(_Highlighter, "_refer", defaultHighlightRefer);
|
|
643
|
-
__publicField$1(_Highlighter, "parsedRefer", modernPath2d.parseSvg(_Highlighter._refer));
|
|
644
|
-
let Highlighter = _Highlighter;
|
|
645
|
-
|
|
646
|
-
class Measurer extends Feature {
|
|
647
472
|
_styleToDomStyle(style) {
|
|
648
473
|
const _style = { ...style };
|
|
649
474
|
for (const key in style) {
|
|
@@ -687,7 +512,7 @@ class Measurer extends Feature {
|
|
|
687
512
|
});
|
|
688
513
|
const ul = document.createElement("ul");
|
|
689
514
|
Object.assign(ul.style, {
|
|
690
|
-
|
|
515
|
+
listStyleType: "inherit",
|
|
691
516
|
padding: "0",
|
|
692
517
|
margin: "0"
|
|
693
518
|
});
|
|
@@ -852,7 +677,10 @@ class Measurer extends Feature {
|
|
|
852
677
|
}
|
|
853
678
|
}
|
|
854
679
|
|
|
855
|
-
class Parser
|
|
680
|
+
class Parser {
|
|
681
|
+
constructor(_text) {
|
|
682
|
+
this._text = _text;
|
|
683
|
+
}
|
|
856
684
|
parse() {
|
|
857
685
|
let { content, computedStyle: style } = this._text;
|
|
858
686
|
const paragraphs = [];
|
|
@@ -873,10 +701,9 @@ class Parser extends Feature {
|
|
|
873
701
|
if (typeof f === "string") {
|
|
874
702
|
paragraph.addFragment(f);
|
|
875
703
|
} else {
|
|
876
|
-
const { content: content2,
|
|
704
|
+
const { content: content2, ...fStyle } = f;
|
|
877
705
|
if (content2 !== void 0) {
|
|
878
|
-
|
|
879
|
-
fragment.highlight = highlight;
|
|
706
|
+
paragraph.addFragment(content2, fStyle);
|
|
880
707
|
}
|
|
881
708
|
}
|
|
882
709
|
});
|
|
@@ -885,19 +712,17 @@ class Parser extends Feature {
|
|
|
885
712
|
const { fragments, ...pStyle } = p;
|
|
886
713
|
const paragraph = new Paragraph(pStyle, style);
|
|
887
714
|
fragments.forEach((f) => {
|
|
888
|
-
const { content: content2,
|
|
715
|
+
const { content: content2, ...fStyle } = f;
|
|
889
716
|
if (content2 !== void 0) {
|
|
890
|
-
|
|
891
|
-
fragment.highlight = highlight;
|
|
717
|
+
paragraph.addFragment(content2, fStyle);
|
|
892
718
|
}
|
|
893
719
|
});
|
|
894
720
|
paragraphs.push(paragraph);
|
|
895
721
|
} else if ("content" in p) {
|
|
896
|
-
const { content: pData,
|
|
722
|
+
const { content: pData, ...pStyle } = p;
|
|
897
723
|
if (pData !== void 0) {
|
|
898
724
|
const paragraph = new Paragraph(pStyle, style);
|
|
899
|
-
|
|
900
|
-
fragment.highlight = highlight;
|
|
725
|
+
paragraph.addFragment(pData);
|
|
901
726
|
paragraphs.push(paragraph);
|
|
902
727
|
}
|
|
903
728
|
}
|
|
@@ -907,71 +732,274 @@ class Parser extends Feature {
|
|
|
907
732
|
}
|
|
908
733
|
}
|
|
909
734
|
|
|
910
|
-
|
|
911
|
-
|
|
735
|
+
function definePlugin(options) {
|
|
736
|
+
return options;
|
|
912
737
|
}
|
|
913
738
|
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
739
|
+
const tempV1 = new modernPath2d.Vector2();
|
|
740
|
+
const tempM1 = new modernPath2d.Matrix3();
|
|
741
|
+
const tempM2 = new modernPath2d.Matrix3();
|
|
742
|
+
function effect() {
|
|
743
|
+
return definePlugin({
|
|
744
|
+
name: "effect",
|
|
745
|
+
getBoundingBox: (text) => {
|
|
746
|
+
const { characters, fontSize, effects } = text;
|
|
747
|
+
const boxes = [];
|
|
748
|
+
characters.forEach((character) => {
|
|
749
|
+
effects?.forEach((style) => {
|
|
750
|
+
const aabb = character.glyphBox.clone();
|
|
751
|
+
const m = getTransform2D(text, style);
|
|
752
|
+
tempV1.set(aabb.left, aabb.top);
|
|
753
|
+
tempV1.applyMatrix3(m);
|
|
754
|
+
aabb.left = tempV1.x;
|
|
755
|
+
aabb.top = tempV1.y;
|
|
756
|
+
tempV1.set(aabb.right, aabb.bottom);
|
|
757
|
+
tempV1.applyMatrix3(m);
|
|
758
|
+
aabb.width = tempV1.x - aabb.left;
|
|
759
|
+
aabb.height = tempV1.y - aabb.top;
|
|
760
|
+
const shadowOffsetX = (style.shadowOffsetX ?? 0) * fontSize;
|
|
761
|
+
const shadowOffsetY = (style.shadowOffsetY ?? 0) * fontSize;
|
|
762
|
+
const textStrokeWidth = Math.max(0.1, style.textStrokeWidth ?? 0) * fontSize;
|
|
763
|
+
aabb.left += shadowOffsetX - textStrokeWidth;
|
|
764
|
+
aabb.top += shadowOffsetY - textStrokeWidth;
|
|
765
|
+
aabb.width += textStrokeWidth * 2;
|
|
766
|
+
aabb.height += textStrokeWidth * 2;
|
|
767
|
+
boxes.push(aabb);
|
|
768
|
+
});
|
|
941
769
|
});
|
|
942
|
-
|
|
943
|
-
|
|
770
|
+
return boxes.length ? modernPath2d.BoundingBox.from(...boxes) : void 0;
|
|
771
|
+
},
|
|
772
|
+
render: (ctx, text) => {
|
|
773
|
+
const { characters, renderBoundingBox, effects } = text;
|
|
774
|
+
if (effects) {
|
|
775
|
+
effects.forEach((style) => {
|
|
776
|
+
uploadColor(style, renderBoundingBox, ctx);
|
|
777
|
+
ctx.save();
|
|
778
|
+
const [a, c, e, b, d, f] = getTransform2D(text, style).transpose().elements;
|
|
779
|
+
ctx.transform(a, b, c, d, e, f);
|
|
780
|
+
characters.forEach((character) => {
|
|
781
|
+
character.drawTo(ctx, style);
|
|
782
|
+
});
|
|
783
|
+
ctx.restore();
|
|
784
|
+
});
|
|
785
|
+
} else {
|
|
786
|
+
characters.forEach((character) => {
|
|
787
|
+
character.drawTo(ctx);
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
function getTransform2D(text, style) {
|
|
794
|
+
const { fontSize, renderBoundingBox } = text;
|
|
795
|
+
const offsetX = (style.offsetX ?? 0) * fontSize;
|
|
796
|
+
const offsetY = (style.offsetY ?? 0) * fontSize;
|
|
797
|
+
const PI_2 = Math.PI * 2;
|
|
798
|
+
const skewX = (style.skewX ?? 0) / 360 * PI_2;
|
|
799
|
+
const skewY = (style.skewY ?? 0) / 360 * PI_2;
|
|
800
|
+
const { left, top, width, height } = renderBoundingBox;
|
|
801
|
+
const centerX = left + width / 2;
|
|
802
|
+
const centerY = top + height / 2;
|
|
803
|
+
tempM1.identity();
|
|
804
|
+
tempM2.makeTranslation(offsetX, offsetY);
|
|
805
|
+
tempM1.multiply(tempM2);
|
|
806
|
+
tempM2.makeTranslation(centerX, centerY);
|
|
807
|
+
tempM1.multiply(tempM2);
|
|
808
|
+
tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
|
|
809
|
+
tempM1.multiply(tempM2);
|
|
810
|
+
tempM2.makeTranslation(-centerX, -centerY);
|
|
811
|
+
tempM1.multiply(tempM2);
|
|
812
|
+
return tempM1.clone();
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const defaultOptions = {
|
|
816
|
+
referImage: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIiBmaWxsPSJub25lIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMyLjQwMjkgMjhIMzUuMTU5NFYzMy4xNzcxQzM1Ljk4MjEgMzIuMzExNSAzNi45NzEgMzEuODczNyAzOC4wOTQ4IDMxLjg3MzdDMzkuNjY3NiAzMS44NzM3IDQwLjkxNjYgMzIuNDI5NSA0MS44MzkgMzMuNTQzN0w0MS44NDAzIDMzLjU0NTNDNDIuNjcxNyAzNC41NzA1IDQzLjA5MTUgMzUuODU1OSA0My4wOTE1IDM3LjM4NzdDNDMuMDkxNSAzOC45NzYxIDQyLjY3MjkgNDAuMzAyOCA0MS44MTgzIDQxLjMzMDRMNDEuODE3MSA0MS4zMzE4QzQwLjg3MzEgNDIuNDQ2MSAzOS41ODMyIDQzIDM3Ljk3MjEgNDNDMzYuNzQ3NyA0MyAzNS43NDg4IDQyLjY1OTkgMzQuOTk1OCA0MS45NjkzVjQyLjcyNDdIMzIuNDAyOVYyOFpNMzcuNTQyOCAzNC4wOTI0QzM2Ljg1NDkgMzQuMDkyNCAzNi4zMDE0IDM0LjM1NjEgMzUuODQ4NyAzNC45MDA0TDM1Ljg0NTIgMzQuOTA0NkMzNS4zMzU4IDM1LjQ4NTMgMzUuMDc3NiAzNi4yOTc2IDM1LjA3NzYgMzcuMzQ4NFYzNy41MDU3QzM1LjA3NzYgMzguNDY0IDM1LjI3NzIgMzkuMjQ0MyAzNS42OTQzIDM5LjgyNzlDMzYuMTQ0MSA0MC40NTg3IDM2Ljc3MjYgNDAuNzgxMyAzNy42MjQ1IDQwLjc4MTNDMzguNTg3NCA0MC43ODEzIDM5LjI3MDcgNDAuNDUyNyAzOS43MTUyIDM5LjgxMjdDNDAuMDcyOCAzOS4yNjg0IDQwLjI3MzcgMzguNDY3MyA0MC4yNzM3IDM3LjM4NzdDNDAuMjczNyAzNi4zMTA1IDQwLjA1MzMgMzUuNTMxMyAzOS42NzgzIDM1LjAwNzdDMzkuMjM3MSAzNC40MDcxIDM4LjUzNDIgMzQuMDkyNCAzNy41NDI4IDM0LjA5MjRaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZD0iTTQ5Ljg2MTQgMzEuODczN0M0OC4xNTM1IDMxLjg3MzcgNDYuODAxNiAzMi40MjM5IDQ1LjgzNDggMzMuNTM5MkM0NC45MzcgMzQuNTQ3MiA0NC40OTY2IDM1Ljg1NiA0NC40OTY2IDM3LjQyN0M0NC40OTY2IDM5LjAzNjggNDQuOTM2NyA0MC4zNjU5IDQ1Ljg1NTkgNDEuMzk0M0M0Ni44MDMxIDQyLjQ3MDYgNDguMTM0OCA0MyA0OS44MjA1IDQzQzUxLjIyNiA0MyA1Mi4zODI2IDQyLjY1NjMgNTMuMjQ3OSA0MS45Njk3QzU0LjEzNTkgNDEuMjYxNCA1NC43MDYxIDQwLjE4ODcgNTQuOTU3MyAzOC43NzkxTDU1IDM4LjUzOTdINTIuMjQ4NEw1Mi4yMjU5IDM4LjcyMDFDNTIuMTM3OSAzOS40MjUxIDUxLjg5MjUgMzkuOTI3OCA1MS41MTA5IDQwLjI1NThDNTEuMTI5NSA0MC41ODM1IDUwLjU4MzEgNDAuNzYxNiA0OS44NDA5IDQwLjc2MTZDNDkuMDAwMSA0MC43NjE2IDQ4LjM5NDkgNDAuNDcxNSA0Ny45OTA3IDM5LjkyMzdMNDcuOTg3NCAzOS45MTk0QzQ3LjUzNTYgMzkuMzQwMSA0Ny4zMTQ0IDM4LjUwNjIgNDcuMzE0NCAzNy40MDc0QzQ3LjMxNDQgMzYuMzMyMiA0Ny41NTQ0IDM1LjUxNzcgNDguMDA1OCAzNC45NTY4TDQ4LjAwNzggMzQuOTU0M0M0OC40NTM3IDM0LjM4MjUgNDkuMDYxOCAzNC4xMTIxIDQ5Ljg2MTQgMzQuMTEyMUM1MC41MjMgMzQuMTEyMSA1MS4wNDUxIDM0LjI2MTUgNTEuNDI3MiAzNC41NDA3QzUxLjc4ODQgMzQuODE5NCA1Mi4wNTMgMzUuMjQ0NyA1Mi4xODgxIDM1Ljg1NzFMNTIuMjIzOSAzNi4wMTk0SDU0Ljk1NDhMNTQuOTE3IDM1Ljc4MzVDNTQuNzA2MyAzNC40NjYgNTQuMTUzNiAzMy40NzAxIDUzLjI2MzQgMzIuODAxOUw1My4yNjAyIDMyLjc5OTVDNTIuMzk1MSAzMi4xNzU1IDUxLjI2MjEgMzEuODczNyA0OS44NjE0IDMxLjg3MzdaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNS43NTYxIDI4LjI3NTNIMjIuNzQ0TDE3IDQyLjcyNDdIMjAuMDE0MUwyMS4zNDI5IDM5LjIwNDlIMjcuMTU3MkwyOC40ODYgNDIuNzI0N0gzMS41MDAxTDI1Ljc1NjEgMjguMjc1M1pNMjIuMjEyNSAzNi45MDc2TDI0LjI1OTYgMzEuNDUzOUwyNi4yODg1IDM2LjkwNzZIMjIuMjEyNVoiIGZpbGw9IiMyMjI1MjkiLz48L3N2Zz4="
|
|
817
|
+
};
|
|
818
|
+
function parseCharsPerRepeat(size, fontSize, total) {
|
|
819
|
+
if (size === "cover") {
|
|
820
|
+
return 0;
|
|
821
|
+
} else if (typeof size === "string") {
|
|
822
|
+
if (size.endsWith("%")) {
|
|
823
|
+
const rate = Number(size.substring(0, size.length - 1)) / 100;
|
|
824
|
+
return Math.ceil(rate * total / fontSize);
|
|
825
|
+
} else if (size.endsWith("rem")) {
|
|
826
|
+
return Number(size.substring(0, size.length - 3));
|
|
827
|
+
} else {
|
|
828
|
+
return Math.ceil(Number(size) / fontSize);
|
|
829
|
+
}
|
|
830
|
+
} else {
|
|
831
|
+
return Math.ceil(size / fontSize);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
function parseStrokeWidthScale(strokeWidth, fontSize, total) {
|
|
835
|
+
if (typeof strokeWidth === "string") {
|
|
836
|
+
if (strokeWidth.endsWith("%")) {
|
|
837
|
+
return Number(strokeWidth.substring(0, strokeWidth.length - 1)) / 100;
|
|
838
|
+
} else if (strokeWidth.endsWith("rem")) {
|
|
839
|
+
const value = Number(strokeWidth.substring(0, strokeWidth.length - 3));
|
|
840
|
+
return value * fontSize / total;
|
|
841
|
+
} else {
|
|
842
|
+
return Number(strokeWidth) / total;
|
|
843
|
+
}
|
|
844
|
+
} else {
|
|
845
|
+
return strokeWidth / total;
|
|
944
846
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
847
|
+
}
|
|
848
|
+
function highlight(options = {}) {
|
|
849
|
+
const config = { ...defaultOptions, ...options };
|
|
850
|
+
const referPaths = modernPath2d.parseSvg(config.referImage);
|
|
851
|
+
const paths = [];
|
|
852
|
+
const clipRects = [];
|
|
853
|
+
return definePlugin({
|
|
854
|
+
name: "highlight",
|
|
855
|
+
paths,
|
|
856
|
+
update: (text) => {
|
|
857
|
+
paths.length = 0;
|
|
858
|
+
const { characters } = text;
|
|
859
|
+
let group;
|
|
860
|
+
const groups = [];
|
|
861
|
+
let prevStyle;
|
|
862
|
+
characters.forEach((character) => {
|
|
863
|
+
const style = character.computedStyle;
|
|
864
|
+
if (!isNone(style.highlightImage)) {
|
|
865
|
+
if (style.highlightSize !== "1rem" && prevStyle?.highlightImage === style.highlightImage && prevStyle?.highlightSize === style.highlightSize && prevStyle?.highlightStrokeWidth === style.highlightStrokeWidth && prevStyle?.highlightOverflow === style.highlightOverflow && group.length && group[0].boundingBox.top === character.boundingBox.top && group[0].fontSize === character.fontSize) {
|
|
866
|
+
group.push(character);
|
|
867
|
+
} else {
|
|
868
|
+
group = [];
|
|
869
|
+
group.push(character);
|
|
870
|
+
groups.push(group);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
prevStyle = style;
|
|
874
|
+
});
|
|
875
|
+
groups.filter((characters2) => characters2.length).map((characters2) => {
|
|
876
|
+
return {
|
|
877
|
+
style: characters2[0].computedStyle,
|
|
878
|
+
box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.glyphBox))
|
|
879
|
+
};
|
|
880
|
+
}).forEach((group2) => {
|
|
881
|
+
const { style, box: groupBox } = group2;
|
|
882
|
+
const { fontSize } = style;
|
|
883
|
+
const strokeWidthScale = parseStrokeWidthScale(style.highlightStrokeWidth, fontSize, groupBox.width);
|
|
884
|
+
const charsPerRepeat = parseCharsPerRepeat(style.highlightSize, fontSize, groupBox.width);
|
|
885
|
+
const highlightOverflow = isNone(style.highlightOverflow) ? charsPerRepeat ? "hidden" : "visible" : style.highlightOverflow;
|
|
886
|
+
const svg = modernPath2d.parseSvgToDom(style.highlightImage);
|
|
887
|
+
const svgPaths = modernPath2d.parseSvg(svg);
|
|
888
|
+
const box = modernPath2d.getPathsBoundingBox(svgPaths);
|
|
889
|
+
const referBoundingBox = modernPath2d.getPathsBoundingBox(referPaths);
|
|
890
|
+
const scale = {
|
|
891
|
+
x: charsPerRepeat ? fontSize * charsPerRepeat * (box.width / referBoundingBox.width) / box.width : groupBox.width * (box.width / referBoundingBox.width) / box.width,
|
|
892
|
+
y: groupBox.height * (box.height / referBoundingBox.height) / box.height
|
|
893
|
+
};
|
|
894
|
+
const styleScale = fontSize / box.width * 2;
|
|
895
|
+
const unitWidth = box.width * scale.x;
|
|
896
|
+
const total = Math.ceil(groupBox.width / unitWidth);
|
|
897
|
+
const offset = {
|
|
898
|
+
x: (box.left - referBoundingBox.left) * scale.x,
|
|
899
|
+
y: (box.top - referBoundingBox.top) * scale.y
|
|
900
|
+
};
|
|
901
|
+
const transform = new modernPath2d.Matrix3().translate(-box.left, -box.top).scale(scale.x, scale.y).translate(groupBox.left, groupBox.top).translate(offset.x, offset.y);
|
|
902
|
+
for (let i = 0; i < total; i++) {
|
|
903
|
+
const _transform = transform.clone().translate(i * unitWidth, 0);
|
|
904
|
+
svgPaths.forEach((original) => {
|
|
905
|
+
const path = original.clone().matrix(_transform);
|
|
906
|
+
if (path.style.strokeWidth) {
|
|
907
|
+
path.style.strokeWidth *= styleScale * strokeWidthScale;
|
|
908
|
+
}
|
|
909
|
+
if (path.style.strokeMiterlimit) {
|
|
910
|
+
path.style.strokeMiterlimit *= styleScale;
|
|
911
|
+
}
|
|
912
|
+
if (path.style.strokeDashoffset) {
|
|
913
|
+
path.style.strokeDashoffset *= styleScale;
|
|
914
|
+
}
|
|
915
|
+
if (path.style.strokeDasharray) {
|
|
916
|
+
path.style.strokeDasharray = path.style.strokeDasharray.map((v) => v * styleScale);
|
|
917
|
+
}
|
|
918
|
+
paths.push(path);
|
|
919
|
+
clipRects[paths.length - 1] = highlightOverflow === "hidden" ? new modernPath2d.BoundingBox(
|
|
920
|
+
groupBox.left,
|
|
921
|
+
groupBox.top - groupBox.height,
|
|
922
|
+
groupBox.width,
|
|
923
|
+
groupBox.height * 3
|
|
924
|
+
) : void 0;
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
},
|
|
929
|
+
renderOrder: -1,
|
|
930
|
+
render: (ctx, text) => {
|
|
931
|
+
paths.forEach((path, index) => {
|
|
932
|
+
drawPath({
|
|
933
|
+
ctx,
|
|
934
|
+
path,
|
|
935
|
+
clipRect: clipRects[index],
|
|
936
|
+
fontSize: text.computedStyle.fontSize
|
|
937
|
+
});
|
|
938
|
+
});
|
|
951
939
|
}
|
|
952
|
-
|
|
953
|
-
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
function parseScale(size, fontSize, total) {
|
|
944
|
+
if (size === "cover") {
|
|
945
|
+
return 1;
|
|
946
|
+
} else if (typeof size === "string") {
|
|
947
|
+
if (size.endsWith("%")) {
|
|
948
|
+
return Number(size.substring(0, size.length - 1)) / 100;
|
|
949
|
+
} else if (size.endsWith("rem")) {
|
|
950
|
+
const value = Number(size.substring(0, size.length - 3));
|
|
951
|
+
return value * fontSize / total;
|
|
952
|
+
} else {
|
|
953
|
+
return Number(size) / total;
|
|
954
954
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
955
|
+
} else {
|
|
956
|
+
return size / total;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
function listStyle() {
|
|
960
|
+
const paths = [];
|
|
961
|
+
return definePlugin({
|
|
962
|
+
name: "listStyle",
|
|
963
|
+
paths,
|
|
964
|
+
update: (text) => {
|
|
965
|
+
paths.length = 0;
|
|
966
|
+
const { paragraphs, computedStyle: style, fontSize } = text;
|
|
967
|
+
let listStyleSize = style.listStyleSize;
|
|
968
|
+
let image;
|
|
969
|
+
if (!isNone(style.listStyleImage)) {
|
|
970
|
+
image = style.listStyleImage;
|
|
971
|
+
} else if (!isNone(style.listStyleType)) {
|
|
972
|
+
const r = fontSize * 0.38 / 2;
|
|
973
|
+
listStyleSize = listStyleSize === "cover" ? r * 2 : listStyleSize;
|
|
974
|
+
switch (style.listStyleType) {
|
|
975
|
+
case "disc":
|
|
976
|
+
image = `<svg width="${r * 2}" height="${r * 2}" xmlns="http://www.w3.org/2000/svg">
|
|
977
|
+
<circle cx="${r}" cy="${r}" r="${r}" fill="${style.color}" />
|
|
978
|
+
</svg>`;
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
958
981
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
982
|
+
if (!image) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
const paddingLeft = fontSize * 0.45;
|
|
986
|
+
const imagePaths = modernPath2d.parseSvg(image);
|
|
987
|
+
const imageBox = modernPath2d.getPathsBoundingBox(imagePaths);
|
|
988
|
+
paragraphs.forEach((paragraph) => {
|
|
989
|
+
const box = paragraph.fragments[0]?.characters[0]?.getGlyphBoundingBox();
|
|
990
|
+
if (box) {
|
|
991
|
+
const scale = parseScale(listStyleSize, style.fontSize, box.height);
|
|
992
|
+
const reScale = box.height / imageBox.height * scale;
|
|
993
|
+
const m = new modernPath2d.Matrix3();
|
|
994
|
+
m.translate(-imageBox.left - imageBox.width, -imageBox.top);
|
|
995
|
+
m.scale(reScale, reScale);
|
|
996
|
+
m.translate(0, box.height / 2 - imageBox.height * reScale / 2);
|
|
997
|
+
m.translate(box.left - paddingLeft, box.top);
|
|
998
|
+
paths.push(...imagePaths.map((p) => p.clone().matrix(m)));
|
|
962
999
|
}
|
|
963
1000
|
});
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
}
|
|
967
|
-
draw(options) {
|
|
968
|
-
const { ctx } = options;
|
|
969
|
-
const { characters } = this._text;
|
|
970
|
-
characters.forEach((character) => {
|
|
971
|
-
character.drawTo(ctx);
|
|
972
|
-
});
|
|
973
|
-
return this;
|
|
974
|
-
}
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
975
1003
|
}
|
|
976
1004
|
|
|
977
1005
|
var __defProp = Object.defineProperty;
|
|
@@ -981,35 +1009,50 @@ var __publicField = (obj, key, value) => {
|
|
|
981
1009
|
return value;
|
|
982
1010
|
};
|
|
983
1011
|
const defaultTextStyles = {
|
|
984
|
-
|
|
985
|
-
|
|
1012
|
+
writingMode: "horizontal-tb",
|
|
1013
|
+
verticalAlign: "baseline",
|
|
1014
|
+
lineHeight: 1,
|
|
1015
|
+
letterSpacing: 0,
|
|
1016
|
+
// font
|
|
986
1017
|
fontSize: 14,
|
|
987
1018
|
fontWeight: "normal",
|
|
988
1019
|
fontFamily: "_fallback",
|
|
989
1020
|
fontStyle: "normal",
|
|
990
1021
|
fontKerning: "normal",
|
|
1022
|
+
// text
|
|
991
1023
|
textWrap: "wrap",
|
|
992
1024
|
textAlign: "start",
|
|
993
|
-
verticalAlign: "baseline",
|
|
994
1025
|
textTransform: "none",
|
|
1026
|
+
textOrientation: "mixed",
|
|
1027
|
+
// color
|
|
1028
|
+
color: "#000",
|
|
1029
|
+
backgroundColor: "rgba(0, 0, 0, 0)",
|
|
1030
|
+
// text
|
|
995
1031
|
textDecoration: "none",
|
|
1032
|
+
// textStroke
|
|
996
1033
|
textStrokeWidth: 0,
|
|
997
1034
|
textStrokeColor: "#000",
|
|
998
|
-
|
|
999
|
-
letterSpacing: 0,
|
|
1035
|
+
// shadow
|
|
1000
1036
|
shadowColor: "rgba(0, 0, 0, 0)",
|
|
1001
1037
|
shadowOffsetX: 0,
|
|
1002
1038
|
shadowOffsetY: 0,
|
|
1003
1039
|
shadowBlur: 0,
|
|
1004
|
-
|
|
1005
|
-
|
|
1040
|
+
// listStyle
|
|
1041
|
+
listStyleType: "none",
|
|
1042
|
+
listStyleImage: "none",
|
|
1043
|
+
listStyleSize: "cover",
|
|
1044
|
+
listStylePosition: "outside",
|
|
1045
|
+
// highlight
|
|
1046
|
+
highlightImage: "none",
|
|
1047
|
+
highlightSize: "cover",
|
|
1048
|
+
highlightStrokeWidth: "100%",
|
|
1049
|
+
highlightOverflow: "none"
|
|
1006
1050
|
};
|
|
1007
1051
|
class Text {
|
|
1008
1052
|
constructor(options = {}) {
|
|
1009
1053
|
__publicField(this, "content");
|
|
1010
1054
|
__publicField(this, "style");
|
|
1011
1055
|
__publicField(this, "effects");
|
|
1012
|
-
__publicField(this, "deformation");
|
|
1013
1056
|
__publicField(this, "measureDom");
|
|
1014
1057
|
__publicField(this, "needsUpdate", true);
|
|
1015
1058
|
__publicField(this, "computedStyle", { ...defaultTextStyles });
|
|
@@ -1018,16 +1061,13 @@ class Text {
|
|
|
1018
1061
|
__publicField(this, "renderBoundingBox", new modernPath2d.BoundingBox());
|
|
1019
1062
|
__publicField(this, "parser", new Parser(this));
|
|
1020
1063
|
__publicField(this, "measurer", new Measurer(this));
|
|
1021
|
-
__publicField(this, "
|
|
1022
|
-
|
|
1023
|
-
__publicField(this, "highlighter", new Highlighter(this));
|
|
1024
|
-
__publicField(this, "renderer2D", new Renderer2D(this));
|
|
1025
|
-
const { content = "", style = {}, effects, deformation, measureDom } = options;
|
|
1064
|
+
__publicField(this, "plugins", /* @__PURE__ */ new Map());
|
|
1065
|
+
const { content = "", style = {}, measureDom, effects } = options;
|
|
1026
1066
|
this.content = content;
|
|
1027
1067
|
this.style = style;
|
|
1028
|
-
this.effects = effects;
|
|
1029
|
-
this.deformation = deformation;
|
|
1030
1068
|
this.measureDom = measureDom;
|
|
1069
|
+
this.effects = effects;
|
|
1070
|
+
this.use(effect()).use(highlight(options.highlight)).use(listStyle());
|
|
1031
1071
|
}
|
|
1032
1072
|
get fontSize() {
|
|
1033
1073
|
return this.computedStyle.fontSize;
|
|
@@ -1035,6 +1075,10 @@ class Text {
|
|
|
1035
1075
|
get characters() {
|
|
1036
1076
|
return this.paragraphs.flatMap((p) => p.fragments.flatMap((f) => f.characters));
|
|
1037
1077
|
}
|
|
1078
|
+
use(plugin) {
|
|
1079
|
+
this.plugins.set(plugin.name, plugin);
|
|
1080
|
+
return this;
|
|
1081
|
+
}
|
|
1038
1082
|
measure(dom = this.measureDom) {
|
|
1039
1083
|
this.computedStyle = { ...defaultTextStyles, ...this.style };
|
|
1040
1084
|
const old = this.paragraphs;
|
|
@@ -1053,15 +1097,23 @@ class Text {
|
|
|
1053
1097
|
this.boundingBox = boundingBox;
|
|
1054
1098
|
const characters = this.characters;
|
|
1055
1099
|
characters.forEach((c) => c.update());
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
}
|
|
1100
|
+
const plugins = [...this.plugins.values()];
|
|
1101
|
+
plugins.sort((a, b) => (a.updateOrder ?? 0) - (b.updateOrder ?? 0)).forEach((plugin) => {
|
|
1102
|
+
plugin.update?.(this);
|
|
1103
|
+
});
|
|
1061
1104
|
const min = modernPath2d.Vector2.MAX;
|
|
1062
1105
|
const max = modernPath2d.Vector2.MIN;
|
|
1063
1106
|
characters.forEach((c) => c.getGlyphMinMax(min, max));
|
|
1064
1107
|
this.renderBoundingBox = new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
1108
|
+
this.renderBoundingBox = modernPath2d.BoundingBox.from(
|
|
1109
|
+
this.renderBoundingBox,
|
|
1110
|
+
...plugins.map((plugin) => {
|
|
1111
|
+
if (plugin.getBoundingBox) {
|
|
1112
|
+
return plugin.getBoundingBox(this);
|
|
1113
|
+
}
|
|
1114
|
+
return modernPath2d.getPathsBoundingBox(plugin.paths ?? []);
|
|
1115
|
+
}).filter(Boolean)
|
|
1116
|
+
);
|
|
1065
1117
|
return this;
|
|
1066
1118
|
}
|
|
1067
1119
|
render(options) {
|
|
@@ -1073,47 +1125,49 @@ class Text {
|
|
|
1073
1125
|
if (this.needsUpdate) {
|
|
1074
1126
|
this.update();
|
|
1075
1127
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
this.effector.draw({ ctx });
|
|
1093
|
-
} else {
|
|
1094
|
-
this.renderer2D.draw({ ctx });
|
|
1095
|
-
}
|
|
1128
|
+
setupView(ctx, pixelRatio, this.renderBoundingBox);
|
|
1129
|
+
uploadColors(ctx, this);
|
|
1130
|
+
const plugins = [...this.plugins.values()];
|
|
1131
|
+
plugins.sort((a, b) => (a.renderOrder ?? 0) - (b.renderOrder ?? 0)).forEach((plugin) => {
|
|
1132
|
+
if (plugin.render) {
|
|
1133
|
+
plugin.render?.(ctx, this);
|
|
1134
|
+
} else if (plugin.paths) {
|
|
1135
|
+
plugin.paths.forEach((path) => {
|
|
1136
|
+
drawPath({
|
|
1137
|
+
ctx,
|
|
1138
|
+
path,
|
|
1139
|
+
fontSize: this.computedStyle.fontSize
|
|
1140
|
+
});
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
});
|
|
1096
1144
|
return this;
|
|
1097
1145
|
}
|
|
1098
1146
|
}
|
|
1099
1147
|
|
|
1100
1148
|
exports.Character = Character;
|
|
1101
|
-
exports.Deformer = Deformer;
|
|
1102
|
-
exports.Effector = Effector;
|
|
1103
1149
|
exports.Fragment = Fragment;
|
|
1104
|
-
exports.Highlighter = Highlighter;
|
|
1105
1150
|
exports.Measurer = Measurer;
|
|
1106
1151
|
exports.Paragraph = Paragraph;
|
|
1107
1152
|
exports.Parser = Parser;
|
|
1108
|
-
exports.Reflector = Reflector;
|
|
1109
|
-
exports.Renderer2D = Renderer2D;
|
|
1110
1153
|
exports.Text = Text;
|
|
1111
|
-
exports.defaultHighlightRefer = defaultHighlightRefer;
|
|
1112
1154
|
exports.defaultTextStyles = defaultTextStyles;
|
|
1155
|
+
exports.definePlugin = definePlugin;
|
|
1113
1156
|
exports.drawPath = drawPath;
|
|
1157
|
+
exports.effect = effect;
|
|
1158
|
+
exports.fillBackground = fillBackground;
|
|
1114
1159
|
exports.filterEmpty = filterEmpty;
|
|
1160
|
+
exports.getTransform2D = getTransform2D;
|
|
1161
|
+
exports.highlight = highlight;
|
|
1162
|
+
exports.isNone = isNone;
|
|
1163
|
+
exports.listStyle = listStyle;
|
|
1115
1164
|
exports.parseColor = parseColor;
|
|
1165
|
+
exports.setupView = setupView;
|
|
1116
1166
|
exports.uploadColor = uploadColor;
|
|
1167
|
+
exports.uploadColors = uploadColors;
|
|
1168
|
+
Object.keys(modernPath2d).forEach(function (k) {
|
|
1169
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = modernPath2d[k];
|
|
1170
|
+
});
|
|
1117
1171
|
Object.keys(modernFont).forEach(function (k) {
|
|
1118
1172
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = modernFont[k];
|
|
1119
1173
|
});
|