modern-text 0.2.37 → 0.2.38
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 +175 -204
- package/dist/index.d.cts +12 -16
- package/dist/index.d.mts +12 -16
- package/dist/index.d.ts +12 -16
- package/dist/index.js +3 -3
- package/dist/index.mjs +176 -204
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -76,27 +76,6 @@ function drawPath(options) {
|
|
|
76
76
|
ctx.restore();
|
|
77
77
|
}
|
|
78
78
|
|
|
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
79
|
function setupView(ctx, pixelRatio, boundingBox) {
|
|
101
80
|
const { left, top, width, height } = boundingBox;
|
|
102
81
|
const view = ctx.canvas;
|
|
@@ -117,9 +96,9 @@ function uploadColors(ctx, text) {
|
|
|
117
96
|
const { paragraphs, computedStyle: style, renderBoundingBox } = text;
|
|
118
97
|
uploadColor(style, renderBoundingBox, ctx);
|
|
119
98
|
paragraphs.forEach((paragraph) => {
|
|
120
|
-
uploadColor(paragraph.computedStyle, paragraph.
|
|
99
|
+
uploadColor(paragraph.computedStyle, paragraph.lineBox, ctx);
|
|
121
100
|
paragraph.fragments.forEach((fragment) => {
|
|
122
|
-
uploadColor(fragment.computedStyle, fragment.
|
|
101
|
+
uploadColor(fragment.computedStyle, fragment.inlineBox, ctx);
|
|
123
102
|
});
|
|
124
103
|
});
|
|
125
104
|
}
|
|
@@ -161,13 +140,9 @@ class Character {
|
|
|
161
140
|
this.content = content;
|
|
162
141
|
this.index = index;
|
|
163
142
|
this.parent = parent;
|
|
164
|
-
|
|
165
|
-
__publicField$3(this, "
|
|
166
|
-
__publicField$3(this, "
|
|
167
|
-
__publicField$3(this, "textHeight", 0);
|
|
168
|
-
// font glyph
|
|
169
|
-
__publicField$3(this, "glyphHeight", 0);
|
|
170
|
-
__publicField$3(this, "glyphWidth", 0);
|
|
143
|
+
__publicField$3(this, "lineBox", new modernPath2d.BoundingBox());
|
|
144
|
+
__publicField$3(this, "inlineBox", new modernPath2d.BoundingBox());
|
|
145
|
+
__publicField$3(this, "glyphBox", new modernPath2d.BoundingBox());
|
|
171
146
|
__publicField$3(this, "underlinePosition", 0);
|
|
172
147
|
__publicField$3(this, "underlineThickness", 0);
|
|
173
148
|
__publicField$3(this, "yStrikeoutPosition", 0);
|
|
@@ -175,7 +150,6 @@ class Character {
|
|
|
175
150
|
__publicField$3(this, "baseline", 0);
|
|
176
151
|
__publicField$3(this, "centerDiviation", 0);
|
|
177
152
|
__publicField$3(this, "path", new modernPath2d.Path2D());
|
|
178
|
-
__publicField$3(this, "glyphBox", new modernPath2d.BoundingBox());
|
|
179
153
|
__publicField$3(this, "center", new modernPath2d.Vector2());
|
|
180
154
|
}
|
|
181
155
|
get computedStyle() {
|
|
@@ -187,6 +161,9 @@ class Character {
|
|
|
187
161
|
get fontSize() {
|
|
188
162
|
return this.computedStyle.fontSize;
|
|
189
163
|
}
|
|
164
|
+
get fontHeight() {
|
|
165
|
+
return this.fontSize * this.computedStyle.lineHeight;
|
|
166
|
+
}
|
|
190
167
|
_font() {
|
|
191
168
|
const font = modernFont.fonts.get(this.computedStyle.fontFamily)?.font;
|
|
192
169
|
if (font instanceof modernFont.Woff || font instanceof modernFont.Ttf) {
|
|
@@ -199,25 +176,24 @@ class Character {
|
|
|
199
176
|
return this;
|
|
200
177
|
}
|
|
201
178
|
const { unitsPerEm, ascender, descender, os2, post } = font;
|
|
202
|
-
const { content, computedStyle
|
|
203
|
-
const { height } = boundingBox;
|
|
179
|
+
const { content, computedStyle } = this;
|
|
204
180
|
const { fontSize } = computedStyle;
|
|
205
181
|
const rate = unitsPerEm / fontSize;
|
|
206
|
-
const
|
|
207
|
-
const
|
|
182
|
+
const advanceWidth = font.getAdvanceWidth(content, fontSize);
|
|
183
|
+
const advanceHeight = (ascender + Math.abs(descender)) / rate;
|
|
208
184
|
const baseline = ascender / rate;
|
|
209
185
|
const yStrikeoutPosition = (ascender - os2.yStrikeoutPosition) / rate;
|
|
210
186
|
const yStrikeoutSize = os2.yStrikeoutSize / rate;
|
|
211
187
|
const underlinePosition = (ascender - post.underlinePosition) / rate;
|
|
212
188
|
const underlineThickness = post.underlineThickness / rate;
|
|
213
|
-
this.
|
|
214
|
-
this.
|
|
189
|
+
this.inlineBox.width = advanceWidth;
|
|
190
|
+
this.inlineBox.height = advanceHeight;
|
|
215
191
|
this.underlinePosition = underlinePosition;
|
|
216
192
|
this.underlineThickness = underlineThickness;
|
|
217
193
|
this.yStrikeoutPosition = yStrikeoutPosition;
|
|
218
194
|
this.yStrikeoutSize = yStrikeoutSize;
|
|
219
195
|
this.baseline = baseline;
|
|
220
|
-
this.centerDiviation =
|
|
196
|
+
this.centerDiviation = advanceHeight / 2 - baseline;
|
|
221
197
|
return this;
|
|
222
198
|
}
|
|
223
199
|
updatePath() {
|
|
@@ -228,45 +204,39 @@ class Character {
|
|
|
228
204
|
const {
|
|
229
205
|
isVertical,
|
|
230
206
|
content,
|
|
231
|
-
textWidth,
|
|
232
|
-
textHeight,
|
|
233
|
-
boundingBox,
|
|
234
207
|
computedStyle,
|
|
235
208
|
baseline,
|
|
236
|
-
|
|
237
|
-
glyphWidth
|
|
209
|
+
inlineBox
|
|
238
210
|
} = this.updateGlyph(font);
|
|
239
211
|
const { os2, ascender, descender } = font;
|
|
240
|
-
const usWinAscent = ascender;
|
|
241
|
-
const usWinDescent = descender;
|
|
242
212
|
const typoAscender = os2.sTypoAscender;
|
|
243
|
-
const { left, top } =
|
|
213
|
+
const { left, top } = inlineBox;
|
|
244
214
|
const { fontSize, fontStyle } = computedStyle;
|
|
245
215
|
let x = left;
|
|
246
216
|
let y = top + baseline;
|
|
247
217
|
let glyphIndex;
|
|
248
218
|
const path = new modernPath2d.Path2D();
|
|
249
219
|
if (isVertical) {
|
|
250
|
-
x += (
|
|
251
|
-
if (Math.abs(
|
|
252
|
-
y -= (
|
|
220
|
+
x += (inlineBox.height - inlineBox.width) / 2;
|
|
221
|
+
if (Math.abs(inlineBox.width - inlineBox.height) > 0.1) {
|
|
222
|
+
y -= (ascender - typoAscender) / (ascender + Math.abs(descender)) * inlineBox.height;
|
|
253
223
|
}
|
|
254
224
|
glyphIndex = void 0;
|
|
255
225
|
}
|
|
256
226
|
if (isVertical && !set1.has(content) && (content.codePointAt(0) <= 256 || set2.has(content))) {
|
|
257
227
|
path.addCommands(
|
|
258
|
-
font.getPathCommands(content, x, top + baseline - (
|
|
228
|
+
font.getPathCommands(content, x, top + baseline - (inlineBox.height - inlineBox.width) / 2, fontSize) ?? []
|
|
259
229
|
);
|
|
260
230
|
const point = {
|
|
261
|
-
y: top - (
|
|
262
|
-
x: x +
|
|
231
|
+
y: top - (inlineBox.height - inlineBox.width) / 2 + inlineBox.height / 2,
|
|
232
|
+
x: x + inlineBox.width / 2
|
|
263
233
|
};
|
|
264
234
|
if (fontStyle === "italic") {
|
|
265
235
|
this._italic(
|
|
266
236
|
path,
|
|
267
237
|
isVertical ? {
|
|
268
238
|
x: point.x,
|
|
269
|
-
y: top - (
|
|
239
|
+
y: top - (inlineBox.height - inlineBox.width) / 2 + baseline
|
|
270
240
|
} : void 0
|
|
271
241
|
);
|
|
272
242
|
}
|
|
@@ -280,8 +250,8 @@ class Character {
|
|
|
280
250
|
this._italic(
|
|
281
251
|
path,
|
|
282
252
|
isVertical ? {
|
|
283
|
-
x: x +
|
|
284
|
-
y: top + typoAscender / (
|
|
253
|
+
x: x + inlineBox.width / 2,
|
|
254
|
+
y: top + typoAscender / (ascender + Math.abs(descender)) * inlineBox.height
|
|
285
255
|
} : void 0
|
|
286
256
|
);
|
|
287
257
|
}
|
|
@@ -292,7 +262,7 @@ class Character {
|
|
|
292
262
|
if (fontStyle === "italic") {
|
|
293
263
|
this._italic(
|
|
294
264
|
path,
|
|
295
|
-
isVertical ? { x: x +
|
|
265
|
+
isVertical ? { x: x + inlineBox.height / 2, y } : void 0
|
|
296
266
|
);
|
|
297
267
|
}
|
|
298
268
|
}
|
|
@@ -319,7 +289,7 @@ class Character {
|
|
|
319
289
|
_decoration() {
|
|
320
290
|
const { isVertical, underlinePosition, yStrikeoutPosition } = this;
|
|
321
291
|
const { textDecoration, fontSize } = this.computedStyle;
|
|
322
|
-
const { left, top, width, height } = this.
|
|
292
|
+
const { left, top, width, height } = this.inlineBox;
|
|
323
293
|
const lineWidth = 0.1 * fontSize;
|
|
324
294
|
let start;
|
|
325
295
|
switch (textDecoration) {
|
|
@@ -361,8 +331,8 @@ class Character {
|
|
|
361
331
|
}
|
|
362
332
|
_italic(path, startPoint) {
|
|
363
333
|
path.skew(-0.24, 0, startPoint || {
|
|
364
|
-
y: this.
|
|
365
|
-
x: this.
|
|
334
|
+
y: this.inlineBox.top + this.baseline,
|
|
335
|
+
x: this.inlineBox.left + this.inlineBox.width / 2
|
|
366
336
|
});
|
|
367
337
|
}
|
|
368
338
|
getGlyphMinMax(min, max, withStyle) {
|
|
@@ -371,9 +341,7 @@ class Character {
|
|
|
371
341
|
} else {
|
|
372
342
|
min ?? (min = modernPath2d.Vector2.MAX);
|
|
373
343
|
max ?? (max = modernPath2d.Vector2.MIN);
|
|
374
|
-
const { left, top } = this.
|
|
375
|
-
const right = left + this.glyphWidth;
|
|
376
|
-
const bottom = top + this.glyphHeight;
|
|
344
|
+
const { left, top, right, bottom } = this.inlineBox;
|
|
377
345
|
min.x = Math.min(min.x, left);
|
|
378
346
|
min.y = Math.min(min.y, top);
|
|
379
347
|
max.x = Math.max(max.x, right);
|
|
@@ -422,7 +390,7 @@ class Fragment {
|
|
|
422
390
|
this.content = content;
|
|
423
391
|
this.style = style;
|
|
424
392
|
this.parent = parent;
|
|
425
|
-
__publicField$2(this, "
|
|
393
|
+
__publicField$2(this, "inlineBox", new modernPath2d.BoundingBox());
|
|
426
394
|
this.updateComputedStyle().initCharacters();
|
|
427
395
|
}
|
|
428
396
|
get computedContent() {
|
|
@@ -457,7 +425,7 @@ class Paragraph {
|
|
|
457
425
|
constructor(style, parentStyle) {
|
|
458
426
|
this.style = style;
|
|
459
427
|
this.parentStyle = parentStyle;
|
|
460
|
-
__publicField$1(this, "
|
|
428
|
+
__publicField$1(this, "lineBox", new modernPath2d.BoundingBox());
|
|
461
429
|
__publicField$1(this, "fragments", []);
|
|
462
430
|
this.updateComputedStyle();
|
|
463
431
|
}
|
|
@@ -559,7 +527,7 @@ class Measurer {
|
|
|
559
527
|
height: pBox.height
|
|
560
528
|
});
|
|
561
529
|
li.querySelectorAll("span").forEach((span, fragmentIndex) => {
|
|
562
|
-
const fBox =
|
|
530
|
+
const fBox = span.getBoundingClientRect();
|
|
563
531
|
fragments.push({
|
|
564
532
|
paragraphIndex,
|
|
565
533
|
fragmentIndex,
|
|
@@ -612,64 +580,43 @@ class Measurer {
|
|
|
612
580
|
measureDom(dom) {
|
|
613
581
|
const { paragraphs } = this._text;
|
|
614
582
|
const rect = dom.getBoundingClientRect();
|
|
615
|
-
const innerEl = dom.querySelector("ul");
|
|
616
|
-
const isVertical = window.getComputedStyle(dom).writingMode.includes("vertical");
|
|
617
|
-
const oldLineHeight = innerEl.style.lineHeight;
|
|
618
|
-
innerEl.style.lineHeight = "4000px";
|
|
619
|
-
const _paragraphs = [[]];
|
|
620
|
-
let fragments = _paragraphs[0];
|
|
621
|
-
const { characters: oldCharacters } = this._measureDom(dom);
|
|
622
|
-
if (oldCharacters.length > 0) {
|
|
623
|
-
fragments.push(oldCharacters[0]);
|
|
624
|
-
oldCharacters.reduce((prev, current) => {
|
|
625
|
-
const attr = isVertical ? "left" : "top";
|
|
626
|
-
if (Math.abs(current[attr] - prev[attr]) > 4e3 / 2) {
|
|
627
|
-
fragments = [];
|
|
628
|
-
_paragraphs.push(fragments);
|
|
629
|
-
}
|
|
630
|
-
fragments.push(current);
|
|
631
|
-
return current;
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
innerEl.style.lineHeight = oldLineHeight;
|
|
635
583
|
const measured = this._measureDom(dom);
|
|
636
584
|
measured.paragraphs.forEach((p) => {
|
|
637
585
|
const _p = paragraphs[p.paragraphIndex];
|
|
638
|
-
_p.
|
|
639
|
-
_p.
|
|
640
|
-
_p.
|
|
641
|
-
_p.
|
|
586
|
+
_p.lineBox.left = p.left - rect.left;
|
|
587
|
+
_p.lineBox.top = p.top - rect.top;
|
|
588
|
+
_p.lineBox.width = p.width;
|
|
589
|
+
_p.lineBox.height = p.height;
|
|
642
590
|
});
|
|
643
591
|
measured.fragments.forEach((f) => {
|
|
644
592
|
const _f = paragraphs[f.paragraphIndex].fragments[f.fragmentIndex];
|
|
645
|
-
_f.
|
|
646
|
-
_f.
|
|
647
|
-
_f.
|
|
648
|
-
_f.
|
|
593
|
+
_f.inlineBox.left = f.left - rect.left;
|
|
594
|
+
_f.inlineBox.top = f.top - rect.top;
|
|
595
|
+
_f.inlineBox.width = f.width;
|
|
596
|
+
_f.inlineBox.height = f.height;
|
|
649
597
|
});
|
|
650
598
|
const results = [];
|
|
651
599
|
let i = 0;
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
textWidth: oldCharacter.width,
|
|
660
|
-
textHeight: oldCharacter.height,
|
|
661
|
-
left: character.left - rect.left,
|
|
662
|
-
top: character.top - rect.top
|
|
663
|
-
});
|
|
664
|
-
const item = paragraphs[paragraphIndex].fragments[fragmentIndex].characters[characterIndex];
|
|
665
|
-
item.boundingBox.left = results[i].left;
|
|
666
|
-
item.boundingBox.top = results[i].top;
|
|
667
|
-
item.boundingBox.width = results[i].width;
|
|
668
|
-
item.boundingBox.height = results[i].height;
|
|
669
|
-
item.textWidth = results[i].textWidth;
|
|
670
|
-
item.textHeight = results[i].textHeight;
|
|
671
|
-
i++;
|
|
600
|
+
measured.characters.forEach((character) => {
|
|
601
|
+
const { paragraphIndex, fragmentIndex, characterIndex } = character;
|
|
602
|
+
results.push({
|
|
603
|
+
...character,
|
|
604
|
+
newParagraphIndex: paragraphIndex,
|
|
605
|
+
left: character.left - rect.left,
|
|
606
|
+
top: character.top - rect.top
|
|
672
607
|
});
|
|
608
|
+
const item = paragraphs[paragraphIndex].fragments[fragmentIndex].characters[characterIndex];
|
|
609
|
+
const result = results[i];
|
|
610
|
+
item.inlineBox.left = result.left;
|
|
611
|
+
item.inlineBox.top = result.top;
|
|
612
|
+
item.inlineBox.width = result.width;
|
|
613
|
+
item.inlineBox.height = result.height;
|
|
614
|
+
const fontHeight = item.fontHeight;
|
|
615
|
+
item.lineBox.left = result.left;
|
|
616
|
+
item.lineBox.top = result.top + (result.height - fontHeight) / 2;
|
|
617
|
+
item.lineBox.height = fontHeight;
|
|
618
|
+
item.lineBox.width = result.width;
|
|
619
|
+
i++;
|
|
673
620
|
});
|
|
674
621
|
return {
|
|
675
622
|
paragraphs,
|
|
@@ -746,82 +693,6 @@ function definePlugin(options) {
|
|
|
746
693
|
return options;
|
|
747
694
|
}
|
|
748
695
|
|
|
749
|
-
const tempV1 = new modernPath2d.Vector2();
|
|
750
|
-
const tempM1 = new modernPath2d.Matrix3();
|
|
751
|
-
const tempM2 = new modernPath2d.Matrix3();
|
|
752
|
-
function effect() {
|
|
753
|
-
return definePlugin({
|
|
754
|
-
name: "effect",
|
|
755
|
-
getBoundingBox: (text) => {
|
|
756
|
-
const { characters, fontSize, effects } = text;
|
|
757
|
-
const boxes = [];
|
|
758
|
-
characters.forEach((character) => {
|
|
759
|
-
effects?.forEach((style) => {
|
|
760
|
-
const aabb = character.glyphBox.clone();
|
|
761
|
-
const m = getTransform2D(text, style);
|
|
762
|
-
tempV1.set(aabb.left, aabb.top);
|
|
763
|
-
tempV1.applyMatrix3(m);
|
|
764
|
-
aabb.left = tempV1.x;
|
|
765
|
-
aabb.top = tempV1.y;
|
|
766
|
-
tempV1.set(aabb.right, aabb.bottom);
|
|
767
|
-
tempV1.applyMatrix3(m);
|
|
768
|
-
aabb.width = tempV1.x - aabb.left;
|
|
769
|
-
aabb.height = tempV1.y - aabb.top;
|
|
770
|
-
const shadowOffsetX = (style.shadowOffsetX ?? 0) * fontSize;
|
|
771
|
-
const shadowOffsetY = (style.shadowOffsetY ?? 0) * fontSize;
|
|
772
|
-
const textStrokeWidth = Math.max(0.1, style.textStrokeWidth ?? 0) * fontSize;
|
|
773
|
-
aabb.left += shadowOffsetX - textStrokeWidth;
|
|
774
|
-
aabb.top += shadowOffsetY - textStrokeWidth;
|
|
775
|
-
aabb.width += textStrokeWidth * 2;
|
|
776
|
-
aabb.height += textStrokeWidth * 2;
|
|
777
|
-
boxes.push(aabb);
|
|
778
|
-
});
|
|
779
|
-
});
|
|
780
|
-
return boxes.length ? modernPath2d.BoundingBox.from(...boxes) : void 0;
|
|
781
|
-
},
|
|
782
|
-
render: (ctx, text) => {
|
|
783
|
-
const { characters, renderBoundingBox, effects } = text;
|
|
784
|
-
if (effects) {
|
|
785
|
-
effects.forEach((style) => {
|
|
786
|
-
uploadColor(style, renderBoundingBox, ctx);
|
|
787
|
-
ctx.save();
|
|
788
|
-
const [a, c, e, b, d, f] = getTransform2D(text, style).transpose().elements;
|
|
789
|
-
ctx.transform(a, b, c, d, e, f);
|
|
790
|
-
characters.forEach((character) => {
|
|
791
|
-
character.drawTo(ctx, style);
|
|
792
|
-
});
|
|
793
|
-
ctx.restore();
|
|
794
|
-
});
|
|
795
|
-
} else {
|
|
796
|
-
characters.forEach((character) => {
|
|
797
|
-
character.drawTo(ctx);
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
function getTransform2D(text, style) {
|
|
804
|
-
const { fontSize, renderBoundingBox } = text;
|
|
805
|
-
const offsetX = (style.offsetX ?? 0) * fontSize;
|
|
806
|
-
const offsetY = (style.offsetY ?? 0) * fontSize;
|
|
807
|
-
const PI_2 = Math.PI * 2;
|
|
808
|
-
const skewX = (style.skewX ?? 0) / 360 * PI_2;
|
|
809
|
-
const skewY = (style.skewY ?? 0) / 360 * PI_2;
|
|
810
|
-
const { left, top, width, height } = renderBoundingBox;
|
|
811
|
-
const centerX = left + width / 2;
|
|
812
|
-
const centerY = top + height / 2;
|
|
813
|
-
tempM1.identity();
|
|
814
|
-
tempM2.makeTranslation(offsetX, offsetY);
|
|
815
|
-
tempM1.multiply(tempM2);
|
|
816
|
-
tempM2.makeTranslation(centerX, centerY);
|
|
817
|
-
tempM1.multiply(tempM2);
|
|
818
|
-
tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
|
|
819
|
-
tempM1.multiply(tempM2);
|
|
820
|
-
tempM2.makeTranslation(-centerX, -centerY);
|
|
821
|
-
tempM1.multiply(tempM2);
|
|
822
|
-
return tempM1.clone();
|
|
823
|
-
}
|
|
824
|
-
|
|
825
696
|
const defaultReferImage = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIiBmaWxsPSJub25lIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMyLjQwMjkgMjhIMzUuMTU5NFYzMy4xNzcxQzM1Ljk4MjEgMzIuMzExNSAzNi45NzEgMzEuODczNyAzOC4wOTQ4IDMxLjg3MzdDMzkuNjY3NiAzMS44NzM3IDQwLjkxNjYgMzIuNDI5NSA0MS44MzkgMzMuNTQzN0w0MS44NDAzIDMzLjU0NTNDNDIuNjcxNyAzNC41NzA1IDQzLjA5MTUgMzUuODU1OSA0My4wOTE1IDM3LjM4NzdDNDMuMDkxNSAzOC45NzYxIDQyLjY3MjkgNDAuMzAyOCA0MS44MTgzIDQxLjMzMDRMNDEuODE3MSA0MS4zMzE4QzQwLjg3MzEgNDIuNDQ2MSAzOS41ODMyIDQzIDM3Ljk3MjEgNDNDMzYuNzQ3NyA0MyAzNS43NDg4IDQyLjY1OTkgMzQuOTk1OCA0MS45NjkzVjQyLjcyNDdIMzIuNDAyOVYyOFpNMzcuNTQyOCAzNC4wOTI0QzM2Ljg1NDkgMzQuMDkyNCAzNi4zMDE0IDM0LjM1NjEgMzUuODQ4NyAzNC45MDA0TDM1Ljg0NTIgMzQuOTA0NkMzNS4zMzU4IDM1LjQ4NTMgMzUuMDc3NiAzNi4yOTc2IDM1LjA3NzYgMzcuMzQ4NFYzNy41MDU3QzM1LjA3NzYgMzguNDY0IDM1LjI3NzIgMzkuMjQ0MyAzNS42OTQzIDM5LjgyNzlDMzYuMTQ0MSA0MC40NTg3IDM2Ljc3MjYgNDAuNzgxMyAzNy42MjQ1IDQwLjc4MTNDMzguNTg3NCA0MC43ODEzIDM5LjI3MDcgNDAuNDUyNyAzOS43MTUyIDM5LjgxMjdDNDAuMDcyOCAzOS4yNjg0IDQwLjI3MzcgMzguNDY3MyA0MC4yNzM3IDM3LjM4NzdDNDAuMjczNyAzNi4zMTA1IDQwLjA1MzMgMzUuNTMxMyAzOS42NzgzIDM1LjAwNzdDMzkuMjM3MSAzNC40MDcxIDM4LjUzNDIgMzQuMDkyNCAzNy41NDI4IDM0LjA5MjRaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZD0iTTQ5Ljg2MTQgMzEuODczN0M0OC4xNTM1IDMxLjg3MzcgNDYuODAxNiAzMi40MjM5IDQ1LjgzNDggMzMuNTM5MkM0NC45MzcgMzQuNTQ3MiA0NC40OTY2IDM1Ljg1NiA0NC40OTY2IDM3LjQyN0M0NC40OTY2IDM5LjAzNjggNDQuOTM2NyA0MC4zNjU5IDQ1Ljg1NTkgNDEuMzk0M0M0Ni44MDMxIDQyLjQ3MDYgNDguMTM0OCA0MyA0OS44MjA1IDQzQzUxLjIyNiA0MyA1Mi4zODI2IDQyLjY1NjMgNTMuMjQ3OSA0MS45Njk3QzU0LjEzNTkgNDEuMjYxNCA1NC43MDYxIDQwLjE4ODcgNTQuOTU3MyAzOC43NzkxTDU1IDM4LjUzOTdINTIuMjQ4NEw1Mi4yMjU5IDM4LjcyMDFDNTIuMTM3OSAzOS40MjUxIDUxLjg5MjUgMzkuOTI3OCA1MS41MTA5IDQwLjI1NThDNTEuMTI5NSA0MC41ODM1IDUwLjU4MzEgNDAuNzYxNiA0OS44NDA5IDQwLjc2MTZDNDkuMDAwMSA0MC43NjE2IDQ4LjM5NDkgNDAuNDcxNSA0Ny45OTA3IDM5LjkyMzdMNDcuOTg3NCAzOS45MTk0QzQ3LjUzNTYgMzkuMzQwMSA0Ny4zMTQ0IDM4LjUwNjIgNDcuMzE0NCAzNy40MDc0QzQ3LjMxNDQgMzYuMzMyMiA0Ny41NTQ0IDM1LjUxNzcgNDguMDA1OCAzNC45NTY4TDQ4LjAwNzggMzQuOTU0M0M0OC40NTM3IDM0LjM4MjUgNDkuMDYxOCAzNC4xMTIxIDQ5Ljg2MTQgMzQuMTEyMUM1MC41MjMgMzQuMTEyMSA1MS4wNDUxIDM0LjI2MTUgNTEuNDI3MiAzNC41NDA3QzUxLjc4ODQgMzQuODE5NCA1Mi4wNTMgMzUuMjQ0NyA1Mi4xODgxIDM1Ljg1NzFMNTIuMjIzOSAzNi4wMTk0SDU0Ljk1NDhMNTQuOTE3IDM1Ljc4MzVDNTQuNzA2MyAzNC40NjYgNTQuMTUzNiAzMy40NzAxIDUzLjI2MzQgMzIuODAxOUw1My4yNjAyIDMyLjc5OTVDNTIuMzk1MSAzMi4xNzU1IDUxLjI2MjEgMzEuODczNyA0OS44NjE0IDMxLjg3MzdaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNS43NTYxIDI4LjI3NTNIMjIuNzQ0TDE3IDQyLjcyNDdIMjAuMDE0MUwyMS4zNDI5IDM5LjIwNDlIMjcuMTU3MkwyOC40ODYgNDIuNzI0N0gzMS41MDAxTDI1Ljc1NjEgMjguMjc1M1pNMjIuMjEyNSAzNi45MDc2TDI0LjI1OTYgMzEuNDUzOUwyNi4yODg1IDM2LjkwNzZIMjIuMjEyNVoiIGZpbGw9IiMyMjI1MjkiLz48L3N2Zz4=";
|
|
826
697
|
function parseCharsPerRepeat(size, fontSize, total) {
|
|
827
698
|
if (size === "cover") {
|
|
@@ -855,22 +726,22 @@ function parseStrokeWidthScale(strokeWidth, fontSize, total) {
|
|
|
855
726
|
}
|
|
856
727
|
function getTransformMatrix(a, b, c, isVertical) {
|
|
857
728
|
let scale;
|
|
858
|
-
if (isVertical) {
|
|
729
|
+
if (!isVertical) {
|
|
859
730
|
scale = {
|
|
860
|
-
x: c.width / b.
|
|
861
|
-
y: c.height / b.
|
|
731
|
+
x: c.width / b.width,
|
|
732
|
+
y: c.height / b.height
|
|
862
733
|
};
|
|
863
734
|
} else {
|
|
864
735
|
scale = {
|
|
865
|
-
x: c.width / b.
|
|
866
|
-
y: c.height / b.
|
|
736
|
+
x: c.width / b.height,
|
|
737
|
+
y: c.height / b.width
|
|
867
738
|
};
|
|
868
739
|
}
|
|
869
740
|
const offset = c.getCenterPoint().add(
|
|
870
741
|
a.getCenterPoint().sub(b.getCenterPoint()).scale(scale.x, scale.y)
|
|
871
742
|
).sub({
|
|
872
|
-
x: a.width * scale.x
|
|
873
|
-
y: a.height * scale.y
|
|
743
|
+
x: a.width / 2 * scale.x,
|
|
744
|
+
y: a.height / 2 * scale.y
|
|
874
745
|
});
|
|
875
746
|
const m = new modernPath2d.Matrix3();
|
|
876
747
|
m.translate(-a.left, -a.top);
|
|
@@ -907,7 +778,7 @@ function highlight() {
|
|
|
907
778
|
characters.forEach((character) => {
|
|
908
779
|
const { isVertical, computedStyle: style } = character;
|
|
909
780
|
if (!isNone(style.highlightImage)) {
|
|
910
|
-
if (style.highlightSize !== "1rem" && prevStyle?.highlightImage === style.highlightImage && prevStyle?.highlightSize === style.highlightSize && prevStyle?.highlightStrokeWidth === style.highlightStrokeWidth && prevStyle?.highlightOverflow === style.highlightOverflow && group.length && (isVertical ? group[0].
|
|
781
|
+
if (style.highlightSize !== "1rem" && prevStyle?.highlightImage === style.highlightImage && prevStyle?.highlightSize === style.highlightSize && prevStyle?.highlightStrokeWidth === style.highlightStrokeWidth && prevStyle?.highlightOverflow === style.highlightOverflow && group.length && (isVertical ? group[0].inlineBox.left === character.inlineBox.left : group[0].inlineBox.top === character.inlineBox.top) && group[0].fontSize === character.fontSize) {
|
|
911
782
|
group.push(character);
|
|
912
783
|
} else {
|
|
913
784
|
group = [];
|
|
@@ -918,12 +789,14 @@ function highlight() {
|
|
|
918
789
|
prevStyle = style;
|
|
919
790
|
});
|
|
920
791
|
groups.filter((characters2) => characters2.length).map((characters2) => {
|
|
792
|
+
const char = characters2[0];
|
|
921
793
|
return {
|
|
922
|
-
style:
|
|
794
|
+
style: char.computedStyle,
|
|
795
|
+
baseline: char.baseline,
|
|
923
796
|
box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.glyphBox))
|
|
924
797
|
};
|
|
925
798
|
}).forEach((group2) => {
|
|
926
|
-
const { style, box: groupBox } = group2;
|
|
799
|
+
const { style, box: groupBox, baseline } = group2;
|
|
927
800
|
const { fontSize, writingMode } = style;
|
|
928
801
|
const isVertical = writingMode.includes("vertical");
|
|
929
802
|
const strokeWidthScale = parseStrokeWidthScale(style.highlightStrokeWidth, fontSize, groupBox.width);
|
|
@@ -933,11 +806,12 @@ function highlight() {
|
|
|
933
806
|
const svgPaths = getPaths(style.highlightImage);
|
|
934
807
|
const box = modernPath2d.getPathsBoundingBox(svgPaths, true);
|
|
935
808
|
const refBox = modernPath2d.getPathsBoundingBox(refPaths, false);
|
|
936
|
-
const unitWidth = charsPerRepeat ? fontSize * charsPerRepeat : groupBox.width;
|
|
809
|
+
const unitWidth = charsPerRepeat ? fontSize * charsPerRepeat : isVertical ? groupBox.height : groupBox.width;
|
|
810
|
+
const unitHeight = baseline * 0.8;
|
|
937
811
|
const transform = getTransformMatrix(
|
|
938
812
|
box,
|
|
939
813
|
refBox,
|
|
940
|
-
new modernPath2d.BoundingBox(groupBox.left, groupBox.top, unitWidth,
|
|
814
|
+
new modernPath2d.BoundingBox(groupBox.left, groupBox.top, isVertical ? unitHeight : unitWidth, isVertical ? unitWidth : unitHeight),
|
|
941
815
|
isVertical
|
|
942
816
|
);
|
|
943
817
|
const styleScale = fontSize / box.width * 2;
|
|
@@ -1056,6 +930,104 @@ function listStyle() {
|
|
|
1056
930
|
});
|
|
1057
931
|
}
|
|
1058
932
|
|
|
933
|
+
const tempV1 = new modernPath2d.Vector2();
|
|
934
|
+
const tempM1 = new modernPath2d.Matrix3();
|
|
935
|
+
const tempM2 = new modernPath2d.Matrix3();
|
|
936
|
+
function render() {
|
|
937
|
+
return definePlugin({
|
|
938
|
+
name: "render",
|
|
939
|
+
getBoundingBox: (text) => {
|
|
940
|
+
const { characters, fontSize, effects } = text;
|
|
941
|
+
const boxes = [];
|
|
942
|
+
characters.forEach((character) => {
|
|
943
|
+
effects?.forEach((style) => {
|
|
944
|
+
const aabb = character.glyphBox.clone();
|
|
945
|
+
const m = getTransform2D(text, style);
|
|
946
|
+
tempV1.set(aabb.left, aabb.top);
|
|
947
|
+
tempV1.applyMatrix3(m);
|
|
948
|
+
aabb.left = tempV1.x;
|
|
949
|
+
aabb.top = tempV1.y;
|
|
950
|
+
tempV1.set(aabb.right, aabb.bottom);
|
|
951
|
+
tempV1.applyMatrix3(m);
|
|
952
|
+
aabb.width = tempV1.x - aabb.left;
|
|
953
|
+
aabb.height = tempV1.y - aabb.top;
|
|
954
|
+
const shadowOffsetX = (style.shadowOffsetX ?? 0) * fontSize;
|
|
955
|
+
const shadowOffsetY = (style.shadowOffsetY ?? 0) * fontSize;
|
|
956
|
+
const textStrokeWidth = Math.max(0.1, style.textStrokeWidth ?? 0) * fontSize;
|
|
957
|
+
aabb.left += shadowOffsetX - textStrokeWidth;
|
|
958
|
+
aabb.top += shadowOffsetY - textStrokeWidth;
|
|
959
|
+
aabb.width += textStrokeWidth * 2;
|
|
960
|
+
aabb.height += textStrokeWidth * 2;
|
|
961
|
+
boxes.push(aabb);
|
|
962
|
+
});
|
|
963
|
+
});
|
|
964
|
+
return boxes.length ? modernPath2d.BoundingBox.from(...boxes) : void 0;
|
|
965
|
+
},
|
|
966
|
+
render: (ctx, text) => {
|
|
967
|
+
const { characters, paragraphs, renderBoundingBox, effects, style } = text;
|
|
968
|
+
function fillBackground(color, box) {
|
|
969
|
+
ctx.fillStyle = color;
|
|
970
|
+
ctx.fillRect(box.left, box.top, box.width, box.height);
|
|
971
|
+
}
|
|
972
|
+
if (style?.backgroundColor) {
|
|
973
|
+
fillBackground(style.backgroundColor, new modernPath2d.BoundingBox(0, 0, ctx.canvas.width, ctx.canvas.height));
|
|
974
|
+
}
|
|
975
|
+
paragraphs.forEach((paragraph) => {
|
|
976
|
+
if (paragraph.style?.backgroundColor) {
|
|
977
|
+
fillBackground(paragraph.style.backgroundColor, paragraph.lineBox);
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
if (effects) {
|
|
981
|
+
effects.forEach((style2) => {
|
|
982
|
+
uploadColor(style2, renderBoundingBox, ctx);
|
|
983
|
+
ctx.save();
|
|
984
|
+
const [a, c, e, b, d, f] = getTransform2D(text, style2).transpose().elements;
|
|
985
|
+
ctx.transform(a, b, c, d, e, f);
|
|
986
|
+
characters.forEach((character) => {
|
|
987
|
+
if (character.parent.style?.backgroundColor) {
|
|
988
|
+
fillBackground(character.parent.style.backgroundColor, character.inlineBox);
|
|
989
|
+
}
|
|
990
|
+
character.drawTo(ctx, style2);
|
|
991
|
+
});
|
|
992
|
+
ctx.restore();
|
|
993
|
+
});
|
|
994
|
+
} else {
|
|
995
|
+
paragraphs.forEach((paragraph) => {
|
|
996
|
+
paragraph.fragments.forEach((fragment) => {
|
|
997
|
+
if (fragment.style?.backgroundColor) {
|
|
998
|
+
fillBackground(fragment.computedStyle.backgroundColor, fragment.inlineBox);
|
|
999
|
+
}
|
|
1000
|
+
fragment.characters.forEach((character) => {
|
|
1001
|
+
character.drawTo(ctx);
|
|
1002
|
+
});
|
|
1003
|
+
});
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
function getTransform2D(text, style) {
|
|
1010
|
+
const { fontSize, renderBoundingBox } = text;
|
|
1011
|
+
const offsetX = (style.offsetX ?? 0) * fontSize;
|
|
1012
|
+
const offsetY = (style.offsetY ?? 0) * fontSize;
|
|
1013
|
+
const PI_2 = Math.PI * 2;
|
|
1014
|
+
const skewX = (style.skewX ?? 0) / 360 * PI_2;
|
|
1015
|
+
const skewY = (style.skewY ?? 0) / 360 * PI_2;
|
|
1016
|
+
const { left, top, width, height } = renderBoundingBox;
|
|
1017
|
+
const centerX = left + width / 2;
|
|
1018
|
+
const centerY = top + height / 2;
|
|
1019
|
+
tempM1.identity();
|
|
1020
|
+
tempM2.makeTranslation(offsetX, offsetY);
|
|
1021
|
+
tempM1.multiply(tempM2);
|
|
1022
|
+
tempM2.makeTranslation(centerX, centerY);
|
|
1023
|
+
tempM1.multiply(tempM2);
|
|
1024
|
+
tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
|
|
1025
|
+
tempM1.multiply(tempM2);
|
|
1026
|
+
tempM2.makeTranslation(-centerX, -centerY);
|
|
1027
|
+
tempM1.multiply(tempM2);
|
|
1028
|
+
return tempM1.clone();
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1059
1031
|
var __defProp = Object.defineProperty;
|
|
1060
1032
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1061
1033
|
var __publicField = (obj, key, value) => {
|
|
@@ -1122,7 +1094,7 @@ class Text {
|
|
|
1122
1094
|
this.style = style;
|
|
1123
1095
|
this.measureDom = measureDom;
|
|
1124
1096
|
this.effects = effects;
|
|
1125
|
-
this.use(
|
|
1097
|
+
this.use(render()).use(highlight()).use(listStyle());
|
|
1126
1098
|
}
|
|
1127
1099
|
get fontSize() {
|
|
1128
1100
|
return this.computedStyle.fontSize;
|
|
@@ -1212,14 +1184,13 @@ exports.Text = Text;
|
|
|
1212
1184
|
exports.defaultTextStyles = defaultTextStyles;
|
|
1213
1185
|
exports.definePlugin = definePlugin;
|
|
1214
1186
|
exports.drawPath = drawPath;
|
|
1215
|
-
exports.effect = effect;
|
|
1216
|
-
exports.fillBackground = fillBackground;
|
|
1217
1187
|
exports.filterEmpty = filterEmpty;
|
|
1218
1188
|
exports.getTransform2D = getTransform2D;
|
|
1219
1189
|
exports.highlight = highlight;
|
|
1220
1190
|
exports.isNone = isNone;
|
|
1221
1191
|
exports.listStyle = listStyle;
|
|
1222
1192
|
exports.parseColor = parseColor;
|
|
1193
|
+
exports.render = render;
|
|
1223
1194
|
exports.setupView = setupView;
|
|
1224
1195
|
exports.uploadColor = uploadColor;
|
|
1225
1196
|
exports.uploadColors = uploadColors;
|