modern-text 0.2.17 → 0.2.18

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 CHANGED
@@ -52,52 +52,27 @@ function parseCssLinearGradient(css, x, y, width, height) {
52
52
  };
53
53
  }
54
54
 
55
- const _tempM1 = new modernPath2d.Matrix3();
56
- const _tempM2 = new modernPath2d.Matrix3();
57
- function drawPath(options, isText = false) {
55
+ function drawPath(options) {
58
56
  const { ctx, path, fontSize, clipRect } = options;
59
57
  ctx.save();
60
58
  ctx.beginPath();
61
- const style = path.style;
62
- path.style = {
63
- ...style,
64
- fill: options.color ?? style.fill,
65
- stroke: options.textStrokeColor ?? style.stroke,
66
- strokeWidth: options.textStrokeWidth ? options.textStrokeWidth * fontSize : style.strokeWidth,
59
+ const pathStyle = path.style;
60
+ const style = {
61
+ ...pathStyle,
62
+ fill: options.color ?? pathStyle.fill,
63
+ stroke: options.textStrokeColor ?? pathStyle.stroke,
64
+ strokeWidth: options.textStrokeWidth ? options.textStrokeWidth * fontSize : pathStyle.strokeWidth,
67
65
  shadowOffsetX: (options.shadowOffsetX ?? 0) * fontSize,
68
66
  shadowOffsetY: (options.shadowOffsetY ?? 0) * fontSize,
69
67
  shadowBlur: (options.shadowBlur ?? 0) * fontSize,
70
68
  shadowColor: options.shadowColor
71
69
  };
72
- const offsetX = (options.offsetX ?? 0) * fontSize;
73
- const offsetY = (options.offsetY ?? 0) * fontSize;
74
- const skewX = (options.skewX ?? 0) / 180 * Math.PI;
75
- const skewY = (options.skewY ?? 0) / 180 * Math.PI;
76
- if (offsetX || offsetY || skewX || skewY) {
77
- _tempM1.makeTranslation(offsetX, offsetY);
78
- _tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
79
- const [a, c, e, b, d, f] = _tempM1.multiply(_tempM2).transpose().elements;
80
- ctx.transform(a, b, c, d, e, f);
81
- }
82
70
  if (clipRect) {
83
71
  ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
84
72
  ctx.clip();
85
73
  ctx.beginPath();
86
74
  }
87
- if (isText && path.style.strokeWidth) {
88
- const scale = path.style.strokeWidth / fontSize + 1;
89
- const box = path.getBoundingBox();
90
- ctx.translate(
91
- box.left * (1 - scale) + box.width * (1 - scale) / 2,
92
- box.top * (1 - scale) + box.height * (1 - scale) / 2
93
- );
94
- ctx.scale(scale, scale);
95
- const clone = path.clone();
96
- clone.style.strokeWidth /= scale * 2;
97
- clone.drawTo(ctx);
98
- } else {
99
- path.drawTo(ctx);
100
- }
75
+ path.drawTo(ctx, style);
101
76
  ctx.restore();
102
77
  }
103
78
 
@@ -416,7 +391,7 @@ class Character {
416
391
  fontSize: this.computedStyle.fontSize,
417
392
  color: this.computedStyle.color,
418
393
  ...config
419
- }, true);
394
+ });
420
395
  }
421
396
  }
422
397
 
@@ -497,21 +472,51 @@ class Deformer extends Feature {
497
472
  }
498
473
  }
499
474
 
475
+ const tempM1 = new modernPath2d.Matrix3();
476
+ const tempM2 = new modernPath2d.Matrix3();
477
+ const tempV1 = new modernPath2d.Vector2();
500
478
  class Effector extends Feature {
479
+ getTransform2D(style) {
480
+ const { fontSize, renderBoundingBox } = this._text;
481
+ const offsetX = (style.offsetX ?? 0) * fontSize;
482
+ const offsetY = (style.offsetY ?? 0) * fontSize;
483
+ const PI_2 = Math.PI * 2;
484
+ const skewX = (style.skewX ?? 0) / 360 * PI_2;
485
+ const skewY = (style.skewY ?? 0) / 360 * PI_2;
486
+ const { left, top, width, height } = renderBoundingBox;
487
+ const centerX = left + width / 2;
488
+ const centerY = top + height / 2;
489
+ tempM1.identity();
490
+ tempM2.makeTranslation(offsetX, offsetY);
491
+ tempM1.multiply(tempM2);
492
+ tempM2.makeTranslation(centerX, centerY);
493
+ tempM1.multiply(tempM2);
494
+ tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
495
+ tempM1.multiply(tempM2);
496
+ tempM2.makeTranslation(-centerX, -centerY);
497
+ tempM1.multiply(tempM2);
498
+ return tempM1.clone();
499
+ }
501
500
  getBoundingBox() {
502
- const { characters, effects } = this._text;
501
+ const { characters, effects, fontSize } = this._text;
503
502
  const boxes = [];
504
503
  characters.forEach((character) => {
505
- const fontSize = character.computedStyle.fontSize;
506
- effects?.forEach((effect) => {
507
- const offsetX = (effect.offsetX ?? 0) * fontSize;
508
- const offsetY = (effect.offsetY ?? 0) * fontSize;
509
- const shadowOffsetX = (effect.shadowOffsetX ?? 0) * fontSize;
510
- const shadowOffsetY = (effect.shadowOffsetY ?? 0) * fontSize;
511
- const textStrokeWidth = Math.max(0.1, effect.textStrokeWidth ?? 0) * fontSize;
504
+ effects?.forEach((style) => {
512
505
  const aabb = character.boundingBox.clone();
513
- aabb.left += offsetX + shadowOffsetX - textStrokeWidth;
514
- aabb.top += offsetY + shadowOffsetY - textStrokeWidth;
506
+ const m = this.getTransform2D(style);
507
+ tempV1.set(aabb.left, aabb.top);
508
+ tempV1.applyMatrix3(m);
509
+ aabb.left = tempV1.x;
510
+ aabb.top = tempV1.y;
511
+ tempV1.set(aabb.right, aabb.bottom);
512
+ tempV1.applyMatrix3(m);
513
+ aabb.width = tempV1.x - aabb.left;
514
+ aabb.height = tempV1.y - aabb.top;
515
+ const shadowOffsetX = (style.shadowOffsetX ?? 0) * fontSize;
516
+ const shadowOffsetY = (style.shadowOffsetY ?? 0) * fontSize;
517
+ const textStrokeWidth = Math.max(0.1, style.textStrokeWidth ?? 0) * fontSize;
518
+ aabb.left += shadowOffsetX - textStrokeWidth;
519
+ aabb.top += shadowOffsetY - textStrokeWidth;
515
520
  aabb.width += textStrokeWidth * 2;
516
521
  aabb.height += textStrokeWidth * 2;
517
522
  boxes.push(aabb);
@@ -521,15 +526,17 @@ class Effector extends Feature {
521
526
  }
522
527
  draw(options) {
523
528
  const { ctx } = options;
524
- const { effects, characters, boundingBox } = this._text;
529
+ const { effects, characters, renderBoundingBox } = this._text;
525
530
  if (effects) {
526
- effects.forEach((effect) => {
527
- uploadColor(effect, boundingBox, ctx);
528
- });
529
- characters.forEach((character) => {
530
- effects.forEach((style) => {
531
+ effects.forEach((style) => {
532
+ uploadColor(style, renderBoundingBox, ctx);
533
+ ctx.save();
534
+ const [a, c, e, b, d, f] = this.getTransform2D(style).transpose().elements;
535
+ ctx.transform(a, b, c, d, e, f);
536
+ characters.forEach((character) => {
531
537
  character.drawTo(ctx, style);
532
538
  });
539
+ ctx.restore();
533
540
  });
534
541
  }
535
542
  return this;
@@ -1046,6 +1053,9 @@ class Text {
1046
1053
  this.deformation = deformation;
1047
1054
  this.measureDom = measureDom;
1048
1055
  }
1056
+ get fontSize() {
1057
+ return this.computedStyle.fontSize;
1058
+ }
1049
1059
  get characters() {
1050
1060
  return this.paragraphs.flatMap((p) => p.fragments.flatMap((f) => f.characters));
1051
1061
  }
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, VectorLike, Vector2 } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, VectorLike, Vector2, Matrix3 } from 'modern-path2d';
2
2
  import { Sfnt, GlyphPathCommand } from 'modern-font';
3
3
  export * from 'modern-font';
4
4
 
@@ -78,7 +78,7 @@ interface DrawShapePathsOptions extends Partial<TextEffect> {
78
78
  fontSize: number;
79
79
  clipRect?: BoundingBox;
80
80
  }
81
- declare function drawPath(options: DrawShapePathsOptions, isText?: boolean): void;
81
+ declare function drawPath(options: DrawShapePathsOptions): void;
82
82
 
83
83
  declare class Fragment {
84
84
  content: string;
@@ -195,6 +195,7 @@ declare class Text {
195
195
  effector: Effector;
196
196
  highlighter: Highlighter;
197
197
  renderer2D: Renderer2D;
198
+ get fontSize(): number;
198
199
  get characters(): Character[];
199
200
  constructor(options?: TextOptions);
200
201
  measure(dom?: HTMLElement | undefined): MeasuredResult;
@@ -216,6 +217,7 @@ interface EffectOptions {
216
217
  ctx: CanvasRenderingContext2D;
217
218
  }
218
219
  declare class Effector extends Feature {
220
+ getTransform2D(style: TextEffect): Matrix3;
219
221
  getBoundingBox(): BoundingBox;
220
222
  draw(options: EffectOptions): this;
221
223
  }
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, VectorLike, Vector2 } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, VectorLike, Vector2, Matrix3 } from 'modern-path2d';
2
2
  import { Sfnt, GlyphPathCommand } from 'modern-font';
3
3
  export * from 'modern-font';
4
4
 
@@ -78,7 +78,7 @@ interface DrawShapePathsOptions extends Partial<TextEffect> {
78
78
  fontSize: number;
79
79
  clipRect?: BoundingBox;
80
80
  }
81
- declare function drawPath(options: DrawShapePathsOptions, isText?: boolean): void;
81
+ declare function drawPath(options: DrawShapePathsOptions): void;
82
82
 
83
83
  declare class Fragment {
84
84
  content: string;
@@ -195,6 +195,7 @@ declare class Text {
195
195
  effector: Effector;
196
196
  highlighter: Highlighter;
197
197
  renderer2D: Renderer2D;
198
+ get fontSize(): number;
198
199
  get characters(): Character[];
199
200
  constructor(options?: TextOptions);
200
201
  measure(dom?: HTMLElement | undefined): MeasuredResult;
@@ -216,6 +217,7 @@ interface EffectOptions {
216
217
  ctx: CanvasRenderingContext2D;
217
218
  }
218
219
  declare class Effector extends Feature {
220
+ getTransform2D(style: TextEffect): Matrix3;
219
221
  getBoundingBox(): BoundingBox;
220
222
  draw(options: EffectOptions): this;
221
223
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, VectorLike, Vector2 } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, VectorLike, Vector2, Matrix3 } from 'modern-path2d';
2
2
  import { Sfnt, GlyphPathCommand } from 'modern-font';
3
3
  export * from 'modern-font';
4
4
 
@@ -78,7 +78,7 @@ interface DrawShapePathsOptions extends Partial<TextEffect> {
78
78
  fontSize: number;
79
79
  clipRect?: BoundingBox;
80
80
  }
81
- declare function drawPath(options: DrawShapePathsOptions, isText?: boolean): void;
81
+ declare function drawPath(options: DrawShapePathsOptions): void;
82
82
 
83
83
  declare class Fragment {
84
84
  content: string;
@@ -195,6 +195,7 @@ declare class Text {
195
195
  effector: Effector;
196
196
  highlighter: Highlighter;
197
197
  renderer2D: Renderer2D;
198
+ get fontSize(): number;
198
199
  get characters(): Character[];
199
200
  constructor(options?: TextOptions);
200
201
  measure(dom?: HTMLElement | undefined): MeasuredResult;
@@ -216,6 +217,7 @@ interface EffectOptions {
216
217
  ctx: CanvasRenderingContext2D;
217
218
  }
218
219
  declare class Effector extends Feature {
220
+ getTransform2D(style: TextEffect): Matrix3;
219
221
  getBoundingBox(): BoundingBox;
220
222
  draw(options: EffectOptions): this;
221
223
  }