Lottie/Bodymovin - Text scaling

Hello all,

I’m trying to build new templates in HTML with exporting sequences out of After Effects by bodymovin and using the lottie library. So far, so good for most part of it.

Only now i would like to create a scaling option for my text (horizontally scaling, not font scaling).
For now i have two options, which both i can’t work out at the moment because i don’t know why:

  • Using an expression within After Effects, (which lottie supports i believe) where the text will horizontally scale within the text box widt (but i can’t find the properties for the horizontal scale)
  • Manipulating the text horizontal scale in Javascript

Does anyone has something worked out for this or does now how to create this?

Kind regards,
Hylke

Hi Hylke,

You can try this effect we use for wrapping some text in a MaxSize custom element, (squash inner text to the width of the parent):

export default class MaxSize extends HTMLElement {
    constructor() {
        super();
    }

    resize() {
        return new Promise(res => {
            const child = this.children[0];
            const parent = this.parentElement;

            window.requestAnimationFrame(() => {
                const parentComputed = window.getComputedStyle(parent);

                const childWidth = child.clientWidth;
                const parentWidth = parent.clientWidth - parseFloat(parentComputed.paddingLeft) - parseFloat(parentComputed.paddingRight);

                //console.log(child, parent);
                //console.log(childWidth, parentWidth);

                if (parentWidth < childWidth) {
                    const scale = parentWidth / childWidth;
                    child.style.transform = `scale(${scale}, 1)`;
                } else {
                    child.style.transform = `scale(1, 1)`;
                }
                window.requestAnimationFrame(res);
            });
        });
    }
}

Import the element into your script like so:

import MaxSize from '@effects/maxsize';
window.customElements.define('max-size', MaxSize);

Then make sure the inner text is inside the element like so:

<div class="header-bar-text">
  <max-size>
    <div class="header-bar-text-inner">${data.headerText}</div>
  </max-size>
</div>

And styling needs flex for the parent, and depending on what way you want to align text, the child may need the transform-origin changed:

.header-bar-text {
    display: flex;
    align-items: center;
    width: 100%;

    .header-bar-text-inner {
        display: inline-block;
        white-space: nowrap;
        transform-origin: 0 0;
    }
}

There’s probably a few ways to do this, no doubt some clever SVG ways too. But this works for us.

We use it like this.

You need to add the max number of pixels for the dom id or class. You just need to replace the [MAX PIXELS] for the number you want. It verifies if all the id’s or classes are higher that the [MAX PIXELS] and adjust them to that size.
The first line removes the max length attribute from all id’s and classes with that filter name before the next apply. We use this inside update, so if there is an update processes it.

$("[lengthAdjust='spacingAndGlyphs']").removeAttr("textLength").removeAttr("lengthAdjust");
$("[id*='name'] text tspan").filter(function (index) {
          return $(this)[0].getComputedTextLength() > [MAX PIXELS];
}).attr("textLength", "[MAX PIXELS]").attr("lengthAdjust", "spacingAndGlyphs");

Maybe there a better way of simplifying this.