modern-text 0.2.5 → 0.2.7

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
@@ -171,9 +171,9 @@ class Character {
171
171
  this.index = index;
172
172
  this.parent = parent;
173
173
  __publicField$4(this, "boundingBox", new modernPath2d.BoundingBox());
174
- __publicField$4(this, "path", new modernPath2d.Path2D());
175
174
  __publicField$4(this, "textWidth", 0);
176
175
  __publicField$4(this, "textHeight", 0);
176
+ __publicField$4(this, "path", new modernPath2d.Path2D());
177
177
  // glyph
178
178
  __publicField$4(this, "commands", []);
179
179
  }
@@ -193,11 +193,14 @@ class Character {
193
193
  }
194
194
  return void 0;
195
195
  }
196
- _updateGlyph(font) {
196
+ updateGlyph(font = this._font()) {
197
+ if (!font) {
198
+ return this;
199
+ }
200
+ const { unitsPerEm, ascender, descender, os2, post } = font;
197
201
  const { content, computedStyle, boundingBox, isVertical } = this;
198
202
  const { left, top, height } = boundingBox;
199
203
  const { fontSize } = computedStyle;
200
- const { unitsPerEm, ascender, descender, os2, post } = font;
201
204
  const rate = unitsPerEm / fontSize;
202
205
  const glyphWidth = font.getAdvanceWidth(content, fontSize);
203
206
  const glyphHeight = (ascender + Math.abs(descender)) / rate;
@@ -218,84 +221,7 @@ class Character {
218
221
  this.centerPoint = this.glyphBox.getCenterPoint();
219
222
  return this;
220
223
  }
221
- _decoration() {
222
- const { isVertical, underlinePosition, yStrikeoutPosition } = this;
223
- const { textDecoration, fontSize } = this.computedStyle;
224
- const { left, top, width, height } = this.boundingBox;
225
- const lineWidth = 0.1 * fontSize;
226
- let start;
227
- switch (textDecoration) {
228
- case "underline":
229
- if (isVertical) {
230
- start = left;
231
- } else {
232
- start = top + underlinePosition;
233
- }
234
- break;
235
- case "line-through":
236
- if (isVertical) {
237
- start = left + width / 2;
238
- } else {
239
- start = top + yStrikeoutPosition;
240
- }
241
- break;
242
- case "none":
243
- default:
244
- return [];
245
- }
246
- if (isVertical) {
247
- return [
248
- { type: "M", x: start, y: top },
249
- { type: "L", x: start, y: top + height },
250
- { type: "L", x: start + lineWidth, y: top + height },
251
- { type: "L", x: start + lineWidth, y: top },
252
- { type: "Z" }
253
- ];
254
- } else {
255
- return [
256
- { type: "M", x: left, y: start },
257
- { type: "L", x: left + width, y: start },
258
- { type: "L", x: left + width, y: start + lineWidth },
259
- { type: "L", x: left, y: start + lineWidth },
260
- { type: "Z" }
261
- ];
262
- }
263
- }
264
- _transform(commands, cb) {
265
- return commands.map((rawCmd) => {
266
- const cmd = { ...rawCmd };
267
- switch (cmd.type) {
268
- case "L":
269
- case "M":
270
- [cmd.x, cmd.y] = cb(cmd.x, cmd.y);
271
- break;
272
- case "Q":
273
- [cmd.x1, cmd.y1] = cb(cmd.x1, cmd.y1);
274
- [cmd.x, cmd.y] = cb(cmd.x, cmd.y);
275
- break;
276
- }
277
- return cmd;
278
- });
279
- }
280
- _italic(commands, startPoint) {
281
- const { baseline, glyphWidth } = this;
282
- const { left, top } = this.boundingBox;
283
- const _startPoint = startPoint || {
284
- y: top + baseline,
285
- x: left + glyphWidth / 2
286
- };
287
- return this._transform(commands, (x, y) => {
288
- const p = getSkewPoint({ x, y }, _startPoint, -0.24, 0);
289
- return [p.x, p.y];
290
- });
291
- }
292
- _rotation90(commands, point) {
293
- return this._transform(commands, (x, y) => {
294
- const p = getPointPosition({ x, y }, point, 90);
295
- return [p.x, p.y];
296
- });
297
- }
298
- updatePath() {
224
+ updateCommands() {
299
225
  const font = this._font();
300
226
  if (!font) {
301
227
  return this;
@@ -310,7 +236,7 @@ class Character {
310
236
  baseline,
311
237
  glyphHeight,
312
238
  glyphWidth
313
- } = this._updateGlyph(font);
239
+ } = this.updateGlyph(font);
314
240
  const { os2, ascender, descender } = font;
315
241
  const usWinAscent = ascender;
316
242
  const usWinDescent = descender;
@@ -368,14 +294,127 @@ class Character {
368
294
  }
369
295
  commands.push(...this._decoration());
370
296
  this.commands = commands;
371
- this.path = new modernPath2d.Path2D(commands);
297
+ return this;
298
+ }
299
+ updatePath() {
300
+ this.path?.copy(new modernPath2d.Path2D(this.commands));
372
301
  return this;
373
302
  }
374
303
  update() {
375
- this.updatePath();
304
+ this.updateCommands().updatePath();
376
305
  return this;
377
306
  }
378
- getMinMax(min = modernPath2d.Point2D.MAX, max = modernPath2d.Point2D.MIN) {
307
+ _decoration() {
308
+ const { isVertical, underlinePosition, yStrikeoutPosition } = this;
309
+ const { textDecoration, fontSize } = this.computedStyle;
310
+ const { left, top, width, height } = this.boundingBox;
311
+ const lineWidth = 0.1 * fontSize;
312
+ let start;
313
+ switch (textDecoration) {
314
+ case "underline":
315
+ if (isVertical) {
316
+ start = left;
317
+ } else {
318
+ start = top + underlinePosition;
319
+ }
320
+ break;
321
+ case "line-through":
322
+ if (isVertical) {
323
+ start = left + width / 2;
324
+ } else {
325
+ start = top + yStrikeoutPosition;
326
+ }
327
+ break;
328
+ case "none":
329
+ default:
330
+ return [];
331
+ }
332
+ if (isVertical) {
333
+ return [
334
+ { type: "M", x: start, y: top },
335
+ { type: "L", x: start, y: top + height },
336
+ { type: "L", x: start + lineWidth, y: top + height },
337
+ { type: "L", x: start + lineWidth, y: top },
338
+ { type: "Z" }
339
+ ];
340
+ } else {
341
+ return [
342
+ { type: "M", x: left, y: start },
343
+ { type: "L", x: left + width, y: start },
344
+ { type: "L", x: left + width, y: start + lineWidth },
345
+ { type: "L", x: left, y: start + lineWidth },
346
+ { type: "Z" }
347
+ ];
348
+ }
349
+ }
350
+ _italic(commands, startPoint) {
351
+ const { baseline, glyphWidth } = this;
352
+ const { left, top } = this.boundingBox;
353
+ const _startPoint = startPoint || {
354
+ y: top + baseline,
355
+ x: left + glyphWidth / 2
356
+ };
357
+ return this._transform(commands, (x, y) => {
358
+ const p = getSkewPoint({ x, y }, _startPoint, -0.24, 0);
359
+ return [p.x, p.y];
360
+ });
361
+ }
362
+ _rotation90(commands, point) {
363
+ return this._transform(commands, (x, y) => {
364
+ const p = getPointPosition({ x, y }, point, 90);
365
+ return [p.x, p.y];
366
+ });
367
+ }
368
+ _transform(commands, cb) {
369
+ return commands.map((rawCmd) => {
370
+ const cmd = { ...rawCmd };
371
+ switch (cmd.type) {
372
+ case "L":
373
+ case "M":
374
+ [cmd.x, cmd.y] = cb(cmd.x, cmd.y);
375
+ break;
376
+ case "Q":
377
+ [cmd.x1, cmd.y1] = cb(cmd.x1, cmd.y1);
378
+ [cmd.x, cmd.y] = cb(cmd.x, cmd.y);
379
+ break;
380
+ }
381
+ return cmd;
382
+ });
383
+ }
384
+ forEachCommand(cb) {
385
+ const commands = this.commands;
386
+ const last = { x: 0, y: 0 };
387
+ const first = { x: 0, y: 0 };
388
+ let isFirst = true;
389
+ let doSetFirstPoint = false;
390
+ for (let i = 0, len = commands.length; i < len; i++) {
391
+ if (isFirst) {
392
+ doSetFirstPoint = true;
393
+ isFirst = false;
394
+ }
395
+ let command = commands[i];
396
+ command = cb(command, i, { last, first }) ?? command;
397
+ switch (command.type) {
398
+ case "M":
399
+ case "L":
400
+ case "Q":
401
+ last.x = command.x;
402
+ last.y = command.y;
403
+ if (doSetFirstPoint) {
404
+ first.x = last.x;
405
+ first.y = last.y;
406
+ }
407
+ break;
408
+ case "Z":
409
+ last.x = first.x;
410
+ last.y = first.y;
411
+ isFirst = true;
412
+ break;
413
+ }
414
+ }
415
+ return this;
416
+ }
417
+ getMinMax(min = modernPath2d.Vector2.MAX, max = modernPath2d.Vector2.MIN) {
379
418
  let last = { x: 0, y: 0 };
380
419
  this.commands.forEach((cmd) => {
381
420
  switch (cmd.type) {
@@ -403,6 +442,13 @@ class Character {
403
442
  });
404
443
  return { min, max };
405
444
  }
445
+ getBoundingBox() {
446
+ const min = modernPath2d.Vector2.MAX;
447
+ const max = modernPath2d.Vector2.MIN;
448
+ this.getMinMax(min, max);
449
+ this.path.getMinMax(min, max);
450
+ return new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
451
+ }
406
452
  drawTo(ctx, config = {}) {
407
453
  drawPaths({
408
454
  ctx,
@@ -545,8 +591,8 @@ class Highlighter extends Feature {
545
591
  if (!this.paths.length) {
546
592
  return new modernPath2d.BoundingBox();
547
593
  }
548
- const min = modernPath2d.Point2D.MAX;
549
- const max = modernPath2d.Point2D.MIN;
594
+ const min = modernPath2d.Vector2.MAX;
595
+ const max = modernPath2d.Vector2.MIN;
550
596
  this.paths.forEach((path) => path.getMinMax(min, max));
551
597
  return new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
552
598
  }
@@ -572,7 +618,7 @@ class Highlighter extends Feature {
572
618
  this.paths = groups.filter((characters2) => characters2.length).map((characters2) => {
573
619
  return {
574
620
  url: characters2[0].parent.highlight.url,
575
- box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.glyphBox)),
621
+ box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.boundingBox)),
576
622
  baseline: Math.max(...characters2.map((c) => c.baseline))
577
623
  };
578
624
  }).map((group2) => this._parseGroup(group2, fontSize)).flat();
@@ -580,8 +626,8 @@ class Highlighter extends Feature {
580
626
  _parseSvg(url) {
581
627
  const svg = modernPath2d.parseSvgToDom(url);
582
628
  const paths = modernPath2d.parseSvg(svg);
583
- const min = modernPath2d.Point2D.MAX;
584
- const max = modernPath2d.Point2D.MIN;
629
+ const min = modernPath2d.Vector2.MAX;
630
+ const max = modernPath2d.Vector2.MIN;
585
631
  paths.forEach((path) => path.getMinMax(min, max));
586
632
  const { x, y, width, height } = new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
587
633
  const viewBox = svg.getAttribute("viewBox").split(" ").map(Number);
@@ -1041,14 +1087,15 @@ class Text {
1041
1087
  const { paragraphs, boundingBox } = this.measure();
1042
1088
  this.paragraphs = paragraphs;
1043
1089
  this.boundingBox = boundingBox;
1044
- this.characters.forEach((c) => c.update());
1090
+ const characters = this.characters;
1091
+ characters.forEach((c) => c.update());
1092
+ this._highlighter.highlight();
1045
1093
  if (this.deformation) {
1046
1094
  this._deformer.deform();
1047
1095
  }
1048
- this._highlighter.highlight();
1049
- const min = modernPath2d.Point2D.MAX;
1050
- const max = modernPath2d.Point2D.MIN;
1051
- this.characters.forEach((c) => c.getMinMax(min, max));
1096
+ const min = modernPath2d.Vector2.MAX;
1097
+ const max = modernPath2d.Vector2.MIN;
1098
+ characters.forEach((c) => c.getMinMax(min, max));
1052
1099
  this.renderBoundingBox = new modernPath2d.BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
1053
1100
  return this;
1054
1101
  }
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, Point2D } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, VectorLike, Vector2 } from 'modern-path2d';
2
2
  import { GlyphPathCommand, Sfnt } from 'modern-font';
3
3
  export * from 'modern-font';
4
4
 
@@ -97,9 +97,9 @@ declare class Character {
97
97
  index: number;
98
98
  parent: Fragment;
99
99
  boundingBox: BoundingBox;
100
- path: Path2D<any>;
101
100
  textWidth: number;
102
101
  textHeight: number;
102
+ path: Path2D<any>;
103
103
  commands: GlyphPathCommand[];
104
104
  glyphHeight: number;
105
105
  glyphWidth: number;
@@ -110,32 +110,29 @@ declare class Character {
110
110
  baseline: number;
111
111
  centerDiviation: number;
112
112
  glyphBox: BoundingBox;
113
- centerPoint: {
114
- x: number;
115
- y: number;
116
- };
113
+ centerPoint: VectorLike;
117
114
  get computedStyle(): TextStyle;
118
115
  get isVertical(): boolean;
119
116
  get fontSize(): number;
120
117
  constructor(content: string, index: number, parent: Fragment);
121
118
  protected _font(): Sfnt | undefined;
122
- protected _updateGlyph(font: Sfnt): this;
123
- protected _decoration(): GlyphPathCommand[];
124
- protected _transform(commands: GlyphPathCommand[], cb: (x: number, y: number) => number[]): GlyphPathCommand[];
125
- protected _italic(commands: GlyphPathCommand[], startPoint?: {
126
- x: number;
127
- y: number;
128
- }): GlyphPathCommand[];
129
- protected _rotation90(commands: GlyphPathCommand[], point: {
130
- x: number;
131
- y: number;
132
- }): GlyphPathCommand[];
119
+ updateGlyph(font?: Sfnt | undefined): this;
120
+ updateCommands(): this;
133
121
  updatePath(): this;
134
122
  update(): this;
135
- getMinMax(min?: Point2D, max?: Point2D): {
136
- min: Point2D;
137
- max: Point2D;
123
+ protected _decoration(): GlyphPathCommand[];
124
+ protected _italic(commands: GlyphPathCommand[], startPoint?: VectorLike): GlyphPathCommand[];
125
+ protected _rotation90(commands: GlyphPathCommand[], point: VectorLike): GlyphPathCommand[];
126
+ protected _transform(commands: GlyphPathCommand[], cb: (x: number, y: number) => number[]): GlyphPathCommand[];
127
+ forEachCommand(cb: (command: GlyphPathCommand, index: number, context: {
128
+ first: VectorLike;
129
+ last: VectorLike;
130
+ }) => void | GlyphPathCommand): this;
131
+ getMinMax(min?: Vector2, max?: Vector2): {
132
+ min: Vector2;
133
+ max: Vector2;
138
134
  };
135
+ getBoundingBox(): BoundingBox;
139
136
  drawTo(ctx: CanvasRenderingContext2D, config?: Partial<TextEffect>): void;
140
137
  }
141
138
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, Point2D } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, VectorLike, Vector2 } from 'modern-path2d';
2
2
  import { GlyphPathCommand, Sfnt } from 'modern-font';
3
3
  export * from 'modern-font';
4
4
 
@@ -97,9 +97,9 @@ declare class Character {
97
97
  index: number;
98
98
  parent: Fragment;
99
99
  boundingBox: BoundingBox;
100
- path: Path2D<any>;
101
100
  textWidth: number;
102
101
  textHeight: number;
102
+ path: Path2D<any>;
103
103
  commands: GlyphPathCommand[];
104
104
  glyphHeight: number;
105
105
  glyphWidth: number;
@@ -110,32 +110,29 @@ declare class Character {
110
110
  baseline: number;
111
111
  centerDiviation: number;
112
112
  glyphBox: BoundingBox;
113
- centerPoint: {
114
- x: number;
115
- y: number;
116
- };
113
+ centerPoint: VectorLike;
117
114
  get computedStyle(): TextStyle;
118
115
  get isVertical(): boolean;
119
116
  get fontSize(): number;
120
117
  constructor(content: string, index: number, parent: Fragment);
121
118
  protected _font(): Sfnt | undefined;
122
- protected _updateGlyph(font: Sfnt): this;
123
- protected _decoration(): GlyphPathCommand[];
124
- protected _transform(commands: GlyphPathCommand[], cb: (x: number, y: number) => number[]): GlyphPathCommand[];
125
- protected _italic(commands: GlyphPathCommand[], startPoint?: {
126
- x: number;
127
- y: number;
128
- }): GlyphPathCommand[];
129
- protected _rotation90(commands: GlyphPathCommand[], point: {
130
- x: number;
131
- y: number;
132
- }): GlyphPathCommand[];
119
+ updateGlyph(font?: Sfnt | undefined): this;
120
+ updateCommands(): this;
133
121
  updatePath(): this;
134
122
  update(): this;
135
- getMinMax(min?: Point2D, max?: Point2D): {
136
- min: Point2D;
137
- max: Point2D;
123
+ protected _decoration(): GlyphPathCommand[];
124
+ protected _italic(commands: GlyphPathCommand[], startPoint?: VectorLike): GlyphPathCommand[];
125
+ protected _rotation90(commands: GlyphPathCommand[], point: VectorLike): GlyphPathCommand[];
126
+ protected _transform(commands: GlyphPathCommand[], cb: (x: number, y: number) => number[]): GlyphPathCommand[];
127
+ forEachCommand(cb: (command: GlyphPathCommand, index: number, context: {
128
+ first: VectorLike;
129
+ last: VectorLike;
130
+ }) => void | GlyphPathCommand): this;
131
+ getMinMax(min?: Vector2, max?: Vector2): {
132
+ min: Vector2;
133
+ max: Vector2;
138
134
  };
135
+ getBoundingBox(): BoundingBox;
139
136
  drawTo(ctx: CanvasRenderingContext2D, config?: Partial<TextEffect>): void;
140
137
  }
141
138
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, Point2D } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, VectorLike, Vector2 } from 'modern-path2d';
2
2
  import { GlyphPathCommand, Sfnt } from 'modern-font';
3
3
  export * from 'modern-font';
4
4
 
@@ -97,9 +97,9 @@ declare class Character {
97
97
  index: number;
98
98
  parent: Fragment;
99
99
  boundingBox: BoundingBox;
100
- path: Path2D<any>;
101
100
  textWidth: number;
102
101
  textHeight: number;
102
+ path: Path2D<any>;
103
103
  commands: GlyphPathCommand[];
104
104
  glyphHeight: number;
105
105
  glyphWidth: number;
@@ -110,32 +110,29 @@ declare class Character {
110
110
  baseline: number;
111
111
  centerDiviation: number;
112
112
  glyphBox: BoundingBox;
113
- centerPoint: {
114
- x: number;
115
- y: number;
116
- };
113
+ centerPoint: VectorLike;
117
114
  get computedStyle(): TextStyle;
118
115
  get isVertical(): boolean;
119
116
  get fontSize(): number;
120
117
  constructor(content: string, index: number, parent: Fragment);
121
118
  protected _font(): Sfnt | undefined;
122
- protected _updateGlyph(font: Sfnt): this;
123
- protected _decoration(): GlyphPathCommand[];
124
- protected _transform(commands: GlyphPathCommand[], cb: (x: number, y: number) => number[]): GlyphPathCommand[];
125
- protected _italic(commands: GlyphPathCommand[], startPoint?: {
126
- x: number;
127
- y: number;
128
- }): GlyphPathCommand[];
129
- protected _rotation90(commands: GlyphPathCommand[], point: {
130
- x: number;
131
- y: number;
132
- }): GlyphPathCommand[];
119
+ updateGlyph(font?: Sfnt | undefined): this;
120
+ updateCommands(): this;
133
121
  updatePath(): this;
134
122
  update(): this;
135
- getMinMax(min?: Point2D, max?: Point2D): {
136
- min: Point2D;
137
- max: Point2D;
123
+ protected _decoration(): GlyphPathCommand[];
124
+ protected _italic(commands: GlyphPathCommand[], startPoint?: VectorLike): GlyphPathCommand[];
125
+ protected _rotation90(commands: GlyphPathCommand[], point: VectorLike): GlyphPathCommand[];
126
+ protected _transform(commands: GlyphPathCommand[], cb: (x: number, y: number) => number[]): GlyphPathCommand[];
127
+ forEachCommand(cb: (command: GlyphPathCommand, index: number, context: {
128
+ first: VectorLike;
129
+ last: VectorLike;
130
+ }) => void | GlyphPathCommand): this;
131
+ getMinMax(min?: Vector2, max?: Vector2): {
132
+ min: Vector2;
133
+ max: Vector2;
138
134
  };
135
+ getBoundingBox(): BoundingBox;
139
136
  drawTo(ctx: CanvasRenderingContext2D, config?: Partial<TextEffect>): void;
140
137
  }
141
138