Slabtype algorithm now a jQuery plugin

Algorithms, Digital Humanities, Graphic Design, jQuery, Source Code, Typography
1/17/12

image

Slabtype, the text rendering algorithm I developed for Public Secrets, has been adapted by web developer Brian McAllister as a jQuery plugin. If you’re interested, you can read details about the inner workings of the original algorithm. Very gratifying to see past work live on in new forms!

 

Source and slides for the Flash Platform Workshop (Updated)

Events, Flash, Flex, Interactive Design, Source Code
2/24/08

UPDATE: The Adobe Connect archive of the workshop has been posted.

Workshop description: Flash is no longer just a plug-in; it has evolved into a massive suite of tools, services and techniques called the Flash Platform. Used for everything from character animation to interactive video to full-featured applications that rival their desktop counterparts, Flash plays a major role in shaping how users experience content on the Internet. This workshop will introduce the Flash Platform with specific emphasis on programming in ActionScript 3.0 and MXML and the basics of working in Flash and Flex (and how you decide when to use which).

For those attending today’s Flash Platform Workshop, this is the place to download the source code and slides.

I encourage you to leave comments on this post with your feedback (positive and negative!) about the workshop. Thanks!

 

The slabtype algorithm, Part 4: Final layout and source code

Algorithms, Flash, Graphic Design, Interactive Design, Source Code, Typography
1/30/08

This is the final installment of a four-part graphical dissection of the “slabtype” text layout algorithm I developed for Public Secrets. For an introduction to the algorithm, visit The slabtype algorithm, Part 1: Background. To review some calculations that set the stage, visit Part 2: Initial calculations. To get into the real meat of the algorithm, visit Part 3: Iterative line splitting.

In this post, we’ll wrap things up by doing our final layout of the text, followed by the source code for the algorithm. The iterative sequence we explored in the previous installment successfully turned our original text:

Original text

into seven separate lines:

All seven lines

We’re almost done. Our next task is to assemble these lines into a slab by scaling them all to an identical pixel width:

Scaled lines

And finally, to scale the entire slab to fit inside the original box, allowing for a minimum amount of padding on each side:

Scaled lines inside slab

And with that, the algorithm has run its course. In conjunction with the treemap algorithm, the slabtype algorithm allows us to dynamically lay out the entire contents of a screen like this

A screen full of slabtype

using only a collection of quotes as a starting point. Due to randomization in the input to the treemap algorithm, even identical collections of quotes are never laid out in exactly the same way. Within Public Secrets, you can briefly see the dynamism of the slabtype algorithm in action when a box containing a quote resizes as it moves from one location to another—the text inside shifts around to keep pace with the changing dimensions of its enclosing rectangle.

This algorithm was included in Public Secrets as a method called formatInscription, which is reproduced below (AS 2.0). I hope this has been a useful exercise—I’d love to get your feedback, questions, or suggestions for improvement.


    /* -- formatInscription : formats the text to fit the slab dimensions -- */
    public function formatInscription(rect:Rectangle, useMargin:Boolean):Void {
       
        // calculate height of the ’ideal’ line
        var idealLineAspectRatio:Number = PS.fontInfo.altGoth3D.aspectRatio * PS.fontInfo.altGoth3D.idealLineLength;
        var idealLineWidth:Number = rect.width;
        var idealLineHeight:Number = idealLineWidth / idealLineAspectRatio;
        var lineCount:Number = Math.floor(rect.height / idealLineHeight);
        var idealCharPerLine:Number = Math.min(60, Math.max(Math.round(this._inscription.length / lineCount), 1));
       
       
        // segment the text into lines
        var words:Array = this._inscription.split(“ ”);
        var lineBreaks:Array = new Array();
        var preText,postText,finalText:String;
        var preDiff,postDiff:Number;
        var wordIndex:Number = 0;
        var lineText:Array = new Array();
       
       
        var counter:Number = 0;
       
        // while we still have words left, build the next line
        while (wordIndex < words.length) {
            postText = “”;
           
            // build two strings (preText and postText) word by word, with one
            // string always one word behind the other, until
            // the length of one string is less than the ideal number of characters
            // per line, while the length of the other is greater than that ideal
            while (postText.length < idealCharPerLine) {
                preText = postText;
                postText += words[wordIndex]+“ ”;
                wordIndex++;
                if (wordIndex >= words.length) {
                    break;
                }
            }
           
            // calculate the character difference between the two strings and the
            // ideal number of characters per line
            preDiff = idealCharPerLine - preText.length;
            postDiff = postText.length - idealCharPerLine;
           
            // if the smaller string is closer to the length of the ideal than
            // the longer string, and doesn’t contain just a single space, then
            // use that one for the line
            if ((preDiff < postDiff) && (preText.length > 2)) {
                finalText = preText;
                wordIndex--;
               
            // otherwise, use the longer string for the line
            } else {
                finalText = postText;
            }
           
            lineText.push(finalText.substr(0, finalText.length-1));
        }
       
        lineCount = lineText.length;
       
        // create inscription clip
        this._inscriptionClip.removeMovieClip();
        this.createEmptyMovieClip(“inscriptionClip”, 10);
        this._inscriptionClip = this[“inscriptionClip”];
       
        // build the text fields
        var curY:Number = 0;
        this._lines = new Array();
        for (var i:Number=0; i<lineCount; i++) {
            this._inscriptionClip.attachMovie(“altGoth3DText”, “line”+i, 10+i);
            this._lines.push(this._inscriptionClip[“line”+i]);
            this._lines[i].content.text = lineText[i];
           
            // scale this line so it exactly fits with width of the rect
            this._lines[i]._yscale = this._lines[i]._xscale = (rect.width / this._lines[i].content.textWidth) * 100;
           
            this._lines[i]._y = curY;
            curY += this._lines[i]._height * .59;
        }
       
        this._inscriptionWidth = rect.width;
        this._inscriptionHeight = curY;
        this._inscriptionAR = this._inscriptionWidth / this._inscriptionHeight;
       
        if (useMargin) {
            var margin:Number = this._margin;
        } else {
            var margin:Number = 0;
        }
       
        // calculate the scaling to apply so the total inscription fits inside the rect
        // centered, with the given margin
        var clipScale:Number;
        clipScale = ((rect.width-(margin * 2)) / rect.width) * 100;
        if (this._inscriptionHeight > rect.height) {
            clipScale = ((rect.height-(margin * 2)) / this._inscriptionHeight) * 100;
        }
        this._inscriptionClip._yscale = this._inscriptionClip._xscale = clipScale;
        this._inscriptionClip._x = (rect.width - (rect.width * (clipScale / 100))) / 2;
        this._inscriptionClip._y = (rect.height - (this._inscriptionHeight * (clipScale / 100))) / 2;
        GraphicUtil.changeColor(this._inscriptionClip, this._colorScheme.text_color);
           
    }


 

Cardinal splines in ActionScript (Updated)

Algorithms, Flex, Source Code
8/20/07

Here’s the code driving the cardinal spline function I mentioned in the post last week on visual prototyping with Flex. ActionScript already has a bezier drawing method called “curveTo,” but it obliges you to specify a control point for every anchor point you add to the curve. This is great for precision, but sometimes you just want to run a smooth curve through a bunch of points without having to figure out where all the control points should be.

That’s what’s great about the cardinal spline—the next and previous points on the curve function as the control points.  (This means you need to add an extra point to the beginning and end of the curve, as you can see in the diagram accompanying the Wikipedia entry for c-splines.) You also get a “tension” parameter which allows you to set how taut the curve is between points.

I’ve included my current incarnation of this routine below.  Here’s how to use it:

  1. Start with an array of values you want to run the curve through: 3, 7, 2, 6
  2. Duplicate the start and end values: 3, 3, 7, 2, 6, 6
  3. Iterate through each pair of the original values, each of which represents a segment of the curve: 3-7, 7-2, 2-6
  4. For each of these iterations, proceed along the curve n number of steps (more steps = a smoother curve)
  5. Call this function at each step to get the value of the curve at that step

If you’re using the function to set the location of a sprite, then you’ll need to maintain two lists of values (one for x position, one for y position) and call the function once for each list as you’re iterating through each segment of the curve.

Update: Here’s an .fla example that uses the function to draw a curved line through twenty random points.

Here’s the source for the function itself:

/** 
 * Returns a value at the given step on the cardinal spline between two other values. 
 * 
 * @param prevVal  The point just prior the curve segment we are evaluating. 
 * @param startVal     The starting point of the curve segment we are evaluating. 
 * @param endVal       The ending point of the curve segment we are evaluating. 
 * @param nextVal  The point just after the curve segment we are evaluating. 
 * @param numSteps     Number of steps in the curve segment. 
 * @param curStep  The current step in the curve segment. 
 * @param easing       Type of interpolation to be applied to the curve segment. 
 * @param tension  How taut the curve is (0 = straight, 1 = curvy) 
 */ 
function getCardinalSplinePoint(prevVal:Number, startVal:Number, endVal:Number, nextVal:Number, numSteps:Number, curStep:Number, easing:String, tension:Number):Number {

    var t1:Number; 
    var t2:Number;
   
    switch (easing) {
   
        case “easeinout”: 
        t1 = endVal - prevVal; 
        t2 = nextVal - startVal; 
        break;
       
        case “noease”: 
        t1 = 0; 
        t2 = 0; 
        break;
       
        case “easein”: 
        t1 = 0; 
        t2 = nextVal - startVal; 
        break;
       
        case “easeout”: 
        t1 = endVal - prevVal; 
        t2 = 0; 
        break; 
    }
   
    t1 *= tension; 
    t2 *= tension;
   
    var s:Number = curStep / numSteps; 
    var h1:Number = (2 * Math.pow(s,3)) - (3 * Math.pow(s,2)) + 1; 
    var h2:Number = -(2 * Math.pow(s,3)) + (3 * Math.pow(s,2)); 
    var h3:Number = Math.pow(s,3) - (2 * Math.pow(s,2)) + s; 
    var h4:Number = Math.pow(s,3) - Math.pow(s,2);
   
    var value:Number = (h1 * startVal) + (h2 * endVal) + (h3 * t1) + (h4 * t2);
   
    return value; 
} 

 

Page 1 of 1 pages