text-to-canvas 1.1.2 → 1.2.0
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/CHANGELOG.md +5 -0
- package/README.md +28 -3
- package/dist/text-to-canvas.cjs +20 -2
- package/dist/text-to-canvas.esm.min.js +189 -178
- package/dist/text-to-canvas.esm.min.js.map +1 -1
- package/dist/text-to-canvas.min.js +1 -1
- package/dist/text-to-canvas.min.js.map +1 -1
- package/dist/text-to-canvas.mjs +20 -2
- package/dist/text-to-canvas.umd.min.js +1 -1
- package/dist/text-to-canvas.umd.min.js.map +1 -1
- package/dist/types/model.d.ts +20 -1
- package/dist/types/util/style.d.ts +3 -0
- package/dist/types/util/trim.d.ts +1 -1
- package/package.json +26 -20
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## v1.2.0
|
|
9
|
+
|
|
10
|
+
- New `strokeColor` and `strokeWidth` text formatting options to control the outline of the text ([#292](https://github.com/stefcameron/text-to-canvas/issues/292)).
|
|
11
|
+
- Note that due to how the `strokeText()` and `measureText()` Canvas APIs work, the stroke is __not considered__ in text placement. Setting a large width will result in the stroke "bleeding" outside the text box.
|
|
12
|
+
|
|
8
13
|
## v1.1.2
|
|
9
14
|
|
|
10
15
|
- Fixed bug where `drawText()` config `fontColor` option was not being included in the base font format used to render the text ([#64](https://github.com/stefcameron/text-to-canvas/issues/64)).
|
package/README.md
CHANGED
|
@@ -49,6 +49,8 @@ $ yarn add text-to-canvas
|
|
|
49
49
|
|
|
50
50
|
This project __optionally__ depends on the [canvas](https://github.com/Automattic/node-canvas) package which enables it to be used in a Node [demo](#node).
|
|
51
51
|
|
|
52
|
+
> ❗️ Note this is __optional__ as `text-to-canvas` does not formally support this library. This is purely for casual testing and as an example of how `text-to-canvas` should technically work with any library that supports the `HTMLCanvasElement` API. `text-to-canvas` only officially supports HTML `<canvas>`.
|
|
53
|
+
|
|
52
54
|
Since this package needs to be compiled for use on the platform on which you intend to install/use it, the author must either include pre-built binaries specific to your OS when they make a [release](https://github.com/Automattic/node-canvas/releases), or a new binary must be compiled by your package manager (i.e. `npm`) upon installation.
|
|
53
55
|
|
|
54
56
|
If you're installing on a newer Apple M1, M2, or M3 computer, or if you're using a version of Node newer than v20 (the latest LTS at time of writing), you may experience a `node-pre-gyp` failure because `canvas` doesn't provide pre-built binaries for the ARM64 architecture, only providing x86-64 (Intel x64) binaries for Node v20.
|
|
@@ -100,7 +102,7 @@ const text = 'Lorem ipsum dolor sit amet';
|
|
|
100
102
|
// OR with some formatting
|
|
101
103
|
const text: Word[] = [
|
|
102
104
|
{ text: 'Lorem' },
|
|
103
|
-
{ text: 'ipsum', format: { fontWeight: 'bold',
|
|
105
|
+
{ text: 'ipsum', format: { fontWeight: 'bold', fontColor: 'red' } },
|
|
104
106
|
{ text: 'dolor', format: { fontStyle: 'italic' } },
|
|
105
107
|
{ text: 'sit' },
|
|
106
108
|
{ text: 'amet' },
|
|
@@ -177,12 +179,14 @@ You can run this demo locally with `npm run node:demo`
|
|
|
177
179
|
| `y` | `0` | Y position of the text box. |
|
|
178
180
|
| `align` | `center` | Text align. Other possible values: `left`, `right`. |
|
|
179
181
|
| `vAlign` | `middle` | Text vertical align. Other possible values: `top`, `bottom`. |
|
|
180
|
-
| `
|
|
182
|
+
| `fontFamily` | `Arial` | Base font family of the text. |
|
|
181
183
|
| `fontSize` | `14` | Base font size of the text in px. |
|
|
182
184
|
| `fontStyle` | `''` | Base font style, same as css font-style. Examples: `italic`, `oblique 40deg`. |
|
|
183
185
|
| `fontVariant` | `''` | Base font variant, same as css font-variant. Examples: `small-caps`. |
|
|
184
186
|
| `fontWeight` | `'400'` | Base font weight, same as css font-weight. Examples: `bold`, `100`. |
|
|
185
187
|
| `fontColor` | `'black'` | Base font color, same as css color. Examples: `blue`, `#00ff00`. |
|
|
188
|
+
| `strokeColor` | `'black'` | Base stroke color, same as css color. Examples: `blue`, `#00ff00`. |
|
|
189
|
+
| `strokeWidth` | `0` | Base stroke width. Positive number; `<=0` means none. Can be fractional. ⚠️ Word splitting does not take into account the stroke, which is applied on the __center__ of the edges of the text via the [strokeText()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeText) Canvas API. Setting a thick stroke will cause it to bleed out of the text box. |
|
|
186
190
|
| `justify` | `false` | Justify text if `true`, it will insert spaces between words when necessary. |
|
|
187
191
|
| `inferWhitespace` | `true` | If whitespace in the text should be inferred. Only applies if the text given to `drawText()` is a `Word[]`. If the text is a `string`, this config setting is ignored. |
|
|
188
192
|
| `overflow` | `true` | Allows the text to overflow out of the box if the box is too narrow/short to fit it all. `false` will clip the text to the box's boundaries. |
|
|
@@ -303,6 +307,10 @@ const drawWords = (baseFormat: TextFormat, spec: RenderSpec) => {
|
|
|
303
307
|
ctx.textBaseline = textBaseline;
|
|
304
308
|
ctx.font = getTextStyle(baseFormat);
|
|
305
309
|
ctx.fillStyle = baseFormat.fontColor;
|
|
310
|
+
ctx.strokeStyle = baseFormat.strokeColor;
|
|
311
|
+
ctx.lineJoin = 'round';
|
|
312
|
+
|
|
313
|
+
const baseStrokeWidth = baseFormat.strokeWidth
|
|
306
314
|
|
|
307
315
|
lines.forEach((line) => {
|
|
308
316
|
line.forEach((pw) => {
|
|
@@ -313,8 +321,19 @@ const drawWords = (baseFormat: TextFormat, spec: RenderSpec) => {
|
|
|
313
321
|
if (pw.format.fontColor) {
|
|
314
322
|
ctx.fillStyle = pw.format.fontColor;
|
|
315
323
|
}
|
|
324
|
+
if (pw.format.strokeColor) {
|
|
325
|
+
ctx.strokeStyle = pw.format.strokeColor;
|
|
326
|
+
}
|
|
316
327
|
}
|
|
317
328
|
ctx.fillText(pw.word.text, pw.x, pw.y);
|
|
329
|
+
// stroke AFTER fill so it goes on top
|
|
330
|
+
const lineWidth = typeof pw.format?.strokeWidth === 'number'
|
|
331
|
+
? pw.format.strokeWidth
|
|
332
|
+
: baseStrokeWidth;
|
|
333
|
+
if (lineWidth > 0) {
|
|
334
|
+
ctx.lineWidth = lineWidth;
|
|
335
|
+
ctx.strokeText(pw.word.text, pw.x, pw.y);
|
|
336
|
+
}
|
|
318
337
|
if (pw.format) {
|
|
319
338
|
ctx.restore();
|
|
320
339
|
}
|
|
@@ -325,7 +344,7 @@ const drawWords = (baseFormat: TextFormat, spec: RenderSpec) => {
|
|
|
325
344
|
|
|
326
345
|
const words: Word[] = [
|
|
327
346
|
{ text: 'Lorem' },
|
|
328
|
-
{ text: 'ipsum', format: { fontWeight: 'bold',
|
|
347
|
+
{ text: 'ipsum', format: { fontWeight: 'bold', fontColor: 'red' } },
|
|
329
348
|
{ text: 'dolor', format: { fontStyle: 'italic' } },
|
|
330
349
|
{ text: 'sit' },
|
|
331
350
|
{ text: 'amet' },
|
|
@@ -363,3 +382,9 @@ worker.onmessage = (event) => {
|
|
|
363
382
|
```
|
|
364
383
|
|
|
365
384
|
</details>
|
|
385
|
+
|
|
386
|
+
# Help
|
|
387
|
+
|
|
388
|
+
## Blurry text
|
|
389
|
+
|
|
390
|
+
If you're experiencing an issue where, "the text quality rendered on the canvas appears lower than that rendered in the DOM across various device resolutions," this may be caused by __pixel density__ settings. See the discussion on [issue #69](https://github.com/stefcameron/text-to-canvas/issues/69#issuecomment-2136498781) for a possible solution.
|
package/dist/text-to-canvas.cjs
CHANGED
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const DEFAULT_FONT_FAMILY = "Arial";
|
|
4
4
|
const DEFAULT_FONT_SIZE = 14;
|
|
5
5
|
const DEFAULT_FONT_COLOR = "black";
|
|
6
|
+
const DEFAULT_STROKE_COLOR = DEFAULT_FONT_COLOR;
|
|
7
|
+
const DEFAULT_STROKE_WIDTH = 0;
|
|
8
|
+
const DEFAULT_STROKE_JOIN = "round";
|
|
6
9
|
const getTextFormat = (format, baseFormat) => {
|
|
7
10
|
return Object.assign(
|
|
8
11
|
{},
|
|
@@ -12,7 +15,9 @@ const getTextFormat = (format, baseFormat) => {
|
|
|
12
15
|
fontWeight: "400",
|
|
13
16
|
fontStyle: "",
|
|
14
17
|
fontVariant: "",
|
|
15
|
-
fontColor: DEFAULT_FONT_COLOR
|
|
18
|
+
fontColor: DEFAULT_FONT_COLOR,
|
|
19
|
+
strokeColor: DEFAULT_STROKE_COLOR,
|
|
20
|
+
strokeWidth: DEFAULT_STROKE_WIDTH
|
|
16
21
|
},
|
|
17
22
|
baseFormat,
|
|
18
23
|
format
|
|
@@ -474,7 +479,9 @@ const drawText = (ctx, text, config) => {
|
|
|
474
479
|
fontStyle: config.fontStyle,
|
|
475
480
|
fontVariant: config.fontVariant,
|
|
476
481
|
fontWeight: config.fontWeight,
|
|
477
|
-
fontColor: config.fontColor
|
|
482
|
+
fontColor: config.fontColor,
|
|
483
|
+
strokeColor: config.strokeColor,
|
|
484
|
+
strokeWidth: config.strokeWidth
|
|
478
485
|
});
|
|
479
486
|
const {
|
|
480
487
|
width: boxWidth,
|
|
@@ -506,6 +513,9 @@ const drawText = (ctx, text, config) => {
|
|
|
506
513
|
ctx.textBaseline = textBaseline;
|
|
507
514
|
ctx.font = getTextStyle(baseFormat);
|
|
508
515
|
ctx.fillStyle = baseFormat.fontColor || DEFAULT_FONT_COLOR;
|
|
516
|
+
ctx.strokeStyle = baseFormat.strokeColor || DEFAULT_STROKE_COLOR;
|
|
517
|
+
ctx.lineJoin = DEFAULT_STROKE_JOIN;
|
|
518
|
+
const baseStrokeWidth = baseFormat.strokeWidth ?? DEFAULT_STROKE_WIDTH;
|
|
509
519
|
if (config.overflow === false) {
|
|
510
520
|
ctx.beginPath();
|
|
511
521
|
ctx.rect(boxX, boxY, boxWidth, boxHeight);
|
|
@@ -520,8 +530,16 @@ const drawText = (ctx, text, config) => {
|
|
|
520
530
|
if (pw.format.fontColor) {
|
|
521
531
|
ctx.fillStyle = pw.format.fontColor;
|
|
522
532
|
}
|
|
533
|
+
if (pw.format.strokeColor) {
|
|
534
|
+
ctx.strokeStyle = pw.format.strokeColor;
|
|
535
|
+
}
|
|
523
536
|
}
|
|
524
537
|
ctx.fillText(pw.word.text, pw.x, pw.y);
|
|
538
|
+
const lineWidth = typeof pw.format?.strokeWidth === "number" ? pw.format.strokeWidth : baseStrokeWidth;
|
|
539
|
+
if (lineWidth > 0) {
|
|
540
|
+
ctx.lineWidth = lineWidth;
|
|
541
|
+
ctx.strokeText(pw.word.text, pw.x, pw.y);
|
|
542
|
+
}
|
|
525
543
|
if (pw.format) {
|
|
526
544
|
ctx.restore();
|
|
527
545
|
}
|