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:
into seven separate 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:
And finally, to scale the entire slab to fit inside the original box, allowing for a minimum amount of padding on each side:
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
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);
}
Making music out of the data of interplanetary exploration.
Making music out of the data of interplanetary exploration.
Here’s a list of links to works cited in my recent talk “Storytelling in the Age of Divided Screens” at Gallaudet University.
I’m very happy to announce the launch of “Timeframing: The Art of Comics on Screens,” a new website that explores what comics have to teach us about creative communication in the age of screen media.
To celebrate the launch of Upgrade Soul, here’s a screen shot of an eleven year old prototype I made that sets artwork from Will Eisner’s “The Treasure of Avenue ‘C’” (a story from New York: The Big City) in two dynamically resizable panels.
Algorithms
Animation
Announcements
Authoring Tools
Comics
Digital Humanities
Electronic Literature
Events
Experiments
Exemplary Work
Flash
Flex
Fun
Games
Graphic Design
Interactive Design
iPhone
jQuery
LA Flash
Miscellaneous
Music
Opertoon
Remembrances
Source Code
Typography
User Experience
Viewfinder
Wii
July 2018
May 2018
February 2015
October 2014
October 2012
February 2012
January 2012
January 2011
April 2010
March 2010
October 2009
February 2009
January 2009
December 2008
September 2008
July 2008
June 2008
April 2008
March 2008
February 2008
January 2008
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007