※現在、「wonderfl build flash online」求人コンテンツ制作に関してのアンケートを実施中です!みなさまのお力添えを頂いて、続々とアンケート結果が集まっていますが、まだまだ募集しております。ご協力のほど、どうぞよろしくお願いいたします!
wonderfl運営事務局
→アンケートページ(※ログインしてからお答えいただけるようになっています。)
handwriting
糸で文字
糸と文字
Sewing
Sewing
cool
lineslines curves
wonderfl
糸で文字すげー
typoパクったら負け
line
スンゲー
cool
どひゃー
糸で文字なにかのCMみたい
すごいとしか言いようがない
ひょろひょろ
びろびろびろびろ
うにょうにょ文字
これはすごい糸
凄い
糸
さすが、Saqooshaさん。
すごすぎ
i just peed a little bit....
pas mal...
にゅるにゅるる
なんじゃこりゃー
すごいー
きたーー
Amazing!!!!!!
素晴らしい!
かわえぇ
シュルシュルシュルー!
おもしろー
Sewing forked from: Sewing
- // forked from Saqoosha's Sewing
- package {
- import caurina.transitions.Equations;
- import caurina.transitions.Tweener;
- import caurina.transitions.properties.CurveModifiers;
- import flash.display.Graphics;
- import flash.display.Sprite;
- import flash.display.StageAlign;
- import flash.display.StageQuality;
- import flash.display.StageScaleMode;
- import flash.events.Event;
- import flash.geom.Point;
- import flash.net.URLLoader;
- import flash.net.URLLoaderDataFormat;
- import flash.net.URLRequest;
- import flash.utils.setTimeout;
- [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
- public class Sewing extends Sprite {
- private var _loader:URLLoader;
- private var _canvas:Sprite;
- private var _paths:Array;
- public function Sewing() {
- Wonderfl.capture_delay(8);
- this.stage.quality = StageQuality.BEST;
- this.stage.align = StageAlign.TOP_LEFT;
- this.stage.scaleMode = StageScaleMode.NO_SCALE;
- CurveModifiers.init();
- this._canvas = this.addChild(new Sprite()) as Sprite;
- this._loader = new URLLoader();
- this._loader.dataFormat = URLLoaderDataFormat.TEXT;
- this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
- this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
- }
- private function _handleLoaded(e:Event):void {
- var svg:XML = new XML(this._loader.data);
- this._paths = [];
- var path:SVGPath;
- var delay:Number = 2.0;
- var cx:Number = parseInt(svg.@width) / 2;
- var cy:Number = parseInt(svg.@height) / 2;
- this._canvas.x = this.stage.stageWidth / 2 - cx;
- this._canvas.y = this.stage.stageHeight / 2 - cy;
- for each (var pathNode:XML in svg..*::path) {
- path = new SVGPath(pathNode);
- this._paths.push(path);
- var i:Number = 0;
- var di:Number = Math.PI * 2 / path.points.length;
- var px:Number = cx;
- var py:Number = this.stage.stageHeight - this._canvas.y;
- for each (var pt:Point in path.points) {
- Tweener.addTween(pt, {
- x: pt.x,
- y: pt.y,
- _bezier:[
- { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
- { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
- ],
- time: 1.0,
- delay: delay,
- transition: Equations.easeNone
- });
- pt.x = px;
- pt.y = py;
- delay += 0.004;
- i += di;
- }
- }
- this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
- setTimeout(function ():void {
- removeEventListener(Event.ENTER_FRAME, _drawPaths);
- }, (delay + 1) * 1000);
- }
- private function _drawPaths(e:Event):void {
- this._canvas.graphics.clear();
- for each (var path:SVGPath in this._paths) {
- path.draw(this._canvas.graphics);
- }
- }
- }
- }
- import flash.display.Graphics;
- import flash.geom.Point;
- import flash.geom.Rectangle;
- /**
- * @class PathToArray
- * @author Helen Triolo (with contributions from many people)
- * @version 1.01
- * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
- * not contain any CRLF characters), and an empty array.
- * Parses the path node to make an array of drawing commands, which include cubic bezier
- * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
- * using Robert Penner's code to convert with accuracy within 1 pixel.
- * Drawing commands are produced in the format originally devised by Peter Hall
- * in his ASVDrawing class. These are the possible elements in array dCmds (and the
- * corresponding Flash drawing API commands to apply them):
- * ['M',[x,y]] moveTo(x,y)
- * ['L',[x,y]] lineTo(x,y)
- * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
- * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
- * ['F',[color,alpha]] beginFill(color,alpha)
- * ['EF'] endFill()
- * History:
- * v1.00 2005/11/13 Original release
- * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
- *
- * @param svgnode (XMLNode) Path node from SVG file
- * @param dCmds (Array) Empty array to write commands to
- */
- class SVGPath {
- private var _commands:Array;
- public function get commands():Array { return this._commands }
- private var _points:Array;
- public function get points():Array { return this._points }
- private function addPoint(... points:Array):void {
- for each (var pt:Point in points) {
- this._addPoint(pt);
- }
- }
- private function _addPoint(pt:Point):void {
- if (pt.x < this._bounds.left) {
- this._bounds.left = pt.x;
- } else if (this._bounds.right < pt.x) {
- this._bounds.right = pt.x;
- }
- if (pt.y < this._bounds.top) {
- this._bounds.top = pt.y;
- } else if (this._bounds.bottom < pt.y) {
- this._bounds.bottom = pt.y;
- }
- this._points.push(pt);
- }
- private var _bounds:Rectangle;
- public function get boundsRect():Rectangle { return this._bounds }
- private var _hasFill:Boolean;
- public function get hasFill():Boolean { return this._hasFill }
- private var _hasStroke:Boolean;
- public function get hasStroke():Boolean { return this._hasStroke }
- public function swapFillAndStroke():void {
- var flg:Boolean = this._hasFill;
- this._hasFill = this._hasStroke;
- this._hasStroke = flg;
- var val:Number = this._fillColor;
- this._fillColor = this._strokeColor;
- this._strokeColor = val;
- val = this._fillAlpha;
- this._fillAlpha = this._strokeAlpha;
- this._strokeAlpha = val;
- }
- private var _fillColor:Number;
- public function get fillColor():Number { return this._fillColor }
- public function set fillColor(col:Number):void { this._fillColor = col }
- private var _fillAlpha:Number;
- public function get fillAlpha():Number { return this._fillAlpha }
- public function set fillAlpha(al:Number):void { this._fillAlpha = al }
- private var _strokeColor:Number;
- public function get strokeColor():Number { return this._strokeColor }
- public function set strokeColor(col:Number):void { this._strokeColor = col }
- private var _strokeAlpha:Number;
- public function get strokeAlpha():Number { return this._strokeAlpha }
- public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
- private var _strokeWidth:Number;
- public function get strokeWidth():Number { return this._strokeWidth }
- public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
- /**
- *
- */
- public function SVGPath(svgNode:XML) {
- this._commands = [];
- this._points = [];
- this._bounds = new Rectangle();
- this._bounds.top = this._bounds.left = Number.MAX_VALUE;
- this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
- this._hasFill = false;
- this._hasStroke = false;
- this.makeDrawCmds(this.extractCmds(svgNode));
- }
- /**
- * @method extractCmds ()
- * @param node (XMLNode) SVG path node
- * @description Parse path node and convert to array of SVG drawing commands and data
- * eg, M,250.8,33.8,c,-33.6,-9.7,-42,19.1,-48.2,22.6,s,-27.9,2.2,-33.3,5.8,
- * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
- * @returns (Array) array of drawing commands
- */
- private function extractCmds(node:XML):Array {
- var i:Number;
- var startColor:Number;
- var thisColor:Number;
- //var hasFill:Boolean = false;
- var hasTransform:Boolean = false;
- //var hasStroke:Boolean = false;
- var hasStrokeWidth:Boolean = false;
- var hasRotate:Number = 0;
- var dstring:String = "";
- var rotation:Number;
- // is there a fill attribute, a transform attribute, a stroke attribute?
- for each (var a:XML in node.attributes()) {
- switch (a.name().toString()) {
- case 'fill': this._hasFill = true; break;
- case 'transform': hasTransform = true; break;
- case 'stroke': this._hasStroke = true; break;
- case 'stroke-width': hasStrokeWidth = true; break;
- }
- }
- if (this._hasFill) {
- // parse for fill color specification
- // if a hex number is specified, startColor will be > 0
- // if a color name is specified, startColor will be 0
- var fillStr:String = node.@fill;
- if (fillStr == 'none') {
- this._hasFill = false;
- } else {
- startColor = fillStr.indexOf("#") + 1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(fillStr);
- if (isNaN(thisColor)) {
- this._hasFill = false;
- } else {
- this._fillColor = thisColor;
- this._fillAlpha = 1.0;
- }
- } else {
- this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
- this._fillAlpha = 1.0;
- }
- }
- }
- // stroke: color, width, alpha
- if (this._hasStroke) {
- // parse for stroke color specification
- var strokeStr:String = node.@stroke;
- if (strokeStr == 'none') {
- this._hasStroke = false;
- } else {
- startColor = strokeStr.indexOf("#")+1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(strokeStr);
- if (isNaN(thisColor)) {
- this._hasStroke = false;
- } else {
- this._strokeWidth = 0;
- this._strokeColor = SVGColor.getByName(strokeStr);
- this._strokeAlpha = 1.0;
- }
- } else {
- this._strokeWidth = 0;
- this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
- this._strokeAlpha = 1.0;
- }
- }
- }
- if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
- // if stroke and fill are both undefined, set fill to black
- if (!this._hasFill && !this._hasStroke) {
- this._hasFill = true;
- this._fillColor = 0;
- this._fillAlpha = 1.0;
- }
- if (hasTransform) {
- // parse for rotation specification
- var transformStr:String = node.@transform;
- hasRotate = transformStr.indexOf("rotate");
- if (hasRotate > -1) {
- var startRotate:Number = transformStr.indexOf("(");
- var endRotate:Number = transformStr.indexOf(")");
- rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
- } else {
- rotation = 0;
- }
- } else rotation = 0;
- // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
- dstring = node.@d;
- if (dstring.indexOf(",") > -1) { // has commas?
- if (dstring.indexOf(" ") > -1) { // yes, has spaces?
- // change spaces to commas, then deal as for Illustrator
- dstring = String2.replace(dstring," ",",");
- }
- } else { // no commas
- // get rid of extra spaces and change rest to commas
- dstring = String2.shrinkSequencesOf(dstring, " ");
- dstring = String2.replace(dstring, " ",",");
- }
- dstring = String2.replace(dstring, "c",",c,");
- dstring = String2.replace(dstring, "C",",C,");
- dstring = String2.replace(dstring, "S",",S,");
- dstring = String2.replace(dstring, "s",",s,");
- // separate the z from the last element
- dstring = String2.replace(dstring, "z",",z");
- // change the following if M can be mid-path
- dstring = String2.replace(dstring, "M","M,");
- dstring = String2.replace(dstring, "L",",L,");
- dstring = String2.replace(dstring, "l",",l,");
- dstring = String2.replace(dstring, "H",",H,");
- dstring = String2.replace(dstring, "h",",h,");
- dstring = String2.replace(dstring, "V",",V,");
- dstring = String2.replace(dstring, "v",",v,");
- dstring = String2.replace(dstring, "Q",",Q,");
- dstring = String2.replace(dstring, "q",",q,");
- dstring = String2.replace(dstring, "T",",T,");
- dstring = String2.replace(dstring, "t",",t,");
- // Adobe includes no delimiter before negative numbers
- dstring = String2.replace(dstring, "-",",-");
- // get rid of any dup commas we might have introduced
- dstring = String2.replace(dstring, ",,",",");
- // get rid of spaces
- // (cr/lf's have to be removed before the xml object can be created,
- // so that is done in xml.onData method)
- dstring = String2.replace(dstring, " ","");
- dstring = String2.replace(dstring, "\t","");
- return dstring.split(",");
- }
- /**
- * @method makeDrawCmds
- * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
- * @description Convert svg draw commands to array of ASVDrawing commands: _commands
- */
- private function makeDrawCmds(svgCmds:Array):void {
- var j:Number = 0, ii:int;
- var qc:Array;
- var firstP:Point;
- var lastP:Point;
- var lastC:Point;
- var cmd:String;
- var cp:Point, pp:Point;
- do {
- cmd = svgCmds[j++];
- switch (cmd) {
- case "M" :
- // moveTo point
- firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- if (this._hasFill) {
- _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
- }
- if (this._hasStroke) {
- _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
- }
- _commands.push(new MoveToCommand(firstP));
- this.addPoint(firstP);
- j += 2;
- if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
- do {
- // if multiple points listed, add the rest as lineTo points
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- }
- break;
- case "l" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "L" :
- do {
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "h" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "H" :
- do {
- lastP = new Point(Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "v" :
- do {
- lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "V" :
- do {
- lastP = new Point(lastP.x, Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "q" :
- do {
- // control is relative to lastP, not lastC
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "Q" :
- do {
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "c" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:lastP.x, y:lastP.y},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "C" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "s" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "S" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "z" :
- case "Z" :
- if (!firstP.equals(lastP)) {
- _commands.push(new LineToCommand(firstP));
- this.addPoint(firstP);
- }
- j++;
- break;
- } // end switch
- } while (j < svgCmds.length);
- }
- /**
- *
- */
- public function draw(graphics:Graphics):void {
- for each (var command:SVGPathCommand in this._commands) {
- command.execute(graphics);
- }
- }
- }
- class String2 {
- /**
- * @class String2
- * @author Helen Triolo, with inclusions from Tim Groleau
- * @description String functions not included in String needed for path->array conversion
- */
- /**
- * @method replace ()
- * @description Replaces sFind in s with sReplace
- * @param s (String) original string
- * @param sFind (String) part to be replaced
- * @param sReplace (String) string to replace it with
- * @returns (String) string with replacement
- */
- public static function replace(s:String, sFind:String, sReplace:String):String {
- return s.split(sFind).join(sReplace);
- }
- /**
- * @method shrinkSequencesOf (Groleau)
- * @description Shrinks all sequences of a given character in a string to one
- * @param s (String) original string
- * @param ch (String) character to be found
- * @returns (String) string with sequences shrunk
- */
- public static function shrinkSequencesOf(s:String, ch:String):String {
- var len:Number = s.length;
- var idx:Number = 0;
- var idx2:Number = 0;
- var rs:String = "";
- while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
- // include string up to first character in sequence
- rs += s.substring(idx, idx2);
- idx = idx2;
- // remove all subsequent characters in sequence
- while ((s.charAt(idx) == ch) && (idx < len)) idx++;
- }
- return rs + s.substring(idx, len);
- }
- }
- class Math2 {
- /**
- * @class Math2
- * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
- * @description Math functions not included in Math needed for path->array conversion
- */
- /**
- * @method ratioTo (Groleau)
- * @description Returns the point on segment [p1,p2] which is ratio times the total distance
- * between p1 and p2 away from p1
- * @param p1 (Object) x and y values of point p1
- * @param p2 (Object) x and y values of point p2
- * @param ratio (Number) real
- * @returns Object
- */
- public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
- return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
- }
- /**
- * @method intersect2Lines (Penner)
- * @description Returns the point of intersection between two lines
- * @param p1, p2 (Objects) points on line 1
- * @param p3, p4 (Objects) points on line 2
- * @returns Object (point of intersection)
- */
- public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
- var x1:Number = p1.x; var y1:Number = p1.y;
- var x4:Number = p4.x; var y4:Number = p4.y;
- var dx1:Number = p2.x - x1;
- var dx2:Number = p3.x - x4;
- if (!(dx1 || dx2)) return NaN;
- var m1:Number = (p2.y - y1) / dx1;
- var m2:Number = (p3.y - y4) / dx2;
- if (!dx1) {
- return { x:x1, y:m2 * (x1 - x4) + y4 };
- } else if (!dx2) {
- return { x:x4, y:m1 * (x4 - x1) + y1 };
- }
- var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
- var yInt:Number = m1 * (xInt - x1) + y1;
- return { x:xInt,y:yInt };
- }
- /**
- * @method rotation
- * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
- * @param dy (Number) pixels
- * @param dx (Number) pixels
- * @returns Number (angle, degrees)
- */
- public static function rotation(dy:Number, dx:Number):Number {
- return Math.atan2(dy, dx) * 180/Math.PI;
- }
- /**
- * @method midPt
- * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
- * @param p1x (Number) pixels
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels
- * @param p2y (Number) pixels
- * @returns Object (midpoint)
- */
- public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
- return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
- }
- /**
- * @method getQuadBez_RP (Penner)
- * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
- * to achieve a specified tolerance
- * @param p1 (Object) endpoint
- * @param c1 (Object) 1st control point
- * @param c2 (Object) 2nd control point
- * @param p2 (Object) endpoint
- * @param k: tolerance (low number = most accurate result)
- * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
- * p1x, p1y, cx, cy, p2x, p2y
- */
- public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
- // find intersection between bezier arms
- var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
- // find distance between the midpoints
- var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
- var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
- // split curve if the quadratic isn't close enough
- if (dx*dx + dy*dy > k) {
- var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
- var b0:Object = halves.b0; var b1:Object = halves.b1;
- // recursive call to subdivide curve
- getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
- getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
- } else {
- // end recursion by saving points
- qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
- }
- }
- /**
- * @method bezierSplit (Penner)
- * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param c1x (Number) pixels, control point 1
- * @param c1y (Number) pixels
- * @param c2x (Number) pixels, control point 2
- * @param c2y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Object (object with two cubic bezier definitions, b0 and b1)
- */
- public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
- var m:Function = Math2.midPt;
- var p1:Object = {x:p1x, y:p1y};
- var p2:Object = {x:p2x, y:p2y};
- var p01:Object = m (p1x, p1y, c1x, c1y);
- var p12:Object = m (c1x, c1y, c2x, c2y);
- var p23:Object = m (c2x, c2y, p2x, p2y);
- var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
- var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
- var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
- /*
- b0:{a:p0, b:p01, c:p02, d:p03},
- b1:{a:p03, b:p13, c:p23, d:p3 }
- */
- return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
- }
- /**
- * @method pointOnCurve (Penner)
- * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
- * of the standard equation:
- * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
- * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param t (Number) if time is 0-1 along curve, value of t to find point at
- * @returns Object (point at time t)
- */
- public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
- var o:Object = new Object();
- o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
- o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
- return o;
- }
- /**
- * @method pointsOnCurve (Penner)
- * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
- * includes:
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- */
- public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- for (var i:Number=0; i <= n; i++) {
- pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method pointsOnLine (Penner)
- * @description Returns an array of point positions and rotations for n evenly spaced points
- * along a line segment
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- *//* ....................................................................
- Returns an array of point positions and rotation for n evenly spaced points along a line segment
- */
- public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- if (p2x != p1x) {
- var m:Number = (p2y-p1y)/(p2x-p1x);
- var b:Number = p1y - p1x * m;
- for (var i:Number=0; i <= n; i++) {
- var x:Number = p1x + ((p2x-p1x)/n) * i;
- pts.push({x:x, y:m*x+b});
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- // vertical segment
- } else {
- for (i=0; i<=n; i++) {
- pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method curveApproxLen
- * @description Returns the approximate length of a curved segment, found by dividing it
- * into two segments at t=0.5
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
- var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
- var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
- var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
- return len1+len2;
- }
- /**
- * @method lineLen
- * @description Returns the length of a line segment
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
- return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
- }
- /**
- * @method roundTo
- * @description Returns a number rounded to specified number of decimals
- * @param n (Number)
- * @param ndec (Number) number of decimals to round to
- * @returns Number
- */
- public static function roundTo(n:Number, ndec:Number):Number {
- var multiplier:Number = Math.pow(10, ndec);
- return Math.round(n*multiplier)/multiplier;
- }
- }
- class SVGColor {
- public static function getByName(name:String):Number {
- var col:Number = SVGColor._colorTable[name];
- return isNaN(col) ? 0 : col;
- }
- private static const _colorTable:Object = {
- blue:0x0000ff,
- green:0x008000,
- red:0xff0000,
- aliceblue:0xf0f8ff,
- antiquewhite:0xfaebd7,
- aqua:0x00ffff,
- aquamarine:0x7fffd4,
- azure:0xf0ffff,
- beige:0xf5f5dc,
- bisque:0xffe4c4,
- black:0x000000,
- blanchedalmond:0xffebcd,
- blueviolet:0x8a2be2,
- brown:0xa52a2a,
- burlywood:0xdeb887,
- cadetblue:0x5f9ea0,
- chartreuse:0x7fff00,
- chocolate:0xd2691e,
- coral:0xff7f50,
- cornflowerblue:0x6495ed,
- cornsilk:0xfff8dc,
- crimson:0xdc143c,
- cyan:0x00ffff,
- darkblue:0x00008b,
- darkcyan:0x008b8b,
- darkgoldenrod:0xb8860b,
- darkgray:0xa9a9a9,
- darkgreen:0x006400,
- darkgrey:0xa9a9a9,
- darkkhaki:0xbdb76b,
- darkmagenta:0x8b008b,
- darkolivegreen:0x556b2f,
- darkorange:0xff8c00,
- darkorchid:0x9932cc,
- darkred:0x8b0000,
- darksalmon:0xe9967a,
- darkseagreen:0x8fbc8f,
- darkslateblue:0x483d8b,
- darkslategray:0x2f4f4f,
- darkslategrey:0x2f4f4f,
- darkturquoise:0x00ced1,
- darkviolet:0x9400d3,
- deeppink:0xff1493,
- deepskyblue:0x00bfff,
- dimgray:0x696969,
- dimgrey:0x696969,
- dodgerblue:0x1e90ff,
- firebrick:0xb22222,
- floralwhite:0xfffaf0,
- forestgreen:0x228b22,
- fuchsia:0xff00ff,
- gainsboro:0xdcdcdc,
- ghostwhite:0xf8f8ff,
- gold:0xffd700,
- goldenrod:0xdaa520,
- gray:0x808080,
- grey:0x808080,
- greenyellow:0xadff2f,
- honeydew:0xf0fff0,
- hotpink:0xff69b4,
- indianred:0xcd5c5c,
- indigo:0x4b0082,
- ivory:0xfffff0,
- khaki:0xf0e68c,
- lavender:0xe6e6fa,
- lavenderblush:0xfff0f5,
- lawngreen:0x7cfc00,
- lemonchiffon:0xfffacd,
- lightblue:0xadd8e6,
- lightcoral:0xf08080,
- lightcyan:0xe0ffff,
- lightgoldenrodyellow:0xfafad2,
- lightgray:0xd3d3d3,
- lightgreen:0x90ee90,
- lightgrey:0xd3d3d3,
- lightpink:0xffb6c1,
- lightsalmon:0xffa07a,
- lightseagreen:0x20b2aa,
- lightskyblue:0x87cefa,
- lightslategray:0x778899,
- lightslategrey:0x778899,
- lightsteelblue:0xb0c4de,
- lightyellow:0xffffe0,
- lime:0x00ff00,
- limegreen:0x32cd32,
- linen:0xfaf0e6,
- magenta:0xff00ff,
- maroon:0x800000,
- mediumaquamarine:0x66cdaa,
- mediumblue:0x0000cd,
- mediumorchid:0xba55d3,
- mediumpurple:0x9370db,
- mediumseagreen:0x3cb371,
- mediumslateblue:0x7b68ee,
- mediumspringgreen:0x00fa9a,
- mediumturquoise:0x48d1cc,
- mediumvioletred:0xc71585,
- midnightblue:0x191970,
- mintcream:0xf5fffa,
- mistyrose:0xffe4e1,
- moccasin:0xffe4b5,
- navajowhite:0xffdead,
- navy:0x000080,
- oldlace:0xfdf5e6,
- olive:0x808000,
- olivedrab:0x6b8e23,
- orange:0xffa500,
- orangered:0xff4500,
- orchid:0xda70d6,
- palegoldenrod:0xeee8aa,
- palegreen:0x98fb98,
- paleturquoise:0xafeeee,
- palevioletred:0xdb7093,
- papayawhip:0xffefd5,
- peachpuff:0xffdab9,
- peru:0xcd853f,
- pink:0xffc0cb,
- plum:0xdda0dd,
- powderblue:0xb0e0e6,
- purple:0x800080,
- rosybrown:0xbc8f8f,
- royalblue:0x4169e1,
- saddlebrown:0x8b4513,
- salmon:0xfa8072,
- sandybrown:0xf4a460,
- seagreen:0x2e8b57,
- seashell:0xfff5ee,
- sienna:0xa0522d,
- silver:0xc0c0c0,
- skyblue:0x87ceeb,
- slateblue:0x6a5acd,
- slategray:0x708090,
- slategrey:0x708090,
- snow:0xfffafa,
- springgreen:0x00ff7f,
- steelblue:0x4682b4,
- tan:0xd2b48c,
- teal:0x008080,
- thistle:0xd8bfd8,
- tomato:0xff6347,
- turquoise:0x40e0d0,
- violet:0xee82ee,
- wheat:0xf5deb3,
- white:0xffffff,
- whitesmoke:0xf5f5f5,
- yellow:0xffff00,
- yellowgreen:0x9acd32
- }
- }
- class SVGPathCommandType {
- public static const BEGIN_FILL_COMMAND:Number = 1;
- public static const LINE_STYLE_COMMAND:Number = 2;
- public static const MOVE_TO_COMMAND:Number = 3;
- public static const LINE_TO_COMMAND:Number = 4;
- public static const CURVE_TO_COMMAND:Number = 5;
- }
- interface ISVGPathCommand {
- function execute(graphics:Graphics):void;
- }
- class SVGPathCommand implements ISVGPathCommand {
- private var _type:Number;
- public function get type():Number { return this._type; }
- public function SVGPathCommand(type:Number = 0) {
- this._type = type;
- }
- public function execute(graphics:Graphics):void {
- throw new Error('Subclass must be implement execute method.');
- }
- }
- class BeginFillCommand extends SVGPathCommand {
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function BeginFillCommand(color:Number, alpha:Number) {
- super(SVGPathCommandType.BEGIN_FILL_COMMAND);
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.beginFill(this._color, this._alpha);
- }
- }
- class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt1:Point;
- public function get x1():Number { return this._pt1.x; }
- public function get y1():Number { return this._pt1.y; }
- private var _pt2:Point;
- public function get x2():Number { return this._pt2.x; }
- public function get y2():Number { return this._pt2.y; }
- public function CurveToCommand(pt1:Point, pt2:Point) {
- super(SVGPathCommandType.CURVE_TO_COMMAND);
- this._pt1 = pt1;
- this._pt2 = pt2;
- }
- public override function execute(graphics:Graphics):void {
- graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
- }
- }
- class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _width:Number;
- public function get width():Number { return this._width; }
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
- super(SVGPathCommandType.LINE_STYLE_COMMAND);
- this._width = width;
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineStyle(this._width, this._color, this._alpha);
- }
- }
- class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function LineToCommand(pt:Point) {
- super(SVGPathCommandType.LINE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineTo(this._pt.x, this._pt.y);
- }
- }
- class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function MoveToCommand(pt:Point) {
- super(SVGPathCommandType.MOVE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.moveTo(this._pt.x, this._pt.y);
- }
- }
- // forked from Saqoosha's Sewing
- package {
- import caurina.transitions.Equations;
- import caurina.transitions.Tweener;
- import caurina.transitions.properties.CurveModifiers;
- import flash.display.Graphics;
- import flash.display.Sprite;
- import flash.display.StageAlign;
- import flash.display.StageQuality;
- import flash.display.StageScaleMode;
- import flash.events.Event;
- import flash.geom.Point;
- import flash.net.URLLoader;
- import flash.net.URLLoaderDataFormat;
- import flash.net.URLRequest;
- import flash.utils.setTimeout;
- [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
- public class Sewing extends Sprite {
- private var _loader:URLLoader;
- private var _canvas:Sprite;
- private var _paths:Array;
- public function Sewing() {
- Wonderfl.capture_delay(8);
- this.stage.quality = StageQuality.BEST;
- this.stage.align = StageAlign.TOP_LEFT;
- this.stage.scaleMode = StageScaleMode.NO_SCALE;
- CurveModifiers.init();
- this._canvas = this.addChild(new Sprite()) as Sprite;
- this._loader = new URLLoader();
- this._loader.dataFormat = URLLoaderDataFormat.TEXT;
- this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
- this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
- }
- private function _handleLoaded(e:Event):void {
- var svg:XML = new XML(this._loader.data);
- this._paths = [];
- var path:SVGPath;
- var delay:Number = 2.0;
- var cx:Number = parseInt(svg.@width) / 2;
- var cy:Number = parseInt(svg.@height) / 2;
- this._canvas.x = this.stage.stageWidth / 2 - cx;
- this._canvas.y = this.stage.stageHeight / 2 - cy;
- for each (var pathNode:XML in svg..*::path) {
- path = new SVGPath(pathNode);
- this._paths.push(path);
- var i:Number = 0;
- var di:Number = Math.PI * 2 / path.points.length;
- var px:Number = cx;
- var py:Number = this.stage.stageHeight - this._canvas.y;
- for each (var pt:Point in path.points) {
- Tweener.addTween(pt, {
- x: pt.x,
- y: pt.y,
- _bezier:[
- { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
- { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
- ],
- time: 1.0,
- delay: delay,
- transition: Equations.easeNone
- });
- pt.x = px;
- pt.y = py;
- delay += 0.004;
- i += di;
- }
- }
- this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
- setTimeout(function ():void {
- removeEventListener(Event.ENTER_FRAME, _drawPaths);
- }, (delay + 1) * 1000);
- }
- private function _drawPaths(e:Event):void {
- this._canvas.graphics.clear();
- for each (var path:SVGPath in this._paths) {
- path.draw(this._canvas.graphics);
- }
- }
- }
- }
- import flash.display.Graphics;
- import flash.geom.Point;
- import flash.geom.Rectangle;
- /**
- * @class PathToArray
- * @author Helen Triolo (with contributions from many people)
- * @version 1.01
- * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
- * not contain any CRLF characters), and an empty array.
- * Parses the path node to make an array of drawing commands, which include cubic bezier
- * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
- * using Robert Penner's code to convert with accuracy within 1 pixel.
- * Drawing commands are produced in the format originally devised by Peter Hall
- * in his ASVDrawing class. These are the possible elements in array dCmds (and the
- * corresponding Flash drawing API commands to apply them):
- * ['M',[x,y]] moveTo(x,y)
- * ['L',[x,y]] lineTo(x,y)
- * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
- * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
- * ['F',[color,alpha]] beginFill(color,alpha)
- * ['EF'] endFill()
- * History:
- * v1.00 2005/11/13 Original release
- * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
- *
- * @param svgnode (XMLNode) Path node from SVG file
- * @param dCmds (Array) Empty array to write commands to
- */
- class SVGPath {
- private var _commands:Array;
- public function get commands():Array { return this._commands }
- private var _points:Array;
- public function get points():Array { return this._points }
- private function addPoint(... points:Array):void {
- for each (var pt:Point in points) {
- this._addPoint(pt);
- }
- }
- private function _addPoint(pt:Point):void {
- if (pt.x < this._bounds.left) {
- this._bounds.left = pt.x;
- } else if (this._bounds.right < pt.x) {
- this._bounds.right = pt.x;
- }
- if (pt.y < this._bounds.top) {
- this._bounds.top = pt.y;
- } else if (this._bounds.bottom < pt.y) {
- this._bounds.bottom = pt.y;
- }
- this._points.push(pt);
- }
- private var _bounds:Rectangle;
- public function get boundsRect():Rectangle { return this._bounds }
- private var _hasFill:Boolean;
- public function get hasFill():Boolean { return this._hasFill }
- private var _hasStroke:Boolean;
- public function get hasStroke():Boolean { return this._hasStroke }
- public function swapFillAndStroke():void {
- var flg:Boolean = this._hasFill;
- this._hasFill = this._hasStroke;
- this._hasStroke = flg;
- var val:Number = this._fillColor;
- this._fillColor = this._strokeColor;
- this._strokeColor = val;
- val = this._fillAlpha;
- this._fillAlpha = this._strokeAlpha;
- this._strokeAlpha = val;
- }
- private var _fillColor:Number;
- public function get fillColor():Number { return this._fillColor }
- public function set fillColor(col:Number):void { this._fillColor = col }
- private var _fillAlpha:Number;
- public function get fillAlpha():Number { return this._fillAlpha }
- public function set fillAlpha(al:Number):void { this._fillAlpha = al }
- private var _strokeColor:Number;
- public function get strokeColor():Number { return this._strokeColor }
- public function set strokeColor(col:Number):void { this._strokeColor = col }
- private var _strokeAlpha:Number;
- public function get strokeAlpha():Number { return this._strokeAlpha }
- public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
- private var _strokeWidth:Number;
- public function get strokeWidth():Number { return this._strokeWidth }
- public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
- /**
- *
- */
- public function SVGPath(svgNode:XML) {
- this._commands = [];
- this._points = [];
- this._bounds = new Rectangle();
- this._bounds.top = this._bounds.left = Number.MAX_VALUE;
- this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
- this._hasFill = false;
- this._hasStroke = false;
- this.makeDrawCmds(this.extractCmds(svgNode));
- }
- /**
- * @method extractCmds ()
- * @param node (XMLNode) SVG path node
- * @description Parse path node and convert to array of SVG drawing commands and data
- * eg, M,250.8,33.8,c,-33.6,-9.7,-42,19.1,-48.2,22.6,s,-27.9,2.2,-33.3,5.8,
- * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
- * @returns (Array) array of drawing commands
- */
- private function extractCmds(node:XML):Array {
- var i:Number;
- var startColor:Number;
- var thisColor:Number;
- //var hasFill:Boolean = false;
- var hasTransform:Boolean = false;
- //var hasStroke:Boolean = false;
- var hasStrokeWidth:Boolean = false;
- var hasRotate:Number = 0;
- var dstring:String = "";
- var rotation:Number;
- // is there a fill attribute, a transform attribute, a stroke attribute?
- for each (var a:XML in node.attributes()) {
- switch (a.name().toString()) {
- case 'fill': this._hasFill = true; break;
- case 'transform': hasTransform = true; break;
- case 'stroke': this._hasStroke = true; break;
- case 'stroke-width': hasStrokeWidth = true; break;
- }
- }
- if (this._hasFill) {
- // parse for fill color specification
- // if a hex number is specified, startColor will be > 0
- // if a color name is specified, startColor will be 0
- var fillStr:String = node.@fill;
- if (fillStr == 'none') {
- this._hasFill = false;
- } else {
- startColor = fillStr.indexOf("#") + 1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(fillStr);
- if (isNaN(thisColor)) {
- this._hasFill = false;
- } else {
- this._fillColor = thisColor;
- this._fillAlpha = 1.0;
- }
- } else {
- this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
- this._fillAlpha = 1.0;
- }
- }
- }
- // stroke: color, width, alpha
- if (this._hasStroke) {
- // parse for stroke color specification
- var strokeStr:String = node.@stroke;
- if (strokeStr == 'none') {
- this._hasStroke = false;
- } else {
- startColor = strokeStr.indexOf("#")+1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(strokeStr);
- if (isNaN(thisColor)) {
- this._hasStroke = false;
- } else {
- this._strokeWidth = 0;
- this._strokeColor = SVGColor.getByName(strokeStr);
- this._strokeAlpha = 1.0;
- }
- } else {
- this._strokeWidth = 0;
- this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
- this._strokeAlpha = 1.0;
- }
- }
- }
- if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
- // if stroke and fill are both undefined, set fill to black
- if (!this._hasFill && !this._hasStroke) {
- this._hasFill = true;
- this._fillColor = 0;
- this._fillAlpha = 1.0;
- }
- if (hasTransform) {
- // parse for rotation specification
- var transformStr:String = node.@transform;
- hasRotate = transformStr.indexOf("rotate");
- if (hasRotate > -1) {
- var startRotate:Number = transformStr.indexOf("(");
- var endRotate:Number = transformStr.indexOf(")");
- rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
- } else {
- rotation = 0;
- }
- } else rotation = 0;
- // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
- dstring = node.@d;
- if (dstring.indexOf(",") > -1) { // has commas?
- if (dstring.indexOf(" ") > -1) { // yes, has spaces?
- // change spaces to commas, then deal as for Illustrator
- dstring = String2.replace(dstring," ",",");
- }
- } else { // no commas
- // get rid of extra spaces and change rest to commas
- dstring = String2.shrinkSequencesOf(dstring, " ");
- dstring = String2.replace(dstring, " ",",");
- }
- dstring = String2.replace(dstring, "c",",c,");
- dstring = String2.replace(dstring, "C",",C,");
- dstring = String2.replace(dstring, "S",",S,");
- dstring = String2.replace(dstring, "s",",s,");
- // separate the z from the last element
- dstring = String2.replace(dstring, "z",",z");
- // change the following if M can be mid-path
- dstring = String2.replace(dstring, "M","M,");
- dstring = String2.replace(dstring, "L",",L,");
- dstring = String2.replace(dstring, "l",",l,");
- dstring = String2.replace(dstring, "H",",H,");
- dstring = String2.replace(dstring, "h",",h,");
- dstring = String2.replace(dstring, "V",",V,");
- dstring = String2.replace(dstring, "v",",v,");
- dstring = String2.replace(dstring, "Q",",Q,");
- dstring = String2.replace(dstring, "q",",q,");
- dstring = String2.replace(dstring, "T",",T,");
- dstring = String2.replace(dstring, "t",",t,");
- // Adobe includes no delimiter before negative numbers
- dstring = String2.replace(dstring, "-",",-");
- // get rid of any dup commas we might have introduced
- dstring = String2.replace(dstring, ",,",",");
- // get rid of spaces
- // (cr/lf's have to be removed before the xml object can be created,
- // so that is done in xml.onData method)
- dstring = String2.replace(dstring, " ","");
- dstring = String2.replace(dstring, "\t","");
- return dstring.split(",");
- }
- /**
- * @method makeDrawCmds
- * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
- * @description Convert svg draw commands to array of ASVDrawing commands: _commands
- */
- private function makeDrawCmds(svgCmds:Array):void {
- var j:Number = 0, ii:int;
- var qc:Array;
- var firstP:Point;
- var lastP:Point;
- var lastC:Point;
- var cmd:String;
- var cp:Point, pp:Point;
- do {
- cmd = svgCmds[j++];
- switch (cmd) {
- case "M" :
- // moveTo point
- firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- if (this._hasFill) {
- _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
- }
- if (this._hasStroke) {
- _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
- }
- _commands.push(new MoveToCommand(firstP));
- this.addPoint(firstP);
- j += 2;
- if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
- do {
- // if multiple points listed, add the rest as lineTo points
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- }
- break;
- case "l" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "L" :
- do {
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "h" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "H" :
- do {
- lastP = new Point(Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "v" :
- do {
- lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "V" :
- do {
- lastP = new Point(lastP.x, Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "q" :
- do {
- // control is relative to lastP, not lastC
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "Q" :
- do {
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "c" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:lastP.x, y:lastP.y},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "C" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "s" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "S" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "z" :
- case "Z" :
- if (!firstP.equals(lastP)) {
- _commands.push(new LineToCommand(firstP));
- this.addPoint(firstP);
- }
- j++;
- break;
- } // end switch
- } while (j < svgCmds.length);
- }
- /**
- *
- */
- public function draw(graphics:Graphics):void {
- for each (var command:SVGPathCommand in this._commands) {
- command.execute(graphics);
- }
- }
- }
- class String2 {
- /**
- * @class String2
- * @author Helen Triolo, with inclusions from Tim Groleau
- * @description String functions not included in String needed for path->array conversion
- */
- /**
- * @method replace ()
- * @description Replaces sFind in s with sReplace
- * @param s (String) original string
- * @param sFind (String) part to be replaced
- * @param sReplace (String) string to replace it with
- * @returns (String) string with replacement
- */
- public static function replace(s:String, sFind:String, sReplace:String):String {
- return s.split(sFind).join(sReplace);
- }
- /**
- * @method shrinkSequencesOf (Groleau)
- * @description Shrinks all sequences of a given character in a string to one
- * @param s (String) original string
- * @param ch (String) character to be found
- * @returns (String) string with sequences shrunk
- */
- public static function shrinkSequencesOf(s:String, ch:String):String {
- var len:Number = s.length;
- var idx:Number = 0;
- var idx2:Number = 0;
- var rs:String = "";
- while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
- // include string up to first character in sequence
- rs += s.substring(idx, idx2);
- idx = idx2;
- // remove all subsequent characters in sequence
- while ((s.charAt(idx) == ch) && (idx < len)) idx++;
- }
- return rs + s.substring(idx, len);
- }
- }
- class Math2 {
- /**
- * @class Math2
- * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
- * @description Math functions not included in Math needed for path->array conversion
- */
- /**
- * @method ratioTo (Groleau)
- * @description Returns the point on segment [p1,p2] which is ratio times the total distance
- * between p1 and p2 away from p1
- * @param p1 (Object) x and y values of point p1
- * @param p2 (Object) x and y values of point p2
- * @param ratio (Number) real
- * @returns Object
- */
- public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
- return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
- }
- /**
- * @method intersect2Lines (Penner)
- * @description Returns the point of intersection between two lines
- * @param p1, p2 (Objects) points on line 1
- * @param p3, p4 (Objects) points on line 2
- * @returns Object (point of intersection)
- */
- public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
- var x1:Number = p1.x; var y1:Number = p1.y;
- var x4:Number = p4.x; var y4:Number = p4.y;
- var dx1:Number = p2.x - x1;
- var dx2:Number = p3.x - x4;
- if (!(dx1 || dx2)) return NaN;
- var m1:Number = (p2.y - y1) / dx1;
- var m2:Number = (p3.y - y4) / dx2;
- if (!dx1) {
- return { x:x1, y:m2 * (x1 - x4) + y4 };
- } else if (!dx2) {
- return { x:x4, y:m1 * (x4 - x1) + y1 };
- }
- var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
- var yInt:Number = m1 * (xInt - x1) + y1;
- return { x:xInt,y:yInt };
- }
- /**
- * @method rotation
- * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
- * @param dy (Number) pixels
- * @param dx (Number) pixels
- * @returns Number (angle, degrees)
- */
- public static function rotation(dy:Number, dx:Number):Number {
- return Math.atan2(dy, dx) * 180/Math.PI;
- }
- /**
- * @method midPt
- * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
- * @param p1x (Number) pixels
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels
- * @param p2y (Number) pixels
- * @returns Object (midpoint)
- */
- public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
- return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
- }
- /**
- * @method getQuadBez_RP (Penner)
- * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
- * to achieve a specified tolerance
- * @param p1 (Object) endpoint
- * @param c1 (Object) 1st control point
- * @param c2 (Object) 2nd control point
- * @param p2 (Object) endpoint
- * @param k: tolerance (low number = most accurate result)
- * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
- * p1x, p1y, cx, cy, p2x, p2y
- */
- public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
- // find intersection between bezier arms
- var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
- // find distance between the midpoints
- var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
- var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
- // split curve if the quadratic isn't close enough
- if (dx*dx + dy*dy > k) {
- var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
- var b0:Object = halves.b0; var b1:Object = halves.b1;
- // recursive call to subdivide curve
- getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
- getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
- } else {
- // end recursion by saving points
- qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
- }
- }
- /**
- * @method bezierSplit (Penner)
- * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param c1x (Number) pixels, control point 1
- * @param c1y (Number) pixels
- * @param c2x (Number) pixels, control point 2
- * @param c2y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Object (object with two cubic bezier definitions, b0 and b1)
- */
- public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
- var m:Function = Math2.midPt;
- var p1:Object = {x:p1x, y:p1y};
- var p2:Object = {x:p2x, y:p2y};
- var p01:Object = m (p1x, p1y, c1x, c1y);
- var p12:Object = m (c1x, c1y, c2x, c2y);
- var p23:Object = m (c2x, c2y, p2x, p2y);
- var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
- var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
- var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
- /*
- b0:{a:p0, b:p01, c:p02, d:p03},
- b1:{a:p03, b:p13, c:p23, d:p3 }
- */
- return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
- }
- /**
- * @method pointOnCurve (Penner)
- * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
- * of the standard equation:
- * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
- * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param t (Number) if time is 0-1 along curve, value of t to find point at
- * @returns Object (point at time t)
- */
- public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
- var o:Object = new Object();
- o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
- o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
- return o;
- }
- /**
- * @method pointsOnCurve (Penner)
- * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
- * includes:
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- */
- public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- for (var i:Number=0; i <= n; i++) {
- pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method pointsOnLine (Penner)
- * @description Returns an array of point positions and rotations for n evenly spaced points
- * along a line segment
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- *//* ....................................................................
- Returns an array of point positions and rotation for n evenly spaced points along a line segment
- */
- public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- if (p2x != p1x) {
- var m:Number = (p2y-p1y)/(p2x-p1x);
- var b:Number = p1y - p1x * m;
- for (var i:Number=0; i <= n; i++) {
- var x:Number = p1x + ((p2x-p1x)/n) * i;
- pts.push({x:x, y:m*x+b});
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- // vertical segment
- } else {
- for (i=0; i<=n; i++) {
- pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method curveApproxLen
- * @description Returns the approximate length of a curved segment, found by dividing it
- * into two segments at t=0.5
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
- var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
- var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
- var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
- return len1+len2;
- }
- /**
- * @method lineLen
- * @description Returns the length of a line segment
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
- return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
- }
- /**
- * @method roundTo
- * @description Returns a number rounded to specified number of decimals
- * @param n (Number)
- * @param ndec (Number) number of decimals to round to
- * @returns Number
- */
- public static function roundTo(n:Number, ndec:Number):Number {
- var multiplier:Number = Math.pow(10, ndec);
- return Math.round(n*multiplier)/multiplier;
- }
- }
- class SVGColor {
- public static function getByName(name:String):Number {
- var col:Number = SVGColor._colorTable[name];
- return isNaN(col) ? 0 : col;
- }
- private static const _colorTable:Object = {
- blue:0x0000ff,
- green:0x008000,
- red:0xff0000,
- aliceblue:0xf0f8ff,
- antiquewhite:0xfaebd7,
- aqua:0x00ffff,
- aquamarine:0x7fffd4,
- azure:0xf0ffff,
- beige:0xf5f5dc,
- bisque:0xffe4c4,
- black:0x000000,
- blanchedalmond:0xffebcd,
- blueviolet:0x8a2be2,
- brown:0xa52a2a,
- burlywood:0xdeb887,
- cadetblue:0x5f9ea0,
- chartreuse:0x7fff00,
- chocolate:0xd2691e,
- coral:0xff7f50,
- cornflowerblue:0x6495ed,
- cornsilk:0xfff8dc,
- crimson:0xdc143c,
- cyan:0x00ffff,
- darkblue:0x00008b,
- darkcyan:0x008b8b,
- darkgoldenrod:0xb8860b,
- darkgray:0xa9a9a9,
- darkgreen:0x006400,
- darkgrey:0xa9a9a9,
- darkkhaki:0xbdb76b,
- darkmagenta:0x8b008b,
- darkolivegreen:0x556b2f,
- darkorange:0xff8c00,
- darkorchid:0x9932cc,
- darkred:0x8b0000,
- darksalmon:0xe9967a,
- darkseagreen:0x8fbc8f,
- darkslateblue:0x483d8b,
- darkslategray:0x2f4f4f,
- darkslategrey:0x2f4f4f,
- darkturquoise:0x00ced1,
- darkviolet:0x9400d3,
- deeppink:0xff1493,
- deepskyblue:0x00bfff,
- dimgray:0x696969,
- dimgrey:0x696969,
- dodgerblue:0x1e90ff,
- firebrick:0xb22222,
- floralwhite:0xfffaf0,
- forestgreen:0x228b22,
- fuchsia:0xff00ff,
- gainsboro:0xdcdcdc,
- ghostwhite:0xf8f8ff,
- gold:0xffd700,
- goldenrod:0xdaa520,
- gray:0x808080,
- grey:0x808080,
- greenyellow:0xadff2f,
- honeydew:0xf0fff0,
- hotpink:0xff69b4,
- indianred:0xcd5c5c,
- indigo:0x4b0082,
- ivory:0xfffff0,
- khaki:0xf0e68c,
- lavender:0xe6e6fa,
- lavenderblush:0xfff0f5,
- lawngreen:0x7cfc00,
- lemonchiffon:0xfffacd,
- lightblue:0xadd8e6,
- lightcoral:0xf08080,
- lightcyan:0xe0ffff,
- lightgoldenrodyellow:0xfafad2,
- lightgray:0xd3d3d3,
- lightgreen:0x90ee90,
- lightgrey:0xd3d3d3,
- lightpink:0xffb6c1,
- lightsalmon:0xffa07a,
- lightseagreen:0x20b2aa,
- lightskyblue:0x87cefa,
- lightslategray:0x778899,
- lightslategrey:0x778899,
- lightsteelblue:0xb0c4de,
- lightyellow:0xffffe0,
- lime:0x00ff00,
- limegreen:0x32cd32,
- linen:0xfaf0e6,
- magenta:0xff00ff,
- maroon:0x800000,
- mediumaquamarine:0x66cdaa,
- mediumblue:0x0000cd,
- mediumorchid:0xba55d3,
- mediumpurple:0x9370db,
- mediumseagreen:0x3cb371,
- mediumslateblue:0x7b68ee,
- mediumspringgreen:0x00fa9a,
- mediumturquoise:0x48d1cc,
- mediumvioletred:0xc71585,
- midnightblue:0x191970,
- mintcream:0xf5fffa,
- mistyrose:0xffe4e1,
- moccasin:0xffe4b5,
- navajowhite:0xffdead,
- navy:0x000080,
- oldlace:0xfdf5e6,
- olive:0x808000,
- olivedrab:0x6b8e23,
- orange:0xffa500,
- orangered:0xff4500,
- orchid:0xda70d6,
- palegoldenrod:0xeee8aa,
- palegreen:0x98fb98,
- paleturquoise:0xafeeee,
- palevioletred:0xdb7093,
- papayawhip:0xffefd5,
- peachpuff:0xffdab9,
- peru:0xcd853f,
- pink:0xffc0cb,
- plum:0xdda0dd,
- powderblue:0xb0e0e6,
- purple:0x800080,
- rosybrown:0xbc8f8f,
- royalblue:0x4169e1,
- saddlebrown:0x8b4513,
- salmon:0xfa8072,
- sandybrown:0xf4a460,
- seagreen:0x2e8b57,
- seashell:0xfff5ee,
- sienna:0xa0522d,
- silver:0xc0c0c0,
- skyblue:0x87ceeb,
- slateblue:0x6a5acd,
- slategray:0x708090,
- slategrey:0x708090,
- snow:0xfffafa,
- springgreen:0x00ff7f,
- steelblue:0x4682b4,
- tan:0xd2b48c,
- teal:0x008080,
- thistle:0xd8bfd8,
- tomato:0xff6347,
- turquoise:0x40e0d0,
- violet:0xee82ee,
- wheat:0xf5deb3,
- white:0xffffff,
- whitesmoke:0xf5f5f5,
- yellow:0xffff00,
- yellowgreen:0x9acd32
- }
- }
- class SVGPathCommandType {
- public static const BEGIN_FILL_COMMAND:Number = 1;
- public static const LINE_STYLE_COMMAND:Number = 2;
- public static const MOVE_TO_COMMAND:Number = 3;
- public static const LINE_TO_COMMAND:Number = 4;
- public static const CURVE_TO_COMMAND:Number = 5;
- }
- interface ISVGPathCommand {
- function execute(graphics:Graphics):void;
- }
- class SVGPathCommand implements ISVGPathCommand {
- private var _type:Number;
- public function get type():Number { return this._type; }
- public function SVGPathCommand(type:Number = 0) {
- this._type = type;
- }
- public function execute(graphics:Graphics):void {
- throw new Error('Subclass must be implement execute method.');
- }
- }
- class BeginFillCommand extends SVGPathCommand {
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function BeginFillCommand(color:Number, alpha:Number) {
- super(SVGPathCommandType.BEGIN_FILL_COMMAND);
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.beginFill(this._color, this._alpha);
- }
- }
- class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt1:Point;
- public function get x1():Number { return this._pt1.x; }
- public function get y1():Number { return this._pt1.y; }
- private var _pt2:Point;
- public function get x2():Number { return this._pt2.x; }
- public function get y2():Number { return this._pt2.y; }
- public function CurveToCommand(pt1:Point, pt2:Point) {
- super(SVGPathCommandType.CURVE_TO_COMMAND);
- this._pt1 = pt1;
- this._pt2 = pt2;
- }
- public override function execute(graphics:Graphics):void {
- graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
- }
- }
- class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _width:Number;
- public function get width():Number { return this._width; }
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
- super(SVGPathCommandType.LINE_STYLE_COMMAND);
- this._width = width;
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineStyle(this._width, this._color, this._alpha);
- }
- }
- class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function LineToCommand(pt:Point) {
- super(SVGPathCommandType.LINE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineTo(this._pt.x, this._pt.y);
- }
- }
- class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function MoveToCommand(pt:Point) {
- super(SVGPathCommandType.MOVE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.moveTo(this._pt.x, this._pt.y);
- }
- }
Sewing forked from: Sewing
- // forked from Saqoosha's Sewing
- package {
- import caurina.transitions.Equations;
- import caurina.transitions.Tweener;
- import caurina.transitions.properties.CurveModifiers;
- import flash.display.Graphics;
- import flash.display.Sprite;
- import flash.display.StageAlign;
- import flash.display.StageQuality;
- import flash.display.StageScaleMode;
- import flash.events.Event;
- import flash.geom.Point;
- import flash.net.URLLoader;
- import flash.net.URLLoaderDataFormat;
- import flash.net.URLRequest;
- import flash.utils.setTimeout;
- [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
- public class Sewing extends Sprite {
- private var _loader:URLLoader;
- private var _canvas:Sprite;
- private var _paths:Array;
- public function Sewing() {
- Wonderfl.capture_delay(8);
- this.stage.quality = StageQuality.BEST;
- this.stage.align = StageAlign.TOP_LEFT;
- this.stage.scaleMode = StageScaleMode.NO_SCALE;
- CurveModifiers.init();
- this._canvas = this.addChild(new Sprite()) as Sprite;
- this._loader = new URLLoader();
- this._loader.dataFormat = URLLoaderDataFormat.TEXT;
- this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
- this._loader.load(new URLRequest('http://upload.wikimedia.org/wikipedia/commons/9/9c/Flag_of_Denmark.svg'));
- }
- private function _handleLoaded(e:Event):void {
- var svg:XML = new XML(this._loader.data);
- this._paths = [];
- var path:SVGPath;
- var delay:Number = 2.0;
- var cx:Number = parseInt(svg.@width) / 2;
- var cy:Number = parseInt(svg.@height) / 2;
- this._canvas.x = this.stage.stageWidth / 2 - cx;
- this._canvas.y = this.stage.stageHeight / 2 - cy;
- for each (var pathNode:XML in svg..*::path) {
- path = new SVGPath(pathNode);
- this._paths.push(path);
- var i:Number = 0;
- var di:Number = Math.PI * 2 / path.points.length;
- var px:Number = cx;
- var py:Number = this.stage.stageHeight - this._canvas.y;
- for each (var pt:Point in path.points) {
- Tweener.addTween(pt, {
- x: pt.x,
- y: pt.y,
- _bezier:[
- { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
- { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
- ],
- time: 1.0,
- delay: delay,
- transition: Equations.easeNone
- });
- pt.x = px;
- pt.y = py;
- delay += 0.004;
- i += di;
- }
- }
- this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
- setTimeout(function ():void {
- removeEventListener(Event.ENTER_FRAME, _drawPaths);
- }, (delay + 1) * 1000);
- }
- private function _drawPaths(e:Event):void {
- this._canvas.graphics.clear();
- for each (var path:SVGPath in this._paths) {
- path.draw(this._canvas.graphics);
- }
- }
- }
- }
- import flash.display.Graphics;
- import flash.geom.Point;
- import flash.geom.Rectangle;
- /**
- * @class PathToArray
- * @author Helen Triolo (with contributions from many people)
- * @version 1.01
- * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
- * not contain any CRLF characters), and an empty array.
- * Parses the path node to make an array of drawing commands, which include cubic bezier
- * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
- * using Robert Penner's code to convert with accuracy within 1 pixel.
- * Drawing commands are produced in the format originally devised by Peter Hall
- * in his ASVDrawing class. These are the possible elements in array dCmds (and the
- * corresponding Flash drawing API commands to apply them):
- * ['M',[x,y]] moveTo(x,y)
- * ['L',[x,y]] lineTo(x,y)
- * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
- * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
- * ['F',[color,alpha]] beginFill(color,alpha)
- * ['EF'] endFill()
- * History:
- * v1.00 2005/11/13 Original release
- * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
- *
- * @param svgnode (XMLNode) Path node from SVG file
- * @param dCmds (Array) Empty array to write commands to
- */
- class SVGPath {
- private var _commands:Array;
- public function get commands():Array { return this._commands }
- private var _points:Array;
- public function get points():Array { return this._points }
- private function addPoint(... points:Array):void {
- for each (var pt:Point in points) {
- this._addPoint(pt);
- }
- }
- private function _addPoint(pt:Point):void {
- if (pt.x < this._bounds.left) {
- this._bounds.left = pt.x;
- } else if (this._bounds.right < pt.x) {
- this._bounds.right = pt.x;
- }
- if (pt.y < this._bounds.top) {
- this._bounds.top = pt.y;
- } else if (this._bounds.bottom < pt.y) {
- this._bounds.bottom = pt.y;
- }
- this._points.push(pt);
- }
- private var _bounds:Rectangle;
- public function get boundsRect():Rectangle { return this._bounds }
- private var _hasFill:Boolean;
- public function get hasFill():Boolean { return this._hasFill }
- private var _hasStroke:Boolean;
- public function get hasStroke():Boolean { return this._hasStroke }
- public function swapFillAndStroke():void {
- var flg:Boolean = this._hasFill;
- this._hasFill = this._hasStroke;
- this._hasStroke = flg;
- var val:Number = this._fillColor;
- this._fillColor = this._strokeColor;
- this._strokeColor = val;
- val = this._fillAlpha;
- this._fillAlpha = this._strokeAlpha;
- this._strokeAlpha = val;
- }
- private var _fillColor:Number;
- public function get fillColor():Number { return this._fillColor }
- public function set fillColor(col:Number):void { this._fillColor = col }
- private var _fillAlpha:Number;
- public function get fillAlpha():Number { return this._fillAlpha }
- public function set fillAlpha(al:Number):void { this._fillAlpha = al }
- private var _strokeColor:Number;
- public function get strokeColor():Number { return this._strokeColor }
- public function set strokeColor(col:Number):void { this._strokeColor = col }
- private var _strokeAlpha:Number;
- public function get strokeAlpha():Number { return this._strokeAlpha }
- public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
- private var _strokeWidth:Number;
- public function get strokeWidth():Number { return this._strokeWidth }
- public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
- /**
- *
- */
- public function SVGPath(svgNode:XML) {
- this._commands = [];
- this._points = [];
- this._bounds = new Rectangle();
- this._bounds.top = this._bounds.left = Number.MAX_VALUE;
- this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
- this._hasFill = false;
- this._hasStroke = false;
- this.makeDrawCmds(this.extractCmds(svgNode));
- }
- /**
- * @method extractCmds ()
- * @param node (XMLNode) SVG path node
- * @description Parse path node and convert to array of SVG drawing commands and data
- * eg, M,250.8,33.8,c,-33.6,-9.7,-42,19.1,-48.2,22.6,s,-27.9,2.2,-33.3,5.8,
- * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
- * @returns (Array) array of drawing commands
- */
- private function extractCmds(node:XML):Array {
- var i:Number;
- var startColor:Number;
- var thisColor:Number;
- //var hasFill:Boolean = false;
- var hasTransform:Boolean = false;
- //var hasStroke:Boolean = false;
- var hasStrokeWidth:Boolean = false;
- var hasRotate:Number = 0;
- var dstring:String = "";
- var rotation:Number;
- // is there a fill attribute, a transform attribute, a stroke attribute?
- for each (var a:XML in node.attributes()) {
- switch (a.name().toString()) {
- case 'fill': this._hasFill = true; break;
- case 'transform': hasTransform = true; break;
- case 'stroke': this._hasStroke = true; break;
- case 'stroke-width': hasStrokeWidth = true; break;
- }
- }
- if (this._hasFill) {
- // parse for fill color specification
- // if a hex number is specified, startColor will be > 0
- // if a color name is specified, startColor will be 0
- var fillStr:String = node.@fill;
- if (fillStr == 'none') {
- this._hasFill = false;
- } else {
- startColor = fillStr.indexOf("#") + 1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(fillStr);
- if (isNaN(thisColor)) {
- this._hasFill = false;
- } else {
- this._fillColor = thisColor;
- this._fillAlpha = 1.0;
- }
- } else {
- this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
- this._fillAlpha = 1.0;
- }
- }
- }
- // stroke: color, width, alpha
- if (this._hasStroke) {
- // parse for stroke color specification
- var strokeStr:String = node.@stroke;
- if (strokeStr == 'none') {
- this._hasStroke = false;
- } else {
- startColor = strokeStr.indexOf("#")+1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(strokeStr);
- if (isNaN(thisColor)) {
- this._hasStroke = false;
- } else {
- this._strokeWidth = 0;
- this._strokeColor = SVGColor.getByName(strokeStr);
- this._strokeAlpha = 1.0;
- }
- } else {
- this._strokeWidth = 0;
- this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
- this._strokeAlpha = 1.0;
- }
- }
- }
- if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
- // if stroke and fill are both undefined, set fill to black
- if (!this._hasFill && !this._hasStroke) {
- this._hasFill = true;
- this._fillColor = 0;
- this._fillAlpha = 1.0;
- }
- if (hasTransform) {
- // parse for rotation specification
- var transformStr:String = node.@transform;
- hasRotate = transformStr.indexOf("rotate");
- if (hasRotate > -1) {
- var startRotate:Number = transformStr.indexOf("(");
- var endRotate:Number = transformStr.indexOf(")");
- rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
- } else {
- rotation = 0;
- }
- } else rotation = 0;
- // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
- dstring = node.@d;
- if (dstring.indexOf(",") > -1) { // has commas?
- if (dstring.indexOf(" ") > -1) { // yes, has spaces?
- // change spaces to commas, then deal as for Illustrator
- dstring = String2.replace(dstring," ",",");
- }
- } else { // no commas
- // get rid of extra spaces and change rest to commas
- dstring = String2.shrinkSequencesOf(dstring, " ");
- dstring = String2.replace(dstring, " ",",");
- }
- dstring = String2.replace(dstring, "c",",c,");
- dstring = String2.replace(dstring, "C",",C,");
- dstring = String2.replace(dstring, "S",",S,");
- dstring = String2.replace(dstring, "s",",s,");
- // separate the z from the last element
- dstring = String2.replace(dstring, "z",",z");
- // change the following if M can be mid-path
- dstring = String2.replace(dstring, "M","M,");
- dstring = String2.replace(dstring, "L",",L,");
- dstring = String2.replace(dstring, "l",",l,");
- dstring = String2.replace(dstring, "H",",H,");
- dstring = String2.replace(dstring, "h",",h,");
- dstring = String2.replace(dstring, "V",",V,");
- dstring = String2.replace(dstring, "v",",v,");
- dstring = String2.replace(dstring, "Q",",Q,");
- dstring = String2.replace(dstring, "q",",q,");
- dstring = String2.replace(dstring, "T",",T,");
- dstring = String2.replace(dstring, "t",",t,");
- // Adobe includes no delimiter before negative numbers
- dstring = String2.replace(dstring, "-",",-");
- // get rid of any dup commas we might have introduced
- dstring = String2.replace(dstring, ",,",",");
- // get rid of spaces
- // (cr/lf's have to be removed before the xml object can be created,
- // so that is done in xml.onData method)
- dstring = String2.replace(dstring, " ","");
- dstring = String2.replace(dstring, "\t","");
- return dstring.split(",");
- }
- /**
- * @method makeDrawCmds
- * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
- * @description Convert svg draw commands to array of ASVDrawing commands: _commands
- */
- private function makeDrawCmds(svgCmds:Array):void {
- var j:Number = 0, ii:int;
- var qc:Array;
- var firstP:Point;
- var lastP:Point;
- var lastC:Point;
- var cmd:String;
- var cp:Point, pp:Point;
- do {
- cmd = svgCmds[j++];
- switch (cmd) {
- case "M" :
- // moveTo point
- firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- if (this._hasFill) {
- _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
- }
- if (this._hasStroke) {
- _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
- }
- _commands.push(new MoveToCommand(firstP));
- this.addPoint(firstP);
- j += 2;
- if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
- do {
- // if multiple points listed, add the rest as lineTo points
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- }
- break;
- case "l" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "L" :
- do {
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "h" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "H" :
- do {
- lastP = new Point(Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "v" :
- do {
- lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "V" :
- do {
- lastP = new Point(lastP.x, Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "q" :
- do {
- // control is relative to lastP, not lastC
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "Q" :
- do {
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "c" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:lastP.x, y:lastP.y},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "C" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "s" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "S" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "z" :
- case "Z" :
- if (!firstP.equals(lastP)) {
- _commands.push(new LineToCommand(firstP));
- this.addPoint(firstP);
- }
- j++;
- break;
- } // end switch
- } while (j < svgCmds.length);
- }
- /**
- *
- */
- public function draw(graphics:Graphics):void {
- for each (var command:SVGPathCommand in this._commands) {
- command.execute(graphics);
- }
- }
- }
- class String2 {
- /**
- * @class String2
- * @author Helen Triolo, with inclusions from Tim Groleau
- * @description String functions not included in String needed for path->array conversion
- */
- /**
- * @method replace ()
- * @description Replaces sFind in s with sReplace
- * @param s (String) original string
- * @param sFind (String) part to be replaced
- * @param sReplace (String) string to replace it with
- * @returns (String) string with replacement
- */
- public static function replace(s:String, sFind:String, sReplace:String):String {
- return s.split(sFind).join(sReplace);
- }
- /**
- * @method shrinkSequencesOf (Groleau)
- * @description Shrinks all sequences of a given character in a string to one
- * @param s (String) original string
- * @param ch (String) character to be found
- * @returns (String) string with sequences shrunk
- */
- public static function shrinkSequencesOf(s:String, ch:String):String {
- var len:Number = s.length;
- var idx:Number = 0;
- var idx2:Number = 0;
- var rs:String = "";
- while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
- // include string up to first character in sequence
- rs += s.substring(idx, idx2);
- idx = idx2;
- // remove all subsequent characters in sequence
- while ((s.charAt(idx) == ch) && (idx < len)) idx++;
- }
- return rs + s.substring(idx, len);
- }
- }
- class Math2 {
- /**
- * @class Math2
- * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
- * @description Math functions not included in Math needed for path->array conversion
- */
- /**
- * @method ratioTo (Groleau)
- * @description Returns the point on segment [p1,p2] which is ratio times the total distance
- * between p1 and p2 away from p1
- * @param p1 (Object) x and y values of point p1
- * @param p2 (Object) x and y values of point p2
- * @param ratio (Number) real
- * @returns Object
- */
- public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
- return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
- }
- /**
- * @method intersect2Lines (Penner)
- * @description Returns the point of intersection between two lines
- * @param p1, p2 (Objects) points on line 1
- * @param p3, p4 (Objects) points on line 2
- * @returns Object (point of intersection)
- */
- public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
- var x1:Number = p1.x; var y1:Number = p1.y;
- var x4:Number = p4.x; var y4:Number = p4.y;
- var dx1:Number = p2.x - x1;
- var dx2:Number = p3.x - x4;
- if (!(dx1 || dx2)) return NaN;
- var m1:Number = (p2.y - y1) / dx1;
- var m2:Number = (p3.y - y4) / dx2;
- if (!dx1) {
- return { x:x1, y:m2 * (x1 - x4) + y4 };
- } else if (!dx2) {
- return { x:x4, y:m1 * (x4 - x1) + y1 };
- }
- var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
- var yInt:Number = m1 * (xInt - x1) + y1;
- return { x:xInt,y:yInt };
- }
- /**
- * @method rotation
- * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
- * @param dy (Number) pixels
- * @param dx (Number) pixels
- * @returns Number (angle, degrees)
- */
- public static function rotation(dy:Number, dx:Number):Number {
- return Math.atan2(dy, dx) * 180/Math.PI;
- }
- /**
- * @method midPt
- * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
- * @param p1x (Number) pixels
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels
- * @param p2y (Number) pixels
- * @returns Object (midpoint)
- */
- public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
- return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
- }
- /**
- * @method getQuadBez_RP (Penner)
- * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
- * to achieve a specified tolerance
- * @param p1 (Object) endpoint
- * @param c1 (Object) 1st control point
- * @param c2 (Object) 2nd control point
- * @param p2 (Object) endpoint
- * @param k: tolerance (low number = most accurate result)
- * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
- * p1x, p1y, cx, cy, p2x, p2y
- */
- public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
- // find intersection between bezier arms
- var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
- // find distance between the midpoints
- var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
- var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
- // split curve if the quadratic isn't close enough
- if (dx*dx + dy*dy > k) {
- var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
- var b0:Object = halves.b0; var b1:Object = halves.b1;
- // recursive call to subdivide curve
- getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
- getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
- } else {
- // end recursion by saving points
- qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
- }
- }
- /**
- * @method bezierSplit (Penner)
- * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param c1x (Number) pixels, control point 1
- * @param c1y (Number) pixels
- * @param c2x (Number) pixels, control point 2
- * @param c2y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Object (object with two cubic bezier definitions, b0 and b1)
- */
- public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
- var m:Function = Math2.midPt;
- var p1:Object = {x:p1x, y:p1y};
- var p2:Object = {x:p2x, y:p2y};
- var p01:Object = m (p1x, p1y, c1x, c1y);
- var p12:Object = m (c1x, c1y, c2x, c2y);
- var p23:Object = m (c2x, c2y, p2x, p2y);
- var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
- var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
- var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
- /*
- b0:{a:p0, b:p01, c:p02, d:p03},
- b1:{a:p03, b:p13, c:p23, d:p3 }
- */
- return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
- }
- /**
- * @method pointOnCurve (Penner)
- * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
- * of the standard equation:
- * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
- * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param t (Number) if time is 0-1 along curve, value of t to find point at
- * @returns Object (point at time t)
- */
- public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
- var o:Object = new Object();
- o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
- o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
- return o;
- }
- /**
- * @method pointsOnCurve (Penner)
- * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
- * includes:
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- */
- public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- for (var i:Number=0; i <= n; i++) {
- pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method pointsOnLine (Penner)
- * @description Returns an array of point positions and rotations for n evenly spaced points
- * along a line segment
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- *//* ....................................................................
- Returns an array of point positions and rotation for n evenly spaced points along a line segment
- */
- public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- if (p2x != p1x) {
- var m:Number = (p2y-p1y)/(p2x-p1x);
- var b:Number = p1y - p1x * m;
- for (var i:Number=0; i <= n; i++) {
- var x:Number = p1x + ((p2x-p1x)/n) * i;
- pts.push({x:x, y:m*x+b});
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- // vertical segment
- } else {
- for (i=0; i<=n; i++) {
- pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method curveApproxLen
- * @description Returns the approximate length of a curved segment, found by dividing it
- * into two segments at t=0.5
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
- var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
- var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
- var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
- return len1+len2;
- }
- /**
- * @method lineLen
- * @description Returns the length of a line segment
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
- return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
- }
- /**
- * @method roundTo
- * @description Returns a number rounded to specified number of decimals
- * @param n (Number)
- * @param ndec (Number) number of decimals to round to
- * @returns Number
- */
- public static function roundTo(n:Number, ndec:Number):Number {
- var multiplier:Number = Math.pow(10, ndec);
- return Math.round(n*multiplier)/multiplier;
- }
- }
- class SVGColor {
- public static function getByName(name:String):Number {
- var col:Number = SVGColor._colorTable[name];
- return isNaN(col) ? 0 : col;
- }
- private static const _colorTable:Object = {
- blue:0x0000ff,
- green:0x008000,
- red:0xff0000,
- aliceblue:0xf0f8ff,
- antiquewhite:0xfaebd7,
- aqua:0x00ffff,
- aquamarine:0x7fffd4,
- azure:0xf0ffff,
- beige:0xf5f5dc,
- bisque:0xffe4c4,
- black:0x000000,
- blanchedalmond:0xffebcd,
- blueviolet:0x8a2be2,
- brown:0xa52a2a,
- burlywood:0xdeb887,
- cadetblue:0x5f9ea0,
- chartreuse:0x7fff00,
- chocolate:0xd2691e,
- coral:0xff7f50,
- cornflowerblue:0x6495ed,
- cornsilk:0xfff8dc,
- crimson:0xdc143c,
- cyan:0x00ffff,
- darkblue:0x00008b,
- darkcyan:0x008b8b,
- darkgoldenrod:0xb8860b,
- darkgray:0xa9a9a9,
- darkgreen:0x006400,
- darkgrey:0xa9a9a9,
- darkkhaki:0xbdb76b,
- darkmagenta:0x8b008b,
- darkolivegreen:0x556b2f,
- darkorange:0xff8c00,
- darkorchid:0x9932cc,
- darkred:0x8b0000,
- darksalmon:0xe9967a,
- darkseagreen:0x8fbc8f,
- darkslateblue:0x483d8b,
- darkslategray:0x2f4f4f,
- darkslategrey:0x2f4f4f,
- darkturquoise:0x00ced1,
- darkviolet:0x9400d3,
- deeppink:0xff1493,
- deepskyblue:0x00bfff,
- dimgray:0x696969,
- dimgrey:0x696969,
- dodgerblue:0x1e90ff,
- firebrick:0xb22222,
- floralwhite:0xfffaf0,
- forestgreen:0x228b22,
- fuchsia:0xff00ff,
- gainsboro:0xdcdcdc,
- ghostwhite:0xf8f8ff,
- gold:0xffd700,
- goldenrod:0xdaa520,
- gray:0x808080,
- grey:0x808080,
- greenyellow:0xadff2f,
- honeydew:0xf0fff0,
- hotpink:0xff69b4,
- indianred:0xcd5c5c,
- indigo:0x4b0082,
- ivory:0xfffff0,
- khaki:0xf0e68c,
- lavender:0xe6e6fa,
- lavenderblush:0xfff0f5,
- lawngreen:0x7cfc00,
- lemonchiffon:0xfffacd,
- lightblue:0xadd8e6,
- lightcoral:0xf08080,
- lightcyan:0xe0ffff,
- lightgoldenrodyellow:0xfafad2,
- lightgray:0xd3d3d3,
- lightgreen:0x90ee90,
- lightgrey:0xd3d3d3,
- lightpink:0xffb6c1,
- lightsalmon:0xffa07a,
- lightseagreen:0x20b2aa,
- lightskyblue:0x87cefa,
- lightslategray:0x778899,
- lightslategrey:0x778899,
- lightsteelblue:0xb0c4de,
- lightyellow:0xffffe0,
- lime:0x00ff00,
- limegreen:0x32cd32,
- linen:0xfaf0e6,
- magenta:0xff00ff,
- maroon:0x800000,
- mediumaquamarine:0x66cdaa,
- mediumblue:0x0000cd,
- mediumorchid:0xba55d3,
- mediumpurple:0x9370db,
- mediumseagreen:0x3cb371,
- mediumslateblue:0x7b68ee,
- mediumspringgreen:0x00fa9a,
- mediumturquoise:0x48d1cc,
- mediumvioletred:0xc71585,
- midnightblue:0x191970,
- mintcream:0xf5fffa,
- mistyrose:0xffe4e1,
- moccasin:0xffe4b5,
- navajowhite:0xffdead,
- navy:0x000080,
- oldlace:0xfdf5e6,
- olive:0x808000,
- olivedrab:0x6b8e23,
- orange:0xffa500,
- orangered:0xff4500,
- orchid:0xda70d6,
- palegoldenrod:0xeee8aa,
- palegreen:0x98fb98,
- paleturquoise:0xafeeee,
- palevioletred:0xdb7093,
- papayawhip:0xffefd5,
- peachpuff:0xffdab9,
- peru:0xcd853f,
- pink:0xffc0cb,
- plum:0xdda0dd,
- powderblue:0xb0e0e6,
- purple:0x800080,
- rosybrown:0xbc8f8f,
- royalblue:0x4169e1,
- saddlebrown:0x8b4513,
- salmon:0xfa8072,
- sandybrown:0xf4a460,
- seagreen:0x2e8b57,
- seashell:0xfff5ee,
- sienna:0xa0522d,
- silver:0xc0c0c0,
- skyblue:0x87ceeb,
- slateblue:0x6a5acd,
- slategray:0x708090,
- slategrey:0x708090,
- snow:0xfffafa,
- springgreen:0x00ff7f,
- steelblue:0x4682b4,
- tan:0xd2b48c,
- teal:0x008080,
- thistle:0xd8bfd8,
- tomato:0xff6347,
- turquoise:0x40e0d0,
- violet:0xee82ee,
- wheat:0xf5deb3,
- white:0xffffff,
- whitesmoke:0xf5f5f5,
- yellow:0xffff00,
- yellowgreen:0x9acd32
- }
- }
- class SVGPathCommandType {
- public static const BEGIN_FILL_COMMAND:Number = 1;
- public static const LINE_STYLE_COMMAND:Number = 2;
- public static const MOVE_TO_COMMAND:Number = 3;
- public static const LINE_TO_COMMAND:Number = 4;
- public static const CURVE_TO_COMMAND:Number = 5;
- }
- interface ISVGPathCommand {
- function execute(graphics:Graphics):void;
- }
- class SVGPathCommand implements ISVGPathCommand {
- private var _type:Number;
- public function get type():Number { return this._type; }
- public function SVGPathCommand(type:Number = 0) {
- this._type = type;
- }
- public function execute(graphics:Graphics):void {
- throw new Error('Subclass must be implement execute method.');
- }
- }
- class BeginFillCommand extends SVGPathCommand {
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function BeginFillCommand(color:Number, alpha:Number) {
- super(SVGPathCommandType.BEGIN_FILL_COMMAND);
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.beginFill(this._color, this._alpha);
- }
- }
- class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt1:Point;
- public function get x1():Number { return this._pt1.x; }
- public function get y1():Number { return this._pt1.y; }
- private var _pt2:Point;
- public function get x2():Number { return this._pt2.x; }
- public function get y2():Number { return this._pt2.y; }
- public function CurveToCommand(pt1:Point, pt2:Point) {
- super(SVGPathCommandType.CURVE_TO_COMMAND);
- this._pt1 = pt1;
- this._pt2 = pt2;
- }
- public override function execute(graphics:Graphics):void {
- graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
- }
- }
- class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _width:Number;
- public function get width():Number { return this._width; }
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
- super(SVGPathCommandType.LINE_STYLE_COMMAND);
- this._width = width;
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineStyle(this._width, this._color, this._alpha);
- }
- }
- class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function LineToCommand(pt:Point) {
- super(SVGPathCommandType.LINE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineTo(this._pt.x, this._pt.y);
- }
- }
- class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function MoveToCommand(pt:Point) {
- super(SVGPathCommandType.MOVE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.moveTo(this._pt.x, this._pt.y);
- }
- }
Sewing forked from: Sewing
- // forked from Saqoosha's Sewing
- package {
- import caurina.transitions.Equations;
- import caurina.transitions.Tweener;
- import caurina.transitions.properties.CurveModifiers;
- import flash.display.Graphics;
- import flash.display.Sprite;
- import flash.display.StageAlign;
- import flash.display.StageQuality;
- import flash.display.StageScaleMode;
- import flash.events.Event;
- import flash.geom.Point;
- import flash.net.URLLoader;
- import flash.net.URLLoaderDataFormat;
- import flash.net.URLRequest;
- import flash.utils.setTimeout;
- [SWF(width=465, height=465, backgroundColor=0xffff00, frameRate=60)]
- public class Sewing extends Sprite {
- private var _loader:URLLoader;
- private var _canvas:Sprite;
- private var _paths:Array;
- public function Sewing() {
- //Wonderfl.capture_delay(58);
- //this.stage.quality = StageQuality.BEST;
- this.stage.align = StageAlign.TOP_LEFT;
- this.stage.scaleMode = StageScaleMode.NO_SCALE;
- CurveModifiers.init();
- this._canvas = this.addChild(new Sprite()) as Sprite;
- this._loader = new URLLoader();
- this._loader.dataFormat = URLLoaderDataFormat.TEXT;
- this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
- this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
- }
- private function _handleLoaded(e:Event):void {
- var svg:XML = new XML(this._loader.data);
- this._paths = [];
- var path:SVGPath;
- var delay:Number = 2.0;
- var cx:Number = parseInt(svg.@width) / 2;
- var cy:Number = parseInt(svg.@height) / 2;
- this._canvas.x = this.stage.stageWidth / 2 - cx;
- this._canvas.y = this.stage.stageHeight / 2 - cy;
- for each (var pathNode:XML in svg..*::path) {
- path = new SVGPath(pathNode);
- this._paths.push(path);
- var i:Number = 0;
- var di:Number = Math.PI * 2 / path.points.length;
- var px:Number = cx;
- var py:Number = this.stage.stageHeight - this._canvas.y;
- for each (var pt:Point in path.points) {
- Tweener.addTween(pt, {
- x: pt.x,
- y: pt.y,
- _bezier:[
- { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
- { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
- ],
- time: 1.0,
- delay: delay,
- transition: Equations.easeNone
- });
- pt.x = px;
- pt.y = py;
- delay += 0.004;
- i += di;
- }
- }
- this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
- setTimeout(function ():void {
- removeEventListener(Event.ENTER_FRAME, _drawPaths);
- }, (delay + 1) * 1000);
- }
- private function _drawPaths(e:Event):void {
- this._canvas.graphics.clear();
- for each (var path:SVGPath in this._paths) {
- path.draw(this._canvas.graphics);
- }
- }
- }
- }
- import flash.display.Graphics;
- import flash.geom.Point;
- import flash.geom.Rectangle;
- /**
- * @class PathToArray
- * @author Helen Triolo (with contributions from many people)
- * @version 1.01
- * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
- * not contain any CRLF characters), and an empty array.
- * Parses the path node to make an array of drawing commands, which include cubic bezier
- * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
- * using Robert Penner's code to convert with accuracy within 1 pixel.
- * Drawing commands are produced in the format originally devised by Peter Hall
- * in his ASVDrawing class. These are the possible elements in array dCmds (and the
- * corresponding Flash drawing API commands to apply them):
- * ['M',[x,y]] moveTo(x,y)
- * ['L',[x,y]] lineTo(x,y)
- * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
- * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
- * ['F',[color,alpha]] beginFill(color,alpha)
- * ['EF'] endFill()
- * History:
- * v1.00 2005/11/13 Original release
- * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
- *
- * @param svgnode (XMLNode) Path node from SVG file
- * @param dCmds (Array) Empty array to write commands to
- */
- class SVGPath {
- private var _commands:Array;
- public function get commands():Array { return this._commands }
- private var _points:Array;
- public function get points():Array { return this._points }
- private function addPoint(... points:Array):void {
- for each (var pt:Point in points) {
- this._addPoint(pt);
- }
- }
- private function _addPoint(pt:Point):void {
- if (pt.x < this._bounds.left) {
- this._bounds.left = pt.x;
- } else if (this._bounds.right < pt.x) {
- this._bounds.right = pt.x;
- }
- if (pt.y < this._bounds.top) {
- this._bounds.top = pt.y;
- } else if (this._bounds.bottom < pt.y) {
- this._bounds.bottom = pt.y;
- }
- this._points.push(pt);
- }
- private var _bounds:Rectangle;
- public function get boundsRect():Rectangle { return this._bounds }
- private var _hasFill:Boolean;
- public function get hasFill():Boolean { return this._hasFill }
- private var _hasStroke:Boolean;
- public function get hasStroke():Boolean { return this._hasStroke }
- public function swapFillAndStroke():void {
- var flg:Boolean = this._hasFill;
- this._hasFill = this._hasStroke;
- this._hasStroke = flg;
- var val:Number = this._fillColor;
- this._fillColor = this._strokeColor;
- this._strokeColor = val;
- val = this._fillAlpha;
- this._fillAlpha = this._strokeAlpha;
- this._strokeAlpha = val;
- }
- private var _fillColor:Number;
- public function get fillColor():Number { return this._fillColor }
- public function set fillColor(col:Number):void { this._fillColor = col }
- private var _fillAlpha:Number;
- public function get fillAlpha():Number { return this._fillAlpha }
- public function set fillAlpha(al:Number):void { this._fillAlpha = al }
- private var _strokeColor:Number;
- public function get strokeColor():Number { return this._strokeColor }
- public function set strokeColor(col:Number):void { this._strokeColor = col }
- private var _strokeAlpha:Number;
- public function get strokeAlpha():Number { return this._strokeAlpha }
- public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
- private var _strokeWidth:Number;
- public function get strokeWidth():Number { return this._strokeWidth }
- public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
- /**
- *
- */
- public function SVGPath(svgNode:XML) {
- this._commands = [];
- this._points = [];
- this._bounds = new Rectangle();
- this._bounds.top = this._bounds.left = Number.MAX_VALUE;
- this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
- this._hasFill = false;
- this._hasStroke = false;
- this.makeDrawCmds(this.extractCmds(svgNode));
- }
- /**
- * @method extractCmds ()
- * @param node (XMLNode) SVG path node
- * @description Parse path node and convert to array of SVG drawing commands and data
- * eg, M,250.8,33.8,c,-33.6,-9.7,-42,19.1,-48.2,22.6,s,-27.9,2.2,-33.3,5.8,
- * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
- * @returns (Array) array of drawing commands
- */
- private function extractCmds(node:XML):Array {
- var i:Number;
- var startColor:Number;
- var thisColor:Number;
- //var hasFill:Boolean = false;
- var hasTransform:Boolean = false;
- //var hasStroke:Boolean = false;
- var hasStrokeWidth:Boolean = false;
- var hasRotate:Number = 0;
- var dstring:String = "";
- var rotation:Number;
- // is there a fill attribute, a transform attribute, a stroke attribute?
- for each (var a:XML in node.attributes()) {
- switch (a.name().toString()) {
- case 'fill': this._hasFill = true; break;
- case 'transform': hasTransform = true; break;
- case 'stroke': this._hasStroke = true; break;
- case 'stroke-width': hasStrokeWidth = true; break;
- }
- }
- if (this._hasFill) {
- // parse for fill color specification
- // if a hex number is specified, startColor will be > 0
- // if a color name is specified, startColor will be 0
- var fillStr:String = node.@fill;
- if (fillStr == 'none') {
- this._hasFill = false;
- } else {
- startColor = fillStr.indexOf("#") + 1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(fillStr);
- if (isNaN(thisColor)) {
- this._hasFill = false;
- } else {
- this._fillColor = thisColor;
- this._fillAlpha = 1.0;
- }
- } else {
- this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
- this._fillAlpha = 1.0;
- }
- }
- }
- // stroke: color, width, alpha
- if (this._hasStroke) {
- // parse for stroke color specification
- var strokeStr:String = node.@stroke;
- if (strokeStr == 'none') {
- this._hasStroke = false;
- } else {
- startColor = strokeStr.indexOf("#")+1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(strokeStr);
- if (isNaN(thisColor)) {
- this._hasStroke = false;
- } else {
- this._strokeWidth = 0;
- this._strokeColor = SVGColor.getByName(strokeStr);
- this._strokeAlpha = 1.0;
- }
- } else {
- this._strokeWidth = 0;
- this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
- this._strokeAlpha = 1.0;
- }
- }
- }
- if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
- // if stroke and fill are both undefined, set fill to black
- if (!this._hasFill && !this._hasStroke) {
- this._hasFill = true;
- this._fillColor = 0;
- this._fillAlpha = 1.0;
- }
- if (hasTransform) {
- // parse for rotation specification
- var transformStr:String = node.@transform;
- hasRotate = transformStr.indexOf("rotate");
- if (hasRotate > -1) {
- var startRotate:Number = transformStr.indexOf("(");
- var endRotate:Number = transformStr.indexOf(")");
- rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
- } else {
- rotation = 0;
- }
- } else rotation = 0;
- // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
- dstring = node.@d;
- if (dstring.indexOf(",") > -1) { // has commas?
- if (dstring.indexOf(" ") > -1) { // yes, has spaces?
- // change spaces to commas, then deal as for Illustrator
- dstring = String2.replace(dstring," ",",");
- }
- } else { // no commas
- // get rid of extra spaces and change rest to commas
- dstring = String2.shrinkSequencesOf(dstring, " ");
- dstring = String2.replace(dstring, " ",",");
- }
- dstring = String2.replace(dstring, "c",",c,");
- dstring = String2.replace(dstring, "C",",C,");
- dstring = String2.replace(dstring, "S",",S,");
- dstring = String2.replace(dstring, "s",",s,");
- // separate the z from the last element
- dstring = String2.replace(dstring, "z",",z");
- // change the following if M can be mid-path
- dstring = String2.replace(dstring, "M","M,");
- dstring = String2.replace(dstring, "L",",L,");
- dstring = String2.replace(dstring, "l",",l,");
- dstring = String2.replace(dstring, "H",",H,");
- dstring = String2.replace(dstring, "h",",h,");
- dstring = String2.replace(dstring, "V",",V,");
- dstring = String2.replace(dstring, "v",",v,");
- dstring = String2.replace(dstring, "Q",",Q,");
- dstring = String2.replace(dstring, "q",",q,");
- dstring = String2.replace(dstring, "T",",T,");
- dstring = String2.replace(dstring, "t",",t,");
- // Adobe includes no delimiter before negative numbers
- dstring = String2.replace(dstring, "-",",-");
- // get rid of any dup commas we might have introduced
- dstring = String2.replace(dstring, ",,",",");
- // get rid of spaces
- // (cr/lf's have to be removed before the xml object can be created,
- // so that is done in xml.onData method)
- dstring = String2.replace(dstring, " ","");
- dstring = String2.replace(dstring, "\t","");
- return dstring.split(",");
- }
- /**
- * @method makeDrawCmds
- * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
- * @description Convert svg draw commands to array of ASVDrawing commands: _commands
- */
- private function makeDrawCmds(svgCmds:Array):void {
- var j:Number = 0, ii:int;
- var qc:Array;
- var firstP:Point;
- var lastP:Point;
- var lastC:Point;
- var cmd:String;
- var cp:Point, pp:Point;
- do {
- cmd = svgCmds[j++];
- switch (cmd) {
- case "M" :
- // moveTo point
- firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- if (this._hasFill) {
- _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
- }
- if (this._hasStroke) {
- _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
- }
- _commands.push(new MoveToCommand(firstP));
- this.addPoint(firstP);
- j += 2;
- if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
- do {
- // if multiple points listed, add the rest as lineTo points
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- }
- break;
- case "l" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "L" :
- do {
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "h" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "H" :
- do {
- lastP = new Point(Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "v" :
- do {
- lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "V" :
- do {
- lastP = new Point(lastP.x, Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "q" :
- do {
- // control is relative to lastP, not lastC
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "Q" :
- do {
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "c" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:lastP.x, y:lastP.y},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "C" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "s" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "S" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "z" :
- case "Z" :
- if (!firstP.equals(lastP)) {
- _commands.push(new LineToCommand(firstP));
- this.addPoint(firstP);
- }
- j++;
- break;
- } // end switch
- } while (j < svgCmds.length);
- }
- /**
- *
- */
- public function draw(graphics:Graphics):void {
- for each (var command:SVGPathCommand in this._commands) {
- command.execute(graphics);
- }
- }
- }
- class String2 {
- /**
- * @class String2
- * @author Helen Triolo, with inclusions from Tim Groleau
- * @description String functions not included in String needed for path->array conversion
- */
- /**
- * @method replace ()
- * @description Replaces sFind in s with sReplace
- * @param s (String) original string
- * @param sFind (String) part to be replaced
- * @param sReplace (String) string to replace it with
- * @returns (String) string with replacement
- */
- public static function replace(s:String, sFind:String, sReplace:String):String {
- return s.split(sFind).join(sReplace);
- }
- /**
- * @method shrinkSequencesOf (Groleau)
- * @description Shrinks all sequences of a given character in a string to one
- * @param s (String) original string
- * @param ch (String) character to be found
- * @returns (String) string with sequences shrunk
- */
- public static function shrinkSequencesOf(s:String, ch:String):String {
- var len:Number = s.length;
- var idx:Number = 0;
- var idx2:Number = 0;
- var rs:String = "";
- while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
- // include string up to first character in sequence
- rs += s.substring(idx, idx2);
- idx = idx2;
- // remove all subsequent characters in sequence
- while ((s.charAt(idx) == ch) && (idx < len)) idx++;
- }
- return rs + s.substring(idx, len);
- }
- }
- class Math2 {
- /**
- * @class Math2
- * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
- * @description Math functions not included in Math needed for path->array conversion
- */
- /**
- * @method ratioTo (Groleau)
- * @description Returns the point on segment [p1,p2] which is ratio times the total distance
- * between p1 and p2 away from p1
- * @param p1 (Object) x and y values of point p1
- * @param p2 (Object) x and y values of point p2
- * @param ratio (Number) real
- * @returns Object
- */
- public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
- return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
- }
- /**
- * @method intersect2Lines (Penner)
- * @description Returns the point of intersection between two lines
- * @param p1, p2 (Objects) points on line 1
- * @param p3, p4 (Objects) points on line 2
- * @returns Object (point of intersection)
- */
- public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
- var x1:Number = p1.x; var y1:Number = p1.y;
- var x4:Number = p4.x; var y4:Number = p4.y;
- var dx1:Number = p2.x - x1;
- var dx2:Number = p3.x - x4;
- if (!(dx1 || dx2)) return NaN;
- var m1:Number = (p2.y - y1) / dx1;
- var m2:Number = (p3.y - y4) / dx2;
- if (!dx1) {
- return { x:x1, y:m2 * (x1 - x4) + y4 };
- } else if (!dx2) {
- return { x:x4, y:m1 * (x4 - x1) + y1 };
- }
- var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
- var yInt:Number = m1 * (xInt - x1) + y1;
- return { x:xInt,y:yInt };
- }
- /**
- * @method rotation
- * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
- * @param dy (Number) pixels
- * @param dx (Number) pixels
- * @returns Number (angle, degrees)
- */
- public static function rotation(dy:Number, dx:Number):Number {
- return Math.atan2(dy, dx) * 180/Math.PI;
- }
- /**
- * @method midPt
- * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
- * @param p1x (Number) pixels
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels
- * @param p2y (Number) pixels
- * @returns Object (midpoint)
- */
- public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
- return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
- }
- /**
- * @method getQuadBez_RP (Penner)
- * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
- * to achieve a specified tolerance
- * @param p1 (Object) endpoint
- * @param c1 (Object) 1st control point
- * @param c2 (Object) 2nd control point
- * @param p2 (Object) endpoint
- * @param k: tolerance (low number = most accurate result)
- * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
- * p1x, p1y, cx, cy, p2x, p2y
- */
- public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
- // find intersection between bezier arms
- var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
- // find distance between the midpoints
- var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
- var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
- // split curve if the quadratic isn't close enough
- if (dx*dx + dy*dy > k) {
- var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
- var b0:Object = halves.b0; var b1:Object = halves.b1;
- // recursive call to subdivide curve
- getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
- getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
- } else {
- // end recursion by saving points
- qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
- }
- }
- /**
- * @method bezierSplit (Penner)
- * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param c1x (Number) pixels, control point 1
- * @param c1y (Number) pixels
- * @param c2x (Number) pixels, control point 2
- * @param c2y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Object (object with two cubic bezier definitions, b0 and b1)
- */
- public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
- var m:Function = Math2.midPt;
- var p1:Object = {x:p1x, y:p1y};
- var p2:Object = {x:p2x, y:p2y};
- var p01:Object = m (p1x, p1y, c1x, c1y);
- var p12:Object = m (c1x, c1y, c2x, c2y);
- var p23:Object = m (c2x, c2y, p2x, p2y);
- var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
- var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
- var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
- /*
- b0:{a:p0, b:p01, c:p02, d:p03},
- b1:{a:p03, b:p13, c:p23, d:p3 }
- */
- return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
- }
- /**
- * @method pointOnCurve (Penner)
- * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
- * of the standard equation:
- * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
- * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param t (Number) if time is 0-1 along curve, value of t to find point at
- * @returns Object (point at time t)
- */
- public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
- var o:Object = new Object();
- o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
- o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
- return o;
- }
- /**
- * @method pointsOnCurve (Penner)
- * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
- * includes:
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- */
- public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- for (var i:Number=0; i <= n; i++) {
- pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method pointsOnLine (Penner)
- * @description Returns an array of point positions and rotations for n evenly spaced points
- * along a line segment
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- *//* ....................................................................
- Returns an array of point positions and rotation for n evenly spaced points along a line segment
- */
- public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- if (p2x != p1x) {
- var m:Number = (p2y-p1y)/(p2x-p1x);
- var b:Number = p1y - p1x * m;
- for (var i:Number=0; i <= n; i++) {
- var x:Number = p1x + ((p2x-p1x)/n) * i;
- pts.push({x:x, y:m*x+b});
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- // vertical segment
- } else {
- for (i=0; i<=n; i++) {
- pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method curveApproxLen
- * @description Returns the approximate length of a curved segment, found by dividing it
- * into two segments at t=0.5
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
- var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
- var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
- var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
- return len1+len2;
- }
- /**
- * @method lineLen
- * @description Returns the length of a line segment
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
- return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
- }
- /**
- * @method roundTo
- * @description Returns a number rounded to specified number of decimals
- * @param n (Number)
- * @param ndec (Number) number of decimals to round to
- * @returns Number
- */
- public static function roundTo(n:Number, ndec:Number):Number {
- var multiplier:Number = Math.pow(10, ndec);
- return Math.round(n*multiplier)/multiplier;
- }
- }
- class SVGColor {
- public static function getByName(name:String):Number {
- var col:Number = SVGColor._colorTable[name];
- return isNaN(col) ? 0 : col;
- }
- private static const _colorTable:Object = {
- blue:0x0000ff,
- green:0x008000,
- red:0xff0000,
- aliceblue:0xf0f8ff,
- antiquewhite:0xfaebd7,
- aqua:0x00ffff,
- aquamarine:0x7fffd4,
- azure:0xf0ffff,
- beige:0xf5f5dc,
- bisque:0xffe4c4,
- black:0x000000,
- blanchedalmond:0xffebcd,
- blueviolet:0x8a2be2,
- brown:0xa52a2a,
- burlywood:0xdeb887,
- cadetblue:0x5f9ea0,
- chartreuse:0x7fff00,
- chocolate:0xd2691e,
- coral:0xff7f50,
- cornflowerblue:0x6495ed,
- cornsilk:0xfff8dc,
- crimson:0xdc143c,
- cyan:0x00ffff,
- darkblue:0x00008b,
- darkcyan:0x008b8b,
- darkgoldenrod:0xb8860b,
- darkgray:0xa9a9a9,
- darkgreen:0x006400,
- darkgrey:0xa9a9a9,
- darkkhaki:0xbdb76b,
- darkmagenta:0x8b008b,
- darkolivegreen:0x556b2f,
- darkorange:0xff8c00,
- darkorchid:0x9932cc,
- darkred:0x8b0000,
- darksalmon:0xe9967a,
- darkseagreen:0x8fbc8f,
- darkslateblue:0x483d8b,
- darkslategray:0x2f4f4f,
- darkslategrey:0x2f4f4f,
- darkturquoise:0x00ced1,
- darkviolet:0x9400d3,
- deeppink:0xff1493,
- deepskyblue:0x00bfff,
- dimgray:0x696969,
- dimgrey:0x696969,
- dodgerblue:0x1e90ff,
- firebrick:0xb22222,
- floralwhite:0xfffaf0,
- forestgreen:0x228b22,
- fuchsia:0xff00ff,
- gainsboro:0xdcdcdc,
- ghostwhite:0xf8f8ff,
- gold:0xffd700,
- goldenrod:0xdaa520,
- gray:0x808080,
- grey:0x808080,
- greenyellow:0xadff2f,
- honeydew:0xf0fff0,
- hotpink:0xff69b4,
- indianred:0xcd5c5c,
- indigo:0x4b0082,
- ivory:0xfffff0,
- khaki:0xf0e68c,
- lavender:0xe6e6fa,
- lavenderblush:0xfff0f5,
- lawngreen:0x7cfc00,
- lemonchiffon:0xfffacd,
- lightblue:0xadd8e6,
- lightcoral:0xf08080,
- lightcyan:0xe0ffff,
- lightgoldenrodyellow:0xfafad2,
- lightgray:0xd3d3d3,
- lightgreen:0x90ee90,
- lightgrey:0xd3d3d3,
- lightpink:0xffb6c1,
- lightsalmon:0xffa07a,
- lightseagreen:0x20b2aa,
- lightskyblue:0x87cefa,
- lightslategray:0x778899,
- lightslategrey:0x778899,
- lightsteelblue:0xb0c4de,
- lightyellow:0xffffe0,
- lime:0x00ff00,
- limegreen:0x32cd32,
- linen:0xfaf0e6,
- magenta:0xff00ff,
- maroon:0x800000,
- mediumaquamarine:0x66cdaa,
- mediumblue:0x0000cd,
- mediumorchid:0xba55d3,
- mediumpurple:0x9370db,
- mediumseagreen:0x3cb371,
- mediumslateblue:0x7b68ee,
- mediumspringgreen:0x00fa9a,
- mediumturquoise:0x48d1cc,
- mediumvioletred:0xc71585,
- midnightblue:0x191970,
- mintcream:0xf5fffa,
- mistyrose:0xffe4e1,
- moccasin:0xffe4b5,
- navajowhite:0xffdead,
- navy:0x000080,
- oldlace:0xfdf5e6,
- olive:0x808000,
- olivedrab:0x6b8e23,
- orange:0xffa500,
- orangered:0xff4500,
- orchid:0xda70d6,
- palegoldenrod:0xeee8aa,
- palegreen:0x98fb98,
- paleturquoise:0xafeeee,
- palevioletred:0xdb7093,
- papayawhip:0xffefd5,
- peachpuff:0xffdab9,
- peru:0xcd853f,
- pink:0xffc0cb,
- plum:0xdda0dd,
- powderblue:0xb0e0e6,
- purple:0x800080,
- rosybrown:0xbc8f8f,
- royalblue:0x4169e1,
- saddlebrown:0x8b4513,
- salmon:0xfa8072,
- sandybrown:0xf4a460,
- seagreen:0x2e8b57,
- seashell:0xfff5ee,
- sienna:0xa0522d,
- silver:0xc0c0c0,
- skyblue:0x87ceeb,
- slateblue:0x6a5acd,
- slategray:0x708090,
- slategrey:0x708090,
- snow:0xfffafa,
- springgreen:0x00ff7f,
- steelblue:0x4682b4,
- tan:0xd2b48c,
- teal:0x008080,
- thistle:0xd8bfd8,
- tomato:0xff6347,
- turquoise:0x40e0d0,
- violet:0xee82ee,
- wheat:0xf5deb3,
- white:0xffffff,
- whitesmoke:0xf5f5f5,
- yellow:0xffff00,
- yellowgreen:0x9acd32
- }
- }
- class SVGPathCommandType {
- public static const BEGIN_FILL_COMMAND:Number = 1;
- public static const LINE_STYLE_COMMAND:Number = 2;
- public static const MOVE_TO_COMMAND:Number = 3;
- public static const LINE_TO_COMMAND:Number = 4;
- public static const CURVE_TO_COMMAND:Number = 5;
- }
- interface ISVGPathCommand {
- function execute(graphics:Graphics):void;
- }
- class SVGPathCommand implements ISVGPathCommand {
- private var _type:Number;
- public function get type():Number { return this._type; }
- public function SVGPathCommand(type:Number = 0) {
- this._type = type;
- }
- public function execute(graphics:Graphics):void {
- throw new Error('Subclass must be implement execute method.');
- }
- }
- class BeginFillCommand extends SVGPathCommand {
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function BeginFillCommand(color:Number, alpha:Number) {
- super(SVGPathCommandType.BEGIN_FILL_COMMAND);
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.beginFill(this._color, this._alpha);
- }
- }
- class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt1:Point;
- public function get x1():Number { return this._pt1.x; }
- public function get y1():Number { return this._pt1.y; }
- private var _pt2:Point;
- public function get x2():Number { return this._pt2.x; }
- public function get y2():Number { return this._pt2.y; }
- public function CurveToCommand(pt1:Point, pt2:Point) {
- super(SVGPathCommandType.CURVE_TO_COMMAND);
- this._pt1 = pt1;
- this._pt2 = pt2;
- }
- public override function execute(graphics:Graphics):void {
- graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
- }
- }
- class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _width:Number;
- public function get width():Number { return this._width; }
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
- super(SVGPathCommandType.LINE_STYLE_COMMAND);
- this._width = width;
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineStyle(this._width, this._color, this._alpha);
- }
- }
- class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function LineToCommand(pt:Point) {
- super(SVGPathCommandType.LINE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineTo(this._pt.x, this._pt.y);
- }
- }
- class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function MoveToCommand(pt:Point) {
- super(SVGPathCommandType.MOVE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.moveTo(this._pt.x, this._pt.y);
- }
- }
Sewing forked from: Sewing
- // forked from Saqoosha's Sewing
- package {
- import caurina.transitions.Equations;
- import caurina.transitions.Tweener;
- import caurina.transitions.properties.CurveModifiers;
- import flash.display.Graphics;
- import flash.display.Sprite;
- import flash.display.StageAlign;
- import flash.display.StageQuality;
- import flash.display.StageScaleMode;
- import flash.events.Event;
- import flash.geom.Point;
- import flash.net.URLLoader;
- import flash.net.URLLoaderDataFormat;
- import flash.net.URLRequest;
- import flash.utils.setTimeout;
- [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
- public class Sewing extends Sprite {
- private var _loader:URLLoader;
- private var _canvas:Sprite;
- private var _paths:Array;
- public function Sewing() {
- Wonderfl.capture_delay(8);
- this.stage.quality = StageQuality.BEST;
- this.stage.align = StageAlign.TOP_LEFT;
- this.stage.scaleMode = StageScaleMode.NO_SCALE;
- CurveModifiers.init();
- this._canvas = this.addChild(new Sprite()) as Sprite;
- this._loader = new URLLoader();
- this._loader.dataFormat = URLLoaderDataFormat.TEXT;
- this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
- this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
- }
- private function _handleLoaded(e:Event):void {
- var svg:XML = new XML(this._loader.data);
- this._paths = [];
- var path:SVGPath;
- var delay:Number = 2.0;
- var cx:Number = parseInt(svg.@width) / 2;
- var cy:Number = parseInt(svg.@height) / 2;
- this._canvas.x = this.stage.stageWidth / 2 - cx;
- this._canvas.y = this.stage.stageHeight / 2 - cy;
- for each (var pathNode:XML in svg..*::path) {
- path = new SVGPath(pathNode);
- this._paths.push(path);
- var i:Number = 0;
- var di:Number = Math.PI * 2 / path.points.length;
- var px:Number = cx;
- var py:Number = this.stage.stageHeight - this._canvas.y;
- for each (var pt:Point in path.points) {
- Tweener.addTween(pt, {
- x: pt.x,
- y: pt.y,
- _bezier:[
- { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
- { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
- ],
- time: 1.0,
- delay: delay,
- transition: Equations.easeNone
- });
- pt.x = px;
- pt.y = py;
- delay += 0.004;
- i += di;
- }
- }
- this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
- setTimeout(function ():void {
- removeEventListener(Event.ENTER_FRAME, _drawPaths);
- }, (delay + 1) * 1000);
- }
- private function _drawPaths(e:Event):void {
- this._canvas.graphics.clear();
- for each (var path:SVGPath in this._paths) {
- path.draw(this._canvas.graphics);
- }
- }
- }
- }
- import flash.display.Graphics;
- import flash.geom.Point;
- import flash.geom.Rectangle;
- /**
- * @class PathToArray
- * @author Helen Triolo (with contributions from many people)
- * @version 1.01
- * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
- * not contain any CRLF characters), and an empty array.
- * Parses the path node to make an array of drawing commands, which include cubic bezier
- * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
- * using Robert Penner's code to convert with accuracy within 1 pixel.
- * Drawing commands are produced in the format originally devised by Peter Hall
- * in his ASVDrawing class. These are the possible elements in array dCmds (and the
- * corresponding Flash drawing API commands to apply them):
- * ['M',[x,y]] moveTo(x,y)
- * ['L',[x,y]] lineTo(x,y)
- * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
- * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
- * ['F',[color,alpha]] beginFill(color,alpha)
- * ['EF'] endFill()
- * History:
- * v1.00 2005/11/13 Original release
- * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
- *
- * @param svgnode (XMLNode) Path node from SVG file
- * @param dCmds (Array) Empty array to write commands to
- */
- class SVGPath {
- private var _commands:Array;
- public function get commands():Array { return this._commands }
- private var _points:Array;
- public function get points():Array { return this._points }
- private function addPoint(... points:Array):void {
- for each (var pt:Point in points) {
- this._addPoint(pt);
- }
- }
- private function _addPoint(pt:Point):void {
- if (pt.x < this._bounds.left) {
- this._bounds.left = pt.x;
- } else if (this._bounds.right < pt.x) {
- this._bounds.right = pt.x;
- }
- if (pt.y < this._bounds.top) {
- this._bounds.top = pt.y;
- } else if (this._bounds.bottom < pt.y) {
- this._bounds.bottom = pt.y;
- }
- this._points.push(pt);
- }
- private var _bounds:Rectangle;
- public function get boundsRect():Rectangle { return this._bounds }
- private var _hasFill:Boolean;
- public function get hasFill():Boolean { return this._hasFill }
- private var _hasStroke:Boolean;
- public function get hasStroke():Boolean { return this._hasStroke }
- public function swapFillAndStroke():void {
- var flg:Boolean = this._hasFill;
- this._hasFill = this._hasStroke;
- this._hasStroke = flg;
- var val:Number = this._fillColor;
- this._fillColor = this._strokeColor;
- this._strokeColor = val;
- val = this._fillAlpha;
- this._fillAlpha = this._strokeAlpha;
- this._strokeAlpha = val;
- }
- private var _fillColor:Number;
- public function get fillColor():Number { return this._fillColor }
- public function set fillColor(col:Number):void { this._fillColor = col }
- private var _fillAlpha:Number;
- public function get fillAlpha():Number { return this._fillAlpha }
- public function set fillAlpha(al:Number):void { this._fillAlpha = al }
- private var _strokeColor:Number;
- public function get strokeColor():Number { return this._strokeColor }
- public function set strokeColor(col:Number):void { this._strokeColor = col }
- private var _strokeAlpha:Number;
- public function get strokeAlpha():Number { return this._strokeAlpha }
- public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
- private var _strokeWidth:Number;
- public function get strokeWidth():Number { return this._strokeWidth }
- public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
- /**
- *
- */
- public function SVGPath(svgNode:XML) {
- this._commands = [];
- this._points = [];
- this._bounds = new Rectangle();
- this._bounds.top = this._bounds.left = Number.MAX_VALUE;
- this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
- this._hasFill = false;
- this._hasStroke = false;
- this.makeDrawCmds(this.extractCmds(svgNode));
- }
- /**
- * @method extractCmds ()
- * @param node (XMLNode) SVG path node
- * @description Parse path node and convert to array of SVG drawing commands and data
- * eg, M,250.8,33.8,c,-33.6,-9.7,-42,19.1,-48.2,22.6,s,-27.9,2.2,-33.3,5.8,
- * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
- * @returns (Array) array of drawing commands
- */
- private function extractCmds(node:XML):Array {
- var i:Number;
- var startColor:Number;
- var thisColor:Number;
- //var hasFill:Boolean = false;
- var hasTransform:Boolean = false;
- //var hasStroke:Boolean = false;
- var hasStrokeWidth:Boolean = false;
- var hasRotate:Number = 0;
- var dstring:String = "";
- var rotation:Number;
- // is there a fill attribute, a transform attribute, a stroke attribute?
- for each (var a:XML in node.attributes()) {
- switch (a.name().toString()) {
- case 'fill': this._hasFill = true; break;
- case 'transform': hasTransform = true; break;
- case 'stroke': this._hasStroke = true; break;
- case 'stroke-width': hasStrokeWidth = true; break;
- }
- }
- if (this._hasFill) {
- // parse for fill color specification
- // if a hex number is specified, startColor will be > 0
- // if a color name is specified, startColor will be 0
- var fillStr:String = node.@fill;
- if (fillStr == 'none') {
- this._hasFill = false;
- } else {
- startColor = fillStr.indexOf("#") + 1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(fillStr);
- if (isNaN(thisColor)) {
- this._hasFill = false;
- } else {
- this._fillColor = thisColor;
- this._fillAlpha = 1.0;
- }
- } else {
- this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
- this._fillAlpha = 1.0;
- }
- }
- }
- // stroke: color, width, alpha
- if (this._hasStroke) {
- // parse for stroke color specification
- var strokeStr:String = node.@stroke;
- if (strokeStr == 'none') {
- this._hasStroke = false;
- } else {
- startColor = strokeStr.indexOf("#")+1;
- if (startColor == 0) { // name specified instead of color number
- thisColor = SVGColor.getByName(strokeStr);
- if (isNaN(thisColor)) {
- this._hasStroke = false;
- } else {
- this._strokeWidth = 0;
- this._strokeColor = SVGColor.getByName(strokeStr);
- this._strokeAlpha = 1.0;
- }
- } else {
- this._strokeWidth = 0;
- this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
- this._strokeAlpha = 1.0;
- }
- }
- }
- if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
- // if stroke and fill are both undefined, set fill to black
- if (!this._hasFill && !this._hasStroke) {
- this._hasFill = true;
- this._fillColor = 0;
- this._fillAlpha = 1.0;
- }
- if (hasTransform) {
- // parse for rotation specification
- var transformStr:String = node.@transform;
- hasRotate = transformStr.indexOf("rotate");
- if (hasRotate > -1) {
- var startRotate:Number = transformStr.indexOf("(");
- var endRotate:Number = transformStr.indexOf(")");
- rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
- } else {
- rotation = 0;
- }
- } else rotation = 0;
- // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
- dstring = node.@d;
- if (dstring.indexOf(",") > -1) { // has commas?
- if (dstring.indexOf(" ") > -1) { // yes, has spaces?
- // change spaces to commas, then deal as for Illustrator
- dstring = String2.replace(dstring," ",",");
- }
- } else { // no commas
- // get rid of extra spaces and change rest to commas
- dstring = String2.shrinkSequencesOf(dstring, " ");
- dstring = String2.replace(dstring, " ",",");
- }
- dstring = String2.replace(dstring, "c",",c,");
- dstring = String2.replace(dstring, "C",",C,");
- dstring = String2.replace(dstring, "S",",S,");
- dstring = String2.replace(dstring, "s",",s,");
- // separate the z from the last element
- dstring = String2.replace(dstring, "z",",z");
- // change the following if M can be mid-path
- dstring = String2.replace(dstring, "M","M,");
- dstring = String2.replace(dstring, "L",",L,");
- dstring = String2.replace(dstring, "l",",l,");
- dstring = String2.replace(dstring, "H",",H,");
- dstring = String2.replace(dstring, "h",",h,");
- dstring = String2.replace(dstring, "V",",V,");
- dstring = String2.replace(dstring, "v",",v,");
- dstring = String2.replace(dstring, "Q",",Q,");
- dstring = String2.replace(dstring, "q",",q,");
- dstring = String2.replace(dstring, "T",",T,");
- dstring = String2.replace(dstring, "t",",t,");
- // Adobe includes no delimiter before negative numbers
- dstring = String2.replace(dstring, "-",",-");
- // get rid of any dup commas we might have introduced
- dstring = String2.replace(dstring, ",,",",");
- // get rid of spaces
- // (cr/lf's have to be removed before the xml object can be created,
- // so that is done in xml.onData method)
- dstring = String2.replace(dstring, " ","");
- dstring = String2.replace(dstring, "\t","");
- return dstring.split(",");
- }
- /**
- * @method makeDrawCmds
- * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
- * @description Convert svg draw commands to array of ASVDrawing commands: _commands
- */
- private function makeDrawCmds(svgCmds:Array):void {
- var j:Number = 0, ii:int;
- var qc:Array;
- var firstP:Point;
- var lastP:Point;
- var lastC:Point;
- var cmd:String;
- var cp:Point, pp:Point;
- do {
- cmd = svgCmds[j++];
- switch (cmd) {
- case "M" :
- // moveTo point
- firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- if (this._hasFill) {
- _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
- }
- if (this._hasStroke) {
- _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
- }
- _commands.push(new MoveToCommand(firstP));
- this.addPoint(firstP);
- j += 2;
- if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
- do {
- // if multiple points listed, add the rest as lineTo points
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- }
- break;
- case "l" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "L" :
- do {
- lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 2;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "h" :
- do {
- lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "H" :
- do {
- lastP = new Point(Number(svgCmds[j]), lastP.y);
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "v" :
- do {
- lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "V" :
- do {
- lastP = new Point(lastP.x, Number(svgCmds[j]));
- _commands.push(new LineToCommand(lastP));
- this.addPoint(lastP);
- firstP = lastP;
- j += 1;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "q" :
- do {
- // control is relative to lastP, not lastC
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "Q" :
- do {
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- _commands.push(new CurveToCommand(lastC, lastP));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "c" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:lastP.x, y:lastP.y},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "C" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 6;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "s" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
- {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
- lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "S" :
- do {
- // don't save if c1.x=c1.y=c2.x=c2.y=0
- if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
- } else {
- qc = [];
- Math2.getQuadBez_RP(
- {x:firstP.x, y:firstP.y},
- {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
- {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
- {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
- 1, qc);
- for (ii=0; ii
- cp = new Point(qc[ii].cx, qc[ii].cy);
- pp = new Point(qc[ii].p2x, qc[ii].p2y);
- _commands.push(new CurveToCommand(cp, pp));
- this.addPoint(cp, pp);
- }
- lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
- lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
- this.addPoint(lastC, lastP);
- firstP = lastP;
- }
- j += 4;
- } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
- break;
- case "z" :
- case "Z" :
- if (!firstP.equals(lastP)) {
- _commands.push(new LineToCommand(firstP));
- this.addPoint(firstP);
- }
- j++;
- break;
- } // end switch
- } while (j < svgCmds.length);
- }
- /**
- *
- */
- public function draw(graphics:Graphics):void {
- for each (var command:SVGPathCommand in this._commands) {
- command.execute(graphics);
- }
- }
- }
- class String2 {
- /**
- * @class String2
- * @author Helen Triolo, with inclusions from Tim Groleau
- * @description String functions not included in String needed for path->array conversion
- */
- /**
- * @method replace ()
- * @description Replaces sFind in s with sReplace
- * @param s (String) original string
- * @param sFind (String) part to be replaced
- * @param sReplace (String) string to replace it with
- * @returns (String) string with replacement
- */
- public static function replace(s:String, sFind:String, sReplace:String):String {
- return s.split(sFind).join(sReplace);
- }
- /**
- * @method shrinkSequencesOf (Groleau)
- * @description Shrinks all sequences of a given character in a string to one
- * @param s (String) original string
- * @param ch (String) character to be found
- * @returns (String) string with sequences shrunk
- */
- public static function shrinkSequencesOf(s:String, ch:String):String {
- var len:Number = s.length;
- var idx:Number = 0;
- var idx2:Number = 0;
- var rs:String = "";
- while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
- // include string up to first character in sequence
- rs += s.substring(idx, idx2);
- idx = idx2;
- // remove all subsequent characters in sequence
- while ((s.charAt(idx) == ch) && (idx < len)) idx++;
- }
- return rs + s.substring(idx, len);
- }
- }
- class Math2 {
- /**
- * @class Math2
- * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
- * @description Math functions not included in Math needed for path->array conversion
- */
- /**
- * @method ratioTo (Groleau)
- * @description Returns the point on segment [p1,p2] which is ratio times the total distance
- * between p1 and p2 away from p1
- * @param p1 (Object) x and y values of point p1
- * @param p2 (Object) x and y values of point p2
- * @param ratio (Number) real
- * @returns Object
- */
- public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
- return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
- }
- /**
- * @method intersect2Lines (Penner)
- * @description Returns the point of intersection between two lines
- * @param p1, p2 (Objects) points on line 1
- * @param p3, p4 (Objects) points on line 2
- * @returns Object (point of intersection)
- */
- public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
- var x1:Number = p1.x; var y1:Number = p1.y;
- var x4:Number = p4.x; var y4:Number = p4.y;
- var dx1:Number = p2.x - x1;
- var dx2:Number = p3.x - x4;
- if (!(dx1 || dx2)) return NaN;
- var m1:Number = (p2.y - y1) / dx1;
- var m2:Number = (p3.y - y4) / dx2;
- if (!dx1) {
- return { x:x1, y:m2 * (x1 - x4) + y4 };
- } else if (!dx2) {
- return { x:x4, y:m1 * (x4 - x1) + y1 };
- }
- var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
- var yInt:Number = m1 * (xInt - x1) + y1;
- return { x:xInt,y:yInt };
- }
- /**
- * @method rotation
- * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
- * @param dy (Number) pixels
- * @param dx (Number) pixels
- * @returns Number (angle, degrees)
- */
- public static function rotation(dy:Number, dx:Number):Number {
- return Math.atan2(dy, dx) * 180/Math.PI;
- }
- /**
- * @method midPt
- * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
- * @param p1x (Number) pixels
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels
- * @param p2y (Number) pixels
- * @returns Object (midpoint)
- */
- public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
- return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
- }
- /**
- * @method getQuadBez_RP (Penner)
- * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
- * to achieve a specified tolerance
- * @param p1 (Object) endpoint
- * @param c1 (Object) 1st control point
- * @param c2 (Object) 2nd control point
- * @param p2 (Object) endpoint
- * @param k: tolerance (low number = most accurate result)
- * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
- * p1x, p1y, cx, cy, p2x, p2y
- */
- public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
- // find intersection between bezier arms
- var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
- // find distance between the midpoints
- var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
- var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
- // split curve if the quadratic isn't close enough
- if (dx*dx + dy*dy > k) {
- var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
- var b0:Object = halves.b0; var b1:Object = halves.b1;
- // recursive call to subdivide curve
- getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
- getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
- } else {
- // end recursion by saving points
- qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
- }
- }
- /**
- * @method bezierSplit (Penner)
- * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param c1x (Number) pixels, control point 1
- * @param c1y (Number) pixels
- * @param c2x (Number) pixels, control point 2
- * @param c2y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Object (object with two cubic bezier definitions, b0 and b1)
- */
- public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
- var m:Function = Math2.midPt;
- var p1:Object = {x:p1x, y:p1y};
- var p2:Object = {x:p2x, y:p2y};
- var p01:Object = m (p1x, p1y, c1x, c1y);
- var p12:Object = m (c1x, c1y, c2x, c2y);
- var p23:Object = m (c2x, c2y, p2x, p2y);
- var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
- var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
- var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
- /*
- b0:{a:p0, b:p01, c:p02, d:p03},
- b1:{a:p03, b:p13, c:p23, d:p3 }
- */
- return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
- }
- /**
- * @method pointOnCurve (Penner)
- * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
- * of the standard equation:
- * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
- * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param t (Number) if time is 0-1 along curve, value of t to find point at
- * @returns Object (point at time t)
- */
- public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
- var o:Object = new Object();
- o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
- o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
- return o;
- }
- /**
- * @method pointsOnCurve (Penner)
- * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
- * includes:
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- */
- public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- for (var i:Number=0; i <= n; i++) {
- pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method pointsOnLine (Penner)
- * @description Returns an array of point positions and rotations for n evenly spaced points
- * along a line segment
- * x,y = location of point defining start of segment
- * r = rotation of segment (last entry has none because it's just a point)
- * n = number of subdivisions into which curve will be divided (pts = n+1)
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @param n (Number) number of points to return
- * @returns Array
- *//* ....................................................................
- Returns an array of point positions and rotation for n evenly spaced points along a line segment
- */
- public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
- var pts:Array = [];
- if (p2x != p1x) {
- var m:Number = (p2y-p1y)/(p2x-p1x);
- var b:Number = p1y - p1x * m;
- for (var i:Number=0; i <= n; i++) {
- var x:Number = p1x + ((p2x-p1x)/n) * i;
- pts.push({x:x, y:m*x+b});
- if (i > 0) {
- pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
- }
- }
- // vertical segment
- } else {
- for (i=0; i<=n; i++) {
- pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
- }
- }
- pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
- return pts;
- }
- /**
- * @method curveApproxLen
- * @description Returns the approximate length of a curved segment, found by dividing it
- * into two segments at t=0.5
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param cx (Number) pixels, control point
- * @param cy (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
- var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
- var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
- var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
- return len1+len2;
- }
- /**
- * @method lineLen
- * @description Returns the length of a line segment
- * @param p1x (Number) pixels, endpoint 1
- * @param p1y (Number) pixels
- * @param p2x (Number) pixels, endpoint 2
- * @param p2y (Number) pixels
- * @returns Number
- */
- public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
- return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
- }
- /**
- * @method roundTo
- * @description Returns a number rounded to specified number of decimals
- * @param n (Number)
- * @param ndec (Number) number of decimals to round to
- * @returns Number
- */
- public static function roundTo(n:Number, ndec:Number):Number {
- var multiplier:Number = Math.pow(10, ndec);
- return Math.round(n*multiplier)/multiplier;
- }
- }
- class SVGColor {
- public static function getByName(name:String):Number {
- var col:Number = SVGColor._colorTable[name];
- return isNaN(col) ? 0 : col;
- }
- private static const _colorTable:Object = {
- blue:0x0000ff,
- green:0x008000,
- red:0xff0000,
- aliceblue:0xf0f8ff,
- antiquewhite:0xfaebd7,
- aqua:0x00ffff,
- aquamarine:0x7fffd4,
- azure:0xf0ffff,
- beige:0xf5f5dc,
- bisque:0xffe4c4,
- black:0x000000,
- blanchedalmond:0xffebcd,
- blueviolet:0x8a2be2,
- brown:0xa52a2a,
- burlywood:0xdeb887,
- cadetblue:0x5f9ea0,
- chartreuse:0x7fff00,
- chocolate:0xd2691e,
- coral:0xff7f50,
- cornflowerblue:0x6495ed,
- cornsilk:0xfff8dc,
- crimson:0xdc143c,
- cyan:0x00ffff,
- darkblue:0x00008b,
- darkcyan:0x008b8b,
- darkgoldenrod:0xb8860b,
- darkgray:0xa9a9a9,
- darkgreen:0x006400,
- darkgrey:0xa9a9a9,
- darkkhaki:0xbdb76b,
- darkmagenta:0x8b008b,
- darkolivegreen:0x556b2f,
- darkorange:0xff8c00,
- darkorchid:0x9932cc,
- darkred:0x8b0000,
- darksalmon:0xe9967a,
- darkseagreen:0x8fbc8f,
- darkslateblue:0x483d8b,
- darkslategray:0x2f4f4f,
- darkslategrey:0x2f4f4f,
- darkturquoise:0x00ced1,
- darkviolet:0x9400d3,
- deeppink:0xff1493,
- deepskyblue:0x00bfff,
- dimgray:0x696969,
- dimgrey:0x696969,
- dodgerblue:0x1e90ff,
- firebrick:0xb22222,
- floralwhite:0xfffaf0,
- forestgreen:0x228b22,
- fuchsia:0xff00ff,
- gainsboro:0xdcdcdc,
- ghostwhite:0xf8f8ff,
- gold:0xffd700,
- goldenrod:0xdaa520,
- gray:0x808080,
- grey:0x808080,
- greenyellow:0xadff2f,
- honeydew:0xf0fff0,
- hotpink:0xff69b4,
- indianred:0xcd5c5c,
- indigo:0x4b0082,
- ivory:0xfffff0,
- khaki:0xf0e68c,
- lavender:0xe6e6fa,
- lavenderblush:0xfff0f5,
- lawngreen:0x7cfc00,
- lemonchiffon:0xfffacd,
- lightblue:0xadd8e6,
- lightcoral:0xf08080,
- lightcyan:0xe0ffff,
- lightgoldenrodyellow:0xfafad2,
- lightgray:0xd3d3d3,
- lightgreen:0x90ee90,
- lightgrey:0xd3d3d3,
- lightpink:0xffb6c1,
- lightsalmon:0xffa07a,
- lightseagreen:0x20b2aa,
- lightskyblue:0x87cefa,
- lightslategray:0x778899,
- lightslategrey:0x778899,
- lightsteelblue:0xb0c4de,
- lightyellow:0xffffe0,
- lime:0x00ff00,
- limegreen:0x32cd32,
- linen:0xfaf0e6,
- magenta:0xff00ff,
- maroon:0x800000,
- mediumaquamarine:0x66cdaa,
- mediumblue:0x0000cd,
- mediumorchid:0xba55d3,
- mediumpurple:0x9370db,
- mediumseagreen:0x3cb371,
- mediumslateblue:0x7b68ee,
- mediumspringgreen:0x00fa9a,
- mediumturquoise:0x48d1cc,
- mediumvioletred:0xc71585,
- midnightblue:0x191970,
- mintcream:0xf5fffa,
- mistyrose:0xffe4e1,
- moccasin:0xffe4b5,
- navajowhite:0xffdead,
- navy:0x000080,
- oldlace:0xfdf5e6,
- olive:0x808000,
- olivedrab:0x6b8e23,
- orange:0xffa500,
- orangered:0xff4500,
- orchid:0xda70d6,
- palegoldenrod:0xeee8aa,
- palegreen:0x98fb98,
- paleturquoise:0xafeeee,
- palevioletred:0xdb7093,
- papayawhip:0xffefd5,
- peachpuff:0xffdab9,
- peru:0xcd853f,
- pink:0xffc0cb,
- plum:0xdda0dd,
- powderblue:0xb0e0e6,
- purple:0x800080,
- rosybrown:0xbc8f8f,
- royalblue:0x4169e1,
- saddlebrown:0x8b4513,
- salmon:0xfa8072,
- sandybrown:0xf4a460,
- seagreen:0x2e8b57,
- seashell:0xfff5ee,
- sienna:0xa0522d,
- silver:0xc0c0c0,
- skyblue:0x87ceeb,
- slateblue:0x6a5acd,
- slategray:0x708090,
- slategrey:0x708090,
- snow:0xfffafa,
- springgreen:0x00ff7f,
- steelblue:0x4682b4,
- tan:0xd2b48c,
- teal:0x008080,
- thistle:0xd8bfd8,
- tomato:0xff6347,
- turquoise:0x40e0d0,
- violet:0xee82ee,
- wheat:0xf5deb3,
- white:0xffffff,
- whitesmoke:0xf5f5f5,
- yellow:0xffff00,
- yellowgreen:0x9acd32
- }
- }
- class SVGPathCommandType {
- public static const BEGIN_FILL_COMMAND:Number = 1;
- public static const LINE_STYLE_COMMAND:Number = 2;
- public static const MOVE_TO_COMMAND:Number = 3;
- public static const LINE_TO_COMMAND:Number = 4;
- public static const CURVE_TO_COMMAND:Number = 5;
- }
- interface ISVGPathCommand {
- function execute(graphics:Graphics):void;
- }
- class SVGPathCommand implements ISVGPathCommand {
- private var _type:Number;
- public function get type():Number { return this._type; }
- public function SVGPathCommand(type:Number = 0) {
- this._type = type;
- }
- public function execute(graphics:Graphics):void {
- throw new Error('Subclass must be implement execute method.');
- }
- }
- class BeginFillCommand extends SVGPathCommand {
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function BeginFillCommand(color:Number, alpha:Number) {
- super(SVGPathCommandType.BEGIN_FILL_COMMAND);
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.beginFill(this._color, this._alpha);
- }
- }
- class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt1:Point;
- public function get x1():Number { return this._pt1.x; }
- public function get y1():Number { return this._pt1.y; }
- private var _pt2:Point;
- public function get x2():Number { return this._pt2.x; }
- public function get y2():Number { return this._pt2.y; }
- public function CurveToCommand(pt1:Point, pt2:Point) {
- super(SVGPathCommandType.CURVE_TO_COMMAND);
- this._pt1 = pt1;
- this._pt2 = pt2;
- }
- public override function execute(graphics:Graphics):void {
- graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
- }
- }
- class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _width:Number;
- public function get width():Number { return this._width; }
- private var _color:Number;
- public function get color():Number { return this._color; }
- private var _alpha:Number;
- public function get alpha():Number { return this._alpha; }
- public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
- super(SVGPathCommandType.LINE_STYLE_COMMAND);
- this._width = width;
- this._color = color;
- this._alpha = alpha;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineStyle(this._width, this._color, this._alpha);
- }
- }
- class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function LineToCommand(pt:Point) {
- super(SVGPathCommandType.LINE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.lineTo(this._pt.x, this._pt.y);
- }
- }
- class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
- private var _pt:Point;
- public function get x():Number { return this._pt.x; }
- public function get y():Number { return this._pt.y; }
- public function MoveToCommand(pt:Point) {
- super(SVGPathCommandType.MOVE_TO_COMMAND);
- this._pt = pt;
- }
- public override function execute(graphics:Graphics):void {
- graphics.moveTo(this._pt.x, this._pt.y);
- }
- }
notice:







