Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions Auto Text Wrap Using String Pixel Length

  • Auto Text Wrap Using String Pixel Length

    Posted by Bryce Poole on October 19, 2014 at 4:39 pm

    Hello,

    I’m trying to code a bit of text that will auto wrap text when the user input string hits a certain max pixel length.

    I know after affects does not natively allow you to get the pixel length of a text layer, so I’ve created a look up table using string.match. I went in and manually counted the pixel width of each character for the font (its variable width) then grouped them into variables based on size. Then, I’m using str.match to see how many times a character from each size group is used, then multiplying that result by its pixel length. At the end everything is summed together to get the overall string length.

    I’ve been using this to drive the position of other elements on screen and it seems to be working well, and its much less processor intensive then some of the screen match versions I’ve seen to calculate text length in AE.

    I’ve also got a bit of code that takes care of the text wrapping perfectly, however, it relys on the str.length being over a trigger amount to make the split, then inserting the “\n” at that location in the string. I’m not quite sure how to wrap my head around using this pixel width input as the trigger, but still using str.length to find the appropriate insert point in the string. I keep trying different things but getting errors.

    I’ve posted to code for the pixel width counter and the text wrap bellow. Any help would be greatly appreciated!

    //On a separate layer from the text wrap code, this section counts the input string pixel width

    //defines the variables

    input = thisComp.layer("ENTER TEXT").text.sourceText + "\n";//this "\n" was needed to account for some of the matches in the string like other "\"s
    var line = input.split("\r")[0];

    var a = (line.match(/i/g)||[]).length;
    var b = (line.match(/:/g)||[]).length;
    var c = (line.match(/\.|!/g)||[]).length;
    var d = (line.match(/l|,|;|‘|\]|\[|\|/g)||[]).length;
    var e = (line.match(/\`|\(|\)|j/g)||[]).length;
    var f = (line.match(/\-/g)||[]).length;
    var g = (line.match(/1| |\}|\{/g)||[]).length;
    var h = (line.match(/r/g)||[]).length;
    var i = (line.match(/f|t|\/|\\|\u201C|\u201D/g)||[]).length;
    var j = (line.match(/s|J|\*/g)||[]).length;
    var k = (line.match(/z|L|\?/g)||[]).length;
    var l = (line.match(/a|c|h|n|u|F|2|7|~/g)||[]).length;
    var m = (line.match(/e|k|E|S|3|5|8|\#|_|/g)||[]).length;
    var n = (line.match(/B|6|9|0|\<|\>|\"/g)||[]).length;
    var o = (line.match(/b|d|g|o|p|q|v|x|y|P|R|Z|4|\=|\+|\$/g)||[]).length;
    var p = (line.match(/T|U|\^/g)||[]).length;
    var q = (line.match(/H/g)||[]).length;
    var r = (line.match(/K|\&/g)||[]).length;
    var s = (line.match(/|D|N/g)||[]).length;
    var t = (line.match(/|C|G|V|X|Y|/g)||[]).length;
    var u = (line.match(/A/g)||[]).length;
    var v = (line.match(/O|\@/g)||[]).length;
    var w = (line.match(/m|M|\%/g)||[]).length;
    var x = (line.match(/Q/g)||[]).length;
    var y = (line.match(/w/g)||[]).length;
    var z = (line.match(/W/g)||[]).length;

    //multiply input variables by each characters pixel width

    var a1 = a*9.5;
    var b1 = b*9.5;
    var c1 = c*9.5;
    var d1 = d*10.5
    var e1 = e*12.5;
    var f1 = f*13.5;
    var g1 = g*15.5;
    var h1 = h*16.5;
    var i1 = i*18.5;
    var j1 = j*19.5;
    var k1 = k*19.5;
    var l1 = l*20.5;
    var m1 = m*21.5;
    var n1 = n*25.5;
    var o1 = o*23.5;
    var p1 = p*24.5;
    var q1 = q*25.5;
    var r1 = r*26.5;
    var s1 = s*27.5;
    var t1 = t*28.5;
    var u1 = u*30.5;
    var v1 = v*31.5;
    var w1 = w*32.5;
    var x1 = x*34.5;
    var y1 = y*37.5;
    var z1 = z*40.5;

    //prints the total value

    (a1+b1+c1+d1+e1+f1+g1+h1+i1+j1+k1+l1+m1+n1+o1+p1+q1+r1+s1+t1+u1+v1+w1+x1+y1+z1);

    //
    // On another layer, this is the text wrap code that needs to be modified
    //

    //define variables
    var str = thisComp.layer("ENTER TEXT").text.sourceText; //user input, source of string
    var strPixLeng = parseInt(thisComp.layer("var CharCounter4OverlayLength").text.sourceText); //layer countering pixel width

    //call function
    var result = stringDivider(str, 60, "\n", strPixLeng);
    result;

    // define function
    function stringDivider(str, width, spaceReplacer, strPixLeng) {
    if (str.length>width) {
    var p=width
    for (;p>0 && str[p]!=' ';p--) {
    }
    if (p>0) {
    var left = str.substring(0, p);
    var right = str.substring(p+1);
    return left + spaceReplacer + stringDivider(right, width, spaceReplacer);
    }
    }
    return str;
    }

    Bryce Poole replied 11 years, 9 months ago 2 Members · 2 Replies
  • 2 Replies
  • Dan Ebberts

    October 19, 2014 at 5:48 pm

    I think I would have set up an array of character widths for the ASCII characters (space) through ~, and then looped through the text character by character, keeping a running total of the accumulated length to that point. That way you’ll know when you’ve exceeded your pixel limit.

    Dan

  • Bryce Poole

    October 19, 2014 at 6:20 pm

    Hey Dan,

    Thanks for the reply, that sounds good! I’m still rather new to JavaScript, so I’m not quite sure how to set that up. Could you give me any pointers? Also, I’m really stuck with how to modify my text wrap script to use this information once I have it.

    I keep running into the issue that I need to use .length to find the correct insert point, but when I pass a pixel width of say 2000 into the function as the ‘width’ variable the script breaks since its expecting character length.

    So far I’m trying this, its not returning any errors, but its also not working. I know I’m definitely making a mistake in there somewhere…

    //define variables
    var str = thisComp.layer(“ENTER TEXT”).text.sourceText; //user input, source of string
    var strPixLeng = parseInt(thisComp.layer(“var CharCounter4OverlayLength”).text.sourceText); //layer countering pixel width

    //call function
    var result = stringDivider(str, str.length, “n”, strPixLeng);
    result;

    // define function
    function stringDivider(str, width, spaceReplacer, strPixLeng) {
    if (strPixLeng>2000) {
    var p= width
    for (;p>0 && strPixLeng< 2000;p--) { } if (p>0) {
    var left = str.substring(0, p);
    var right = str.substring(p+1);
    return left + spaceReplacer + stringDivider(right, width, spaceReplacer);
    }
    }
    return str;
    }

    Any help on solving this would be appreciated.

    Thanks again!

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy