Skip to content

Instantly share code, notes, and snippets.

@trxcllnt
Created October 6, 2011 19:53
Show Gist options
  • Select an option

  • Save trxcllnt/1268467 to your computer and use it in GitHub Desktop.

Select an option

Save trxcllnt/1268467 to your computer and use it in GitHub Desktop.
package
{
import embeds.*;
import flash.display.*;
import org.swiftsuspenders.*;
import org.tinytlf.*;
import org.tinytlf.html.*;
import org.tinytlf.util.TagSoup;
[SWF(width = "452", height = "500")]
public class Base extends Sprite
{
private var helvetica:Helvetica;
private var helveticaBold:HelveticaBold;
private var helveticaItalic:HelveticaItalic;
private var helveticaBoldItalic:HelveticaBoldItalic;
protected const injector:Injector = new TextEngineInjector(new TextEngine());
protected var dom:IDOMNode;
public function Base()
{
super();
const g:Graphics = graphics;
g.beginFill(0xFFFFFF, 1);
g.lineStyle(1, 0xCCCCCC);
g.drawRect(1, 1, stage.stageWidth - 1, stage.stageHeight - 1);
const css:CSS = injector.getInstance(CSS);
css.inject(new CSSSource().toString());
const source:String = new HTMLSource().toString();
const html:XML = TagSoup.toXML(source);
css.inject(html..style.text().toString());
const body:XML = html.localName() == 'body' ? html : (html..body[0] || <body>{html}</body>);
dom = new DOMNode(body);
}
}
}
package
{
import flash.events.MouseEvent;
import org.tinytlf.ITextEngine;
import org.tinytlf.html.CSS;
import org.tinytlf.interaction.Observables;
import org.tinytlf.layout.sector.*;
[SWF(width = "452", height = "500")]
public class Circle extends Base
{
public function Circle()
{
super();
const css:CSS = injector.getInstance(CSS);
css.inject(
'*{' +
'font-name: Helvetica;' +
'}' +
'p{' +
'text-align: justify;' +
'}');
injector.injectInto(dom);
const tsfm:ITextSectorFactoryMap = injector.getInstance(ITextSectorFactoryMap);
const panes:Array = injector.getInstance(Array, '<TextPane>');
const pane:TextPane = panes[0];
pane.width = 200;
pane.height = 498;
pane.textSectors = tsfm.
instantiate(dom.nodeName).
create(dom).
map(function(rect:TextRectangle, ... args):TextRectangle {
rect.aligner = new CircleAligner();
if(rect is TextSector)
TextSector(rect).renderer = new CircleRenderer();
return rect;
});
const containers:Array = injector.getInstance(Array, '<Sprite>');
addChild(containers[0]);
containers[0].y += 1;
containers[0].x += 1;
const obs:Observables = injector.getInstance(Observables);
obs.mouseWheel(stage).subscribe(function(me:MouseEvent):void {
engine.scrollPosition -= me.delta;
});
const engine:ITextEngine = injector.getInstance(ITextEngine);
engine.invalidate();
}
}
}
import flash.geom.*;
import flash.text.engine.*;
import org.tinytlf.layout.alignment.*;
import org.tinytlf.layout.sector.*;
import org.tinytlf.util.*;
/**
* CircleRenderer breaks the lines normally, lays them out, then breaks them
* again in a circle shape. This is very inefficient, because the first render
* pass creates lines with a single atom (so we're guaranteed to have more lines
* the first time than the second, so we know how to break them the second time
* around).
*/
internal class CircleRenderer extends StandardSectorRenderer
{
override public function render(block:TextBlock, sector:TextSector, lines:Array = null):Array /*<TextLine>*/
{
lines = super.render(block, sector, lines);
lines = sector.layout.layout(lines, sector);
var line:TextLine = lines[0];
const newLines:Array = [line];
while(true)
{
line = createTextLine(block, line, a.getSize(sector, lines.shift()));
if(line == null) break;
newLines.push(line);
}
while(lines.length > 0)
{
TextLineUtil.checkIn(TextLineUtil.cleanLine(lines.pop()));
}
return newLines;
}
}
internal class CircleAligner extends AlignerBase
{
override public function getSize(rect:TextRectangle, previousItem:* = null):Number
{
if(previousItem is TextRectangle)
return rect.width;
const pLine:TextLine = previousItem as TextLine;
const d:Number = rect.width - rect.paddingLeft - rect.paddingRight;
const r:Number = d * 0.5;
var y:Number = 0;
if(pLine)
y = Math.max(pLine.y + pLine.descent + rect.leading, 0);
if(y > d)
y %= d;
const indent:Number = (rect is TextSector) ? TextSector(rect).textIndent : 0;
const point:Point = xAtY(y, new Point(r, r), r);
return Math.floor(point.y - point.x - indent);
}
override public function getStart(rect:TextRectangle, thisItem:*):Number
{
if(thisItem is TextRectangle || !thisItem)
return rect.paddingLeft;
const indent:Number = (rect is TextSector) ? TextSector(rect).textIndent : 0;
const d:Number = rect.width - rect.paddingLeft - rect.paddingRight;
const r:Number = d * 0.5;
var y:Number = Math.max(thisItem.y - thisItem.ascent, 0);
if(y > d)
y %= d;
const point:Point = xAtY(y, new Point(r, r), r);
return Math.floor(point.x);
}
private function xAtY(yValue:Number, center:Point, radius:Number):Point
{
// equation of circle is (x-h)^2 + (y-k)^2 = r^2 -> x^2 - 2hx + h^2 + (value-k)^2 = r^2
// use the textbook notation
const a:Number = 1;
const b:Number = -2 * center.x;
const c:Number = center.x * center.x + (yValue - center.y) * (yValue - center.y) - radius * radius;
var d:Number = b * b - 4 * a * c;
if(d < 0)
return null;
d = Math.sqrt(d);
// note that 2*a = 2 since a = 1 and 1/2a = 1/2, so I'm adjusting the quadratic formula appropriately
return new Point(0.5 * (-b - d), 0.5 * (-b + d));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment