modern-text 0.2.20 → 0.2.22

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, Matrix3, Vector2, parseSvgToDom, parseSvg } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, Matrix3, Vector2, parseSvg, parseSvgToDom } from 'modern-path2d';
2
2
  import { fonts, Woff, Ttf } from 'modern-font';
3
3
  export * from 'modern-font';
4
4
 
@@ -67,7 +67,7 @@ function drawPath(options) {
67
67
  shadowColor: options.shadowColor
68
68
  };
69
69
  if (clipRect) {
70
- ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
70
+ ctx.rect(clipRect.left, clipRect.top, clipRect.width, clipRect.height);
71
71
  ctx.clip();
72
72
  ctx.beginPath();
73
73
  }
@@ -187,8 +187,8 @@ class Character {
187
187
  return this;
188
188
  }
189
189
  const { unitsPerEm, ascender, descender, os2, post } = font;
190
- const { content, computedStyle, boundingBox, isVertical } = this;
191
- const { left, top, height } = boundingBox;
190
+ const { content, computedStyle, boundingBox } = this;
191
+ const { height } = boundingBox;
192
192
  const { fontSize } = computedStyle;
193
193
  const rate = unitsPerEm / fontSize;
194
194
  const glyphWidth = font.getAdvanceWidth(content, fontSize);
@@ -206,8 +206,6 @@ class Character {
206
206
  this.yStrikeoutSize = yStrikeoutSize;
207
207
  this.baseline = baseline;
208
208
  this.centerDiviation = 0.5 * height - baseline;
209
- this.glyphBox = isVertical ? new BoundingBox(left, top, glyphHeight, glyphWidth) : new BoundingBox(left, top, glyphWidth, glyphHeight);
210
- this.centerPoint = this.glyphBox.getCenterPoint();
211
209
  return this;
212
210
  }
213
211
  updatePath() {
@@ -289,6 +287,8 @@ class Character {
289
287
  strokeWidth: computedStyle.textStrokeWidth ? computedStyle.textStrokeWidth * fontSize * 0.03 : 0
290
288
  };
291
289
  this.path = path;
290
+ this.glyphBox = this.getGlyphBoundingBox();
291
+ this.center = this.glyphBox.getCenterPoint();
292
292
  return this;
293
293
  }
294
294
  update() {
@@ -377,11 +377,11 @@ class Character {
377
377
  return cmd;
378
378
  });
379
379
  }
380
- getMinMax(min, max) {
380
+ getGlyphMinMax(min, max) {
381
381
  return this.path.getMinMax(min, max);
382
382
  }
383
- getBoundingBox() {
384
- return this.path.getBoundingBox();
383
+ getGlyphBoundingBox(withStyle) {
384
+ return this.path.getBoundingBox(withStyle);
385
385
  }
386
386
  drawTo(ctx, config = {}) {
387
387
  drawPath({
@@ -501,7 +501,7 @@ class Effector extends Feature {
501
501
  const boxes = [];
502
502
  characters.forEach((character) => {
503
503
  effects?.forEach((style) => {
504
- const aabb = character.boundingBox.clone();
504
+ const aabb = character.glyphBox.clone();
505
505
  const m = this.getTransform2D(style);
506
506
  tempV1.set(aabb.left, aabb.top);
507
507
  tempV1.applyMatrix3(m);
@@ -548,11 +548,27 @@ var __publicField$1 = (obj, key, value) => {
548
548
  __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
549
549
  return value;
550
550
  };
551
- class Highlighter extends Feature {
551
+ const defaultHighlightRefer = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIiBmaWxsPSJub25lIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMyLjQwMjkgMjhIMzUuMTU5NFYzMy4xNzcxQzM1Ljk4MjEgMzIuMzExNSAzNi45NzEgMzEuODczNyAzOC4wOTQ4IDMxLjg3MzdDMzkuNjY3NiAzMS44NzM3IDQwLjkxNjYgMzIuNDI5NSA0MS44MzkgMzMuNTQzN0w0MS44NDAzIDMzLjU0NTNDNDIuNjcxNyAzNC41NzA1IDQzLjA5MTUgMzUuODU1OSA0My4wOTE1IDM3LjM4NzdDNDMuMDkxNSAzOC45NzYxIDQyLjY3MjkgNDAuMzAyOCA0MS44MTgzIDQxLjMzMDRMNDEuODE3MSA0MS4zMzE4QzQwLjg3MzEgNDIuNDQ2MSAzOS41ODMyIDQzIDM3Ljk3MjEgNDNDMzYuNzQ3NyA0MyAzNS43NDg4IDQyLjY1OTkgMzQuOTk1OCA0MS45NjkzVjQyLjcyNDdIMzIuNDAyOVYyOFpNMzcuNTQyOCAzNC4wOTI0QzM2Ljg1NDkgMzQuMDkyNCAzNi4zMDE0IDM0LjM1NjEgMzUuODQ4NyAzNC45MDA0TDM1Ljg0NTIgMzQuOTA0NkMzNS4zMzU4IDM1LjQ4NTMgMzUuMDc3NiAzNi4yOTc2IDM1LjA3NzYgMzcuMzQ4NFYzNy41MDU3QzM1LjA3NzYgMzguNDY0IDM1LjI3NzIgMzkuMjQ0MyAzNS42OTQzIDM5LjgyNzlDMzYuMTQ0MSA0MC40NTg3IDM2Ljc3MjYgNDAuNzgxMyAzNy42MjQ1IDQwLjc4MTNDMzguNTg3NCA0MC43ODEzIDM5LjI3MDcgNDAuNDUyNyAzOS43MTUyIDM5LjgxMjdDNDAuMDcyOCAzOS4yNjg0IDQwLjI3MzcgMzguNDY3MyA0MC4yNzM3IDM3LjM4NzdDNDAuMjczNyAzNi4zMTA1IDQwLjA1MzMgMzUuNTMxMyAzOS42NzgzIDM1LjAwNzdDMzkuMjM3MSAzNC40MDcxIDM4LjUzNDIgMzQuMDkyNCAzNy41NDI4IDM0LjA5MjRaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZD0iTTQ5Ljg2MTQgMzEuODczN0M0OC4xNTM1IDMxLjg3MzcgNDYuODAxNiAzMi40MjM5IDQ1LjgzNDggMzMuNTM5MkM0NC45MzcgMzQuNTQ3MiA0NC40OTY2IDM1Ljg1NiA0NC40OTY2IDM3LjQyN0M0NC40OTY2IDM5LjAzNjggNDQuOTM2NyA0MC4zNjU5IDQ1Ljg1NTkgNDEuMzk0M0M0Ni44MDMxIDQyLjQ3MDYgNDguMTM0OCA0MyA0OS44MjA1IDQzQzUxLjIyNiA0MyA1Mi4zODI2IDQyLjY1NjMgNTMuMjQ3OSA0MS45Njk3QzU0LjEzNTkgNDEuMjYxNCA1NC43MDYxIDQwLjE4ODcgNTQuOTU3MyAzOC43NzkxTDU1IDM4LjUzOTdINTIuMjQ4NEw1Mi4yMjU5IDM4LjcyMDFDNTIuMTM3OSAzOS40MjUxIDUxLjg5MjUgMzkuOTI3OCA1MS41MTA5IDQwLjI1NThDNTEuMTI5NSA0MC41ODM1IDUwLjU4MzEgNDAuNzYxNiA0OS44NDA5IDQwLjc2MTZDNDkuMDAwMSA0MC43NjE2IDQ4LjM5NDkgNDAuNDcxNSA0Ny45OTA3IDM5LjkyMzdMNDcuOTg3NCAzOS45MTk0QzQ3LjUzNTYgMzkuMzQwMSA0Ny4zMTQ0IDM4LjUwNjIgNDcuMzE0NCAzNy40MDc0QzQ3LjMxNDQgMzYuMzMyMiA0Ny41NTQ0IDM1LjUxNzcgNDguMDA1OCAzNC45NTY4TDQ4LjAwNzggMzQuOTU0M0M0OC40NTM3IDM0LjM4MjUgNDkuMDYxOCAzNC4xMTIxIDQ5Ljg2MTQgMzQuMTEyMUM1MC41MjMgMzQuMTEyMSA1MS4wNDUxIDM0LjI2MTUgNTEuNDI3MiAzNC41NDA3QzUxLjc4ODQgMzQuODE5NCA1Mi4wNTMgMzUuMjQ0NyA1Mi4xODgxIDM1Ljg1NzFMNTIuMjIzOSAzNi4wMTk0SDU0Ljk1NDhMNTQuOTE3IDM1Ljc4MzVDNTQuNzA2MyAzNC40NjYgNTQuMTUzNiAzMy40NzAxIDUzLjI2MzQgMzIuODAxOUw1My4yNjAyIDMyLjc5OTVDNTIuMzk1MSAzMi4xNzU1IDUxLjI2MjEgMzEuODczNyA0OS44NjE0IDMxLjg3MzdaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNS43NTYxIDI4LjI3NTNIMjIuNzQ0TDE3IDQyLjcyNDdIMjAuMDE0MUwyMS4zNDI5IDM5LjIwNDlIMjcuMTU3MkwyOC40ODYgNDIuNzI0N0gzMS41MDAxTDI1Ljc1NjEgMjguMjc1M1pNMjIuMjEyNSAzNi45MDc2TDI0LjI1OTYgMzEuNDUzOUwyNi4yODg1IDM2LjkwNzZIMjIuMjEyNVoiIGZpbGw9IiMyMjI1MjkiLz48L3N2Zz4=";
552
+ const _Highlighter = class _Highlighter extends Feature {
552
553
  constructor() {
553
554
  super(...arguments);
554
555
  __publicField$1(this, "paths", []);
555
556
  }
557
+ static get refer() {
558
+ return this._refer;
559
+ }
560
+ static set refer(refer) {
561
+ this._refer = refer;
562
+ this.parsedRefer = parseSvg(refer);
563
+ }
564
+ getReferBoundingBox() {
565
+ const max = Vector2.MIN;
566
+ const min = Vector2.MAX;
567
+ _Highlighter.parsedRefer.forEach((path) => {
568
+ path.getMinMax(min, max);
569
+ });
570
+ return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
571
+ }
556
572
  getBoundingBox() {
557
573
  if (!this.paths.length) {
558
574
  return void 0;
@@ -570,7 +586,7 @@ class Highlighter extends Feature {
570
586
  characters.forEach((character) => {
571
587
  const highlight = character.parent.highlight;
572
588
  if (highlight?.url) {
573
- if (prevHighlight?.url === highlight.url && (group.length && group[0].boundingBox.top === character.boundingBox.top && group[0].fontSize === character.fontSize)) {
589
+ if (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) {
574
590
  group.push(character);
575
591
  } else {
576
592
  group = [];
@@ -582,8 +598,8 @@ class Highlighter extends Feature {
582
598
  });
583
599
  this.paths = groups.filter((characters2) => characters2.length).map((characters2) => {
584
600
  return {
585
- url: characters2[0].parent.highlight.url,
586
- box: BoundingBox.from(...characters2.map((c) => c.boundingBox)),
601
+ highlight: characters2[0].parent.highlight,
602
+ box: BoundingBox.from(...characters2.map((c) => c.glyphBox)),
587
603
  baseline: Math.max(...characters2.map((c) => c.baseline)),
588
604
  fontSize: characters2[0].fontSize
589
605
  };
@@ -597,60 +613,57 @@ class Highlighter extends Feature {
597
613
  paths.forEach((path) => path.getMinMax(min, max));
598
614
  return {
599
615
  paths,
600
- box: new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y),
601
- viewBox: new BoundingBox(...svg.getAttribute("viewBox").split(" ").map(Number))
616
+ box: new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y)
602
617
  };
603
618
  }
604
619
  _parseGroup(group) {
605
- const { url, box: groupBox, baseline, fontSize } = group;
606
- const { box, viewBox, paths } = this._parseSvg(url);
607
- const centerY = viewBox.top + viewBox.height / 2;
620
+ const { highlight, box: groupBox, fontSize } = group;
621
+ const {
622
+ strokeWidth = 1,
623
+ repeatXByFontsize = 0,
624
+ overflowXHidden = Boolean(repeatXByFontsize)
625
+ } = highlight;
626
+ const { box, paths } = this._parseSvg(highlight.url);
608
627
  const result = [];
609
- const type = centerY > box.top ? 0 : 1;
610
- function transformPathStyle(path, scale) {
611
- if (path.style.strokeWidth) {
612
- path.style.strokeWidth *= scale;
613
- }
614
- if (path.style.strokeMiterlimit) {
615
- path.style.strokeMiterlimit *= scale;
616
- }
617
- if (path.style.strokeDashoffset) {
618
- path.style.strokeDashoffset *= scale;
619
- }
620
- if (path.style.strokeDasharray) {
621
- path.style.strokeDasharray = path.style.strokeDasharray.map((v) => v * scale);
622
- }
623
- }
624
- if (type === 0) {
625
- const offset = {
626
- x: groupBox.left - fontSize * 0.2,
627
- y: groupBox.top
628
- };
629
- const scaleX = (groupBox.width + fontSize * 0.2 * 2) / box.width;
630
- const scaleY = groupBox.height / box.height;
631
- const m = new Matrix3().translate(-box.x, -box.y).scale(scaleX, scaleY).translate(offset.x, offset.y);
628
+ const referBoundingBox = this.getReferBoundingBox();
629
+ const scale = {
630
+ x: repeatXByFontsize ? fontSize * repeatXByFontsize * (box.width / referBoundingBox.width) / box.width : groupBox.width * (box.width / referBoundingBox.width) / box.width,
631
+ y: groupBox.height * (box.height / referBoundingBox.height) / box.height
632
+ };
633
+ const styleScale = fontSize / box.width * 2;
634
+ const unitWidth = box.width * scale.x;
635
+ const total = Math.ceil(groupBox.width / unitWidth);
636
+ const offset = {
637
+ x: (box.left - referBoundingBox.left) * scale.x,
638
+ y: (box.top - referBoundingBox.top) * scale.y
639
+ };
640
+ const transform = new Matrix3().translate(-box.left, -box.top).scale(scale.x, scale.y).translate(groupBox.left, groupBox.top).translate(offset.x, offset.y);
641
+ for (let i = 0; i < total; i++) {
642
+ const _transform = transform.clone().translate(i * unitWidth, 0);
632
643
  paths.forEach((original) => {
633
- const path = original.clone().transform(m);
634
- transformPathStyle(path, scaleX);
635
- result.push({ path });
636
- });
637
- } else if (type === 1) {
638
- const scale = fontSize / box.width;
639
- const width = box.width * scale;
640
- const length = Math.ceil(groupBox.width / width);
641
- const offset = {
642
- x: groupBox.left,
643
- y: groupBox.top + baseline + fontSize * 0.1
644
- };
645
- const m = new Matrix3().translate(-box.x, -box.y).scale(scale, scale).translate(offset.x, offset.y);
646
- for (let i = 0; i < length; i++) {
647
- const _m = m.clone().translate(i * width, 0);
648
- paths.forEach((original) => {
649
- const path = original.clone().transform(_m);
650
- transformPathStyle(path, scale);
651
- result.push({ clipRect: groupBox, path });
644
+ const path = original.clone().transform(_transform);
645
+ if (path.style.strokeWidth) {
646
+ path.style.strokeWidth *= styleScale * strokeWidth;
647
+ }
648
+ if (path.style.strokeMiterlimit) {
649
+ path.style.strokeMiterlimit *= styleScale;
650
+ }
651
+ if (path.style.strokeDashoffset) {
652
+ path.style.strokeDashoffset *= styleScale;
653
+ }
654
+ if (path.style.strokeDasharray) {
655
+ path.style.strokeDasharray = path.style.strokeDasharray.map((v) => v * styleScale);
656
+ }
657
+ result.push({
658
+ clipRect: overflowXHidden ? new BoundingBox(
659
+ groupBox.left + offset.x * 2,
660
+ groupBox.top - groupBox.height,
661
+ groupBox.width - offset.x * 2,
662
+ groupBox.height * 3
663
+ ) : void 0,
664
+ path
652
665
  });
653
- }
666
+ });
654
667
  }
655
668
  return result;
656
669
  }
@@ -665,7 +678,10 @@ class Highlighter extends Feature {
665
678
  });
666
679
  return this;
667
680
  }
668
- }
681
+ };
682
+ __publicField$1(_Highlighter, "_refer", defaultHighlightRefer);
683
+ __publicField$1(_Highlighter, "parsedRefer", parseSvg(_Highlighter._refer));
684
+ let Highlighter = _Highlighter;
669
685
 
670
686
  class Measurer extends Feature {
671
687
  _styleToDomStyle(style) {
@@ -1076,13 +1092,14 @@ class Text {
1076
1092
  this.boundingBox = boundingBox;
1077
1093
  const characters = this.characters;
1078
1094
  characters.forEach((c) => c.update());
1079
- this.highlighter.highlight();
1080
1095
  if (this.deformation) {
1081
1096
  this.deformer.deform();
1097
+ } else {
1098
+ this.highlighter.highlight();
1082
1099
  }
1083
1100
  const min = Vector2.MAX;
1084
1101
  const max = Vector2.MIN;
1085
- characters.forEach((c) => c.getMinMax(min, max));
1102
+ characters.forEach((c) => c.getGlyphMinMax(min, max));
1086
1103
  this.renderBoundingBox = new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
1087
1104
  return this;
1088
1105
  }
@@ -1119,4 +1136,4 @@ class Text {
1119
1136
  }
1120
1137
  }
1121
1138
 
1122
- export { Character, Deformer, Effector, Fragment, Highlighter, Measurer, Paragraph, Parser, Reflector, Renderer2D, Text, defaultTextStyles, drawPath, filterEmpty, getPointPosition, getRotationPoint, getScalePoint, getSkewPoint, parseColor, uploadColor };
1139
+ export { Character, Deformer, Effector, Fragment, Highlighter, Measurer, Paragraph, Parser, Reflector, Renderer2D, Text, defaultHighlightRefer, defaultTextStyles, drawPath, filterEmpty, getPointPosition, getRotationPoint, getScalePoint, getSkewPoint, parseColor, uploadColor };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modern-text",
3
3
  "type": "module",
4
- "version": "0.2.20",
4
+ "version": "0.2.22",
5
5
  "packageManager": "pnpm@9.9.0",
6
6
  "description": "Measure and render text in a way that describes the DOM.",
7
7
  "author": "wxm",