multiline-canvas-text
Advanced tools
Comparing version 1.0.3 to 2.0.0
@@ -11,5 +11,31 @@ export interface IFont { | ||
canvas: HTMLCanvasElement; | ||
lastCharacterPosition: IPoint; | ||
cursor: IPoint; | ||
lines: string[]; | ||
} | ||
export declare function drawText(text: string, width: number, fontName: string, fontSize: number, lineSpacing?: number, color?: string): IDrawTextResult; | ||
export declare const TextAlign: { | ||
CENTER: string; | ||
LEFT: string; | ||
RIGHT: string; | ||
}; | ||
/** | ||
* Creates a canvas of the given width and renders the string into it | ||
* @param {string} text | ||
* @param {number} width | ||
* @param {string} fontName | ||
* @param {number} fontSize | ||
* @param {number} lineSpacing | ||
* @param {string} color | ||
* @param {boolean} strokeText | ||
* @param {string} align | ||
* @returns {IDrawTextResult} | ||
*/ | ||
export declare function drawText(text: string, width: number, fontName: string, fontSize: number, lineSpacing?: number, color?: string, strokeText?: boolean, align?: string): IDrawTextResult; | ||
/** | ||
* Breaks up a string into lines that fit within the supplied width. | ||
* @param {string} text | ||
* @param {number} width | ||
* @param {string} fontName | ||
* @param {number} fontSize | ||
* @returns {string[]} | ||
*/ | ||
export declare function fitText(text: string, width: number, fontName: string, fontSize: number): string[]; |
153
index.js
@@ -5,5 +5,22 @@ "use strict"; | ||
exports.drawText = drawText; | ||
exports.fitText = fitText; | ||
exports.TextAlign = void 0; | ||
var _trimCanvas = require("./trimCanvas"); | ||
var TextAlign = { | ||
CENTER: 'center', | ||
LEFT: 'left', | ||
RIGHT: 'right' | ||
}; | ||
/** | ||
* For a given string, returns a new string in which all the separate words (characters divided by a space) fit in the given width. Can add spaces into original words if they are too long. | ||
* @param {string} text | ||
* @param {number} availableWidth | ||
* @param {IFont} font | ||
* @returns {string} | ||
*/ | ||
exports.TextAlign = TextAlign; | ||
function splitIntoFittingWords(text, availableWidth, font) { | ||
@@ -37,3 +54,12 @@ var splitResults = []; | ||
} | ||
/** | ||
* Groups a given string into fitting parts. What a part is is defined by the character to split the original string on. | ||
* @param {string} text | ||
* @param {string} splitOn | ||
* @param {number} availableWidth | ||
* @param {IFont} font | ||
* @returns {string[]} | ||
*/ | ||
function groupText(text, splitOn, availableWidth, font) { | ||
@@ -61,4 +87,17 @@ return text.split(splitOn).reduce(function (resultingLines, currentItem) { | ||
} | ||
/** | ||
* Creates a canvas of the given width and renders the string into it | ||
* @param {string} text | ||
* @param {number} width | ||
* @param {string} fontName | ||
* @param {number} fontSize | ||
* @param {number} lineSpacing | ||
* @param {string} color | ||
* @param {boolean} strokeText | ||
* @param {string} align | ||
* @returns {IDrawTextResult} | ||
*/ | ||
function drawText(text, width, fontName, fontSize, lineSpacing, color) { | ||
function drawText(text, width, fontName, fontSize, lineSpacing, color, strokeText, align) { | ||
if (lineSpacing === void 0) { | ||
@@ -72,25 +111,61 @@ lineSpacing = 0; | ||
// for now, just add spacing to fix fonts falling ut of view sometimes (at the bottom specifically) | ||
if (strokeText === void 0) { | ||
strokeText = false; | ||
} | ||
if (align === void 0) { | ||
align = 'center'; | ||
} | ||
var alignModes = [TextAlign.LEFT, TextAlign.CENTER, TextAlign.RIGHT]; | ||
if (alignModes.indexOf(align) === -1) { | ||
throw new Error("Invalid alignMode (possible options: " + alignModes.join(',') + ")"); | ||
} // for now, just add spacing to fix fonts falling ut of view sometimes (at the bottom specifically) | ||
// padding will be removed by trimming canvas at the end | ||
var padding = { | ||
x: 10, | ||
y: 15 | ||
}; | ||
var font = { | ||
size: fontSize, | ||
name: fontName | ||
}; | ||
var lines = fitText(text, width, font); // create and init canvas | ||
x: 20, | ||
y: fontSize * 2 | ||
}; // todo this needs a better fix | ||
var font = createFont(fontName, fontSize); | ||
var lines = fitText(text, width - 2 * padding.x, fontName, fontSize); // create and init canvas | ||
var canvas = document.createElement('canvas'); | ||
canvas.width = width + 2 * padding.x; | ||
canvas.width = width; // + 2 * padding.x; | ||
canvas.height = lines.length * fontSize + (lines.length - 1) * lineSpacing + 2 * padding.y; | ||
var context = canvas.getContext('2d'); | ||
context.font = getCanvasFontProperty(font); | ||
context.textAlign = 'center'; | ||
context.textBaseline = 'top'; // draw lines | ||
context.textAlign = align; | ||
context.textBaseline = 'top'; | ||
context.fillStyle = color; | ||
context.strokeStyle = color; // draw lines | ||
var centerX = canvas.width * 0.5; | ||
var baseX; | ||
switch (align) { | ||
case TextAlign.RIGHT: | ||
{ | ||
baseX = canvas.width - padding.x; | ||
break; | ||
} | ||
case TextAlign.LEFT: | ||
{ | ||
baseX = padding.x; | ||
break; | ||
} | ||
case TextAlign.CENTER: | ||
{ | ||
baseX = canvas.width * 0.5; | ||
break; | ||
} | ||
} | ||
var yOffset = 0; | ||
var lastCharacterPosition = { | ||
var cursor = { | ||
x: canvas.width * 0.5, | ||
@@ -100,5 +175,9 @@ y: yOffset | ||
lines.forEach(function (line) { | ||
context.fillStyle = color; | ||
context.fillText(line, centerX, yOffset); | ||
lastCharacterPosition = { | ||
if (strokeText) { | ||
context.strokeText(line, baseX, yOffset); | ||
} else { | ||
context.fillText(line, baseX, yOffset); | ||
} | ||
cursor = { | ||
x: canvas.width * 0.5 + 0.5 * getTextWidth(line, font).width, | ||
@@ -110,15 +189,45 @@ y: yOffset | ||
return { | ||
lastCharacterPosition: lastCharacterPosition, | ||
lines: [], | ||
lines: lines, | ||
cursor: cursor, | ||
canvas: (0, _trimCanvas.trimCanvas)(canvas) | ||
}; | ||
} | ||
/** | ||
* Breaks up a string into lines that fit within the supplied width. | ||
* @param {string} text | ||
* @param {number} width | ||
* @param {string} fontName | ||
* @param {number} fontSize | ||
* @returns {string[]} | ||
*/ | ||
function fitText(text, width, font) { | ||
function fitText(text, width, fontName, fontSize) { | ||
var font = createFont(fontName, fontSize); | ||
var fittingWords = splitIntoFittingWords(text, width, font); | ||
return groupText(fittingWords, ' ', width, font); | ||
} | ||
/** | ||
* Formats fontName and fontSize into a css string for canvas. | ||
* @param {IFont} font | ||
* @returns {string} | ||
*/ | ||
function getCanvasFontProperty(font) { | ||
return font.size + "px " + font.name; | ||
} | ||
} | ||
/** | ||
* Create IFont object | ||
* @param {string} name | ||
* @param {number} size | ||
* @returns {IFont} | ||
*/ | ||
var createFont = function createFont(name, size) { | ||
return { | ||
size: size, | ||
name: name | ||
}; | ||
}; |
{ | ||
"name": "multiline-canvas-text", | ||
"version": "1.0.3", | ||
"description": "Render multiline text to canvas", | ||
"version": "2.0.0", | ||
"description": "Render a string to canvas, breaking it up into multiple lines to fit the given width.", | ||
"main": "./index.js", | ||
@@ -6,0 +6,0 @@ "types": "./index.d.ts", |
# multiline-canvas-text | ||
Render a string to canvas, breaking it up into multiple lines to fit the given width. | ||
## install | ||
```sh | ||
npm install multiline-canvas-text | ||
``` | ||
## demo | ||
Check out the [interactive example](https://petervdn.github.io/multiline-canvas-text/example/). | ||
## usage | ||
```javascript | ||
import { drawText } from "multiline-canvas-text"; | ||
const text = 'The quick brown fox jumps over the lazy dog'; | ||
const width = 40; // width in pixels to fit the text | ||
const font = 'Arial'; // font should be available in the page | ||
const fontSize = 20; // in pixels | ||
const lineSpacing = 1; // vertical spacing between the lines | ||
const color = 'white'; // can be any valid css color string: 'black', #FFF', 'rgba(0,0,0,0.5)', etc | ||
const strokeText = false; // true results in calling strokeText instead of fillText | ||
const result = drawText(text, width, font, fontSize, lineSpacing, color, strokeText); | ||
element.appendChild(result.canvas); | ||
``` | ||
The result object contains 3 properties: | ||
* `canvas`: The generated canvas element with the rendered text. This canvas has the width that was given to the `drawText` method, but can obviously vary in height. | ||
* `lines`: An array that shows how the string was broken up into multiple lines, for example: `["The quick brown", "fox jumps over", "the lazy dog"]` | ||
* `cursor`: if you are replicating an interactive textfield in canvas, you may want to add a blinking cursor to increase the user experience. The `cursor` property holds `x` and `y` values for where to draw it. **This value is not correct at the moment!** |
@@ -8,14 +8,6 @@ "use strict"; | ||
function trimCanvas(canvas) { | ||
var ctx = canvas.getContext('2d'); // create a temporary canvas in which we will draw back the trimmed text | ||
var copy = document.createElement('canvas').getContext('2d'); // Use the Canvas Image Data API, in order to get all the | ||
// underlying pixels data of that canvas. This will basically | ||
// return an array (Uint8ClampedArray) containing the data in the | ||
// RGBA order. Every 4 items represent one pixel. | ||
var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height); // total pixels | ||
var l = pixels.data.length; // main loop counter and pixels coordinates | ||
var x; | ||
var ctx = canvas.getContext('2d'); | ||
var copy = document.createElement('canvas').getContext('2d'); | ||
var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height); | ||
var l = pixels.data.length; | ||
var y; // an object that will store the area that isn't transparent | ||
@@ -33,4 +25,3 @@ | ||
if (pixels.data[i + 3] !== 0) { | ||
// find it's coordinates | ||
x = i / 4 % canvas.width; | ||
// find its coordinates | ||
y = ~~(i / 4 / canvas.width); // store/update those coordinates | ||
@@ -41,16 +32,15 @@ // inside our bounding box Object | ||
bound.top = y; | ||
} | ||
} // if (bound.left === null) { | ||
// bound.left = x; | ||
// } else if (x < bound.left) { | ||
// bound.left = x; | ||
// } | ||
// | ||
// if (bound.right === null) { | ||
// bound.right = x; | ||
// } else if (bound.right < x) { | ||
// bound.right = x; | ||
// } | ||
if (bound.left === null) { | ||
bound.left = x; | ||
} else if (x < bound.left) { | ||
bound.left = x; | ||
} | ||
if (bound.right === null) { | ||
bound.right = x; | ||
} else if (bound.right < x) { | ||
bound.right = x; | ||
} | ||
if (bound.bottom === null) { | ||
@@ -67,6 +57,7 @@ bound.bottom = y; | ||
var trimHeight = bound.bottom - bound.top; | ||
var trimWidth = bound.right - bound.left; // get the zone (trimWidth x trimHeight) as an ImageData | ||
var trimWidth = canvas.width; // do not trim horizontally | ||
// get the zone (trimWidth x trimHeight) as an ImageData | ||
// (Uint8ClampedArray of pixels) from our canvas | ||
var trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight); // Draw back the ImageData into the canvas | ||
var trimmed = ctx.getImageData(0, bound.top, trimWidth, trimHeight); // Draw back the ImageData into the canvas | ||
@@ -73,0 +64,0 @@ copy.canvas.width = trimWidth; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
177101
291
33