Pixi.js: PIXI.Text letterSpacing

Created on 24 Jan 2018  路  22Comments  路  Source: pixijs/pixi.js

Using the "letterSpacing", PIXI.Text draws incorrectly

pixi-text

After viewing the source code and searching Google, I got to make it work correctly

pixi-text

I had to append the canvas in the document, otherwise it does not work.
Any ideas on this?

canvas.style.letterSpacing = style.letterSpacing + 'px';
document.body.appendChild(canvas);
Text.prototype.drawLetterSpacing = function drawLetterSpacing(text, x, y) {
    var isStroke = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;

    var style = this._style;

    // letterSpacing of 0 means normal
    var letterSpacing = style.letterSpacing;

    // if (letterSpacing === 0) {
        if (isStroke) {
            this.context.strokeText(text, x, y);
        } else {
            this.context.fillText(text, x, y);
        }

        // return;
    // }

    // var characters = String.prototype.split.call(text, '');
    // var currentPosition = x;
    // var index = 0;
    // var current = '';
    //
    // while (index < text.length) {
    //     current = characters[index++];
    //     if (isStroke) {
    //         this.context.strokeText(current, currentPosition, y);
    //     } else {
    //         this.context.fillText(current, currentPosition, y);
    //     }
    //     currentPosition += this.context.measureText(current).width + letterSpacing;
    // }
};

I would also like to do something like this

canvas.style.mozOsxFontSmoothing = 'grayscale';
canvas.style.webkitFontSmoothing = 'antialiased';
Stale 馃捑 v4.x (Legacy) 馃摙 Accepting PRs

Most helpful comment

All 22 comments

When I try to replicate your text using pixi-text-style, there aren't any issues with the letter spacing.
http://pixijs.io/pixi-text-style/#%7B%22style%22%3A%7B%22dropShadow%22%3Atrue%2C%22dropShadowAngle%22%3A-1.5%2C%22dropShadowColor%22%3A%22white%22%2C%22dropShadowDistance%22%3A3%2C%22fill%22%3A%22%23d70b00%22%2C%22fontSize%22%3A93%2C%22fontWeight%22%3A%22bold%22%2C%22letterSpacing%22%3A7%2C%22padding%22%3A10%7D%2C%22text%22%3A%22WATER%22%2C%22background%22%3A%22%2300ffff%22%7D
Could you see if you could reproduce on that tool please?

Arial - bad font, it does not have kerning!
I used the Muller font.
Can I use custom fonts in this tool?

Oh, it's not a drop shadow, red is a html-text, and white is a pixi-text

Ah I see. So, is your issue that letter spacing isn't working at all for you, on that font, or that it's not matching the look of html text with css letter spacing?

The letter spacing works, but it does not work correctly, thus it does not coincide with css!
If I add a style to the canvas of the text:
canvas.style.letterSpacing = '6px';
That works correctly, but there is a need to add an element of canvas to the document

This is not a problem with a specific font, I tried the Arial font - it turns out the same! PIXI.Text ignores font kerning when changing letter spacing
pixi-text

the thing is tho, doing
canvas.style.letterSpacing = '6px';
is not a spec agreed ability. It works in Chrome, but not in IE, for example (last time I checked).

So therefore we use our own calculation for letter spacing, which is why you see the difference.

So I make issue here.

Text can not automatically configure kerning, as does this font!
You can check it yourself on any project, the result will be the same for all

Font 'Times New Roman'
pixi-text

Pixi text
pixi-text

Problem space
pixi-text

even in FF it does not work

The code for it in pixi is

        const characters = String.prototype.split.call(text, '');
        let currentPosition = x;
        let index = 0;
        let current = '';

        while (index < text.length)
        {
            current = characters[index++];
            if (isStroke)
            {
                this.context.strokeText(current, currentPosition, y);
            }
            else
            {
                this.context.fillText(current, currentPosition, y);
            }
            currentPosition += this.context.measureText(current).width + letterSpacing;
        }

So rather than draw all of the text at once normally, it draws one letter at a time, trying to calculate the correct x co-ordinate to draw each one by asking the canvas how wide the existing text already is. This solution comes up against issues with wide characters, like W and A.

You're red arrows point to the big gaps, but I'd point to the different in the top right of the W and the bottom left of the A, and the bottom right of the A and the top left of the T. Here you can see why the method of measuring text via the canvas then adding a bit of extra spacing comes unstuck. With 0 letter spacing, the top right of the W actually overlaps the bottom left of the A.

No actual answers or solutions here, I'm afraid, just explaining how the code works and thus why letter spacing can make things look poor on some fonts.

Yes, I know this, that he draws text by one letter

I found another text construction algorithm and it works better
https://stackoverflow.com/a/34058109/8236153
"Basically it uses measureText() to get the width of the whole string, and then removes the first character of the string and measures the width of the remaining string, and uses the difference to calculate the correct positioning - thus taking into account kerning pairs and the like. See the given link for more pseudocode."

function fillTextWithSpacing(context, text, x, y, spacing){
    wAll = context.measureText(text).width;

    do{
    char = text.substr(0, 1);
    text = text.substr(1);
    context.fillText(char, x, y);

    if (text == "")
        wShorter = 0;
    else
        wShorter = context.measureText(text).width;


    wChar = wAll - wShorter;

    x += wChar + spacing;
    wAll = wShorter;

    } while (text != "");
}

There is a possibility that you will change the algorithm?

Yeah, it'd be making the letter spacing act more in line with how people would expect it to look.

And, can you explain, please, how does PIXI.settings.SCALE_MODE affect text (texture)?
If I use the default settings, then the text is blurry, but in the original canvas it is sharp

PIXI.settings.SCALE_MODE = 0; // default

pixi-text

PIXI.settings.SCALE_MODE = 1;

pixi-text

http://pixijs.download/dev/docs/PIXI.html#.SCALE_MODES
0 = Linear texture scaling = smoother textures (but can look blurry)
1= Nearest texture scaling = sharper pixellated edges (but can look ugly if texture resolution doesn't match render resolution)

I changed the Text.js plugin.
What can I do, can I make a pull request or put the source code here?

If you made a PR, that'd be awesome :)

@gizmooo Do you think you'll get a chance to a submit a PR for this please? It would be super helpful :)

@gizmooo It would be very helpful if you could make a PR for this problem, as It should help lots of users stop experiencing cutting off letters without workaround padding and improve general text look. It would be pleasant if you at least will share your solution.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

As far as we can tell the issue still isn't fixed. Can you the fix be applied please?

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings