※現在、「wonderfl build flash online」求人コンテンツ制作に関してのアンケートを実施中です!みなさまのお力添えを頂いて、続々とアンケート結果が集まっていますが、まだまだ募集しております。ご協力のほど、どうぞよろしくお願いいたします!

wonderfl運営事務局
→アンケートページ(※ログインしてからお答えいただけるようになっています。)

 notice: Flash editor updated! Join the development! Thanks to MiniBuilder


FAVORITE BY
:
:
糸で文字
:
AnimationDrawing紐で文字が生成されてく。
:
text紐で文字。StringでString
:
SVG糸で文字を書く
:
effectsewing text effect
:
糸と文字
:
:
AnimationDrawing紐で文字が生成されてく。
:
:
:
:
:
:
:
motionlineamazing
:
:
Sewing
:
Sewing
:
:
cool
:
:
:
SVGWow, very interesting effect :)
:
:
:
:
textCool text effect
:
:
lineslines curves
:
wonderfl
:
:
:
:
糸で文字すげー
:
typoパクったら負け
:
sewingtextawesome!
:
lineimpressive
:
line
:
:
スンゲー
:
cool
:
どひゃー
:
糸で文字なにかのCMみたい
:
すごいとしか言いようがない
:
:
ひょろひょろ
:
:
びろびろびろびろ
:
:
うにょうにょ文字
:
これはすごい糸
:
:
:
凄い
:
:
:
さすが、Saqooshaさん。
:
すごすぎ
:
:
i just peed a little bit....
:
pas mal...
:
にゅるにゅるる
:
svgこれはすごい!コードの行数もすごい
:
なんじゃこりゃー
:
すごいー
:
きたーー
:
Amazing!!!!!!
:
素晴らしい!
:
かわえぇ
:
シュルシュルシュルー!
:
おもしろー
:
すごい
:
すご
:
FORKED
  1. // forked from Saqoosha's Sewing
  2. package {
  3. import caurina.transitions.Equations;
  4. import caurina.transitions.Tweener;
  5. import caurina.transitions.properties.CurveModifiers;
  6. import flash.display.Graphics;
  7. import flash.display.Sprite;
  8. import flash.display.StageAlign;
  9. import flash.display.StageQuality;
  10. import flash.display.StageScaleMode;
  11. import flash.events.Event;
  12. import flash.geom.Point;
  13. import flash.net.URLLoader;
  14. import flash.net.URLLoaderDataFormat;
  15. import flash.net.URLRequest;
  16. import flash.utils.setTimeout;
  17. [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
  18. public class Sewing extends Sprite {
  19. private var _loader:URLLoader;
  20. private var _canvas:Sprite;
  21. private var _paths:Array;
  22. public function Sewing() {
  23. Wonderfl.capture_delay(8);
  24. this.stage.quality = StageQuality.BEST;
  25. this.stage.align = StageAlign.TOP_LEFT;
  26. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  27. CurveModifiers.init();
  28. this._canvas = this.addChild(new Sprite()) as Sprite;
  29. this._loader = new URLLoader();
  30. this._loader.dataFormat = URLLoaderDataFormat.TEXT;
  31. this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
  32. this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
  33. }
  34. private function _handleLoaded(e:Event):void {
  35. var svg:XML = new XML(this._loader.data);
  36. this._paths = [];
  37. var path:SVGPath;
  38. var delay:Number = 2.0;
  39. var cx:Number = parseInt(svg.@width) / 2;
  40. var cy:Number = parseInt(svg.@height) / 2;
  41. this._canvas.x = this.stage.stageWidth / 2 - cx;
  42. this._canvas.y = this.stage.stageHeight / 2 - cy;
  43. for each (var pathNode:XML in svg..*::path) {
  44. path = new SVGPath(pathNode);
  45. this._paths.push(path);
  46. var i:Number = 0;
  47. var di:Number = Math.PI * 2 / path.points.length;
  48. var px:Number = cx;
  49. var py:Number = this.stage.stageHeight - this._canvas.y;
  50. for each (var pt:Point in path.points) {
  51. Tweener.addTween(pt, {
  52. x: pt.x,
  53. y: pt.y,
  54. _bezier:[
  55. { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
  56. { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
  57. ],
  58. time: 1.0,
  59. delay: delay,
  60. transition: Equations.easeNone
  61. });
  62. pt.x = px;
  63. pt.y = py;
  64. delay += 0.004;
  65. i += di;
  66. }
  67. }
  68. this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
  69. setTimeout(function ():void {
  70. removeEventListener(Event.ENTER_FRAME, _drawPaths);
  71. }, (delay + 1) * 1000);
  72. }
  73. private function _drawPaths(e:Event):void {
  74. this._canvas.graphics.clear();
  75. for each (var path:SVGPath in this._paths) {
  76. path.draw(this._canvas.graphics);
  77. }
  78. }
  79. }
  80. }
  81. import flash.display.Graphics;
  82. import flash.geom.Point;
  83. import flash.geom.Rectangle;
  84. /**
  85. * @class PathToArray
  86. * @author Helen Triolo (with contributions from many people)
  87. * @version 1.01
  88. * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
  89. * not contain any CRLF characters), and an empty array.
  90. * Parses the path node to make an array of drawing commands, which include cubic bezier
  91. * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
  92. * using Robert Penner's code to convert with accuracy within 1 pixel.
  93. * Drawing commands are produced in the format originally devised by Peter Hall
  94. * in his ASVDrawing class. These are the possible elements in array dCmds (and the
  95. * corresponding Flash drawing API commands to apply them):
  96. * ['M',[x,y]] moveTo(x,y)
  97. * ['L',[x,y]] lineTo(x,y)
  98. * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
  99. * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
  100. * ['F',[color,alpha]] beginFill(color,alpha)
  101. * ['EF'] endFill()
  102. * History:
  103. * v1.00 2005/11/13 Original release
  104. * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
  105. *
  106. * @param svgnode (XMLNode) Path node from SVG file
  107. * @param dCmds (Array) Empty array to write commands to
  108. */
  109. class SVGPath {
  110. private var _commands:Array;
  111. public function get commands():Array { return this._commands }
  112. private var _points:Array;
  113. public function get points():Array { return this._points }
  114. private function addPoint(... points:Array):void {
  115. for each (var pt:Point in points) {
  116. this._addPoint(pt);
  117. }
  118. }
  119. private function _addPoint(pt:Point):void {
  120. if (pt.x < this._bounds.left) {
  121. this._bounds.left = pt.x;
  122. } else if (this._bounds.right < pt.x) {
  123. this._bounds.right = pt.x;
  124. }
  125. if (pt.y < this._bounds.top) {
  126. this._bounds.top = pt.y;
  127. } else if (this._bounds.bottom < pt.y) {
  128. this._bounds.bottom = pt.y;
  129. }
  130. this._points.push(pt);
  131. }
  132. private var _bounds:Rectangle;
  133. public function get boundsRect():Rectangle { return this._bounds }
  134. private var _hasFill:Boolean;
  135. public function get hasFill():Boolean { return this._hasFill }
  136. private var _hasStroke:Boolean;
  137. public function get hasStroke():Boolean { return this._hasStroke }
  138. public function swapFillAndStroke():void {
  139. var flg:Boolean = this._hasFill;
  140. this._hasFill = this._hasStroke;
  141. this._hasStroke = flg;
  142. var val:Number = this._fillColor;
  143. this._fillColor = this._strokeColor;
  144. this._strokeColor = val;
  145. val = this._fillAlpha;
  146. this._fillAlpha = this._strokeAlpha;
  147. this._strokeAlpha = val;
  148. }
  149. private var _fillColor:Number;
  150. public function get fillColor():Number { return this._fillColor }
  151. public function set fillColor(col:Number):void { this._fillColor = col }
  152. private var _fillAlpha:Number;
  153. public function get fillAlpha():Number { return this._fillAlpha }
  154. public function set fillAlpha(al:Number):void { this._fillAlpha = al }
  155. private var _strokeColor:Number;
  156. public function get strokeColor():Number { return this._strokeColor }
  157. public function set strokeColor(col:Number):void { this._strokeColor = col }
  158. private var _strokeAlpha:Number;
  159. public function get strokeAlpha():Number { return this._strokeAlpha }
  160. public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
  161. private var _strokeWidth:Number;
  162. public function get strokeWidth():Number { return this._strokeWidth }
  163. public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
  164. /**
  165. *
  166. */
  167. public function SVGPath(svgNode:XML) {
  168. this._commands = [];
  169. this._points = [];
  170. this._bounds = new Rectangle();
  171. this._bounds.top = this._bounds.left = Number.MAX_VALUE;
  172. this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
  173. this._hasFill = false;
  174. this._hasStroke = false;
  175. this.makeDrawCmds(this.extractCmds(svgNode));
  176. }
  177. /**
  178. * @method extractCmds ()
  179. * @param node (XMLNode) SVG path node
  180. * @description Parse path node and convert to array of SVG drawing commands and data
  181. * 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,
  182. * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
  183. * @returns (Array) array of drawing commands
  184. */
  185. private function extractCmds(node:XML):Array {
  186. var i:Number;
  187. var startColor:Number;
  188. var thisColor:Number;
  189. //var hasFill:Boolean = false;
  190. var hasTransform:Boolean = false;
  191. //var hasStroke:Boolean = false;
  192. var hasStrokeWidth:Boolean = false;
  193. var hasRotate:Number = 0;
  194. var dstring:String = "";
  195. var rotation:Number;
  196. // is there a fill attribute, a transform attribute, a stroke attribute?
  197. for each (var a:XML in node.attributes()) {
  198. switch (a.name().toString()) {
  199. case 'fill': this._hasFill = true; break;
  200. case 'transform': hasTransform = true; break;
  201. case 'stroke': this._hasStroke = true; break;
  202. case 'stroke-width': hasStrokeWidth = true; break;
  203. }
  204. }
  205. if (this._hasFill) {
  206. // parse for fill color specification
  207. // if a hex number is specified, startColor will be > 0
  208. // if a color name is specified, startColor will be 0
  209. var fillStr:String = node.@fill;
  210. if (fillStr == 'none') {
  211. this._hasFill = false;
  212. } else {
  213. startColor = fillStr.indexOf("#") + 1;
  214. if (startColor == 0) { // name specified instead of color number
  215. thisColor = SVGColor.getByName(fillStr);
  216. if (isNaN(thisColor)) {
  217. this._hasFill = false;
  218. } else {
  219. this._fillColor = thisColor;
  220. this._fillAlpha = 1.0;
  221. }
  222. } else {
  223. this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
  224. this._fillAlpha = 1.0;
  225. }
  226. }
  227. }
  228. // stroke: color, width, alpha
  229. if (this._hasStroke) {
  230. // parse for stroke color specification
  231. var strokeStr:String = node.@stroke;
  232. if (strokeStr == 'none') {
  233. this._hasStroke = false;
  234. } else {
  235. startColor = strokeStr.indexOf("#")+1;
  236. if (startColor == 0) { // name specified instead of color number
  237. thisColor = SVGColor.getByName(strokeStr);
  238. if (isNaN(thisColor)) {
  239. this._hasStroke = false;
  240. } else {
  241. this._strokeWidth = 0;
  242. this._strokeColor = SVGColor.getByName(strokeStr);
  243. this._strokeAlpha = 1.0;
  244. }
  245. } else {
  246. this._strokeWidth = 0;
  247. this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
  248. this._strokeAlpha = 1.0;
  249. }
  250. }
  251. }
  252. if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
  253. // if stroke and fill are both undefined, set fill to black
  254. if (!this._hasFill && !this._hasStroke) {
  255. this._hasFill = true;
  256. this._fillColor = 0;
  257. this._fillAlpha = 1.0;
  258. }
  259. if (hasTransform) {
  260. // parse for rotation specification
  261. var transformStr:String = node.@transform;
  262. hasRotate = transformStr.indexOf("rotate");
  263. if (hasRotate > -1) {
  264. var startRotate:Number = transformStr.indexOf("(");
  265. var endRotate:Number = transformStr.indexOf(")");
  266. rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
  267. } else {
  268. rotation = 0;
  269. }
  270. } else rotation = 0;
  271. // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
  272. dstring = node.@d;
  273. if (dstring.indexOf(",") > -1) { // has commas?
  274. if (dstring.indexOf(" ") > -1) { // yes, has spaces?
  275. // change spaces to commas, then deal as for Illustrator
  276. dstring = String2.replace(dstring," ",",");
  277. }
  278. } else { // no commas
  279. // get rid of extra spaces and change rest to commas
  280. dstring = String2.shrinkSequencesOf(dstring, " ");
  281. dstring = String2.replace(dstring, " ",",");
  282. }
  283. dstring = String2.replace(dstring, "c",",c,");
  284. dstring = String2.replace(dstring, "C",",C,");
  285. dstring = String2.replace(dstring, "S",",S,");
  286. dstring = String2.replace(dstring, "s",",s,");
  287. // separate the z from the last element
  288. dstring = String2.replace(dstring, "z",",z");
  289. // change the following if M can be mid-path
  290. dstring = String2.replace(dstring, "M","M,");
  291. dstring = String2.replace(dstring, "L",",L,");
  292. dstring = String2.replace(dstring, "l",",l,");
  293. dstring = String2.replace(dstring, "H",",H,");
  294. dstring = String2.replace(dstring, "h",",h,");
  295. dstring = String2.replace(dstring, "V",",V,");
  296. dstring = String2.replace(dstring, "v",",v,");
  297. dstring = String2.replace(dstring, "Q",",Q,");
  298. dstring = String2.replace(dstring, "q",",q,");
  299. dstring = String2.replace(dstring, "T",",T,");
  300. dstring = String2.replace(dstring, "t",",t,");
  301. // Adobe includes no delimiter before negative numbers
  302. dstring = String2.replace(dstring, "-",",-");
  303. // get rid of any dup commas we might have introduced
  304. dstring = String2.replace(dstring, ",,",",");
  305. // get rid of spaces
  306. // (cr/lf's have to be removed before the xml object can be created,
  307. // so that is done in xml.onData method)
  308. dstring = String2.replace(dstring, " ","");
  309. dstring = String2.replace(dstring, "\t","");
  310. return dstring.split(",");
  311. }
  312. /**
  313. * @method makeDrawCmds
  314. * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
  315. * @description Convert svg draw commands to array of ASVDrawing commands: _commands
  316. */
  317. private function makeDrawCmds(svgCmds:Array):void {
  318. var j:Number = 0, ii:int;
  319. var qc:Array;
  320. var firstP:Point;
  321. var lastP:Point;
  322. var lastC:Point;
  323. var cmd:String;
  324. var cp:Point, pp:Point;
  325. do {
  326. cmd = svgCmds[j++];
  327. switch (cmd) {
  328. case "M" :
  329. // moveTo point
  330. firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  331. if (this._hasFill) {
  332. _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
  333. }
  334. if (this._hasStroke) {
  335. _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
  336. }
  337. _commands.push(new MoveToCommand(firstP));
  338. this.addPoint(firstP);
  339. j += 2;
  340. if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
  341. do {
  342. // if multiple points listed, add the rest as lineTo points
  343. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  344. _commands.push(new LineToCommand(lastP));
  345. this.addPoint(lastP);
  346. firstP = lastP;
  347. j += 2;
  348. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  349. }
  350. break;
  351. case "l" :
  352. do {
  353. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  354. _commands.push(new LineToCommand(lastP));
  355. this.addPoint(lastP);
  356. firstP = lastP;
  357. j += 2;
  358. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  359. break;
  360. case "L" :
  361. do {
  362. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  363. _commands.push(new LineToCommand(lastP));
  364. this.addPoint(lastP);
  365. firstP = lastP;
  366. j += 2;
  367. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  368. break;
  369. case "h" :
  370. do {
  371. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
  372. _commands.push(new LineToCommand(lastP));
  373. this.addPoint(lastP);
  374. firstP = lastP;
  375. j += 1;
  376. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  377. break;
  378. case "H" :
  379. do {
  380. lastP = new Point(Number(svgCmds[j]), lastP.y);
  381. _commands.push(new LineToCommand(lastP));
  382. this.addPoint(lastP);
  383. firstP = lastP;
  384. j += 1;
  385. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  386. break;
  387. case "v" :
  388. do {
  389. lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
  390. _commands.push(new LineToCommand(lastP));
  391. this.addPoint(lastP);
  392. firstP = lastP;
  393. j += 1;
  394. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  395. break;
  396. case "V" :
  397. do {
  398. lastP = new Point(lastP.x, Number(svgCmds[j]));
  399. _commands.push(new LineToCommand(lastP));
  400. this.addPoint(lastP);
  401. firstP = lastP;
  402. j += 1;
  403. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  404. break;
  405. case "q" :
  406. do {
  407. // control is relative to lastP, not lastC
  408. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  409. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  410. _commands.push(new CurveToCommand(lastC, lastP));
  411. this.addPoint(lastC, lastP);
  412. firstP = lastP;
  413. j += 4;
  414. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  415. break;
  416. case "Q" :
  417. do {
  418. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  419. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  420. _commands.push(new CurveToCommand(lastC, lastP));
  421. this.addPoint(lastC, lastP);
  422. firstP = lastP;
  423. j += 4;
  424. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  425. break;
  426. case "c" :
  427. do {
  428. // don't save if c1.x=c1.y=c2.x=c2.y=0
  429. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  430. } else {
  431. qc = [];
  432. Math2.getQuadBez_RP(
  433. {x:lastP.x, y:lastP.y},
  434. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  435. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  436. {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
  437. 1, qc);
  438. for (ii=0; ii
  439. cp = new Point(qc[ii].cx, qc[ii].cy);
  440. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  441. _commands.push(new CurveToCommand(cp, pp));
  442. this.addPoint(cp, pp);
  443. }
  444. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  445. lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
  446. this.addPoint(lastC, lastP);
  447. firstP = lastP;
  448. }
  449. j += 6;
  450. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  451. break;
  452. case "C" :
  453. do {
  454. // don't save if c1.x=c1.y=c2.x=c2.y=0
  455. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  456. } else {
  457. qc = [];
  458. Math2.getQuadBez_RP(
  459. {x:firstP.x, y:firstP.y},
  460. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  461. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  462. {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
  463. 1, qc);
  464. for (ii=0; ii
  465. cp = new Point(qc[ii].cx, qc[ii].cy);
  466. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  467. _commands.push(new CurveToCommand(cp, pp));
  468. this.addPoint(cp, pp);
  469. }
  470. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  471. lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
  472. this.addPoint(lastC, lastP);
  473. firstP = lastP;
  474. }
  475. j += 6;
  476. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  477. break;
  478. case "s" :
  479. do {
  480. // don't save if c1.x=c1.y=c2.x=c2.y=0
  481. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  482. } else {
  483. qc = [];
  484. Math2.getQuadBez_RP(
  485. {x:firstP.x, y:firstP.y},
  486. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  487. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  488. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  489. 1, qc);
  490. for (ii=0; ii
  491. cp = new Point(qc[ii].cx, qc[ii].cy);
  492. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  493. _commands.push(new CurveToCommand(cp, pp));
  494. this.addPoint(cp, pp);
  495. }
  496. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  497. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  498. this.addPoint(lastC, lastP);
  499. firstP = lastP;
  500. }
  501. j += 4;
  502. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  503. break;
  504. case "S" :
  505. do {
  506. // don't save if c1.x=c1.y=c2.x=c2.y=0
  507. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  508. } else {
  509. qc = [];
  510. Math2.getQuadBez_RP(
  511. {x:firstP.x, y:firstP.y},
  512. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  513. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  514. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  515. 1, qc);
  516. for (ii=0; ii
  517. cp = new Point(qc[ii].cx, qc[ii].cy);
  518. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  519. _commands.push(new CurveToCommand(cp, pp));
  520. this.addPoint(cp, pp);
  521. }
  522. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  523. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  524. this.addPoint(lastC, lastP);
  525. firstP = lastP;
  526. }
  527. j += 4;
  528. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  529. break;
  530. case "z" :
  531. case "Z" :
  532. if (!firstP.equals(lastP)) {
  533. _commands.push(new LineToCommand(firstP));
  534. this.addPoint(firstP);
  535. }
  536. j++;
  537. break;
  538. } // end switch
  539. } while (j < svgCmds.length);
  540. }
  541. /**
  542. *
  543. */
  544. public function draw(graphics:Graphics):void {
  545. for each (var command:SVGPathCommand in this._commands) {
  546. command.execute(graphics);
  547. }
  548. }
  549. }
  550. class String2 {
  551. /**
  552. * @class String2
  553. * @author Helen Triolo, with inclusions from Tim Groleau
  554. * @description String functions not included in String needed for path->array conversion
  555. */
  556. /**
  557. * @method replace ()
  558. * @description Replaces sFind in s with sReplace
  559. * @param s (String) original string
  560. * @param sFind (String) part to be replaced
  561. * @param sReplace (String) string to replace it with
  562. * @returns (String) string with replacement
  563. */
  564. public static function replace(s:String, sFind:String, sReplace:String):String {
  565. return s.split(sFind).join(sReplace);
  566. }
  567. /**
  568. * @method shrinkSequencesOf (Groleau)
  569. * @description Shrinks all sequences of a given character in a string to one
  570. * @param s (String) original string
  571. * @param ch (String) character to be found
  572. * @returns (String) string with sequences shrunk
  573. */
  574. public static function shrinkSequencesOf(s:String, ch:String):String {
  575. var len:Number = s.length;
  576. var idx:Number = 0;
  577. var idx2:Number = 0;
  578. var rs:String = "";
  579. while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
  580. // include string up to first character in sequence
  581. rs += s.substring(idx, idx2);
  582. idx = idx2;
  583. // remove all subsequent characters in sequence
  584. while ((s.charAt(idx) == ch) && (idx < len)) idx++;
  585. }
  586. return rs + s.substring(idx, len);
  587. }
  588. }
  589. class Math2 {
  590. /**
  591. * @class Math2
  592. * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
  593. * @description Math functions not included in Math needed for path->array conversion
  594. */
  595. /**
  596. * @method ratioTo (Groleau)
  597. * @description Returns the point on segment [p1,p2] which is ratio times the total distance
  598. * between p1 and p2 away from p1
  599. * @param p1 (Object) x and y values of point p1
  600. * @param p2 (Object) x and y values of point p2
  601. * @param ratio (Number) real
  602. * @returns Object
  603. */
  604. public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
  605. return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
  606. }
  607. /**
  608. * @method intersect2Lines (Penner)
  609. * @description Returns the point of intersection between two lines
  610. * @param p1, p2 (Objects) points on line 1
  611. * @param p3, p4 (Objects) points on line 2
  612. * @returns Object (point of intersection)
  613. */
  614. public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
  615. var x1:Number = p1.x; var y1:Number = p1.y;
  616. var x4:Number = p4.x; var y4:Number = p4.y;
  617. var dx1:Number = p2.x - x1;
  618. var dx2:Number = p3.x - x4;
  619. if (!(dx1 || dx2)) return NaN;
  620. var m1:Number = (p2.y - y1) / dx1;
  621. var m2:Number = (p3.y - y4) / dx2;
  622. if (!dx1) {
  623. return { x:x1, y:m2 * (x1 - x4) + y4 };
  624. } else if (!dx2) {
  625. return { x:x4, y:m1 * (x4 - x1) + y1 };
  626. }
  627. var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
  628. var yInt:Number = m1 * (xInt - x1) + y1;
  629. return { x:xInt,y:yInt };
  630. }
  631. /**
  632. * @method rotation
  633. * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
  634. * @param dy (Number) pixels
  635. * @param dx (Number) pixels
  636. * @returns Number (angle, degrees)
  637. */
  638. public static function rotation(dy:Number, dx:Number):Number {
  639. return Math.atan2(dy, dx) * 180/Math.PI;
  640. }
  641. /**
  642. * @method midPt
  643. * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
  644. * @param p1x (Number) pixels
  645. * @param p1y (Number) pixels
  646. * @param p2x (Number) pixels
  647. * @param p2y (Number) pixels
  648. * @returns Object (midpoint)
  649. */
  650. public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
  651. return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
  652. }
  653. /**
  654. * @method getQuadBez_RP (Penner)
  655. * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
  656. * to achieve a specified tolerance
  657. * @param p1 (Object) endpoint
  658. * @param c1 (Object) 1st control point
  659. * @param c2 (Object) 2nd control point
  660. * @param p2 (Object) endpoint
  661. * @param k: tolerance (low number = most accurate result)
  662. * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
  663. * p1x, p1y, cx, cy, p2x, p2y
  664. */
  665. public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
  666. // find intersection between bezier arms
  667. var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
  668. // find distance between the midpoints
  669. var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
  670. var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
  671. // split curve if the quadratic isn't close enough
  672. if (dx*dx + dy*dy > k) {
  673. var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
  674. var b0:Object = halves.b0; var b1:Object = halves.b1;
  675. // recursive call to subdivide curve
  676. getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
  677. getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
  678. } else {
  679. // end recursion by saving points
  680. qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
  681. }
  682. }
  683. /**
  684. * @method bezierSplit (Penner)
  685. * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
  686. * @param p1x (Number) pixels, endpoint 1
  687. * @param p1y (Number) pixels
  688. * @param c1x (Number) pixels, control point 1
  689. * @param c1y (Number) pixels
  690. * @param c2x (Number) pixels, control point 2
  691. * @param c2y (Number) pixels
  692. * @param p2x (Number) pixels, endpoint 2
  693. * @param p2y (Number) pixels
  694. * @returns Object (object with two cubic bezier definitions, b0 and b1)
  695. */
  696. public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
  697. var m:Function = Math2.midPt;
  698. var p1:Object = {x:p1x, y:p1y};
  699. var p2:Object = {x:p2x, y:p2y};
  700. var p01:Object = m (p1x, p1y, c1x, c1y);
  701. var p12:Object = m (c1x, c1y, c2x, c2y);
  702. var p23:Object = m (c2x, c2y, p2x, p2y);
  703. var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
  704. var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
  705. var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
  706. /*
  707. b0:{a:p0, b:p01, c:p02, d:p03},
  708. b1:{a:p03, b:p13, c:p23, d:p3 }
  709. */
  710. return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
  711. }
  712. /**
  713. * @method pointOnCurve (Penner)
  714. * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
  715. * of the standard equation:
  716. * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
  717. * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
  718. * @param p1x (Number) pixels, endpoint 1
  719. * @param p1y (Number) pixels
  720. * @param cx (Number) pixels, control point
  721. * @param cy (Number) pixels
  722. * @param p2x (Number) pixels, endpoint 2
  723. * @param p2y (Number) pixels
  724. * @param t (Number) if time is 0-1 along curve, value of t to find point at
  725. * @returns Object (point at time t)
  726. */
  727. public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
  728. var o:Object = new Object();
  729. o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
  730. o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
  731. return o;
  732. }
  733. /**
  734. * @method pointsOnCurve (Penner)
  735. * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
  736. * includes:
  737. * x,y = location of point defining start of segment
  738. * r = rotation of segment (last entry has none because it's just a point)
  739. * n = number of subdivisions into which curve will be divided (pts = n+1)
  740. * @param p1x (Number) pixels, endpoint 1
  741. * @param p1y (Number) pixels
  742. * @param cx (Number) pixels, control point
  743. * @param cy (Number) pixels
  744. * @param p2x (Number) pixels, endpoint 2
  745. * @param p2y (Number) pixels
  746. * @param n (Number) number of points to return
  747. * @returns Array
  748. */
  749. public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
  750. var pts:Array = [];
  751. for (var i:Number=0; i <= n; i++) {
  752. pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
  753. if (i > 0) {
  754. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  755. }
  756. }
  757. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  758. return pts;
  759. }
  760. /**
  761. * @method pointsOnLine (Penner)
  762. * @description Returns an array of point positions and rotations for n evenly spaced points
  763. * along a line segment
  764. * x,y = location of point defining start of segment
  765. * r = rotation of segment (last entry has none because it's just a point)
  766. * n = number of subdivisions into which curve will be divided (pts = n+1)
  767. * @param p1x (Number) pixels, endpoint 1
  768. * @param p1y (Number) pixels
  769. * @param p2x (Number) pixels, endpoint 2
  770. * @param p2y (Number) pixels
  771. * @param n (Number) number of points to return
  772. * @returns Array
  773. *//* ....................................................................
  774. Returns an array of point positions and rotation for n evenly spaced points along a line segment
  775. */
  776. public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
  777. var pts:Array = [];
  778. if (p2x != p1x) {
  779. var m:Number = (p2y-p1y)/(p2x-p1x);
  780. var b:Number = p1y - p1x * m;
  781. for (var i:Number=0; i <= n; i++) {
  782. var x:Number = p1x + ((p2x-p1x)/n) * i;
  783. pts.push({x:x, y:m*x+b});
  784. if (i > 0) {
  785. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  786. }
  787. }
  788. // vertical segment
  789. } else {
  790. for (i=0; i<=n; i++) {
  791. pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
  792. }
  793. }
  794. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  795. return pts;
  796. }
  797. /**
  798. * @method curveApproxLen
  799. * @description Returns the approximate length of a curved segment, found by dividing it
  800. * into two segments at t=0.5
  801. * @param p1x (Number) pixels, endpoint 1
  802. * @param p1y (Number) pixels
  803. * @param cx (Number) pixels, control point
  804. * @param cy (Number) pixels
  805. * @param p2x (Number) pixels, endpoint 2
  806. * @param p2y (Number) pixels
  807. * @returns Number
  808. */
  809. public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
  810. var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
  811. var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
  812. var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
  813. return len1+len2;
  814. }
  815. /**
  816. * @method lineLen
  817. * @description Returns the length of a line segment
  818. * @param p1x (Number) pixels, endpoint 1
  819. * @param p1y (Number) pixels
  820. * @param p2x (Number) pixels, endpoint 2
  821. * @param p2y (Number) pixels
  822. * @returns Number
  823. */
  824. public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
  825. return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
  826. }
  827. /**
  828. * @method roundTo
  829. * @description Returns a number rounded to specified number of decimals
  830. * @param n (Number)
  831. * @param ndec (Number) number of decimals to round to
  832. * @returns Number
  833. */
  834. public static function roundTo(n:Number, ndec:Number):Number {
  835. var multiplier:Number = Math.pow(10, ndec);
  836. return Math.round(n*multiplier)/multiplier;
  837. }
  838. }
  839. class SVGColor {
  840. public static function getByName(name:String):Number {
  841. var col:Number = SVGColor._colorTable[name];
  842. return isNaN(col) ? 0 : col;
  843. }
  844. private static const _colorTable:Object = {
  845. blue:0x0000ff,
  846. green:0x008000,
  847. red:0xff0000,
  848. aliceblue:0xf0f8ff,
  849. antiquewhite:0xfaebd7,
  850. aqua:0x00ffff,
  851. aquamarine:0x7fffd4,
  852. azure:0xf0ffff,
  853. beige:0xf5f5dc,
  854. bisque:0xffe4c4,
  855. black:0x000000,
  856. blanchedalmond:0xffebcd,
  857. blueviolet:0x8a2be2,
  858. brown:0xa52a2a,
  859. burlywood:0xdeb887,
  860. cadetblue:0x5f9ea0,
  861. chartreuse:0x7fff00,
  862. chocolate:0xd2691e,
  863. coral:0xff7f50,
  864. cornflowerblue:0x6495ed,
  865. cornsilk:0xfff8dc,
  866. crimson:0xdc143c,
  867. cyan:0x00ffff,
  868. darkblue:0x00008b,
  869. darkcyan:0x008b8b,
  870. darkgoldenrod:0xb8860b,
  871. darkgray:0xa9a9a9,
  872. darkgreen:0x006400,
  873. darkgrey:0xa9a9a9,
  874. darkkhaki:0xbdb76b,
  875. darkmagenta:0x8b008b,
  876. darkolivegreen:0x556b2f,
  877. darkorange:0xff8c00,
  878. darkorchid:0x9932cc,
  879. darkred:0x8b0000,
  880. darksalmon:0xe9967a,
  881. darkseagreen:0x8fbc8f,
  882. darkslateblue:0x483d8b,
  883. darkslategray:0x2f4f4f,
  884. darkslategrey:0x2f4f4f,
  885. darkturquoise:0x00ced1,
  886. darkviolet:0x9400d3,
  887. deeppink:0xff1493,
  888. deepskyblue:0x00bfff,
  889. dimgray:0x696969,
  890. dimgrey:0x696969,
  891. dodgerblue:0x1e90ff,
  892. firebrick:0xb22222,
  893. floralwhite:0xfffaf0,
  894. forestgreen:0x228b22,
  895. fuchsia:0xff00ff,
  896. gainsboro:0xdcdcdc,
  897. ghostwhite:0xf8f8ff,
  898. gold:0xffd700,
  899. goldenrod:0xdaa520,
  900. gray:0x808080,
  901. grey:0x808080,
  902. greenyellow:0xadff2f,
  903. honeydew:0xf0fff0,
  904. hotpink:0xff69b4,
  905. indianred:0xcd5c5c,
  906. indigo:0x4b0082,
  907. ivory:0xfffff0,
  908. khaki:0xf0e68c,
  909. lavender:0xe6e6fa,
  910. lavenderblush:0xfff0f5,
  911. lawngreen:0x7cfc00,
  912. lemonchiffon:0xfffacd,
  913. lightblue:0xadd8e6,
  914. lightcoral:0xf08080,
  915. lightcyan:0xe0ffff,
  916. lightgoldenrodyellow:0xfafad2,
  917. lightgray:0xd3d3d3,
  918. lightgreen:0x90ee90,
  919. lightgrey:0xd3d3d3,
  920. lightpink:0xffb6c1,
  921. lightsalmon:0xffa07a,
  922. lightseagreen:0x20b2aa,
  923. lightskyblue:0x87cefa,
  924. lightslategray:0x778899,
  925. lightslategrey:0x778899,
  926. lightsteelblue:0xb0c4de,
  927. lightyellow:0xffffe0,
  928. lime:0x00ff00,
  929. limegreen:0x32cd32,
  930. linen:0xfaf0e6,
  931. magenta:0xff00ff,
  932. maroon:0x800000,
  933. mediumaquamarine:0x66cdaa,
  934. mediumblue:0x0000cd,
  935. mediumorchid:0xba55d3,
  936. mediumpurple:0x9370db,
  937. mediumseagreen:0x3cb371,
  938. mediumslateblue:0x7b68ee,
  939. mediumspringgreen:0x00fa9a,
  940. mediumturquoise:0x48d1cc,
  941. mediumvioletred:0xc71585,
  942. midnightblue:0x191970,
  943. mintcream:0xf5fffa,
  944. mistyrose:0xffe4e1,
  945. moccasin:0xffe4b5,
  946. navajowhite:0xffdead,
  947. navy:0x000080,
  948. oldlace:0xfdf5e6,
  949. olive:0x808000,
  950. olivedrab:0x6b8e23,
  951. orange:0xffa500,
  952. orangered:0xff4500,
  953. orchid:0xda70d6,
  954. palegoldenrod:0xeee8aa,
  955. palegreen:0x98fb98,
  956. paleturquoise:0xafeeee,
  957. palevioletred:0xdb7093,
  958. papayawhip:0xffefd5,
  959. peachpuff:0xffdab9,
  960. peru:0xcd853f,
  961. pink:0xffc0cb,
  962. plum:0xdda0dd,
  963. powderblue:0xb0e0e6,
  964. purple:0x800080,
  965. rosybrown:0xbc8f8f,
  966. royalblue:0x4169e1,
  967. saddlebrown:0x8b4513,
  968. salmon:0xfa8072,
  969. sandybrown:0xf4a460,
  970. seagreen:0x2e8b57,
  971. seashell:0xfff5ee,
  972. sienna:0xa0522d,
  973. silver:0xc0c0c0,
  974. skyblue:0x87ceeb,
  975. slateblue:0x6a5acd,
  976. slategray:0x708090,
  977. slategrey:0x708090,
  978. snow:0xfffafa,
  979. springgreen:0x00ff7f,
  980. steelblue:0x4682b4,
  981. tan:0xd2b48c,
  982. teal:0x008080,
  983. thistle:0xd8bfd8,
  984. tomato:0xff6347,
  985. turquoise:0x40e0d0,
  986. violet:0xee82ee,
  987. wheat:0xf5deb3,
  988. white:0xffffff,
  989. whitesmoke:0xf5f5f5,
  990. yellow:0xffff00,
  991. yellowgreen:0x9acd32
  992. }
  993. }
  994. class SVGPathCommandType {
  995. public static const BEGIN_FILL_COMMAND:Number = 1;
  996. public static const LINE_STYLE_COMMAND:Number = 2;
  997. public static const MOVE_TO_COMMAND:Number = 3;
  998. public static const LINE_TO_COMMAND:Number = 4;
  999. public static const CURVE_TO_COMMAND:Number = 5;
  1000. }
  1001. interface ISVGPathCommand {
  1002. function execute(graphics:Graphics):void;
  1003. }
  1004. class SVGPathCommand implements ISVGPathCommand {
  1005. private var _type:Number;
  1006. public function get type():Number { return this._type; }
  1007. public function SVGPathCommand(type:Number = 0) {
  1008. this._type = type;
  1009. }
  1010. public function execute(graphics:Graphics):void {
  1011. throw new Error('Subclass must be implement execute method.');
  1012. }
  1013. }
  1014. class BeginFillCommand extends SVGPathCommand {
  1015. private var _color:Number;
  1016. public function get color():Number { return this._color; }
  1017. private var _alpha:Number;
  1018. public function get alpha():Number { return this._alpha; }
  1019. public function BeginFillCommand(color:Number, alpha:Number) {
  1020. super(SVGPathCommandType.BEGIN_FILL_COMMAND);
  1021. this._color = color;
  1022. this._alpha = alpha;
  1023. }
  1024. public override function execute(graphics:Graphics):void {
  1025. graphics.beginFill(this._color, this._alpha);
  1026. }
  1027. }
  1028. class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1029. private var _pt1:Point;
  1030. public function get x1():Number { return this._pt1.x; }
  1031. public function get y1():Number { return this._pt1.y; }
  1032. private var _pt2:Point;
  1033. public function get x2():Number { return this._pt2.x; }
  1034. public function get y2():Number { return this._pt2.y; }
  1035. public function CurveToCommand(pt1:Point, pt2:Point) {
  1036. super(SVGPathCommandType.CURVE_TO_COMMAND);
  1037. this._pt1 = pt1;
  1038. this._pt2 = pt2;
  1039. }
  1040. public override function execute(graphics:Graphics):void {
  1041. graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
  1042. }
  1043. }
  1044. class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
  1045. private var _width:Number;
  1046. public function get width():Number { return this._width; }
  1047. private var _color:Number;
  1048. public function get color():Number { return this._color; }
  1049. private var _alpha:Number;
  1050. public function get alpha():Number { return this._alpha; }
  1051. public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
  1052. super(SVGPathCommandType.LINE_STYLE_COMMAND);
  1053. this._width = width;
  1054. this._color = color;
  1055. this._alpha = alpha;
  1056. }
  1057. public override function execute(graphics:Graphics):void {
  1058. graphics.lineStyle(this._width, this._color, this._alpha);
  1059. }
  1060. }
  1061. class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
  1062. private var _pt:Point;
  1063. public function get x():Number { return this._pt.x; }
  1064. public function get y():Number { return this._pt.y; }
  1065. public function LineToCommand(pt:Point) {
  1066. super(SVGPathCommandType.LINE_TO_COMMAND);
  1067. this._pt = pt;
  1068. }
  1069. public override function execute(graphics:Graphics):void {
  1070. graphics.lineTo(this._pt.x, this._pt.y);
  1071. }
  1072. }
  1073. class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1074. private var _pt:Point;
  1075. public function get x():Number { return this._pt.x; }
  1076. public function get y():Number { return this._pt.y; }
  1077. public function MoveToCommand(pt:Point) {
  1078. super(SVGPathCommandType.MOVE_TO_COMMAND);
  1079. this._pt = pt;
  1080. }
  1081. public override function execute(graphics:Graphics):void {
  1082. graphics.moveTo(this._pt.x, this._pt.y);
  1083. }
  1084. }
noswf
  1. // forked from Saqoosha's Sewing
  2. package {
  3. import caurina.transitions.Equations;
  4. import caurina.transitions.Tweener;
  5. import caurina.transitions.properties.CurveModifiers;
  6. import flash.display.Graphics;
  7. import flash.display.Sprite;
  8. import flash.display.StageAlign;
  9. import flash.display.StageQuality;
  10. import flash.display.StageScaleMode;
  11. import flash.events.Event;
  12. import flash.geom.Point;
  13. import flash.net.URLLoader;
  14. import flash.net.URLLoaderDataFormat;
  15. import flash.net.URLRequest;
  16. import flash.utils.setTimeout;
  17. [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
  18. public class Sewing extends Sprite {
  19. private var _loader:URLLoader;
  20. private var _canvas:Sprite;
  21. private var _paths:Array;
  22. public function Sewing() {
  23. Wonderfl.capture_delay(8);
  24. this.stage.quality = StageQuality.BEST;
  25. this.stage.align = StageAlign.TOP_LEFT;
  26. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  27. CurveModifiers.init();
  28. this._canvas = this.addChild(new Sprite()) as Sprite;
  29. this._loader = new URLLoader();
  30. this._loader.dataFormat = URLLoaderDataFormat.TEXT;
  31. this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
  32. this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
  33. }
  34. private function _handleLoaded(e:Event):void {
  35. var svg:XML = new XML(this._loader.data);
  36. this._paths = [];
  37. var path:SVGPath;
  38. var delay:Number = 2.0;
  39. var cx:Number = parseInt(svg.@width) / 2;
  40. var cy:Number = parseInt(svg.@height) / 2;
  41. this._canvas.x = this.stage.stageWidth / 2 - cx;
  42. this._canvas.y = this.stage.stageHeight / 2 - cy;
  43. for each (var pathNode:XML in svg..*::path) {
  44. path = new SVGPath(pathNode);
  45. this._paths.push(path);
  46. var i:Number = 0;
  47. var di:Number = Math.PI * 2 / path.points.length;
  48. var px:Number = cx;
  49. var py:Number = this.stage.stageHeight - this._canvas.y;
  50. for each (var pt:Point in path.points) {
  51. Tweener.addTween(pt, {
  52. x: pt.x,
  53. y: pt.y,
  54. _bezier:[
  55. { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
  56. { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
  57. ],
  58. time: 1.0,
  59. delay: delay,
  60. transition: Equations.easeNone
  61. });
  62. pt.x = px;
  63. pt.y = py;
  64. delay += 0.004;
  65. i += di;
  66. }
  67. }
  68. this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
  69. setTimeout(function ():void {
  70. removeEventListener(Event.ENTER_FRAME, _drawPaths);
  71. }, (delay + 1) * 1000);
  72. }
  73. private function _drawPaths(e:Event):void {
  74. this._canvas.graphics.clear();
  75. for each (var path:SVGPath in this._paths) {
  76. path.draw(this._canvas.graphics);
  77. }
  78. }
  79. }
  80. }
  81. import flash.display.Graphics;
  82. import flash.geom.Point;
  83. import flash.geom.Rectangle;
  84. /**
  85. * @class PathToArray
  86. * @author Helen Triolo (with contributions from many people)
  87. * @version 1.01
  88. * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
  89. * not contain any CRLF characters), and an empty array.
  90. * Parses the path node to make an array of drawing commands, which include cubic bezier
  91. * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
  92. * using Robert Penner's code to convert with accuracy within 1 pixel.
  93. * Drawing commands are produced in the format originally devised by Peter Hall
  94. * in his ASVDrawing class. These are the possible elements in array dCmds (and the
  95. * corresponding Flash drawing API commands to apply them):
  96. * ['M',[x,y]] moveTo(x,y)
  97. * ['L',[x,y]] lineTo(x,y)
  98. * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
  99. * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
  100. * ['F',[color,alpha]] beginFill(color,alpha)
  101. * ['EF'] endFill()
  102. * History:
  103. * v1.00 2005/11/13 Original release
  104. * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
  105. *
  106. * @param svgnode (XMLNode) Path node from SVG file
  107. * @param dCmds (Array) Empty array to write commands to
  108. */
  109. class SVGPath {
  110. private var _commands:Array;
  111. public function get commands():Array { return this._commands }
  112. private var _points:Array;
  113. public function get points():Array { return this._points }
  114. private function addPoint(... points:Array):void {
  115. for each (var pt:Point in points) {
  116. this._addPoint(pt);
  117. }
  118. }
  119. private function _addPoint(pt:Point):void {
  120. if (pt.x < this._bounds.left) {
  121. this._bounds.left = pt.x;
  122. } else if (this._bounds.right < pt.x) {
  123. this._bounds.right = pt.x;
  124. }
  125. if (pt.y < this._bounds.top) {
  126. this._bounds.top = pt.y;
  127. } else if (this._bounds.bottom < pt.y) {
  128. this._bounds.bottom = pt.y;
  129. }
  130. this._points.push(pt);
  131. }
  132. private var _bounds:Rectangle;
  133. public function get boundsRect():Rectangle { return this._bounds }
  134. private var _hasFill:Boolean;
  135. public function get hasFill():Boolean { return this._hasFill }
  136. private var _hasStroke:Boolean;
  137. public function get hasStroke():Boolean { return this._hasStroke }
  138. public function swapFillAndStroke():void {
  139. var flg:Boolean = this._hasFill;
  140. this._hasFill = this._hasStroke;
  141. this._hasStroke = flg;
  142. var val:Number = this._fillColor;
  143. this._fillColor = this._strokeColor;
  144. this._strokeColor = val;
  145. val = this._fillAlpha;
  146. this._fillAlpha = this._strokeAlpha;
  147. this._strokeAlpha = val;
  148. }
  149. private var _fillColor:Number;
  150. public function get fillColor():Number { return this._fillColor }
  151. public function set fillColor(col:Number):void { this._fillColor = col }
  152. private var _fillAlpha:Number;
  153. public function get fillAlpha():Number { return this._fillAlpha }
  154. public function set fillAlpha(al:Number):void { this._fillAlpha = al }
  155. private var _strokeColor:Number;
  156. public function get strokeColor():Number { return this._strokeColor }
  157. public function set strokeColor(col:Number):void { this._strokeColor = col }
  158. private var _strokeAlpha:Number;
  159. public function get strokeAlpha():Number { return this._strokeAlpha }
  160. public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
  161. private var _strokeWidth:Number;
  162. public function get strokeWidth():Number { return this._strokeWidth }
  163. public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
  164. /**
  165. *
  166. */
  167. public function SVGPath(svgNode:XML) {
  168. this._commands = [];
  169. this._points = [];
  170. this._bounds = new Rectangle();
  171. this._bounds.top = this._bounds.left = Number.MAX_VALUE;
  172. this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
  173. this._hasFill = false;
  174. this._hasStroke = false;
  175. this.makeDrawCmds(this.extractCmds(svgNode));
  176. }
  177. /**
  178. * @method extractCmds ()
  179. * @param node (XMLNode) SVG path node
  180. * @description Parse path node and convert to array of SVG drawing commands and data
  181. * 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,
  182. * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
  183. * @returns (Array) array of drawing commands
  184. */
  185. private function extractCmds(node:XML):Array {
  186. var i:Number;
  187. var startColor:Number;
  188. var thisColor:Number;
  189. //var hasFill:Boolean = false;
  190. var hasTransform:Boolean = false;
  191. //var hasStroke:Boolean = false;
  192. var hasStrokeWidth:Boolean = false;
  193. var hasRotate:Number = 0;
  194. var dstring:String = "";
  195. var rotation:Number;
  196. // is there a fill attribute, a transform attribute, a stroke attribute?
  197. for each (var a:XML in node.attributes()) {
  198. switch (a.name().toString()) {
  199. case 'fill': this._hasFill = true; break;
  200. case 'transform': hasTransform = true; break;
  201. case 'stroke': this._hasStroke = true; break;
  202. case 'stroke-width': hasStrokeWidth = true; break;
  203. }
  204. }
  205. if (this._hasFill) {
  206. // parse for fill color specification
  207. // if a hex number is specified, startColor will be > 0
  208. // if a color name is specified, startColor will be 0
  209. var fillStr:String = node.@fill;
  210. if (fillStr == 'none') {
  211. this._hasFill = false;
  212. } else {
  213. startColor = fillStr.indexOf("#") + 1;
  214. if (startColor == 0) { // name specified instead of color number
  215. thisColor = SVGColor.getByName(fillStr);
  216. if (isNaN(thisColor)) {
  217. this._hasFill = false;
  218. } else {
  219. this._fillColor = thisColor;
  220. this._fillAlpha = 1.0;
  221. }
  222. } else {
  223. this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
  224. this._fillAlpha = 1.0;
  225. }
  226. }
  227. }
  228. // stroke: color, width, alpha
  229. if (this._hasStroke) {
  230. // parse for stroke color specification
  231. var strokeStr:String = node.@stroke;
  232. if (strokeStr == 'none') {
  233. this._hasStroke = false;
  234. } else {
  235. startColor = strokeStr.indexOf("#")+1;
  236. if (startColor == 0) { // name specified instead of color number
  237. thisColor = SVGColor.getByName(strokeStr);
  238. if (isNaN(thisColor)) {
  239. this._hasStroke = false;
  240. } else {
  241. this._strokeWidth = 0;
  242. this._strokeColor = SVGColor.getByName(strokeStr);
  243. this._strokeAlpha = 1.0;
  244. }
  245. } else {
  246. this._strokeWidth = 0;
  247. this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
  248. this._strokeAlpha = 1.0;
  249. }
  250. }
  251. }
  252. if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
  253. // if stroke and fill are both undefined, set fill to black
  254. if (!this._hasFill && !this._hasStroke) {
  255. this._hasFill = true;
  256. this._fillColor = 0;
  257. this._fillAlpha = 1.0;
  258. }
  259. if (hasTransform) {
  260. // parse for rotation specification
  261. var transformStr:String = node.@transform;
  262. hasRotate = transformStr.indexOf("rotate");
  263. if (hasRotate > -1) {
  264. var startRotate:Number = transformStr.indexOf("(");
  265. var endRotate:Number = transformStr.indexOf(")");
  266. rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
  267. } else {
  268. rotation = 0;
  269. }
  270. } else rotation = 0;
  271. // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
  272. dstring = node.@d;
  273. if (dstring.indexOf(",") > -1) { // has commas?
  274. if (dstring.indexOf(" ") > -1) { // yes, has spaces?
  275. // change spaces to commas, then deal as for Illustrator
  276. dstring = String2.replace(dstring," ",",");
  277. }
  278. } else { // no commas
  279. // get rid of extra spaces and change rest to commas
  280. dstring = String2.shrinkSequencesOf(dstring, " ");
  281. dstring = String2.replace(dstring, " ",",");
  282. }
  283. dstring = String2.replace(dstring, "c",",c,");
  284. dstring = String2.replace(dstring, "C",",C,");
  285. dstring = String2.replace(dstring, "S",",S,");
  286. dstring = String2.replace(dstring, "s",",s,");
  287. // separate the z from the last element
  288. dstring = String2.replace(dstring, "z",",z");
  289. // change the following if M can be mid-path
  290. dstring = String2.replace(dstring, "M","M,");
  291. dstring = String2.replace(dstring, "L",",L,");
  292. dstring = String2.replace(dstring, "l",",l,");
  293. dstring = String2.replace(dstring, "H",",H,");
  294. dstring = String2.replace(dstring, "h",",h,");
  295. dstring = String2.replace(dstring, "V",",V,");
  296. dstring = String2.replace(dstring, "v",",v,");
  297. dstring = String2.replace(dstring, "Q",",Q,");
  298. dstring = String2.replace(dstring, "q",",q,");
  299. dstring = String2.replace(dstring, "T",",T,");
  300. dstring = String2.replace(dstring, "t",",t,");
  301. // Adobe includes no delimiter before negative numbers
  302. dstring = String2.replace(dstring, "-",",-");
  303. // get rid of any dup commas we might have introduced
  304. dstring = String2.replace(dstring, ",,",",");
  305. // get rid of spaces
  306. // (cr/lf's have to be removed before the xml object can be created,
  307. // so that is done in xml.onData method)
  308. dstring = String2.replace(dstring, " ","");
  309. dstring = String2.replace(dstring, "\t","");
  310. return dstring.split(",");
  311. }
  312. /**
  313. * @method makeDrawCmds
  314. * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
  315. * @description Convert svg draw commands to array of ASVDrawing commands: _commands
  316. */
  317. private function makeDrawCmds(svgCmds:Array):void {
  318. var j:Number = 0, ii:int;
  319. var qc:Array;
  320. var firstP:Point;
  321. var lastP:Point;
  322. var lastC:Point;
  323. var cmd:String;
  324. var cp:Point, pp:Point;
  325. do {
  326. cmd = svgCmds[j++];
  327. switch (cmd) {
  328. case "M" :
  329. // moveTo point
  330. firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  331. if (this._hasFill) {
  332. _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
  333. }
  334. if (this._hasStroke) {
  335. _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
  336. }
  337. _commands.push(new MoveToCommand(firstP));
  338. this.addPoint(firstP);
  339. j += 2;
  340. if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
  341. do {
  342. // if multiple points listed, add the rest as lineTo points
  343. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  344. _commands.push(new LineToCommand(lastP));
  345. this.addPoint(lastP);
  346. firstP = lastP;
  347. j += 2;
  348. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  349. }
  350. break;
  351. case "l" :
  352. do {
  353. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  354. _commands.push(new LineToCommand(lastP));
  355. this.addPoint(lastP);
  356. firstP = lastP;
  357. j += 2;
  358. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  359. break;
  360. case "L" :
  361. do {
  362. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  363. _commands.push(new LineToCommand(lastP));
  364. this.addPoint(lastP);
  365. firstP = lastP;
  366. j += 2;
  367. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  368. break;
  369. case "h" :
  370. do {
  371. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
  372. _commands.push(new LineToCommand(lastP));
  373. this.addPoint(lastP);
  374. firstP = lastP;
  375. j += 1;
  376. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  377. break;
  378. case "H" :
  379. do {
  380. lastP = new Point(Number(svgCmds[j]), lastP.y);
  381. _commands.push(new LineToCommand(lastP));
  382. this.addPoint(lastP);
  383. firstP = lastP;
  384. j += 1;
  385. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  386. break;
  387. case "v" :
  388. do {
  389. lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
  390. _commands.push(new LineToCommand(lastP));
  391. this.addPoint(lastP);
  392. firstP = lastP;
  393. j += 1;
  394. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  395. break;
  396. case "V" :
  397. do {
  398. lastP = new Point(lastP.x, Number(svgCmds[j]));
  399. _commands.push(new LineToCommand(lastP));
  400. this.addPoint(lastP);
  401. firstP = lastP;
  402. j += 1;
  403. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  404. break;
  405. case "q" :
  406. do {
  407. // control is relative to lastP, not lastC
  408. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  409. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  410. _commands.push(new CurveToCommand(lastC, lastP));
  411. this.addPoint(lastC, lastP);
  412. firstP = lastP;
  413. j += 4;
  414. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  415. break;
  416. case "Q" :
  417. do {
  418. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  419. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  420. _commands.push(new CurveToCommand(lastC, lastP));
  421. this.addPoint(lastC, lastP);
  422. firstP = lastP;
  423. j += 4;
  424. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  425. break;
  426. case "c" :
  427. do {
  428. // don't save if c1.x=c1.y=c2.x=c2.y=0
  429. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  430. } else {
  431. qc = [];
  432. Math2.getQuadBez_RP(
  433. {x:lastP.x, y:lastP.y},
  434. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  435. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  436. {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
  437. 1, qc);
  438. for (ii=0; ii
  439. cp = new Point(qc[ii].cx, qc[ii].cy);
  440. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  441. _commands.push(new CurveToCommand(cp, pp));
  442. this.addPoint(cp, pp);
  443. }
  444. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  445. lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
  446. this.addPoint(lastC, lastP);
  447. firstP = lastP;
  448. }
  449. j += 6;
  450. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  451. break;
  452. case "C" :
  453. do {
  454. // don't save if c1.x=c1.y=c2.x=c2.y=0
  455. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  456. } else {
  457. qc = [];
  458. Math2.getQuadBez_RP(
  459. {x:firstP.x, y:firstP.y},
  460. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  461. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  462. {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
  463. 1, qc);
  464. for (ii=0; ii
  465. cp = new Point(qc[ii].cx, qc[ii].cy);
  466. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  467. _commands.push(new CurveToCommand(cp, pp));
  468. this.addPoint(cp, pp);
  469. }
  470. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  471. lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
  472. this.addPoint(lastC, lastP);
  473. firstP = lastP;
  474. }
  475. j += 6;
  476. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  477. break;
  478. case "s" :
  479. do {
  480. // don't save if c1.x=c1.y=c2.x=c2.y=0
  481. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  482. } else {
  483. qc = [];
  484. Math2.getQuadBez_RP(
  485. {x:firstP.x, y:firstP.y},
  486. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  487. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  488. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  489. 1, qc);
  490. for (ii=0; ii
  491. cp = new Point(qc[ii].cx, qc[ii].cy);
  492. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  493. _commands.push(new CurveToCommand(cp, pp));
  494. this.addPoint(cp, pp);
  495. }
  496. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  497. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  498. this.addPoint(lastC, lastP);
  499. firstP = lastP;
  500. }
  501. j += 4;
  502. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  503. break;
  504. case "S" :
  505. do {
  506. // don't save if c1.x=c1.y=c2.x=c2.y=0
  507. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  508. } else {
  509. qc = [];
  510. Math2.getQuadBez_RP(
  511. {x:firstP.x, y:firstP.y},
  512. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  513. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  514. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  515. 1, qc);
  516. for (ii=0; ii
  517. cp = new Point(qc[ii].cx, qc[ii].cy);
  518. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  519. _commands.push(new CurveToCommand(cp, pp));
  520. this.addPoint(cp, pp);
  521. }
  522. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  523. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  524. this.addPoint(lastC, lastP);
  525. firstP = lastP;
  526. }
  527. j += 4;
  528. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  529. break;
  530. case "z" :
  531. case "Z" :
  532. if (!firstP.equals(lastP)) {
  533. _commands.push(new LineToCommand(firstP));
  534. this.addPoint(firstP);
  535. }
  536. j++;
  537. break;
  538. } // end switch
  539. } while (j < svgCmds.length);
  540. }
  541. /**
  542. *
  543. */
  544. public function draw(graphics:Graphics):void {
  545. for each (var command:SVGPathCommand in this._commands) {
  546. command.execute(graphics);
  547. }
  548. }
  549. }
  550. class String2 {
  551. /**
  552. * @class String2
  553. * @author Helen Triolo, with inclusions from Tim Groleau
  554. * @description String functions not included in String needed for path->array conversion
  555. */
  556. /**
  557. * @method replace ()
  558. * @description Replaces sFind in s with sReplace
  559. * @param s (String) original string
  560. * @param sFind (String) part to be replaced
  561. * @param sReplace (String) string to replace it with
  562. * @returns (String) string with replacement
  563. */
  564. public static function replace(s:String, sFind:String, sReplace:String):String {
  565. return s.split(sFind).join(sReplace);
  566. }
  567. /**
  568. * @method shrinkSequencesOf (Groleau)
  569. * @description Shrinks all sequences of a given character in a string to one
  570. * @param s (String) original string
  571. * @param ch (String) character to be found
  572. * @returns (String) string with sequences shrunk
  573. */
  574. public static function shrinkSequencesOf(s:String, ch:String):String {
  575. var len:Number = s.length;
  576. var idx:Number = 0;
  577. var idx2:Number = 0;
  578. var rs:String = "";
  579. while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
  580. // include string up to first character in sequence
  581. rs += s.substring(idx, idx2);
  582. idx = idx2;
  583. // remove all subsequent characters in sequence
  584. while ((s.charAt(idx) == ch) && (idx < len)) idx++;
  585. }
  586. return rs + s.substring(idx, len);
  587. }
  588. }
  589. class Math2 {
  590. /**
  591. * @class Math2
  592. * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
  593. * @description Math functions not included in Math needed for path->array conversion
  594. */
  595. /**
  596. * @method ratioTo (Groleau)
  597. * @description Returns the point on segment [p1,p2] which is ratio times the total distance
  598. * between p1 and p2 away from p1
  599. * @param p1 (Object) x and y values of point p1
  600. * @param p2 (Object) x and y values of point p2
  601. * @param ratio (Number) real
  602. * @returns Object
  603. */
  604. public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
  605. return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
  606. }
  607. /**
  608. * @method intersect2Lines (Penner)
  609. * @description Returns the point of intersection between two lines
  610. * @param p1, p2 (Objects) points on line 1
  611. * @param p3, p4 (Objects) points on line 2
  612. * @returns Object (point of intersection)
  613. */
  614. public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
  615. var x1:Number = p1.x; var y1:Number = p1.y;
  616. var x4:Number = p4.x; var y4:Number = p4.y;
  617. var dx1:Number = p2.x - x1;
  618. var dx2:Number = p3.x - x4;
  619. if (!(dx1 || dx2)) return NaN;
  620. var m1:Number = (p2.y - y1) / dx1;
  621. var m2:Number = (p3.y - y4) / dx2;
  622. if (!dx1) {
  623. return { x:x1, y:m2 * (x1 - x4) + y4 };
  624. } else if (!dx2) {
  625. return { x:x4, y:m1 * (x4 - x1) + y1 };
  626. }
  627. var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
  628. var yInt:Number = m1 * (xInt - x1) + y1;
  629. return { x:xInt,y:yInt };
  630. }
  631. /**
  632. * @method rotation
  633. * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
  634. * @param dy (Number) pixels
  635. * @param dx (Number) pixels
  636. * @returns Number (angle, degrees)
  637. */
  638. public static function rotation(dy:Number, dx:Number):Number {
  639. return Math.atan2(dy, dx) * 180/Math.PI;
  640. }
  641. /**
  642. * @method midPt
  643. * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
  644. * @param p1x (Number) pixels
  645. * @param p1y (Number) pixels
  646. * @param p2x (Number) pixels
  647. * @param p2y (Number) pixels
  648. * @returns Object (midpoint)
  649. */
  650. public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
  651. return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
  652. }
  653. /**
  654. * @method getQuadBez_RP (Penner)
  655. * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
  656. * to achieve a specified tolerance
  657. * @param p1 (Object) endpoint
  658. * @param c1 (Object) 1st control point
  659. * @param c2 (Object) 2nd control point
  660. * @param p2 (Object) endpoint
  661. * @param k: tolerance (low number = most accurate result)
  662. * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
  663. * p1x, p1y, cx, cy, p2x, p2y
  664. */
  665. public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
  666. // find intersection between bezier arms
  667. var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
  668. // find distance between the midpoints
  669. var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
  670. var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
  671. // split curve if the quadratic isn't close enough
  672. if (dx*dx + dy*dy > k) {
  673. var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
  674. var b0:Object = halves.b0; var b1:Object = halves.b1;
  675. // recursive call to subdivide curve
  676. getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
  677. getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
  678. } else {
  679. // end recursion by saving points
  680. qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
  681. }
  682. }
  683. /**
  684. * @method bezierSplit (Penner)
  685. * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
  686. * @param p1x (Number) pixels, endpoint 1
  687. * @param p1y (Number) pixels
  688. * @param c1x (Number) pixels, control point 1
  689. * @param c1y (Number) pixels
  690. * @param c2x (Number) pixels, control point 2
  691. * @param c2y (Number) pixels
  692. * @param p2x (Number) pixels, endpoint 2
  693. * @param p2y (Number) pixels
  694. * @returns Object (object with two cubic bezier definitions, b0 and b1)
  695. */
  696. public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
  697. var m:Function = Math2.midPt;
  698. var p1:Object = {x:p1x, y:p1y};
  699. var p2:Object = {x:p2x, y:p2y};
  700. var p01:Object = m (p1x, p1y, c1x, c1y);
  701. var p12:Object = m (c1x, c1y, c2x, c2y);
  702. var p23:Object = m (c2x, c2y, p2x, p2y);
  703. var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
  704. var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
  705. var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
  706. /*
  707. b0:{a:p0, b:p01, c:p02, d:p03},
  708. b1:{a:p03, b:p13, c:p23, d:p3 }
  709. */
  710. return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
  711. }
  712. /**
  713. * @method pointOnCurve (Penner)
  714. * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
  715. * of the standard equation:
  716. * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
  717. * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
  718. * @param p1x (Number) pixels, endpoint 1
  719. * @param p1y (Number) pixels
  720. * @param cx (Number) pixels, control point
  721. * @param cy (Number) pixels
  722. * @param p2x (Number) pixels, endpoint 2
  723. * @param p2y (Number) pixels
  724. * @param t (Number) if time is 0-1 along curve, value of t to find point at
  725. * @returns Object (point at time t)
  726. */
  727. public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
  728. var o:Object = new Object();
  729. o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
  730. o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
  731. return o;
  732. }
  733. /**
  734. * @method pointsOnCurve (Penner)
  735. * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
  736. * includes:
  737. * x,y = location of point defining start of segment
  738. * r = rotation of segment (last entry has none because it's just a point)
  739. * n = number of subdivisions into which curve will be divided (pts = n+1)
  740. * @param p1x (Number) pixels, endpoint 1
  741. * @param p1y (Number) pixels
  742. * @param cx (Number) pixels, control point
  743. * @param cy (Number) pixels
  744. * @param p2x (Number) pixels, endpoint 2
  745. * @param p2y (Number) pixels
  746. * @param n (Number) number of points to return
  747. * @returns Array
  748. */
  749. public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
  750. var pts:Array = [];
  751. for (var i:Number=0; i <= n; i++) {
  752. pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
  753. if (i > 0) {
  754. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  755. }
  756. }
  757. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  758. return pts;
  759. }
  760. /**
  761. * @method pointsOnLine (Penner)
  762. * @description Returns an array of point positions and rotations for n evenly spaced points
  763. * along a line segment
  764. * x,y = location of point defining start of segment
  765. * r = rotation of segment (last entry has none because it's just a point)
  766. * n = number of subdivisions into which curve will be divided (pts = n+1)
  767. * @param p1x (Number) pixels, endpoint 1
  768. * @param p1y (Number) pixels
  769. * @param p2x (Number) pixels, endpoint 2
  770. * @param p2y (Number) pixels
  771. * @param n (Number) number of points to return
  772. * @returns Array
  773. *//* ....................................................................
  774. Returns an array of point positions and rotation for n evenly spaced points along a line segment
  775. */
  776. public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
  777. var pts:Array = [];
  778. if (p2x != p1x) {
  779. var m:Number = (p2y-p1y)/(p2x-p1x);
  780. var b:Number = p1y - p1x * m;
  781. for (var i:Number=0; i <= n; i++) {
  782. var x:Number = p1x + ((p2x-p1x)/n) * i;
  783. pts.push({x:x, y:m*x+b});
  784. if (i > 0) {
  785. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  786. }
  787. }
  788. // vertical segment
  789. } else {
  790. for (i=0; i<=n; i++) {
  791. pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
  792. }
  793. }
  794. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  795. return pts;
  796. }
  797. /**
  798. * @method curveApproxLen
  799. * @description Returns the approximate length of a curved segment, found by dividing it
  800. * into two segments at t=0.5
  801. * @param p1x (Number) pixels, endpoint 1
  802. * @param p1y (Number) pixels
  803. * @param cx (Number) pixels, control point
  804. * @param cy (Number) pixels
  805. * @param p2x (Number) pixels, endpoint 2
  806. * @param p2y (Number) pixels
  807. * @returns Number
  808. */
  809. public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
  810. var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
  811. var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
  812. var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
  813. return len1+len2;
  814. }
  815. /**
  816. * @method lineLen
  817. * @description Returns the length of a line segment
  818. * @param p1x (Number) pixels, endpoint 1
  819. * @param p1y (Number) pixels
  820. * @param p2x (Number) pixels, endpoint 2
  821. * @param p2y (Number) pixels
  822. * @returns Number
  823. */
  824. public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
  825. return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
  826. }
  827. /**
  828. * @method roundTo
  829. * @description Returns a number rounded to specified number of decimals
  830. * @param n (Number)
  831. * @param ndec (Number) number of decimals to round to
  832. * @returns Number
  833. */
  834. public static function roundTo(n:Number, ndec:Number):Number {
  835. var multiplier:Number = Math.pow(10, ndec);
  836. return Math.round(n*multiplier)/multiplier;
  837. }
  838. }
  839. class SVGColor {
  840. public static function getByName(name:String):Number {
  841. var col:Number = SVGColor._colorTable[name];
  842. return isNaN(col) ? 0 : col;
  843. }
  844. private static const _colorTable:Object = {
  845. blue:0x0000ff,
  846. green:0x008000,
  847. red:0xff0000,
  848. aliceblue:0xf0f8ff,
  849. antiquewhite:0xfaebd7,
  850. aqua:0x00ffff,
  851. aquamarine:0x7fffd4,
  852. azure:0xf0ffff,
  853. beige:0xf5f5dc,
  854. bisque:0xffe4c4,
  855. black:0x000000,
  856. blanchedalmond:0xffebcd,
  857. blueviolet:0x8a2be2,
  858. brown:0xa52a2a,
  859. burlywood:0xdeb887,
  860. cadetblue:0x5f9ea0,
  861. chartreuse:0x7fff00,
  862. chocolate:0xd2691e,
  863. coral:0xff7f50,
  864. cornflowerblue:0x6495ed,
  865. cornsilk:0xfff8dc,
  866. crimson:0xdc143c,
  867. cyan:0x00ffff,
  868. darkblue:0x00008b,
  869. darkcyan:0x008b8b,
  870. darkgoldenrod:0xb8860b,
  871. darkgray:0xa9a9a9,
  872. darkgreen:0x006400,
  873. darkgrey:0xa9a9a9,
  874. darkkhaki:0xbdb76b,
  875. darkmagenta:0x8b008b,
  876. darkolivegreen:0x556b2f,
  877. darkorange:0xff8c00,
  878. darkorchid:0x9932cc,
  879. darkred:0x8b0000,
  880. darksalmon:0xe9967a,
  881. darkseagreen:0x8fbc8f,
  882. darkslateblue:0x483d8b,
  883. darkslategray:0x2f4f4f,
  884. darkslategrey:0x2f4f4f,
  885. darkturquoise:0x00ced1,
  886. darkviolet:0x9400d3,
  887. deeppink:0xff1493,
  888. deepskyblue:0x00bfff,
  889. dimgray:0x696969,
  890. dimgrey:0x696969,
  891. dodgerblue:0x1e90ff,
  892. firebrick:0xb22222,
  893. floralwhite:0xfffaf0,
  894. forestgreen:0x228b22,
  895. fuchsia:0xff00ff,
  896. gainsboro:0xdcdcdc,
  897. ghostwhite:0xf8f8ff,
  898. gold:0xffd700,
  899. goldenrod:0xdaa520,
  900. gray:0x808080,
  901. grey:0x808080,
  902. greenyellow:0xadff2f,
  903. honeydew:0xf0fff0,
  904. hotpink:0xff69b4,
  905. indianred:0xcd5c5c,
  906. indigo:0x4b0082,
  907. ivory:0xfffff0,
  908. khaki:0xf0e68c,
  909. lavender:0xe6e6fa,
  910. lavenderblush:0xfff0f5,
  911. lawngreen:0x7cfc00,
  912. lemonchiffon:0xfffacd,
  913. lightblue:0xadd8e6,
  914. lightcoral:0xf08080,
  915. lightcyan:0xe0ffff,
  916. lightgoldenrodyellow:0xfafad2,
  917. lightgray:0xd3d3d3,
  918. lightgreen:0x90ee90,
  919. lightgrey:0xd3d3d3,
  920. lightpink:0xffb6c1,
  921. lightsalmon:0xffa07a,
  922. lightseagreen:0x20b2aa,
  923. lightskyblue:0x87cefa,
  924. lightslategray:0x778899,
  925. lightslategrey:0x778899,
  926. lightsteelblue:0xb0c4de,
  927. lightyellow:0xffffe0,
  928. lime:0x00ff00,
  929. limegreen:0x32cd32,
  930. linen:0xfaf0e6,
  931. magenta:0xff00ff,
  932. maroon:0x800000,
  933. mediumaquamarine:0x66cdaa,
  934. mediumblue:0x0000cd,
  935. mediumorchid:0xba55d3,
  936. mediumpurple:0x9370db,
  937. mediumseagreen:0x3cb371,
  938. mediumslateblue:0x7b68ee,
  939. mediumspringgreen:0x00fa9a,
  940. mediumturquoise:0x48d1cc,
  941. mediumvioletred:0xc71585,
  942. midnightblue:0x191970,
  943. mintcream:0xf5fffa,
  944. mistyrose:0xffe4e1,
  945. moccasin:0xffe4b5,
  946. navajowhite:0xffdead,
  947. navy:0x000080,
  948. oldlace:0xfdf5e6,
  949. olive:0x808000,
  950. olivedrab:0x6b8e23,
  951. orange:0xffa500,
  952. orangered:0xff4500,
  953. orchid:0xda70d6,
  954. palegoldenrod:0xeee8aa,
  955. palegreen:0x98fb98,
  956. paleturquoise:0xafeeee,
  957. palevioletred:0xdb7093,
  958. papayawhip:0xffefd5,
  959. peachpuff:0xffdab9,
  960. peru:0xcd853f,
  961. pink:0xffc0cb,
  962. plum:0xdda0dd,
  963. powderblue:0xb0e0e6,
  964. purple:0x800080,
  965. rosybrown:0xbc8f8f,
  966. royalblue:0x4169e1,
  967. saddlebrown:0x8b4513,
  968. salmon:0xfa8072,
  969. sandybrown:0xf4a460,
  970. seagreen:0x2e8b57,
  971. seashell:0xfff5ee,
  972. sienna:0xa0522d,
  973. silver:0xc0c0c0,
  974. skyblue:0x87ceeb,
  975. slateblue:0x6a5acd,
  976. slategray:0x708090,
  977. slategrey:0x708090,
  978. snow:0xfffafa,
  979. springgreen:0x00ff7f,
  980. steelblue:0x4682b4,
  981. tan:0xd2b48c,
  982. teal:0x008080,
  983. thistle:0xd8bfd8,
  984. tomato:0xff6347,
  985. turquoise:0x40e0d0,
  986. violet:0xee82ee,
  987. wheat:0xf5deb3,
  988. white:0xffffff,
  989. whitesmoke:0xf5f5f5,
  990. yellow:0xffff00,
  991. yellowgreen:0x9acd32
  992. }
  993. }
  994. class SVGPathCommandType {
  995. public static const BEGIN_FILL_COMMAND:Number = 1;
  996. public static const LINE_STYLE_COMMAND:Number = 2;
  997. public static const MOVE_TO_COMMAND:Number = 3;
  998. public static const LINE_TO_COMMAND:Number = 4;
  999. public static const CURVE_TO_COMMAND:Number = 5;
  1000. }
  1001. interface ISVGPathCommand {
  1002. function execute(graphics:Graphics):void;
  1003. }
  1004. class SVGPathCommand implements ISVGPathCommand {
  1005. private var _type:Number;
  1006. public function get type():Number { return this._type; }
  1007. public function SVGPathCommand(type:Number = 0) {
  1008. this._type = type;
  1009. }
  1010. public function execute(graphics:Graphics):void {
  1011. throw new Error('Subclass must be implement execute method.');
  1012. }
  1013. }
  1014. class BeginFillCommand extends SVGPathCommand {
  1015. private var _color:Number;
  1016. public function get color():Number { return this._color; }
  1017. private var _alpha:Number;
  1018. public function get alpha():Number { return this._alpha; }
  1019. public function BeginFillCommand(color:Number, alpha:Number) {
  1020. super(SVGPathCommandType.BEGIN_FILL_COMMAND);
  1021. this._color = color;
  1022. this._alpha = alpha;
  1023. }
  1024. public override function execute(graphics:Graphics):void {
  1025. graphics.beginFill(this._color, this._alpha);
  1026. }
  1027. }
  1028. class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1029. private var _pt1:Point;
  1030. public function get x1():Number { return this._pt1.x; }
  1031. public function get y1():Number { return this._pt1.y; }
  1032. private var _pt2:Point;
  1033. public function get x2():Number { return this._pt2.x; }
  1034. public function get y2():Number { return this._pt2.y; }
  1035. public function CurveToCommand(pt1:Point, pt2:Point) {
  1036. super(SVGPathCommandType.CURVE_TO_COMMAND);
  1037. this._pt1 = pt1;
  1038. this._pt2 = pt2;
  1039. }
  1040. public override function execute(graphics:Graphics):void {
  1041. graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
  1042. }
  1043. }
  1044. class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
  1045. private var _width:Number;
  1046. public function get width():Number { return this._width; }
  1047. private var _color:Number;
  1048. public function get color():Number { return this._color; }
  1049. private var _alpha:Number;
  1050. public function get alpha():Number { return this._alpha; }
  1051. public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
  1052. super(SVGPathCommandType.LINE_STYLE_COMMAND);
  1053. this._width = width;
  1054. this._color = color;
  1055. this._alpha = alpha;
  1056. }
  1057. public override function execute(graphics:Graphics):void {
  1058. graphics.lineStyle(this._width, this._color, this._alpha);
  1059. }
  1060. }
  1061. class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
  1062. private var _pt:Point;
  1063. public function get x():Number { return this._pt.x; }
  1064. public function get y():Number { return this._pt.y; }
  1065. public function LineToCommand(pt:Point) {
  1066. super(SVGPathCommandType.LINE_TO_COMMAND);
  1067. this._pt = pt;
  1068. }
  1069. public override function execute(graphics:Graphics):void {
  1070. graphics.lineTo(this._pt.x, this._pt.y);
  1071. }
  1072. }
  1073. class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1074. private var _pt:Point;
  1075. public function get x():Number { return this._pt.x; }
  1076. public function get y():Number { return this._pt.y; }
  1077. public function MoveToCommand(pt:Point) {
  1078. super(SVGPathCommandType.MOVE_TO_COMMAND);
  1079. this._pt = pt;
  1080. }
  1081. public override function execute(graphics:Graphics):void {
  1082. graphics.moveTo(this._pt.x, this._pt.y);
  1083. }
  1084. }
noswf
  1. // forked from Saqoosha's Sewing
  2. package {
  3. import caurina.transitions.Equations;
  4. import caurina.transitions.Tweener;
  5. import caurina.transitions.properties.CurveModifiers;
  6. import flash.display.Graphics;
  7. import flash.display.Sprite;
  8. import flash.display.StageAlign;
  9. import flash.display.StageQuality;
  10. import flash.display.StageScaleMode;
  11. import flash.events.Event;
  12. import flash.geom.Point;
  13. import flash.net.URLLoader;
  14. import flash.net.URLLoaderDataFormat;
  15. import flash.net.URLRequest;
  16. import flash.utils.setTimeout;
  17. [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
  18. public class Sewing extends Sprite {
  19. private var _loader:URLLoader;
  20. private var _canvas:Sprite;
  21. private var _paths:Array;
  22. public function Sewing() {
  23. Wonderfl.capture_delay(8);
  24. this.stage.quality = StageQuality.BEST;
  25. this.stage.align = StageAlign.TOP_LEFT;
  26. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  27. CurveModifiers.init();
  28. this._canvas = this.addChild(new Sprite()) as Sprite;
  29. this._loader = new URLLoader();
  30. this._loader.dataFormat = URLLoaderDataFormat.TEXT;
  31. this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
  32. this._loader.load(new URLRequest('http://upload.wikimedia.org/wikipedia/commons/9/9c/Flag_of_Denmark.svg'));
  33. }
  34. private function _handleLoaded(e:Event):void {
  35. var svg:XML = new XML(this._loader.data);
  36. this._paths = [];
  37. var path:SVGPath;
  38. var delay:Number = 2.0;
  39. var cx:Number = parseInt(svg.@width) / 2;
  40. var cy:Number = parseInt(svg.@height) / 2;
  41. this._canvas.x = this.stage.stageWidth / 2 - cx;
  42. this._canvas.y = this.stage.stageHeight / 2 - cy;
  43. for each (var pathNode:XML in svg..*::path) {
  44. path = new SVGPath(pathNode);
  45. this._paths.push(path);
  46. var i:Number = 0;
  47. var di:Number = Math.PI * 2 / path.points.length;
  48. var px:Number = cx;
  49. var py:Number = this.stage.stageHeight - this._canvas.y;
  50. for each (var pt:Point in path.points) {
  51. Tweener.addTween(pt, {
  52. x: pt.x,
  53. y: pt.y,
  54. _bezier:[
  55. { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
  56. { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
  57. ],
  58. time: 1.0,
  59. delay: delay,
  60. transition: Equations.easeNone
  61. });
  62. pt.x = px;
  63. pt.y = py;
  64. delay += 0.004;
  65. i += di;
  66. }
  67. }
  68. this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
  69. setTimeout(function ():void {
  70. removeEventListener(Event.ENTER_FRAME, _drawPaths);
  71. }, (delay + 1) * 1000);
  72. }
  73. private function _drawPaths(e:Event):void {
  74. this._canvas.graphics.clear();
  75. for each (var path:SVGPath in this._paths) {
  76. path.draw(this._canvas.graphics);
  77. }
  78. }
  79. }
  80. }
  81. import flash.display.Graphics;
  82. import flash.geom.Point;
  83. import flash.geom.Rectangle;
  84. /**
  85. * @class PathToArray
  86. * @author Helen Triolo (with contributions from many people)
  87. * @version 1.01
  88. * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
  89. * not contain any CRLF characters), and an empty array.
  90. * Parses the path node to make an array of drawing commands, which include cubic bezier
  91. * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
  92. * using Robert Penner's code to convert with accuracy within 1 pixel.
  93. * Drawing commands are produced in the format originally devised by Peter Hall
  94. * in his ASVDrawing class. These are the possible elements in array dCmds (and the
  95. * corresponding Flash drawing API commands to apply them):
  96. * ['M',[x,y]] moveTo(x,y)
  97. * ['L',[x,y]] lineTo(x,y)
  98. * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
  99. * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
  100. * ['F',[color,alpha]] beginFill(color,alpha)
  101. * ['EF'] endFill()
  102. * History:
  103. * v1.00 2005/11/13 Original release
  104. * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
  105. *
  106. * @param svgnode (XMLNode) Path node from SVG file
  107. * @param dCmds (Array) Empty array to write commands to
  108. */
  109. class SVGPath {
  110. private var _commands:Array;
  111. public function get commands():Array { return this._commands }
  112. private var _points:Array;
  113. public function get points():Array { return this._points }
  114. private function addPoint(... points:Array):void {
  115. for each (var pt:Point in points) {
  116. this._addPoint(pt);
  117. }
  118. }
  119. private function _addPoint(pt:Point):void {
  120. if (pt.x < this._bounds.left) {
  121. this._bounds.left = pt.x;
  122. } else if (this._bounds.right < pt.x) {
  123. this._bounds.right = pt.x;
  124. }
  125. if (pt.y < this._bounds.top) {
  126. this._bounds.top = pt.y;
  127. } else if (this._bounds.bottom < pt.y) {
  128. this._bounds.bottom = pt.y;
  129. }
  130. this._points.push(pt);
  131. }
  132. private var _bounds:Rectangle;
  133. public function get boundsRect():Rectangle { return this._bounds }
  134. private var _hasFill:Boolean;
  135. public function get hasFill():Boolean { return this._hasFill }
  136. private var _hasStroke:Boolean;
  137. public function get hasStroke():Boolean { return this._hasStroke }
  138. public function swapFillAndStroke():void {
  139. var flg:Boolean = this._hasFill;
  140. this._hasFill = this._hasStroke;
  141. this._hasStroke = flg;
  142. var val:Number = this._fillColor;
  143. this._fillColor = this._strokeColor;
  144. this._strokeColor = val;
  145. val = this._fillAlpha;
  146. this._fillAlpha = this._strokeAlpha;
  147. this._strokeAlpha = val;
  148. }
  149. private var _fillColor:Number;
  150. public function get fillColor():Number { return this._fillColor }
  151. public function set fillColor(col:Number):void { this._fillColor = col }
  152. private var _fillAlpha:Number;
  153. public function get fillAlpha():Number { return this._fillAlpha }
  154. public function set fillAlpha(al:Number):void { this._fillAlpha = al }
  155. private var _strokeColor:Number;
  156. public function get strokeColor():Number { return this._strokeColor }
  157. public function set strokeColor(col:Number):void { this._strokeColor = col }
  158. private var _strokeAlpha:Number;
  159. public function get strokeAlpha():Number { return this._strokeAlpha }
  160. public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
  161. private var _strokeWidth:Number;
  162. public function get strokeWidth():Number { return this._strokeWidth }
  163. public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
  164. /**
  165. *
  166. */
  167. public function SVGPath(svgNode:XML) {
  168. this._commands = [];
  169. this._points = [];
  170. this._bounds = new Rectangle();
  171. this._bounds.top = this._bounds.left = Number.MAX_VALUE;
  172. this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
  173. this._hasFill = false;
  174. this._hasStroke = false;
  175. this.makeDrawCmds(this.extractCmds(svgNode));
  176. }
  177. /**
  178. * @method extractCmds ()
  179. * @param node (XMLNode) SVG path node
  180. * @description Parse path node and convert to array of SVG drawing commands and data
  181. * 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,
  182. * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
  183. * @returns (Array) array of drawing commands
  184. */
  185. private function extractCmds(node:XML):Array {
  186. var i:Number;
  187. var startColor:Number;
  188. var thisColor:Number;
  189. //var hasFill:Boolean = false;
  190. var hasTransform:Boolean = false;
  191. //var hasStroke:Boolean = false;
  192. var hasStrokeWidth:Boolean = false;
  193. var hasRotate:Number = 0;
  194. var dstring:String = "";
  195. var rotation:Number;
  196. // is there a fill attribute, a transform attribute, a stroke attribute?
  197. for each (var a:XML in node.attributes()) {
  198. switch (a.name().toString()) {
  199. case 'fill': this._hasFill = true; break;
  200. case 'transform': hasTransform = true; break;
  201. case 'stroke': this._hasStroke = true; break;
  202. case 'stroke-width': hasStrokeWidth = true; break;
  203. }
  204. }
  205. if (this._hasFill) {
  206. // parse for fill color specification
  207. // if a hex number is specified, startColor will be > 0
  208. // if a color name is specified, startColor will be 0
  209. var fillStr:String = node.@fill;
  210. if (fillStr == 'none') {
  211. this._hasFill = false;
  212. } else {
  213. startColor = fillStr.indexOf("#") + 1;
  214. if (startColor == 0) { // name specified instead of color number
  215. thisColor = SVGColor.getByName(fillStr);
  216. if (isNaN(thisColor)) {
  217. this._hasFill = false;
  218. } else {
  219. this._fillColor = thisColor;
  220. this._fillAlpha = 1.0;
  221. }
  222. } else {
  223. this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
  224. this._fillAlpha = 1.0;
  225. }
  226. }
  227. }
  228. // stroke: color, width, alpha
  229. if (this._hasStroke) {
  230. // parse for stroke color specification
  231. var strokeStr:String = node.@stroke;
  232. if (strokeStr == 'none') {
  233. this._hasStroke = false;
  234. } else {
  235. startColor = strokeStr.indexOf("#")+1;
  236. if (startColor == 0) { // name specified instead of color number
  237. thisColor = SVGColor.getByName(strokeStr);
  238. if (isNaN(thisColor)) {
  239. this._hasStroke = false;
  240. } else {
  241. this._strokeWidth = 0;
  242. this._strokeColor = SVGColor.getByName(strokeStr);
  243. this._strokeAlpha = 1.0;
  244. }
  245. } else {
  246. this._strokeWidth = 0;
  247. this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
  248. this._strokeAlpha = 1.0;
  249. }
  250. }
  251. }
  252. if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
  253. // if stroke and fill are both undefined, set fill to black
  254. if (!this._hasFill && !this._hasStroke) {
  255. this._hasFill = true;
  256. this._fillColor = 0;
  257. this._fillAlpha = 1.0;
  258. }
  259. if (hasTransform) {
  260. // parse for rotation specification
  261. var transformStr:String = node.@transform;
  262. hasRotate = transformStr.indexOf("rotate");
  263. if (hasRotate > -1) {
  264. var startRotate:Number = transformStr.indexOf("(");
  265. var endRotate:Number = transformStr.indexOf(")");
  266. rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
  267. } else {
  268. rotation = 0;
  269. }
  270. } else rotation = 0;
  271. // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
  272. dstring = node.@d;
  273. if (dstring.indexOf(",") > -1) { // has commas?
  274. if (dstring.indexOf(" ") > -1) { // yes, has spaces?
  275. // change spaces to commas, then deal as for Illustrator
  276. dstring = String2.replace(dstring," ",",");
  277. }
  278. } else { // no commas
  279. // get rid of extra spaces and change rest to commas
  280. dstring = String2.shrinkSequencesOf(dstring, " ");
  281. dstring = String2.replace(dstring, " ",",");
  282. }
  283. dstring = String2.replace(dstring, "c",",c,");
  284. dstring = String2.replace(dstring, "C",",C,");
  285. dstring = String2.replace(dstring, "S",",S,");
  286. dstring = String2.replace(dstring, "s",",s,");
  287. // separate the z from the last element
  288. dstring = String2.replace(dstring, "z",",z");
  289. // change the following if M can be mid-path
  290. dstring = String2.replace(dstring, "M","M,");
  291. dstring = String2.replace(dstring, "L",",L,");
  292. dstring = String2.replace(dstring, "l",",l,");
  293. dstring = String2.replace(dstring, "H",",H,");
  294. dstring = String2.replace(dstring, "h",",h,");
  295. dstring = String2.replace(dstring, "V",",V,");
  296. dstring = String2.replace(dstring, "v",",v,");
  297. dstring = String2.replace(dstring, "Q",",Q,");
  298. dstring = String2.replace(dstring, "q",",q,");
  299. dstring = String2.replace(dstring, "T",",T,");
  300. dstring = String2.replace(dstring, "t",",t,");
  301. // Adobe includes no delimiter before negative numbers
  302. dstring = String2.replace(dstring, "-",",-");
  303. // get rid of any dup commas we might have introduced
  304. dstring = String2.replace(dstring, ",,",",");
  305. // get rid of spaces
  306. // (cr/lf's have to be removed before the xml object can be created,
  307. // so that is done in xml.onData method)
  308. dstring = String2.replace(dstring, " ","");
  309. dstring = String2.replace(dstring, "\t","");
  310. return dstring.split(",");
  311. }
  312. /**
  313. * @method makeDrawCmds
  314. * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
  315. * @description Convert svg draw commands to array of ASVDrawing commands: _commands
  316. */
  317. private function makeDrawCmds(svgCmds:Array):void {
  318. var j:Number = 0, ii:int;
  319. var qc:Array;
  320. var firstP:Point;
  321. var lastP:Point;
  322. var lastC:Point;
  323. var cmd:String;
  324. var cp:Point, pp:Point;
  325. do {
  326. cmd = svgCmds[j++];
  327. switch (cmd) {
  328. case "M" :
  329. // moveTo point
  330. firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  331. if (this._hasFill) {
  332. _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
  333. }
  334. if (this._hasStroke) {
  335. _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
  336. }
  337. _commands.push(new MoveToCommand(firstP));
  338. this.addPoint(firstP);
  339. j += 2;
  340. if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
  341. do {
  342. // if multiple points listed, add the rest as lineTo points
  343. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  344. _commands.push(new LineToCommand(lastP));
  345. this.addPoint(lastP);
  346. firstP = lastP;
  347. j += 2;
  348. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  349. }
  350. break;
  351. case "l" :
  352. do {
  353. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  354. _commands.push(new LineToCommand(lastP));
  355. this.addPoint(lastP);
  356. firstP = lastP;
  357. j += 2;
  358. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  359. break;
  360. case "L" :
  361. do {
  362. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  363. _commands.push(new LineToCommand(lastP));
  364. this.addPoint(lastP);
  365. firstP = lastP;
  366. j += 2;
  367. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  368. break;
  369. case "h" :
  370. do {
  371. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
  372. _commands.push(new LineToCommand(lastP));
  373. this.addPoint(lastP);
  374. firstP = lastP;
  375. j += 1;
  376. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  377. break;
  378. case "H" :
  379. do {
  380. lastP = new Point(Number(svgCmds[j]), lastP.y);
  381. _commands.push(new LineToCommand(lastP));
  382. this.addPoint(lastP);
  383. firstP = lastP;
  384. j += 1;
  385. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  386. break;
  387. case "v" :
  388. do {
  389. lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
  390. _commands.push(new LineToCommand(lastP));
  391. this.addPoint(lastP);
  392. firstP = lastP;
  393. j += 1;
  394. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  395. break;
  396. case "V" :
  397. do {
  398. lastP = new Point(lastP.x, Number(svgCmds[j]));
  399. _commands.push(new LineToCommand(lastP));
  400. this.addPoint(lastP);
  401. firstP = lastP;
  402. j += 1;
  403. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  404. break;
  405. case "q" :
  406. do {
  407. // control is relative to lastP, not lastC
  408. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  409. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  410. _commands.push(new CurveToCommand(lastC, lastP));
  411. this.addPoint(lastC, lastP);
  412. firstP = lastP;
  413. j += 4;
  414. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  415. break;
  416. case "Q" :
  417. do {
  418. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  419. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  420. _commands.push(new CurveToCommand(lastC, lastP));
  421. this.addPoint(lastC, lastP);
  422. firstP = lastP;
  423. j += 4;
  424. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  425. break;
  426. case "c" :
  427. do {
  428. // don't save if c1.x=c1.y=c2.x=c2.y=0
  429. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  430. } else {
  431. qc = [];
  432. Math2.getQuadBez_RP(
  433. {x:lastP.x, y:lastP.y},
  434. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  435. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  436. {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
  437. 1, qc);
  438. for (ii=0; ii
  439. cp = new Point(qc[ii].cx, qc[ii].cy);
  440. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  441. _commands.push(new CurveToCommand(cp, pp));
  442. this.addPoint(cp, pp);
  443. }
  444. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  445. lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
  446. this.addPoint(lastC, lastP);
  447. firstP = lastP;
  448. }
  449. j += 6;
  450. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  451. break;
  452. case "C" :
  453. do {
  454. // don't save if c1.x=c1.y=c2.x=c2.y=0
  455. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  456. } else {
  457. qc = [];
  458. Math2.getQuadBez_RP(
  459. {x:firstP.x, y:firstP.y},
  460. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  461. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  462. {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
  463. 1, qc);
  464. for (ii=0; ii
  465. cp = new Point(qc[ii].cx, qc[ii].cy);
  466. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  467. _commands.push(new CurveToCommand(cp, pp));
  468. this.addPoint(cp, pp);
  469. }
  470. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  471. lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
  472. this.addPoint(lastC, lastP);
  473. firstP = lastP;
  474. }
  475. j += 6;
  476. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  477. break;
  478. case "s" :
  479. do {
  480. // don't save if c1.x=c1.y=c2.x=c2.y=0
  481. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  482. } else {
  483. qc = [];
  484. Math2.getQuadBez_RP(
  485. {x:firstP.x, y:firstP.y},
  486. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  487. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  488. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  489. 1, qc);
  490. for (ii=0; ii
  491. cp = new Point(qc[ii].cx, qc[ii].cy);
  492. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  493. _commands.push(new CurveToCommand(cp, pp));
  494. this.addPoint(cp, pp);
  495. }
  496. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  497. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  498. this.addPoint(lastC, lastP);
  499. firstP = lastP;
  500. }
  501. j += 4;
  502. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  503. break;
  504. case "S" :
  505. do {
  506. // don't save if c1.x=c1.y=c2.x=c2.y=0
  507. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  508. } else {
  509. qc = [];
  510. Math2.getQuadBez_RP(
  511. {x:firstP.x, y:firstP.y},
  512. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  513. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  514. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  515. 1, qc);
  516. for (ii=0; ii
  517. cp = new Point(qc[ii].cx, qc[ii].cy);
  518. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  519. _commands.push(new CurveToCommand(cp, pp));
  520. this.addPoint(cp, pp);
  521. }
  522. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  523. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  524. this.addPoint(lastC, lastP);
  525. firstP = lastP;
  526. }
  527. j += 4;
  528. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  529. break;
  530. case "z" :
  531. case "Z" :
  532. if (!firstP.equals(lastP)) {
  533. _commands.push(new LineToCommand(firstP));
  534. this.addPoint(firstP);
  535. }
  536. j++;
  537. break;
  538. } // end switch
  539. } while (j < svgCmds.length);
  540. }
  541. /**
  542. *
  543. */
  544. public function draw(graphics:Graphics):void {
  545. for each (var command:SVGPathCommand in this._commands) {
  546. command.execute(graphics);
  547. }
  548. }
  549. }
  550. class String2 {
  551. /**
  552. * @class String2
  553. * @author Helen Triolo, with inclusions from Tim Groleau
  554. * @description String functions not included in String needed for path->array conversion
  555. */
  556. /**
  557. * @method replace ()
  558. * @description Replaces sFind in s with sReplace
  559. * @param s (String) original string
  560. * @param sFind (String) part to be replaced
  561. * @param sReplace (String) string to replace it with
  562. * @returns (String) string with replacement
  563. */
  564. public static function replace(s:String, sFind:String, sReplace:String):String {
  565. return s.split(sFind).join(sReplace);
  566. }
  567. /**
  568. * @method shrinkSequencesOf (Groleau)
  569. * @description Shrinks all sequences of a given character in a string to one
  570. * @param s (String) original string
  571. * @param ch (String) character to be found
  572. * @returns (String) string with sequences shrunk
  573. */
  574. public static function shrinkSequencesOf(s:String, ch:String):String {
  575. var len:Number = s.length;
  576. var idx:Number = 0;
  577. var idx2:Number = 0;
  578. var rs:String = "";
  579. while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
  580. // include string up to first character in sequence
  581. rs += s.substring(idx, idx2);
  582. idx = idx2;
  583. // remove all subsequent characters in sequence
  584. while ((s.charAt(idx) == ch) && (idx < len)) idx++;
  585. }
  586. return rs + s.substring(idx, len);
  587. }
  588. }
  589. class Math2 {
  590. /**
  591. * @class Math2
  592. * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
  593. * @description Math functions not included in Math needed for path->array conversion
  594. */
  595. /**
  596. * @method ratioTo (Groleau)
  597. * @description Returns the point on segment [p1,p2] which is ratio times the total distance
  598. * between p1 and p2 away from p1
  599. * @param p1 (Object) x and y values of point p1
  600. * @param p2 (Object) x and y values of point p2
  601. * @param ratio (Number) real
  602. * @returns Object
  603. */
  604. public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
  605. return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
  606. }
  607. /**
  608. * @method intersect2Lines (Penner)
  609. * @description Returns the point of intersection between two lines
  610. * @param p1, p2 (Objects) points on line 1
  611. * @param p3, p4 (Objects) points on line 2
  612. * @returns Object (point of intersection)
  613. */
  614. public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
  615. var x1:Number = p1.x; var y1:Number = p1.y;
  616. var x4:Number = p4.x; var y4:Number = p4.y;
  617. var dx1:Number = p2.x - x1;
  618. var dx2:Number = p3.x - x4;
  619. if (!(dx1 || dx2)) return NaN;
  620. var m1:Number = (p2.y - y1) / dx1;
  621. var m2:Number = (p3.y - y4) / dx2;
  622. if (!dx1) {
  623. return { x:x1, y:m2 * (x1 - x4) + y4 };
  624. } else if (!dx2) {
  625. return { x:x4, y:m1 * (x4 - x1) + y1 };
  626. }
  627. var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
  628. var yInt:Number = m1 * (xInt - x1) + y1;
  629. return { x:xInt,y:yInt };
  630. }
  631. /**
  632. * @method rotation
  633. * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
  634. * @param dy (Number) pixels
  635. * @param dx (Number) pixels
  636. * @returns Number (angle, degrees)
  637. */
  638. public static function rotation(dy:Number, dx:Number):Number {
  639. return Math.atan2(dy, dx) * 180/Math.PI;
  640. }
  641. /**
  642. * @method midPt
  643. * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
  644. * @param p1x (Number) pixels
  645. * @param p1y (Number) pixels
  646. * @param p2x (Number) pixels
  647. * @param p2y (Number) pixels
  648. * @returns Object (midpoint)
  649. */
  650. public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
  651. return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
  652. }
  653. /**
  654. * @method getQuadBez_RP (Penner)
  655. * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
  656. * to achieve a specified tolerance
  657. * @param p1 (Object) endpoint
  658. * @param c1 (Object) 1st control point
  659. * @param c2 (Object) 2nd control point
  660. * @param p2 (Object) endpoint
  661. * @param k: tolerance (low number = most accurate result)
  662. * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
  663. * p1x, p1y, cx, cy, p2x, p2y
  664. */
  665. public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
  666. // find intersection between bezier arms
  667. var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
  668. // find distance between the midpoints
  669. var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
  670. var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
  671. // split curve if the quadratic isn't close enough
  672. if (dx*dx + dy*dy > k) {
  673. var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
  674. var b0:Object = halves.b0; var b1:Object = halves.b1;
  675. // recursive call to subdivide curve
  676. getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
  677. getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
  678. } else {
  679. // end recursion by saving points
  680. qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
  681. }
  682. }
  683. /**
  684. * @method bezierSplit (Penner)
  685. * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
  686. * @param p1x (Number) pixels, endpoint 1
  687. * @param p1y (Number) pixels
  688. * @param c1x (Number) pixels, control point 1
  689. * @param c1y (Number) pixels
  690. * @param c2x (Number) pixels, control point 2
  691. * @param c2y (Number) pixels
  692. * @param p2x (Number) pixels, endpoint 2
  693. * @param p2y (Number) pixels
  694. * @returns Object (object with two cubic bezier definitions, b0 and b1)
  695. */
  696. public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
  697. var m:Function = Math2.midPt;
  698. var p1:Object = {x:p1x, y:p1y};
  699. var p2:Object = {x:p2x, y:p2y};
  700. var p01:Object = m (p1x, p1y, c1x, c1y);
  701. var p12:Object = m (c1x, c1y, c2x, c2y);
  702. var p23:Object = m (c2x, c2y, p2x, p2y);
  703. var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
  704. var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
  705. var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
  706. /*
  707. b0:{a:p0, b:p01, c:p02, d:p03},
  708. b1:{a:p03, b:p13, c:p23, d:p3 }
  709. */
  710. return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
  711. }
  712. /**
  713. * @method pointOnCurve (Penner)
  714. * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
  715. * of the standard equation:
  716. * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
  717. * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
  718. * @param p1x (Number) pixels, endpoint 1
  719. * @param p1y (Number) pixels
  720. * @param cx (Number) pixels, control point
  721. * @param cy (Number) pixels
  722. * @param p2x (Number) pixels, endpoint 2
  723. * @param p2y (Number) pixels
  724. * @param t (Number) if time is 0-1 along curve, value of t to find point at
  725. * @returns Object (point at time t)
  726. */
  727. public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
  728. var o:Object = new Object();
  729. o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
  730. o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
  731. return o;
  732. }
  733. /**
  734. * @method pointsOnCurve (Penner)
  735. * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
  736. * includes:
  737. * x,y = location of point defining start of segment
  738. * r = rotation of segment (last entry has none because it's just a point)
  739. * n = number of subdivisions into which curve will be divided (pts = n+1)
  740. * @param p1x (Number) pixels, endpoint 1
  741. * @param p1y (Number) pixels
  742. * @param cx (Number) pixels, control point
  743. * @param cy (Number) pixels
  744. * @param p2x (Number) pixels, endpoint 2
  745. * @param p2y (Number) pixels
  746. * @param n (Number) number of points to return
  747. * @returns Array
  748. */
  749. public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
  750. var pts:Array = [];
  751. for (var i:Number=0; i <= n; i++) {
  752. pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
  753. if (i > 0) {
  754. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  755. }
  756. }
  757. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  758. return pts;
  759. }
  760. /**
  761. * @method pointsOnLine (Penner)
  762. * @description Returns an array of point positions and rotations for n evenly spaced points
  763. * along a line segment
  764. * x,y = location of point defining start of segment
  765. * r = rotation of segment (last entry has none because it's just a point)
  766. * n = number of subdivisions into which curve will be divided (pts = n+1)
  767. * @param p1x (Number) pixels, endpoint 1
  768. * @param p1y (Number) pixels
  769. * @param p2x (Number) pixels, endpoint 2
  770. * @param p2y (Number) pixels
  771. * @param n (Number) number of points to return
  772. * @returns Array
  773. *//* ....................................................................
  774. Returns an array of point positions and rotation for n evenly spaced points along a line segment
  775. */
  776. public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
  777. var pts:Array = [];
  778. if (p2x != p1x) {
  779. var m:Number = (p2y-p1y)/(p2x-p1x);
  780. var b:Number = p1y - p1x * m;
  781. for (var i:Number=0; i <= n; i++) {
  782. var x:Number = p1x + ((p2x-p1x)/n) * i;
  783. pts.push({x:x, y:m*x+b});
  784. if (i > 0) {
  785. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  786. }
  787. }
  788. // vertical segment
  789. } else {
  790. for (i=0; i<=n; i++) {
  791. pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
  792. }
  793. }
  794. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  795. return pts;
  796. }
  797. /**
  798. * @method curveApproxLen
  799. * @description Returns the approximate length of a curved segment, found by dividing it
  800. * into two segments at t=0.5
  801. * @param p1x (Number) pixels, endpoint 1
  802. * @param p1y (Number) pixels
  803. * @param cx (Number) pixels, control point
  804. * @param cy (Number) pixels
  805. * @param p2x (Number) pixels, endpoint 2
  806. * @param p2y (Number) pixels
  807. * @returns Number
  808. */
  809. public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
  810. var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
  811. var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
  812. var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
  813. return len1+len2;
  814. }
  815. /**
  816. * @method lineLen
  817. * @description Returns the length of a line segment
  818. * @param p1x (Number) pixels, endpoint 1
  819. * @param p1y (Number) pixels
  820. * @param p2x (Number) pixels, endpoint 2
  821. * @param p2y (Number) pixels
  822. * @returns Number
  823. */
  824. public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
  825. return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
  826. }
  827. /**
  828. * @method roundTo
  829. * @description Returns a number rounded to specified number of decimals
  830. * @param n (Number)
  831. * @param ndec (Number) number of decimals to round to
  832. * @returns Number
  833. */
  834. public static function roundTo(n:Number, ndec:Number):Number {
  835. var multiplier:Number = Math.pow(10, ndec);
  836. return Math.round(n*multiplier)/multiplier;
  837. }
  838. }
  839. class SVGColor {
  840. public static function getByName(name:String):Number {
  841. var col:Number = SVGColor._colorTable[name];
  842. return isNaN(col) ? 0 : col;
  843. }
  844. private static const _colorTable:Object = {
  845. blue:0x0000ff,
  846. green:0x008000,
  847. red:0xff0000,
  848. aliceblue:0xf0f8ff,
  849. antiquewhite:0xfaebd7,
  850. aqua:0x00ffff,
  851. aquamarine:0x7fffd4,
  852. azure:0xf0ffff,
  853. beige:0xf5f5dc,
  854. bisque:0xffe4c4,
  855. black:0x000000,
  856. blanchedalmond:0xffebcd,
  857. blueviolet:0x8a2be2,
  858. brown:0xa52a2a,
  859. burlywood:0xdeb887,
  860. cadetblue:0x5f9ea0,
  861. chartreuse:0x7fff00,
  862. chocolate:0xd2691e,
  863. coral:0xff7f50,
  864. cornflowerblue:0x6495ed,
  865. cornsilk:0xfff8dc,
  866. crimson:0xdc143c,
  867. cyan:0x00ffff,
  868. darkblue:0x00008b,
  869. darkcyan:0x008b8b,
  870. darkgoldenrod:0xb8860b,
  871. darkgray:0xa9a9a9,
  872. darkgreen:0x006400,
  873. darkgrey:0xa9a9a9,
  874. darkkhaki:0xbdb76b,
  875. darkmagenta:0x8b008b,
  876. darkolivegreen:0x556b2f,
  877. darkorange:0xff8c00,
  878. darkorchid:0x9932cc,
  879. darkred:0x8b0000,
  880. darksalmon:0xe9967a,
  881. darkseagreen:0x8fbc8f,
  882. darkslateblue:0x483d8b,
  883. darkslategray:0x2f4f4f,
  884. darkslategrey:0x2f4f4f,
  885. darkturquoise:0x00ced1,
  886. darkviolet:0x9400d3,
  887. deeppink:0xff1493,
  888. deepskyblue:0x00bfff,
  889. dimgray:0x696969,
  890. dimgrey:0x696969,
  891. dodgerblue:0x1e90ff,
  892. firebrick:0xb22222,
  893. floralwhite:0xfffaf0,
  894. forestgreen:0x228b22,
  895. fuchsia:0xff00ff,
  896. gainsboro:0xdcdcdc,
  897. ghostwhite:0xf8f8ff,
  898. gold:0xffd700,
  899. goldenrod:0xdaa520,
  900. gray:0x808080,
  901. grey:0x808080,
  902. greenyellow:0xadff2f,
  903. honeydew:0xf0fff0,
  904. hotpink:0xff69b4,
  905. indianred:0xcd5c5c,
  906. indigo:0x4b0082,
  907. ivory:0xfffff0,
  908. khaki:0xf0e68c,
  909. lavender:0xe6e6fa,
  910. lavenderblush:0xfff0f5,
  911. lawngreen:0x7cfc00,
  912. lemonchiffon:0xfffacd,
  913. lightblue:0xadd8e6,
  914. lightcoral:0xf08080,
  915. lightcyan:0xe0ffff,
  916. lightgoldenrodyellow:0xfafad2,
  917. lightgray:0xd3d3d3,
  918. lightgreen:0x90ee90,
  919. lightgrey:0xd3d3d3,
  920. lightpink:0xffb6c1,
  921. lightsalmon:0xffa07a,
  922. lightseagreen:0x20b2aa,
  923. lightskyblue:0x87cefa,
  924. lightslategray:0x778899,
  925. lightslategrey:0x778899,
  926. lightsteelblue:0xb0c4de,
  927. lightyellow:0xffffe0,
  928. lime:0x00ff00,
  929. limegreen:0x32cd32,
  930. linen:0xfaf0e6,
  931. magenta:0xff00ff,
  932. maroon:0x800000,
  933. mediumaquamarine:0x66cdaa,
  934. mediumblue:0x0000cd,
  935. mediumorchid:0xba55d3,
  936. mediumpurple:0x9370db,
  937. mediumseagreen:0x3cb371,
  938. mediumslateblue:0x7b68ee,
  939. mediumspringgreen:0x00fa9a,
  940. mediumturquoise:0x48d1cc,
  941. mediumvioletred:0xc71585,
  942. midnightblue:0x191970,
  943. mintcream:0xf5fffa,
  944. mistyrose:0xffe4e1,
  945. moccasin:0xffe4b5,
  946. navajowhite:0xffdead,
  947. navy:0x000080,
  948. oldlace:0xfdf5e6,
  949. olive:0x808000,
  950. olivedrab:0x6b8e23,
  951. orange:0xffa500,
  952. orangered:0xff4500,
  953. orchid:0xda70d6,
  954. palegoldenrod:0xeee8aa,
  955. palegreen:0x98fb98,
  956. paleturquoise:0xafeeee,
  957. palevioletred:0xdb7093,
  958. papayawhip:0xffefd5,
  959. peachpuff:0xffdab9,
  960. peru:0xcd853f,
  961. pink:0xffc0cb,
  962. plum:0xdda0dd,
  963. powderblue:0xb0e0e6,
  964. purple:0x800080,
  965. rosybrown:0xbc8f8f,
  966. royalblue:0x4169e1,
  967. saddlebrown:0x8b4513,
  968. salmon:0xfa8072,
  969. sandybrown:0xf4a460,
  970. seagreen:0x2e8b57,
  971. seashell:0xfff5ee,
  972. sienna:0xa0522d,
  973. silver:0xc0c0c0,
  974. skyblue:0x87ceeb,
  975. slateblue:0x6a5acd,
  976. slategray:0x708090,
  977. slategrey:0x708090,
  978. snow:0xfffafa,
  979. springgreen:0x00ff7f,
  980. steelblue:0x4682b4,
  981. tan:0xd2b48c,
  982. teal:0x008080,
  983. thistle:0xd8bfd8,
  984. tomato:0xff6347,
  985. turquoise:0x40e0d0,
  986. violet:0xee82ee,
  987. wheat:0xf5deb3,
  988. white:0xffffff,
  989. whitesmoke:0xf5f5f5,
  990. yellow:0xffff00,
  991. yellowgreen:0x9acd32
  992. }
  993. }
  994. class SVGPathCommandType {
  995. public static const BEGIN_FILL_COMMAND:Number = 1;
  996. public static const LINE_STYLE_COMMAND:Number = 2;
  997. public static const MOVE_TO_COMMAND:Number = 3;
  998. public static const LINE_TO_COMMAND:Number = 4;
  999. public static const CURVE_TO_COMMAND:Number = 5;
  1000. }
  1001. interface ISVGPathCommand {
  1002. function execute(graphics:Graphics):void;
  1003. }
  1004. class SVGPathCommand implements ISVGPathCommand {
  1005. private var _type:Number;
  1006. public function get type():Number { return this._type; }
  1007. public function SVGPathCommand(type:Number = 0) {
  1008. this._type = type;
  1009. }
  1010. public function execute(graphics:Graphics):void {
  1011. throw new Error('Subclass must be implement execute method.');
  1012. }
  1013. }
  1014. class BeginFillCommand extends SVGPathCommand {
  1015. private var _color:Number;
  1016. public function get color():Number { return this._color; }
  1017. private var _alpha:Number;
  1018. public function get alpha():Number { return this._alpha; }
  1019. public function BeginFillCommand(color:Number, alpha:Number) {
  1020. super(SVGPathCommandType.BEGIN_FILL_COMMAND);
  1021. this._color = color;
  1022. this._alpha = alpha;
  1023. }
  1024. public override function execute(graphics:Graphics):void {
  1025. graphics.beginFill(this._color, this._alpha);
  1026. }
  1027. }
  1028. class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1029. private var _pt1:Point;
  1030. public function get x1():Number { return this._pt1.x; }
  1031. public function get y1():Number { return this._pt1.y; }
  1032. private var _pt2:Point;
  1033. public function get x2():Number { return this._pt2.x; }
  1034. public function get y2():Number { return this._pt2.y; }
  1035. public function CurveToCommand(pt1:Point, pt2:Point) {
  1036. super(SVGPathCommandType.CURVE_TO_COMMAND);
  1037. this._pt1 = pt1;
  1038. this._pt2 = pt2;
  1039. }
  1040. public override function execute(graphics:Graphics):void {
  1041. graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
  1042. }
  1043. }
  1044. class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
  1045. private var _width:Number;
  1046. public function get width():Number { return this._width; }
  1047. private var _color:Number;
  1048. public function get color():Number { return this._color; }
  1049. private var _alpha:Number;
  1050. public function get alpha():Number { return this._alpha; }
  1051. public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
  1052. super(SVGPathCommandType.LINE_STYLE_COMMAND);
  1053. this._width = width;
  1054. this._color = color;
  1055. this._alpha = alpha;
  1056. }
  1057. public override function execute(graphics:Graphics):void {
  1058. graphics.lineStyle(this._width, this._color, this._alpha);
  1059. }
  1060. }
  1061. class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
  1062. private var _pt:Point;
  1063. public function get x():Number { return this._pt.x; }
  1064. public function get y():Number { return this._pt.y; }
  1065. public function LineToCommand(pt:Point) {
  1066. super(SVGPathCommandType.LINE_TO_COMMAND);
  1067. this._pt = pt;
  1068. }
  1069. public override function execute(graphics:Graphics):void {
  1070. graphics.lineTo(this._pt.x, this._pt.y);
  1071. }
  1072. }
  1073. class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1074. private var _pt:Point;
  1075. public function get x():Number { return this._pt.x; }
  1076. public function get y():Number { return this._pt.y; }
  1077. public function MoveToCommand(pt:Point) {
  1078. super(SVGPathCommandType.MOVE_TO_COMMAND);
  1079. this._pt = pt;
  1080. }
  1081. public override function execute(graphics:Graphics):void {
  1082. graphics.moveTo(this._pt.x, this._pt.y);
  1083. }
  1084. }
noswf
  1. // forked from Saqoosha's Sewing
  2. package {
  3. import caurina.transitions.Equations;
  4. import caurina.transitions.Tweener;
  5. import caurina.transitions.properties.CurveModifiers;
  6. import flash.display.Graphics;
  7. import flash.display.Sprite;
  8. import flash.display.StageAlign;
  9. import flash.display.StageQuality;
  10. import flash.display.StageScaleMode;
  11. import flash.events.Event;
  12. import flash.geom.Point;
  13. import flash.net.URLLoader;
  14. import flash.net.URLLoaderDataFormat;
  15. import flash.net.URLRequest;
  16. import flash.utils.setTimeout;
  17. [SWF(width=465, height=465, backgroundColor=0xffff00, frameRate=60)]
  18. public class Sewing extends Sprite {
  19. private var _loader:URLLoader;
  20. private var _canvas:Sprite;
  21. private var _paths:Array;
  22. public function Sewing() {
  23. //Wonderfl.capture_delay(58);
  24. //this.stage.quality = StageQuality.BEST;
  25. this.stage.align = StageAlign.TOP_LEFT;
  26. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  27. CurveModifiers.init();
  28. this._canvas = this.addChild(new Sprite()) as Sprite;
  29. this._loader = new URLLoader();
  30. this._loader.dataFormat = URLLoaderDataFormat.TEXT;
  31. this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
  32. this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
  33. }
  34. private function _handleLoaded(e:Event):void {
  35. var svg:XML = new XML(this._loader.data);
  36. this._paths = [];
  37. var path:SVGPath;
  38. var delay:Number = 2.0;
  39. var cx:Number = parseInt(svg.@width) / 2;
  40. var cy:Number = parseInt(svg.@height) / 2;
  41. this._canvas.x = this.stage.stageWidth / 2 - cx;
  42. this._canvas.y = this.stage.stageHeight / 2 - cy;
  43. for each (var pathNode:XML in svg..*::path) {
  44. path = new SVGPath(pathNode);
  45. this._paths.push(path);
  46. var i:Number = 0;
  47. var di:Number = Math.PI * 2 / path.points.length;
  48. var px:Number = cx;
  49. var py:Number = this.stage.stageHeight - this._canvas.y;
  50. for each (var pt:Point in path.points) {
  51. Tweener.addTween(pt, {
  52. x: pt.x,
  53. y: pt.y,
  54. _bezier:[
  55. { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
  56. { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
  57. ],
  58. time: 1.0,
  59. delay: delay,
  60. transition: Equations.easeNone
  61. });
  62. pt.x = px;
  63. pt.y = py;
  64. delay += 0.004;
  65. i += di;
  66. }
  67. }
  68. this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
  69. setTimeout(function ():void {
  70. removeEventListener(Event.ENTER_FRAME, _drawPaths);
  71. }, (delay + 1) * 1000);
  72. }
  73. private function _drawPaths(e:Event):void {
  74. this._canvas.graphics.clear();
  75. for each (var path:SVGPath in this._paths) {
  76. path.draw(this._canvas.graphics);
  77. }
  78. }
  79. }
  80. }
  81. import flash.display.Graphics;
  82. import flash.geom.Point;
  83. import flash.geom.Rectangle;
  84. /**
  85. * @class PathToArray
  86. * @author Helen Triolo (with contributions from many people)
  87. * @version 1.01
  88. * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
  89. * not contain any CRLF characters), and an empty array.
  90. * Parses the path node to make an array of drawing commands, which include cubic bezier
  91. * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
  92. * using Robert Penner's code to convert with accuracy within 1 pixel.
  93. * Drawing commands are produced in the format originally devised by Peter Hall
  94. * in his ASVDrawing class. These are the possible elements in array dCmds (and the
  95. * corresponding Flash drawing API commands to apply them):
  96. * ['M',[x,y]] moveTo(x,y)
  97. * ['L',[x,y]] lineTo(x,y)
  98. * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
  99. * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
  100. * ['F',[color,alpha]] beginFill(color,alpha)
  101. * ['EF'] endFill()
  102. * History:
  103. * v1.00 2005/11/13 Original release
  104. * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
  105. *
  106. * @param svgnode (XMLNode) Path node from SVG file
  107. * @param dCmds (Array) Empty array to write commands to
  108. */
  109. class SVGPath {
  110. private var _commands:Array;
  111. public function get commands():Array { return this._commands }
  112. private var _points:Array;
  113. public function get points():Array { return this._points }
  114. private function addPoint(... points:Array):void {
  115. for each (var pt:Point in points) {
  116. this._addPoint(pt);
  117. }
  118. }
  119. private function _addPoint(pt:Point):void {
  120. if (pt.x < this._bounds.left) {
  121. this._bounds.left = pt.x;
  122. } else if (this._bounds.right < pt.x) {
  123. this._bounds.right = pt.x;
  124. }
  125. if (pt.y < this._bounds.top) {
  126. this._bounds.top = pt.y;
  127. } else if (this._bounds.bottom < pt.y) {
  128. this._bounds.bottom = pt.y;
  129. }
  130. this._points.push(pt);
  131. }
  132. private var _bounds:Rectangle;
  133. public function get boundsRect():Rectangle { return this._bounds }
  134. private var _hasFill:Boolean;
  135. public function get hasFill():Boolean { return this._hasFill }
  136. private var _hasStroke:Boolean;
  137. public function get hasStroke():Boolean { return this._hasStroke }
  138. public function swapFillAndStroke():void {
  139. var flg:Boolean = this._hasFill;
  140. this._hasFill = this._hasStroke;
  141. this._hasStroke = flg;
  142. var val:Number = this._fillColor;
  143. this._fillColor = this._strokeColor;
  144. this._strokeColor = val;
  145. val = this._fillAlpha;
  146. this._fillAlpha = this._strokeAlpha;
  147. this._strokeAlpha = val;
  148. }
  149. private var _fillColor:Number;
  150. public function get fillColor():Number { return this._fillColor }
  151. public function set fillColor(col:Number):void { this._fillColor = col }
  152. private var _fillAlpha:Number;
  153. public function get fillAlpha():Number { return this._fillAlpha }
  154. public function set fillAlpha(al:Number):void { this._fillAlpha = al }
  155. private var _strokeColor:Number;
  156. public function get strokeColor():Number { return this._strokeColor }
  157. public function set strokeColor(col:Number):void { this._strokeColor = col }
  158. private var _strokeAlpha:Number;
  159. public function get strokeAlpha():Number { return this._strokeAlpha }
  160. public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
  161. private var _strokeWidth:Number;
  162. public function get strokeWidth():Number { return this._strokeWidth }
  163. public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
  164. /**
  165. *
  166. */
  167. public function SVGPath(svgNode:XML) {
  168. this._commands = [];
  169. this._points = [];
  170. this._bounds = new Rectangle();
  171. this._bounds.top = this._bounds.left = Number.MAX_VALUE;
  172. this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
  173. this._hasFill = false;
  174. this._hasStroke = false;
  175. this.makeDrawCmds(this.extractCmds(svgNode));
  176. }
  177. /**
  178. * @method extractCmds ()
  179. * @param node (XMLNode) SVG path node
  180. * @description Parse path node and convert to array of SVG drawing commands and data
  181. * 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,
  182. * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
  183. * @returns (Array) array of drawing commands
  184. */
  185. private function extractCmds(node:XML):Array {
  186. var i:Number;
  187. var startColor:Number;
  188. var thisColor:Number;
  189. //var hasFill:Boolean = false;
  190. var hasTransform:Boolean = false;
  191. //var hasStroke:Boolean = false;
  192. var hasStrokeWidth:Boolean = false;
  193. var hasRotate:Number = 0;
  194. var dstring:String = "";
  195. var rotation:Number;
  196. // is there a fill attribute, a transform attribute, a stroke attribute?
  197. for each (var a:XML in node.attributes()) {
  198. switch (a.name().toString()) {
  199. case 'fill': this._hasFill = true; break;
  200. case 'transform': hasTransform = true; break;
  201. case 'stroke': this._hasStroke = true; break;
  202. case 'stroke-width': hasStrokeWidth = true; break;
  203. }
  204. }
  205. if (this._hasFill) {
  206. // parse for fill color specification
  207. // if a hex number is specified, startColor will be > 0
  208. // if a color name is specified, startColor will be 0
  209. var fillStr:String = node.@fill;
  210. if (fillStr == 'none') {
  211. this._hasFill = false;
  212. } else {
  213. startColor = fillStr.indexOf("#") + 1;
  214. if (startColor == 0) { // name specified instead of color number
  215. thisColor = SVGColor.getByName(fillStr);
  216. if (isNaN(thisColor)) {
  217. this._hasFill = false;
  218. } else {
  219. this._fillColor = thisColor;
  220. this._fillAlpha = 1.0;
  221. }
  222. } else {
  223. this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
  224. this._fillAlpha = 1.0;
  225. }
  226. }
  227. }
  228. // stroke: color, width, alpha
  229. if (this._hasStroke) {
  230. // parse for stroke color specification
  231. var strokeStr:String = node.@stroke;
  232. if (strokeStr == 'none') {
  233. this._hasStroke = false;
  234. } else {
  235. startColor = strokeStr.indexOf("#")+1;
  236. if (startColor == 0) { // name specified instead of color number
  237. thisColor = SVGColor.getByName(strokeStr);
  238. if (isNaN(thisColor)) {
  239. this._hasStroke = false;
  240. } else {
  241. this._strokeWidth = 0;
  242. this._strokeColor = SVGColor.getByName(strokeStr);
  243. this._strokeAlpha = 1.0;
  244. }
  245. } else {
  246. this._strokeWidth = 0;
  247. this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
  248. this._strokeAlpha = 1.0;
  249. }
  250. }
  251. }
  252. if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
  253. // if stroke and fill are both undefined, set fill to black
  254. if (!this._hasFill && !this._hasStroke) {
  255. this._hasFill = true;
  256. this._fillColor = 0;
  257. this._fillAlpha = 1.0;
  258. }
  259. if (hasTransform) {
  260. // parse for rotation specification
  261. var transformStr:String = node.@transform;
  262. hasRotate = transformStr.indexOf("rotate");
  263. if (hasRotate > -1) {
  264. var startRotate:Number = transformStr.indexOf("(");
  265. var endRotate:Number = transformStr.indexOf(")");
  266. rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
  267. } else {
  268. rotation = 0;
  269. }
  270. } else rotation = 0;
  271. // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
  272. dstring = node.@d;
  273. if (dstring.indexOf(",") > -1) { // has commas?
  274. if (dstring.indexOf(" ") > -1) { // yes, has spaces?
  275. // change spaces to commas, then deal as for Illustrator
  276. dstring = String2.replace(dstring," ",",");
  277. }
  278. } else { // no commas
  279. // get rid of extra spaces and change rest to commas
  280. dstring = String2.shrinkSequencesOf(dstring, " ");
  281. dstring = String2.replace(dstring, " ",",");
  282. }
  283. dstring = String2.replace(dstring, "c",",c,");
  284. dstring = String2.replace(dstring, "C",",C,");
  285. dstring = String2.replace(dstring, "S",",S,");
  286. dstring = String2.replace(dstring, "s",",s,");
  287. // separate the z from the last element
  288. dstring = String2.replace(dstring, "z",",z");
  289. // change the following if M can be mid-path
  290. dstring = String2.replace(dstring, "M","M,");
  291. dstring = String2.replace(dstring, "L",",L,");
  292. dstring = String2.replace(dstring, "l",",l,");
  293. dstring = String2.replace(dstring, "H",",H,");
  294. dstring = String2.replace(dstring, "h",",h,");
  295. dstring = String2.replace(dstring, "V",",V,");
  296. dstring = String2.replace(dstring, "v",",v,");
  297. dstring = String2.replace(dstring, "Q",",Q,");
  298. dstring = String2.replace(dstring, "q",",q,");
  299. dstring = String2.replace(dstring, "T",",T,");
  300. dstring = String2.replace(dstring, "t",",t,");
  301. // Adobe includes no delimiter before negative numbers
  302. dstring = String2.replace(dstring, "-",",-");
  303. // get rid of any dup commas we might have introduced
  304. dstring = String2.replace(dstring, ",,",",");
  305. // get rid of spaces
  306. // (cr/lf's have to be removed before the xml object can be created,
  307. // so that is done in xml.onData method)
  308. dstring = String2.replace(dstring, " ","");
  309. dstring = String2.replace(dstring, "\t","");
  310. return dstring.split(",");
  311. }
  312. /**
  313. * @method makeDrawCmds
  314. * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
  315. * @description Convert svg draw commands to array of ASVDrawing commands: _commands
  316. */
  317. private function makeDrawCmds(svgCmds:Array):void {
  318. var j:Number = 0, ii:int;
  319. var qc:Array;
  320. var firstP:Point;
  321. var lastP:Point;
  322. var lastC:Point;
  323. var cmd:String;
  324. var cp:Point, pp:Point;
  325. do {
  326. cmd = svgCmds[j++];
  327. switch (cmd) {
  328. case "M" :
  329. // moveTo point
  330. firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  331. if (this._hasFill) {
  332. _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
  333. }
  334. if (this._hasStroke) {
  335. _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
  336. }
  337. _commands.push(new MoveToCommand(firstP));
  338. this.addPoint(firstP);
  339. j += 2;
  340. if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
  341. do {
  342. // if multiple points listed, add the rest as lineTo points
  343. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  344. _commands.push(new LineToCommand(lastP));
  345. this.addPoint(lastP);
  346. firstP = lastP;
  347. j += 2;
  348. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  349. }
  350. break;
  351. case "l" :
  352. do {
  353. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  354. _commands.push(new LineToCommand(lastP));
  355. this.addPoint(lastP);
  356. firstP = lastP;
  357. j += 2;
  358. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  359. break;
  360. case "L" :
  361. do {
  362. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  363. _commands.push(new LineToCommand(lastP));
  364. this.addPoint(lastP);
  365. firstP = lastP;
  366. j += 2;
  367. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  368. break;
  369. case "h" :
  370. do {
  371. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
  372. _commands.push(new LineToCommand(lastP));
  373. this.addPoint(lastP);
  374. firstP = lastP;
  375. j += 1;
  376. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  377. break;
  378. case "H" :
  379. do {
  380. lastP = new Point(Number(svgCmds[j]), lastP.y);
  381. _commands.push(new LineToCommand(lastP));
  382. this.addPoint(lastP);
  383. firstP = lastP;
  384. j += 1;
  385. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  386. break;
  387. case "v" :
  388. do {
  389. lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
  390. _commands.push(new LineToCommand(lastP));
  391. this.addPoint(lastP);
  392. firstP = lastP;
  393. j += 1;
  394. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  395. break;
  396. case "V" :
  397. do {
  398. lastP = new Point(lastP.x, Number(svgCmds[j]));
  399. _commands.push(new LineToCommand(lastP));
  400. this.addPoint(lastP);
  401. firstP = lastP;
  402. j += 1;
  403. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  404. break;
  405. case "q" :
  406. do {
  407. // control is relative to lastP, not lastC
  408. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  409. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  410. _commands.push(new CurveToCommand(lastC, lastP));
  411. this.addPoint(lastC, lastP);
  412. firstP = lastP;
  413. j += 4;
  414. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  415. break;
  416. case "Q" :
  417. do {
  418. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  419. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  420. _commands.push(new CurveToCommand(lastC, lastP));
  421. this.addPoint(lastC, lastP);
  422. firstP = lastP;
  423. j += 4;
  424. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  425. break;
  426. case "c" :
  427. do {
  428. // don't save if c1.x=c1.y=c2.x=c2.y=0
  429. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  430. } else {
  431. qc = [];
  432. Math2.getQuadBez_RP(
  433. {x:lastP.x, y:lastP.y},
  434. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  435. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  436. {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
  437. 1, qc);
  438. for (ii=0; ii
  439. cp = new Point(qc[ii].cx, qc[ii].cy);
  440. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  441. _commands.push(new CurveToCommand(cp, pp));
  442. this.addPoint(cp, pp);
  443. }
  444. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  445. lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
  446. this.addPoint(lastC, lastP);
  447. firstP = lastP;
  448. }
  449. j += 6;
  450. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  451. break;
  452. case "C" :
  453. do {
  454. // don't save if c1.x=c1.y=c2.x=c2.y=0
  455. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  456. } else {
  457. qc = [];
  458. Math2.getQuadBez_RP(
  459. {x:firstP.x, y:firstP.y},
  460. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  461. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  462. {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
  463. 1, qc);
  464. for (ii=0; ii
  465. cp = new Point(qc[ii].cx, qc[ii].cy);
  466. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  467. _commands.push(new CurveToCommand(cp, pp));
  468. this.addPoint(cp, pp);
  469. }
  470. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  471. lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
  472. this.addPoint(lastC, lastP);
  473. firstP = lastP;
  474. }
  475. j += 6;
  476. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  477. break;
  478. case "s" :
  479. do {
  480. // don't save if c1.x=c1.y=c2.x=c2.y=0
  481. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  482. } else {
  483. qc = [];
  484. Math2.getQuadBez_RP(
  485. {x:firstP.x, y:firstP.y},
  486. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  487. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  488. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  489. 1, qc);
  490. for (ii=0; ii
  491. cp = new Point(qc[ii].cx, qc[ii].cy);
  492. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  493. _commands.push(new CurveToCommand(cp, pp));
  494. this.addPoint(cp, pp);
  495. }
  496. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  497. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  498. this.addPoint(lastC, lastP);
  499. firstP = lastP;
  500. }
  501. j += 4;
  502. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  503. break;
  504. case "S" :
  505. do {
  506. // don't save if c1.x=c1.y=c2.x=c2.y=0
  507. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  508. } else {
  509. qc = [];
  510. Math2.getQuadBez_RP(
  511. {x:firstP.x, y:firstP.y},
  512. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  513. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  514. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  515. 1, qc);
  516. for (ii=0; ii
  517. cp = new Point(qc[ii].cx, qc[ii].cy);
  518. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  519. _commands.push(new CurveToCommand(cp, pp));
  520. this.addPoint(cp, pp);
  521. }
  522. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  523. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  524. this.addPoint(lastC, lastP);
  525. firstP = lastP;
  526. }
  527. j += 4;
  528. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  529. break;
  530. case "z" :
  531. case "Z" :
  532. if (!firstP.equals(lastP)) {
  533. _commands.push(new LineToCommand(firstP));
  534. this.addPoint(firstP);
  535. }
  536. j++;
  537. break;
  538. } // end switch
  539. } while (j < svgCmds.length);
  540. }
  541. /**
  542. *
  543. */
  544. public function draw(graphics:Graphics):void {
  545. for each (var command:SVGPathCommand in this._commands) {
  546. command.execute(graphics);
  547. }
  548. }
  549. }
  550. class String2 {
  551. /**
  552. * @class String2
  553. * @author Helen Triolo, with inclusions from Tim Groleau
  554. * @description String functions not included in String needed for path->array conversion
  555. */
  556. /**
  557. * @method replace ()
  558. * @description Replaces sFind in s with sReplace
  559. * @param s (String) original string
  560. * @param sFind (String) part to be replaced
  561. * @param sReplace (String) string to replace it with
  562. * @returns (String) string with replacement
  563. */
  564. public static function replace(s:String, sFind:String, sReplace:String):String {
  565. return s.split(sFind).join(sReplace);
  566. }
  567. /**
  568. * @method shrinkSequencesOf (Groleau)
  569. * @description Shrinks all sequences of a given character in a string to one
  570. * @param s (String) original string
  571. * @param ch (String) character to be found
  572. * @returns (String) string with sequences shrunk
  573. */
  574. public static function shrinkSequencesOf(s:String, ch:String):String {
  575. var len:Number = s.length;
  576. var idx:Number = 0;
  577. var idx2:Number = 0;
  578. var rs:String = "";
  579. while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
  580. // include string up to first character in sequence
  581. rs += s.substring(idx, idx2);
  582. idx = idx2;
  583. // remove all subsequent characters in sequence
  584. while ((s.charAt(idx) == ch) && (idx < len)) idx++;
  585. }
  586. return rs + s.substring(idx, len);
  587. }
  588. }
  589. class Math2 {
  590. /**
  591. * @class Math2
  592. * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
  593. * @description Math functions not included in Math needed for path->array conversion
  594. */
  595. /**
  596. * @method ratioTo (Groleau)
  597. * @description Returns the point on segment [p1,p2] which is ratio times the total distance
  598. * between p1 and p2 away from p1
  599. * @param p1 (Object) x and y values of point p1
  600. * @param p2 (Object) x and y values of point p2
  601. * @param ratio (Number) real
  602. * @returns Object
  603. */
  604. public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
  605. return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
  606. }
  607. /**
  608. * @method intersect2Lines (Penner)
  609. * @description Returns the point of intersection between two lines
  610. * @param p1, p2 (Objects) points on line 1
  611. * @param p3, p4 (Objects) points on line 2
  612. * @returns Object (point of intersection)
  613. */
  614. public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
  615. var x1:Number = p1.x; var y1:Number = p1.y;
  616. var x4:Number = p4.x; var y4:Number = p4.y;
  617. var dx1:Number = p2.x - x1;
  618. var dx2:Number = p3.x - x4;
  619. if (!(dx1 || dx2)) return NaN;
  620. var m1:Number = (p2.y - y1) / dx1;
  621. var m2:Number = (p3.y - y4) / dx2;
  622. if (!dx1) {
  623. return { x:x1, y:m2 * (x1 - x4) + y4 };
  624. } else if (!dx2) {
  625. return { x:x4, y:m1 * (x4 - x1) + y1 };
  626. }
  627. var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
  628. var yInt:Number = m1 * (xInt - x1) + y1;
  629. return { x:xInt,y:yInt };
  630. }
  631. /**
  632. * @method rotation
  633. * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
  634. * @param dy (Number) pixels
  635. * @param dx (Number) pixels
  636. * @returns Number (angle, degrees)
  637. */
  638. public static function rotation(dy:Number, dx:Number):Number {
  639. return Math.atan2(dy, dx) * 180/Math.PI;
  640. }
  641. /**
  642. * @method midPt
  643. * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
  644. * @param p1x (Number) pixels
  645. * @param p1y (Number) pixels
  646. * @param p2x (Number) pixels
  647. * @param p2y (Number) pixels
  648. * @returns Object (midpoint)
  649. */
  650. public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
  651. return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
  652. }
  653. /**
  654. * @method getQuadBez_RP (Penner)
  655. * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
  656. * to achieve a specified tolerance
  657. * @param p1 (Object) endpoint
  658. * @param c1 (Object) 1st control point
  659. * @param c2 (Object) 2nd control point
  660. * @param p2 (Object) endpoint
  661. * @param k: tolerance (low number = most accurate result)
  662. * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
  663. * p1x, p1y, cx, cy, p2x, p2y
  664. */
  665. public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
  666. // find intersection between bezier arms
  667. var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
  668. // find distance between the midpoints
  669. var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
  670. var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
  671. // split curve if the quadratic isn't close enough
  672. if (dx*dx + dy*dy > k) {
  673. var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
  674. var b0:Object = halves.b0; var b1:Object = halves.b1;
  675. // recursive call to subdivide curve
  676. getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
  677. getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
  678. } else {
  679. // end recursion by saving points
  680. qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
  681. }
  682. }
  683. /**
  684. * @method bezierSplit (Penner)
  685. * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
  686. * @param p1x (Number) pixels, endpoint 1
  687. * @param p1y (Number) pixels
  688. * @param c1x (Number) pixels, control point 1
  689. * @param c1y (Number) pixels
  690. * @param c2x (Number) pixels, control point 2
  691. * @param c2y (Number) pixels
  692. * @param p2x (Number) pixels, endpoint 2
  693. * @param p2y (Number) pixels
  694. * @returns Object (object with two cubic bezier definitions, b0 and b1)
  695. */
  696. public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
  697. var m:Function = Math2.midPt;
  698. var p1:Object = {x:p1x, y:p1y};
  699. var p2:Object = {x:p2x, y:p2y};
  700. var p01:Object = m (p1x, p1y, c1x, c1y);
  701. var p12:Object = m (c1x, c1y, c2x, c2y);
  702. var p23:Object = m (c2x, c2y, p2x, p2y);
  703. var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
  704. var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
  705. var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
  706. /*
  707. b0:{a:p0, b:p01, c:p02, d:p03},
  708. b1:{a:p03, b:p13, c:p23, d:p3 }
  709. */
  710. return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
  711. }
  712. /**
  713. * @method pointOnCurve (Penner)
  714. * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
  715. * of the standard equation:
  716. * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
  717. * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
  718. * @param p1x (Number) pixels, endpoint 1
  719. * @param p1y (Number) pixels
  720. * @param cx (Number) pixels, control point
  721. * @param cy (Number) pixels
  722. * @param p2x (Number) pixels, endpoint 2
  723. * @param p2y (Number) pixels
  724. * @param t (Number) if time is 0-1 along curve, value of t to find point at
  725. * @returns Object (point at time t)
  726. */
  727. public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
  728. var o:Object = new Object();
  729. o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
  730. o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
  731. return o;
  732. }
  733. /**
  734. * @method pointsOnCurve (Penner)
  735. * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
  736. * includes:
  737. * x,y = location of point defining start of segment
  738. * r = rotation of segment (last entry has none because it's just a point)
  739. * n = number of subdivisions into which curve will be divided (pts = n+1)
  740. * @param p1x (Number) pixels, endpoint 1
  741. * @param p1y (Number) pixels
  742. * @param cx (Number) pixels, control point
  743. * @param cy (Number) pixels
  744. * @param p2x (Number) pixels, endpoint 2
  745. * @param p2y (Number) pixels
  746. * @param n (Number) number of points to return
  747. * @returns Array
  748. */
  749. public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
  750. var pts:Array = [];
  751. for (var i:Number=0; i <= n; i++) {
  752. pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
  753. if (i > 0) {
  754. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  755. }
  756. }
  757. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  758. return pts;
  759. }
  760. /**
  761. * @method pointsOnLine (Penner)
  762. * @description Returns an array of point positions and rotations for n evenly spaced points
  763. * along a line segment
  764. * x,y = location of point defining start of segment
  765. * r = rotation of segment (last entry has none because it's just a point)
  766. * n = number of subdivisions into which curve will be divided (pts = n+1)
  767. * @param p1x (Number) pixels, endpoint 1
  768. * @param p1y (Number) pixels
  769. * @param p2x (Number) pixels, endpoint 2
  770. * @param p2y (Number) pixels
  771. * @param n (Number) number of points to return
  772. * @returns Array
  773. *//* ....................................................................
  774. Returns an array of point positions and rotation for n evenly spaced points along a line segment
  775. */
  776. public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
  777. var pts:Array = [];
  778. if (p2x != p1x) {
  779. var m:Number = (p2y-p1y)/(p2x-p1x);
  780. var b:Number = p1y - p1x * m;
  781. for (var i:Number=0; i <= n; i++) {
  782. var x:Number = p1x + ((p2x-p1x)/n) * i;
  783. pts.push({x:x, y:m*x+b});
  784. if (i > 0) {
  785. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  786. }
  787. }
  788. // vertical segment
  789. } else {
  790. for (i=0; i<=n; i++) {
  791. pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
  792. }
  793. }
  794. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  795. return pts;
  796. }
  797. /**
  798. * @method curveApproxLen
  799. * @description Returns the approximate length of a curved segment, found by dividing it
  800. * into two segments at t=0.5
  801. * @param p1x (Number) pixels, endpoint 1
  802. * @param p1y (Number) pixels
  803. * @param cx (Number) pixels, control point
  804. * @param cy (Number) pixels
  805. * @param p2x (Number) pixels, endpoint 2
  806. * @param p2y (Number) pixels
  807. * @returns Number
  808. */
  809. public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
  810. var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
  811. var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
  812. var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
  813. return len1+len2;
  814. }
  815. /**
  816. * @method lineLen
  817. * @description Returns the length of a line segment
  818. * @param p1x (Number) pixels, endpoint 1
  819. * @param p1y (Number) pixels
  820. * @param p2x (Number) pixels, endpoint 2
  821. * @param p2y (Number) pixels
  822. * @returns Number
  823. */
  824. public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
  825. return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
  826. }
  827. /**
  828. * @method roundTo
  829. * @description Returns a number rounded to specified number of decimals
  830. * @param n (Number)
  831. * @param ndec (Number) number of decimals to round to
  832. * @returns Number
  833. */
  834. public static function roundTo(n:Number, ndec:Number):Number {
  835. var multiplier:Number = Math.pow(10, ndec);
  836. return Math.round(n*multiplier)/multiplier;
  837. }
  838. }
  839. class SVGColor {
  840. public static function getByName(name:String):Number {
  841. var col:Number = SVGColor._colorTable[name];
  842. return isNaN(col) ? 0 : col;
  843. }
  844. private static const _colorTable:Object = {
  845. blue:0x0000ff,
  846. green:0x008000,
  847. red:0xff0000,
  848. aliceblue:0xf0f8ff,
  849. antiquewhite:0xfaebd7,
  850. aqua:0x00ffff,
  851. aquamarine:0x7fffd4,
  852. azure:0xf0ffff,
  853. beige:0xf5f5dc,
  854. bisque:0xffe4c4,
  855. black:0x000000,
  856. blanchedalmond:0xffebcd,
  857. blueviolet:0x8a2be2,
  858. brown:0xa52a2a,
  859. burlywood:0xdeb887,
  860. cadetblue:0x5f9ea0,
  861. chartreuse:0x7fff00,
  862. chocolate:0xd2691e,
  863. coral:0xff7f50,
  864. cornflowerblue:0x6495ed,
  865. cornsilk:0xfff8dc,
  866. crimson:0xdc143c,
  867. cyan:0x00ffff,
  868. darkblue:0x00008b,
  869. darkcyan:0x008b8b,
  870. darkgoldenrod:0xb8860b,
  871. darkgray:0xa9a9a9,
  872. darkgreen:0x006400,
  873. darkgrey:0xa9a9a9,
  874. darkkhaki:0xbdb76b,
  875. darkmagenta:0x8b008b,
  876. darkolivegreen:0x556b2f,
  877. darkorange:0xff8c00,
  878. darkorchid:0x9932cc,
  879. darkred:0x8b0000,
  880. darksalmon:0xe9967a,
  881. darkseagreen:0x8fbc8f,
  882. darkslateblue:0x483d8b,
  883. darkslategray:0x2f4f4f,
  884. darkslategrey:0x2f4f4f,
  885. darkturquoise:0x00ced1,
  886. darkviolet:0x9400d3,
  887. deeppink:0xff1493,
  888. deepskyblue:0x00bfff,
  889. dimgray:0x696969,
  890. dimgrey:0x696969,
  891. dodgerblue:0x1e90ff,
  892. firebrick:0xb22222,
  893. floralwhite:0xfffaf0,
  894. forestgreen:0x228b22,
  895. fuchsia:0xff00ff,
  896. gainsboro:0xdcdcdc,
  897. ghostwhite:0xf8f8ff,
  898. gold:0xffd700,
  899. goldenrod:0xdaa520,
  900. gray:0x808080,
  901. grey:0x808080,
  902. greenyellow:0xadff2f,
  903. honeydew:0xf0fff0,
  904. hotpink:0xff69b4,
  905. indianred:0xcd5c5c,
  906. indigo:0x4b0082,
  907. ivory:0xfffff0,
  908. khaki:0xf0e68c,
  909. lavender:0xe6e6fa,
  910. lavenderblush:0xfff0f5,
  911. lawngreen:0x7cfc00,
  912. lemonchiffon:0xfffacd,
  913. lightblue:0xadd8e6,
  914. lightcoral:0xf08080,
  915. lightcyan:0xe0ffff,
  916. lightgoldenrodyellow:0xfafad2,
  917. lightgray:0xd3d3d3,
  918. lightgreen:0x90ee90,
  919. lightgrey:0xd3d3d3,
  920. lightpink:0xffb6c1,
  921. lightsalmon:0xffa07a,
  922. lightseagreen:0x20b2aa,
  923. lightskyblue:0x87cefa,
  924. lightslategray:0x778899,
  925. lightslategrey:0x778899,
  926. lightsteelblue:0xb0c4de,
  927. lightyellow:0xffffe0,
  928. lime:0x00ff00,
  929. limegreen:0x32cd32,
  930. linen:0xfaf0e6,
  931. magenta:0xff00ff,
  932. maroon:0x800000,
  933. mediumaquamarine:0x66cdaa,
  934. mediumblue:0x0000cd,
  935. mediumorchid:0xba55d3,
  936. mediumpurple:0x9370db,
  937. mediumseagreen:0x3cb371,
  938. mediumslateblue:0x7b68ee,
  939. mediumspringgreen:0x00fa9a,
  940. mediumturquoise:0x48d1cc,
  941. mediumvioletred:0xc71585,
  942. midnightblue:0x191970,
  943. mintcream:0xf5fffa,
  944. mistyrose:0xffe4e1,
  945. moccasin:0xffe4b5,
  946. navajowhite:0xffdead,
  947. navy:0x000080,
  948. oldlace:0xfdf5e6,
  949. olive:0x808000,
  950. olivedrab:0x6b8e23,
  951. orange:0xffa500,
  952. orangered:0xff4500,
  953. orchid:0xda70d6,
  954. palegoldenrod:0xeee8aa,
  955. palegreen:0x98fb98,
  956. paleturquoise:0xafeeee,
  957. palevioletred:0xdb7093,
  958. papayawhip:0xffefd5,
  959. peachpuff:0xffdab9,
  960. peru:0xcd853f,
  961. pink:0xffc0cb,
  962. plum:0xdda0dd,
  963. powderblue:0xb0e0e6,
  964. purple:0x800080,
  965. rosybrown:0xbc8f8f,
  966. royalblue:0x4169e1,
  967. saddlebrown:0x8b4513,
  968. salmon:0xfa8072,
  969. sandybrown:0xf4a460,
  970. seagreen:0x2e8b57,
  971. seashell:0xfff5ee,
  972. sienna:0xa0522d,
  973. silver:0xc0c0c0,
  974. skyblue:0x87ceeb,
  975. slateblue:0x6a5acd,
  976. slategray:0x708090,
  977. slategrey:0x708090,
  978. snow:0xfffafa,
  979. springgreen:0x00ff7f,
  980. steelblue:0x4682b4,
  981. tan:0xd2b48c,
  982. teal:0x008080,
  983. thistle:0xd8bfd8,
  984. tomato:0xff6347,
  985. turquoise:0x40e0d0,
  986. violet:0xee82ee,
  987. wheat:0xf5deb3,
  988. white:0xffffff,
  989. whitesmoke:0xf5f5f5,
  990. yellow:0xffff00,
  991. yellowgreen:0x9acd32
  992. }
  993. }
  994. class SVGPathCommandType {
  995. public static const BEGIN_FILL_COMMAND:Number = 1;
  996. public static const LINE_STYLE_COMMAND:Number = 2;
  997. public static const MOVE_TO_COMMAND:Number = 3;
  998. public static const LINE_TO_COMMAND:Number = 4;
  999. public static const CURVE_TO_COMMAND:Number = 5;
  1000. }
  1001. interface ISVGPathCommand {
  1002. function execute(graphics:Graphics):void;
  1003. }
  1004. class SVGPathCommand implements ISVGPathCommand {
  1005. private var _type:Number;
  1006. public function get type():Number { return this._type; }
  1007. public function SVGPathCommand(type:Number = 0) {
  1008. this._type = type;
  1009. }
  1010. public function execute(graphics:Graphics):void {
  1011. throw new Error('Subclass must be implement execute method.');
  1012. }
  1013. }
  1014. class BeginFillCommand extends SVGPathCommand {
  1015. private var _color:Number;
  1016. public function get color():Number { return this._color; }
  1017. private var _alpha:Number;
  1018. public function get alpha():Number { return this._alpha; }
  1019. public function BeginFillCommand(color:Number, alpha:Number) {
  1020. super(SVGPathCommandType.BEGIN_FILL_COMMAND);
  1021. this._color = color;
  1022. this._alpha = alpha;
  1023. }
  1024. public override function execute(graphics:Graphics):void {
  1025. graphics.beginFill(this._color, this._alpha);
  1026. }
  1027. }
  1028. class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1029. private var _pt1:Point;
  1030. public function get x1():Number { return this._pt1.x; }
  1031. public function get y1():Number { return this._pt1.y; }
  1032. private var _pt2:Point;
  1033. public function get x2():Number { return this._pt2.x; }
  1034. public function get y2():Number { return this._pt2.y; }
  1035. public function CurveToCommand(pt1:Point, pt2:Point) {
  1036. super(SVGPathCommandType.CURVE_TO_COMMAND);
  1037. this._pt1 = pt1;
  1038. this._pt2 = pt2;
  1039. }
  1040. public override function execute(graphics:Graphics):void {
  1041. graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
  1042. }
  1043. }
  1044. class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
  1045. private var _width:Number;
  1046. public function get width():Number { return this._width; }
  1047. private var _color:Number;
  1048. public function get color():Number { return this._color; }
  1049. private var _alpha:Number;
  1050. public function get alpha():Number { return this._alpha; }
  1051. public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
  1052. super(SVGPathCommandType.LINE_STYLE_COMMAND);
  1053. this._width = width;
  1054. this._color = color;
  1055. this._alpha = alpha;
  1056. }
  1057. public override function execute(graphics:Graphics):void {
  1058. graphics.lineStyle(this._width, this._color, this._alpha);
  1059. }
  1060. }
  1061. class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
  1062. private var _pt:Point;
  1063. public function get x():Number { return this._pt.x; }
  1064. public function get y():Number { return this._pt.y; }
  1065. public function LineToCommand(pt:Point) {
  1066. super(SVGPathCommandType.LINE_TO_COMMAND);
  1067. this._pt = pt;
  1068. }
  1069. public override function execute(graphics:Graphics):void {
  1070. graphics.lineTo(this._pt.x, this._pt.y);
  1071. }
  1072. }
  1073. class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1074. private var _pt:Point;
  1075. public function get x():Number { return this._pt.x; }
  1076. public function get y():Number { return this._pt.y; }
  1077. public function MoveToCommand(pt:Point) {
  1078. super(SVGPathCommandType.MOVE_TO_COMMAND);
  1079. this._pt = pt;
  1080. }
  1081. public override function execute(graphics:Graphics):void {
  1082. graphics.moveTo(this._pt.x, this._pt.y);
  1083. }
  1084. }
noswf
  1. // forked from Saqoosha's Sewing
  2. package {
  3. import caurina.transitions.Equations;
  4. import caurina.transitions.Tweener;
  5. import caurina.transitions.properties.CurveModifiers;
  6. import flash.display.Graphics;
  7. import flash.display.Sprite;
  8. import flash.display.StageAlign;
  9. import flash.display.StageQuality;
  10. import flash.display.StageScaleMode;
  11. import flash.events.Event;
  12. import flash.geom.Point;
  13. import flash.net.URLLoader;
  14. import flash.net.URLLoaderDataFormat;
  15. import flash.net.URLRequest;
  16. import flash.utils.setTimeout;
  17. [SWF(width=465, height=465, backgroundColor=0xffffff, frameRate=60)]
  18. public class Sewing extends Sprite {
  19. private var _loader:URLLoader;
  20. private var _canvas:Sprite;
  21. private var _paths:Array;
  22. public function Sewing() {
  23. Wonderfl.capture_delay(8);
  24. this.stage.quality = StageQuality.BEST;
  25. this.stage.align = StageAlign.TOP_LEFT;
  26. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  27. CurveModifiers.init();
  28. this._canvas = this.addChild(new Sprite()) as Sprite;
  29. this._loader = new URLLoader();
  30. this._loader.dataFormat = URLLoaderDataFormat.TEXT;
  31. this._loader.addEventListener(Event.COMPLETE, this._handleLoaded);
  32. this._loader.load(new URLRequest('http://saqoosha.net/lab/wonderfl/saqoosha.svg'));
  33. }
  34. private function _handleLoaded(e:Event):void {
  35. var svg:XML = new XML(this._loader.data);
  36. this._paths = [];
  37. var path:SVGPath;
  38. var delay:Number = 2.0;
  39. var cx:Number = parseInt(svg.@width) / 2;
  40. var cy:Number = parseInt(svg.@height) / 2;
  41. this._canvas.x = this.stage.stageWidth / 2 - cx;
  42. this._canvas.y = this.stage.stageHeight / 2 - cy;
  43. for each (var pathNode:XML in svg..*::path) {
  44. path = new SVGPath(pathNode);
  45. this._paths.push(path);
  46. var i:Number = 0;
  47. var di:Number = Math.PI * 2 / path.points.length;
  48. var px:Number = cx;
  49. var py:Number = this.stage.stageHeight - this._canvas.y;
  50. for each (var pt:Point in path.points) {
  51. Tweener.addTween(pt, {
  52. x: pt.x,
  53. y: pt.y,
  54. _bezier:[
  55. { x:cx + Math.sin(delay * 1.3) * 300 + Math.sin(delay * 10.3) * 80, y:50 },
  56. { x:100 - Math.sin(delay * 7.2) * 80, y:50 }
  57. ],
  58. time: 1.0,
  59. delay: delay,
  60. transition: Equations.easeNone
  61. });
  62. pt.x = px;
  63. pt.y = py;
  64. delay += 0.004;
  65. i += di;
  66. }
  67. }
  68. this.addEventListener(Event.ENTER_FRAME, this._drawPaths);
  69. setTimeout(function ():void {
  70. removeEventListener(Event.ENTER_FRAME, _drawPaths);
  71. }, (delay + 1) * 1000);
  72. }
  73. private function _drawPaths(e:Event):void {
  74. this._canvas.graphics.clear();
  75. for each (var path:SVGPath in this._paths) {
  76. path.draw(this._canvas.graphics);
  77. }
  78. }
  79. }
  80. }
  81. import flash.display.Graphics;
  82. import flash.geom.Point;
  83. import flash.geom.Rectangle;
  84. /**
  85. * @class PathToArray
  86. * @author Helen Triolo (with contributions from many people)
  87. * @version 1.01
  88. * @description Takes as input an SVG Path node (eg, from Illustrator 10, SVG Factory, etc, but must
  89. * not contain any CRLF characters), and an empty array.
  90. * Parses the path node to make an array of drawing commands, which include cubic bezier
  91. * draw commands. Converts the cubic beziers to an array of equivalent quad beziers,
  92. * using Robert Penner's code to convert with accuracy within 1 pixel.
  93. * Drawing commands are produced in the format originally devised by Peter Hall
  94. * in his ASVDrawing class. These are the possible elements in array dCmds (and the
  95. * corresponding Flash drawing API commands to apply them):
  96. * ['M',[x,y]] moveTo(x,y)
  97. * ['L',[x,y]] lineTo(x,y)
  98. * ['C',[cx,cy,ax,ay]] moveTo(cx,cy,ax,ay)
  99. * ['S',[width,color,alpha]] lineStyle(widtb,color,alpha)
  100. * ['F',[color,alpha]] beginFill(color,alpha)
  101. * ['EF'] endFill()
  102. * History:
  103. * v1.00 2005/11/13 Original release
  104. * v1.01 2006/05/06 Stroke corrected to stroke, line 250 (thanks Gábor Szabó)
  105. *
  106. * @param svgnode (XMLNode) Path node from SVG file
  107. * @param dCmds (Array) Empty array to write commands to
  108. */
  109. class SVGPath {
  110. private var _commands:Array;
  111. public function get commands():Array { return this._commands }
  112. private var _points:Array;
  113. public function get points():Array { return this._points }
  114. private function addPoint(... points:Array):void {
  115. for each (var pt:Point in points) {
  116. this._addPoint(pt);
  117. }
  118. }
  119. private function _addPoint(pt:Point):void {
  120. if (pt.x < this._bounds.left) {
  121. this._bounds.left = pt.x;
  122. } else if (this._bounds.right < pt.x) {
  123. this._bounds.right = pt.x;
  124. }
  125. if (pt.y < this._bounds.top) {
  126. this._bounds.top = pt.y;
  127. } else if (this._bounds.bottom < pt.y) {
  128. this._bounds.bottom = pt.y;
  129. }
  130. this._points.push(pt);
  131. }
  132. private var _bounds:Rectangle;
  133. public function get boundsRect():Rectangle { return this._bounds }
  134. private var _hasFill:Boolean;
  135. public function get hasFill():Boolean { return this._hasFill }
  136. private var _hasStroke:Boolean;
  137. public function get hasStroke():Boolean { return this._hasStroke }
  138. public function swapFillAndStroke():void {
  139. var flg:Boolean = this._hasFill;
  140. this._hasFill = this._hasStroke;
  141. this._hasStroke = flg;
  142. var val:Number = this._fillColor;
  143. this._fillColor = this._strokeColor;
  144. this._strokeColor = val;
  145. val = this._fillAlpha;
  146. this._fillAlpha = this._strokeAlpha;
  147. this._strokeAlpha = val;
  148. }
  149. private var _fillColor:Number;
  150. public function get fillColor():Number { return this._fillColor }
  151. public function set fillColor(col:Number):void { this._fillColor = col }
  152. private var _fillAlpha:Number;
  153. public function get fillAlpha():Number { return this._fillAlpha }
  154. public function set fillAlpha(al:Number):void { this._fillAlpha = al }
  155. private var _strokeColor:Number;
  156. public function get strokeColor():Number { return this._strokeColor }
  157. public function set strokeColor(col:Number):void { this._strokeColor = col }
  158. private var _strokeAlpha:Number;
  159. public function get strokeAlpha():Number { return this._strokeAlpha }
  160. public function set strokeAlpha(al:Number):void { this._strokeAlpha = al }
  161. private var _strokeWidth:Number;
  162. public function get strokeWidth():Number { return this._strokeWidth }
  163. public function set strokeWidth(wd:Number):void { this._strokeWidth = wd }
  164. /**
  165. *
  166. */
  167. public function SVGPath(svgNode:XML) {
  168. this._commands = [];
  169. this._points = [];
  170. this._bounds = new Rectangle();
  171. this._bounds.top = this._bounds.left = Number.MAX_VALUE;
  172. this._bounds.bottom = this._bounds.right = Number.MIN_VALUE;
  173. this._hasFill = false;
  174. this._hasStroke = false;
  175. this.makeDrawCmds(this.extractCmds(svgNode));
  176. }
  177. /**
  178. * @method extractCmds ()
  179. * @param node (XMLNode) SVG path node
  180. * @description Parse path node and convert to array of SVG drawing commands and data
  181. * 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,
  182. * c,-5.3,3.5,-17.3,23.5,-8.4,41.6
  183. * @returns (Array) array of drawing commands
  184. */
  185. private function extractCmds(node:XML):Array {
  186. var i:Number;
  187. var startColor:Number;
  188. var thisColor:Number;
  189. //var hasFill:Boolean = false;
  190. var hasTransform:Boolean = false;
  191. //var hasStroke:Boolean = false;
  192. var hasStrokeWidth:Boolean = false;
  193. var hasRotate:Number = 0;
  194. var dstring:String = "";
  195. var rotation:Number;
  196. // is there a fill attribute, a transform attribute, a stroke attribute?
  197. for each (var a:XML in node.attributes()) {
  198. switch (a.name().toString()) {
  199. case 'fill': this._hasFill = true; break;
  200. case 'transform': hasTransform = true; break;
  201. case 'stroke': this._hasStroke = true; break;
  202. case 'stroke-width': hasStrokeWidth = true; break;
  203. }
  204. }
  205. if (this._hasFill) {
  206. // parse for fill color specification
  207. // if a hex number is specified, startColor will be > 0
  208. // if a color name is specified, startColor will be 0
  209. var fillStr:String = node.@fill;
  210. if (fillStr == 'none') {
  211. this._hasFill = false;
  212. } else {
  213. startColor = fillStr.indexOf("#") + 1;
  214. if (startColor == 0) { // name specified instead of color number
  215. thisColor = SVGColor.getByName(fillStr);
  216. if (isNaN(thisColor)) {
  217. this._hasFill = false;
  218. } else {
  219. this._fillColor = thisColor;
  220. this._fillAlpha = 1.0;
  221. }
  222. } else {
  223. this._fillColor = parseInt(fillStr.substr(startColor, 6), 16);
  224. this._fillAlpha = 1.0;
  225. }
  226. }
  227. }
  228. // stroke: color, width, alpha
  229. if (this._hasStroke) {
  230. // parse for stroke color specification
  231. var strokeStr:String = node.@stroke;
  232. if (strokeStr == 'none') {
  233. this._hasStroke = false;
  234. } else {
  235. startColor = strokeStr.indexOf("#")+1;
  236. if (startColor == 0) { // name specified instead of color number
  237. thisColor = SVGColor.getByName(strokeStr);
  238. if (isNaN(thisColor)) {
  239. this._hasStroke = false;
  240. } else {
  241. this._strokeWidth = 0;
  242. this._strokeColor = SVGColor.getByName(strokeStr);
  243. this._strokeAlpha = 1.0;
  244. }
  245. } else {
  246. this._strokeWidth = 0;
  247. this._strokeColor = parseInt(strokeStr.substr(startColor,6),16);
  248. this._strokeAlpha = 1.0;
  249. }
  250. }
  251. }
  252. if (hasStrokeWidth) this._strokeWidth = Number(node.attribute("stroke-width"));
  253. // if stroke and fill are both undefined, set fill to black
  254. if (!this._hasFill && !this._hasStroke) {
  255. this._hasFill = true;
  256. this._fillColor = 0;
  257. this._fillAlpha = 1.0;
  258. }
  259. if (hasTransform) {
  260. // parse for rotation specification
  261. var transformStr:String = node.@transform;
  262. hasRotate = transformStr.indexOf("rotate");
  263. if (hasRotate > -1) {
  264. var startRotate:Number = transformStr.indexOf("(");
  265. var endRotate:Number = transformStr.indexOf(")");
  266. rotation = parseInt(transformStr.substr(startRotate+1, endRotate-startRotate));
  267. } else {
  268. rotation = 0;
  269. }
  270. } else rotation = 0;
  271. // if commas included, is it Adobe Illustrator (no spaces) or SVG Factory/other?
  272. dstring = node.@d;
  273. if (dstring.indexOf(",") > -1) { // has commas?
  274. if (dstring.indexOf(" ") > -1) { // yes, has spaces?
  275. // change spaces to commas, then deal as for Illustrator
  276. dstring = String2.replace(dstring," ",",");
  277. }
  278. } else { // no commas
  279. // get rid of extra spaces and change rest to commas
  280. dstring = String2.shrinkSequencesOf(dstring, " ");
  281. dstring = String2.replace(dstring, " ",",");
  282. }
  283. dstring = String2.replace(dstring, "c",",c,");
  284. dstring = String2.replace(dstring, "C",",C,");
  285. dstring = String2.replace(dstring, "S",",S,");
  286. dstring = String2.replace(dstring, "s",",s,");
  287. // separate the z from the last element
  288. dstring = String2.replace(dstring, "z",",z");
  289. // change the following if M can be mid-path
  290. dstring = String2.replace(dstring, "M","M,");
  291. dstring = String2.replace(dstring, "L",",L,");
  292. dstring = String2.replace(dstring, "l",",l,");
  293. dstring = String2.replace(dstring, "H",",H,");
  294. dstring = String2.replace(dstring, "h",",h,");
  295. dstring = String2.replace(dstring, "V",",V,");
  296. dstring = String2.replace(dstring, "v",",v,");
  297. dstring = String2.replace(dstring, "Q",",Q,");
  298. dstring = String2.replace(dstring, "q",",q,");
  299. dstring = String2.replace(dstring, "T",",T,");
  300. dstring = String2.replace(dstring, "t",",t,");
  301. // Adobe includes no delimiter before negative numbers
  302. dstring = String2.replace(dstring, "-",",-");
  303. // get rid of any dup commas we might have introduced
  304. dstring = String2.replace(dstring, ",,",",");
  305. // get rid of spaces
  306. // (cr/lf's have to be removed before the xml object can be created,
  307. // so that is done in xml.onData method)
  308. dstring = String2.replace(dstring, " ","");
  309. dstring = String2.replace(dstring, "\t","");
  310. return dstring.split(",");
  311. }
  312. /**
  313. * @method makeDrawCmds
  314. * @param svgCmds (Array) array of svg draw commands (as output from extractCmds)
  315. * @description Convert svg draw commands to array of ASVDrawing commands: _commands
  316. */
  317. private function makeDrawCmds(svgCmds:Array):void {
  318. var j:Number = 0, ii:int;
  319. var qc:Array;
  320. var firstP:Point;
  321. var lastP:Point;
  322. var lastC:Point;
  323. var cmd:String;
  324. var cp:Point, pp:Point;
  325. do {
  326. cmd = svgCmds[j++];
  327. switch (cmd) {
  328. case "M" :
  329. // moveTo point
  330. firstP = lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  331. if (this._hasFill) {
  332. _commands.push(new BeginFillCommand(this._fillColor, this._fillAlpha));
  333. }
  334. if (this._hasStroke) {
  335. _commands.push(new LineStyleCommand(this._strokeWidth, this._strokeColor, this._strokeAlpha));
  336. }
  337. _commands.push(new MoveToCommand(firstP));
  338. this.addPoint(firstP);
  339. j += 2;
  340. if (j < svgCmds.length && !isNaN(Number(svgCmds[j]))) {
  341. do {
  342. // if multiple points listed, add the rest as lineTo points
  343. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  344. _commands.push(new LineToCommand(lastP));
  345. this.addPoint(lastP);
  346. firstP = lastP;
  347. j += 2;
  348. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  349. }
  350. break;
  351. case "l" :
  352. do {
  353. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  354. _commands.push(new LineToCommand(lastP));
  355. this.addPoint(lastP);
  356. firstP = lastP;
  357. j += 2;
  358. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  359. break;
  360. case "L" :
  361. do {
  362. lastP = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  363. _commands.push(new LineToCommand(lastP));
  364. this.addPoint(lastP);
  365. firstP = lastP;
  366. j += 2;
  367. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  368. break;
  369. case "h" :
  370. do {
  371. lastP = new Point(lastP.x+Number(svgCmds[j]), lastP.y);
  372. _commands.push(new LineToCommand(lastP));
  373. this.addPoint(lastP);
  374. firstP = lastP;
  375. j += 1;
  376. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  377. break;
  378. case "H" :
  379. do {
  380. lastP = new Point(Number(svgCmds[j]), lastP.y);
  381. _commands.push(new LineToCommand(lastP));
  382. this.addPoint(lastP);
  383. firstP = lastP;
  384. j += 1;
  385. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  386. break;
  387. case "v" :
  388. do {
  389. lastP = new Point(lastP.x, lastP.y+Number(svgCmds[j]));
  390. _commands.push(new LineToCommand(lastP));
  391. this.addPoint(lastP);
  392. firstP = lastP;
  393. j += 1;
  394. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  395. break;
  396. case "V" :
  397. do {
  398. lastP = new Point(lastP.x, Number(svgCmds[j]));
  399. _commands.push(new LineToCommand(lastP));
  400. this.addPoint(lastP);
  401. firstP = lastP;
  402. j += 1;
  403. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  404. break;
  405. case "q" :
  406. do {
  407. // control is relative to lastP, not lastC
  408. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  409. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  410. _commands.push(new CurveToCommand(lastC, lastP));
  411. this.addPoint(lastC, lastP);
  412. firstP = lastP;
  413. j += 4;
  414. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  415. break;
  416. case "Q" :
  417. do {
  418. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  419. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  420. _commands.push(new CurveToCommand(lastC, lastP));
  421. this.addPoint(lastC, lastP);
  422. firstP = lastP;
  423. j += 4;
  424. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  425. break;
  426. case "c" :
  427. do {
  428. // don't save if c1.x=c1.y=c2.x=c2.y=0
  429. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  430. } else {
  431. qc = [];
  432. Math2.getQuadBez_RP(
  433. {x:lastP.x, y:lastP.y},
  434. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  435. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  436. {x:lastP.x+Number(svgCmds[j+4]), y:lastP.y+Number(svgCmds[j+5])},
  437. 1, qc);
  438. for (ii=0; ii
  439. cp = new Point(qc[ii].cx, qc[ii].cy);
  440. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  441. _commands.push(new CurveToCommand(cp, pp));
  442. this.addPoint(cp, pp);
  443. }
  444. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  445. lastP = new Point(lastP.x+Number(svgCmds[j+4]), lastP.y+Number(svgCmds[j+5]));
  446. this.addPoint(lastC, lastP);
  447. firstP = lastP;
  448. }
  449. j += 6;
  450. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  451. break;
  452. case "C" :
  453. do {
  454. // don't save if c1.x=c1.y=c2.x=c2.y=0
  455. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  456. } else {
  457. qc = [];
  458. Math2.getQuadBez_RP(
  459. {x:firstP.x, y:firstP.y},
  460. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  461. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  462. {x:Number(svgCmds[j+4]), y:Number(svgCmds[j+5])},
  463. 1, qc);
  464. for (ii=0; ii
  465. cp = new Point(qc[ii].cx, qc[ii].cy);
  466. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  467. _commands.push(new CurveToCommand(cp, pp));
  468. this.addPoint(cp, pp);
  469. }
  470. lastC = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  471. lastP = new Point(Number(svgCmds[j+4]), Number(svgCmds[j+5]));
  472. this.addPoint(lastC, lastP);
  473. firstP = lastP;
  474. }
  475. j += 6;
  476. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  477. break;
  478. case "s" :
  479. do {
  480. // don't save if c1.x=c1.y=c2.x=c2.y=0
  481. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  482. } else {
  483. qc = [];
  484. Math2.getQuadBez_RP(
  485. {x:firstP.x, y:firstP.y},
  486. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  487. {x:lastP.x+Number(svgCmds[j]), y:lastP.y+Number(svgCmds[j+1])},
  488. {x:lastP.x+Number(svgCmds[j+2]), y:lastP.y+Number(svgCmds[j+3])},
  489. 1, qc);
  490. for (ii=0; ii
  491. cp = new Point(qc[ii].cx, qc[ii].cy);
  492. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  493. _commands.push(new CurveToCommand(cp, pp));
  494. this.addPoint(cp, pp);
  495. }
  496. lastC = new Point(lastP.x+Number(svgCmds[j]), lastP.y+Number(svgCmds[j+1]));
  497. lastP = new Point(lastP.x+Number(svgCmds[j+2]), lastP.y+Number(svgCmds[j+3]));
  498. this.addPoint(lastC, lastP);
  499. firstP = lastP;
  500. }
  501. j += 4;
  502. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  503. break;
  504. case "S" :
  505. do {
  506. // don't save if c1.x=c1.y=c2.x=c2.y=0
  507. if (!Number(svgCmds[j]) && !Number(svgCmds[j+1]) && !Number(svgCmds[j+2]) && !Number(svgCmds[j+3])) {
  508. } else {
  509. qc = [];
  510. Math2.getQuadBez_RP(
  511. {x:firstP.x, y:firstP.y},
  512. {x:lastP.x + (lastP.x - lastC.x), y:lastP.y + (lastP.y - lastC.y)},
  513. {x:Number(svgCmds[j]), y:Number(svgCmds[j+1])},
  514. {x:Number(svgCmds[j+2]), y:Number(svgCmds[j+3])},
  515. 1, qc);
  516. for (ii=0; ii
  517. cp = new Point(qc[ii].cx, qc[ii].cy);
  518. pp = new Point(qc[ii].p2x, qc[ii].p2y);
  519. _commands.push(new CurveToCommand(cp, pp));
  520. this.addPoint(cp, pp);
  521. }
  522. lastC = new Point(Number(svgCmds[j]), Number(svgCmds[j+1]));
  523. lastP = new Point(Number(svgCmds[j+2]), Number(svgCmds[j+3]));
  524. this.addPoint(lastC, lastP);
  525. firstP = lastP;
  526. }
  527. j += 4;
  528. } while (j < svgCmds.length && !isNaN(Number(svgCmds[j])));
  529. break;
  530. case "z" :
  531. case "Z" :
  532. if (!firstP.equals(lastP)) {
  533. _commands.push(new LineToCommand(firstP));
  534. this.addPoint(firstP);
  535. }
  536. j++;
  537. break;
  538. } // end switch
  539. } while (j < svgCmds.length);
  540. }
  541. /**
  542. *
  543. */
  544. public function draw(graphics:Graphics):void {
  545. for each (var command:SVGPathCommand in this._commands) {
  546. command.execute(graphics);
  547. }
  548. }
  549. }
  550. class String2 {
  551. /**
  552. * @class String2
  553. * @author Helen Triolo, with inclusions from Tim Groleau
  554. * @description String functions not included in String needed for path->array conversion
  555. */
  556. /**
  557. * @method replace ()
  558. * @description Replaces sFind in s with sReplace
  559. * @param s (String) original string
  560. * @param sFind (String) part to be replaced
  561. * @param sReplace (String) string to replace it with
  562. * @returns (String) string with replacement
  563. */
  564. public static function replace(s:String, sFind:String, sReplace:String):String {
  565. return s.split(sFind).join(sReplace);
  566. }
  567. /**
  568. * @method shrinkSequencesOf (Groleau)
  569. * @description Shrinks all sequences of a given character in a string to one
  570. * @param s (String) original string
  571. * @param ch (String) character to be found
  572. * @returns (String) string with sequences shrunk
  573. */
  574. public static function shrinkSequencesOf(s:String, ch:String):String {
  575. var len:Number = s.length;
  576. var idx:Number = 0;
  577. var idx2:Number = 0;
  578. var rs:String = "";
  579. while ((idx2 = s.indexOf(ch, idx) + 1) != 0) {
  580. // include string up to first character in sequence
  581. rs += s.substring(idx, idx2);
  582. idx = idx2;
  583. // remove all subsequent characters in sequence
  584. while ((s.charAt(idx) == ch) && (idx < len)) idx++;
  585. }
  586. return rs + s.substring(idx, len);
  587. }
  588. }
  589. class Math2 {
  590. /**
  591. * @class Math2
  592. * @author Helen Triolo, with inclusions from Robert Penner, Tim Groleau
  593. * @description Math functions not included in Math needed for path->array conversion
  594. */
  595. /**
  596. * @method ratioTo (Groleau)
  597. * @description Returns the point on segment [p1,p2] which is ratio times the total distance
  598. * between p1 and p2 away from p1
  599. * @param p1 (Object) x and y values of point p1
  600. * @param p2 (Object) x and y values of point p2
  601. * @param ratio (Number) real
  602. * @returns Object
  603. */
  604. public static function ratioTo(p1:Object, p2:Object, ratio:Number):Object {
  605. return {x:p1.x + (p2.x - p1.x) * ratio, y:p1.y + (p2.y - p1.y) * ratio };
  606. }
  607. /**
  608. * @method intersect2Lines (Penner)
  609. * @description Returns the point of intersection between two lines
  610. * @param p1, p2 (Objects) points on line 1
  611. * @param p3, p4 (Objects) points on line 2
  612. * @returns Object (point of intersection)
  613. */
  614. public static function intersect2Lines (p1:Object, p2:Object, p3:Object, p4:Object):Object {
  615. var x1:Number = p1.x; var y1:Number = p1.y;
  616. var x4:Number = p4.x; var y4:Number = p4.y;
  617. var dx1:Number = p2.x - x1;
  618. var dx2:Number = p3.x - x4;
  619. if (!(dx1 || dx2)) return NaN;
  620. var m1:Number = (p2.y - y1) / dx1;
  621. var m2:Number = (p3.y - y4) / dx2;
  622. if (!dx1) {
  623. return { x:x1, y:m2 * (x1 - x4) + y4 };
  624. } else if (!dx2) {
  625. return { x:x4, y:m1 * (x4 - x1) + y1 };
  626. }
  627. var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
  628. var yInt:Number = m1 * (xInt - x1) + y1;
  629. return { x:xInt,y:yInt };
  630. }
  631. /**
  632. * @method rotation
  633. * @description Returns the angle in degrees from the horizontal to a point dy up and dx over
  634. * @param dy (Number) pixels
  635. * @param dx (Number) pixels
  636. * @returns Number (angle, degrees)
  637. */
  638. public static function rotation(dy:Number, dx:Number):Number {
  639. return Math.atan2(dy, dx) * 180/Math.PI;
  640. }
  641. /**
  642. * @method midPt
  643. * @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
  644. * @param p1x (Number) pixels
  645. * @param p1y (Number) pixels
  646. * @param p2x (Number) pixels
  647. * @param p2y (Number) pixels
  648. * @returns Object (midpoint)
  649. */
  650. public static function midPt(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Object {
  651. return {x:(p1x + p2x)/2, y:(p1y + p2y)/2};
  652. }
  653. /**
  654. * @method getQuadBez_RP (Penner)
  655. * @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
  656. * to achieve a specified tolerance
  657. * @param p1 (Object) endpoint
  658. * @param c1 (Object) 1st control point
  659. * @param c2 (Object) 2nd control point
  660. * @param p2 (Object) endpoint
  661. * @param k: tolerance (low number = most accurate result)
  662. * @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
  663. * p1x, p1y, cx, cy, p2x, p2y
  664. */
  665. public static function getQuadBez_RP(p1:Object, c1:Object, c2:Object, p2:Object, k:Number, qcurves:Array):void {
  666. // find intersection between bezier arms
  667. var s:Object = Math2.intersect2Lines (p1, c1, c2, p2);
  668. // find distance between the midpoints
  669. var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
  670. var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
  671. // split curve if the quadratic isn't close enough
  672. if (dx*dx + dy*dy > k) {
  673. var halves:Object = Math2.bezierSplit (p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
  674. var b0:Object = halves.b0; var b1:Object = halves.b1;
  675. // recursive call to subdivide curve
  676. getQuadBez_RP (p1, b0.c1, b0.c2, b0.p2, k, qcurves);
  677. getQuadBez_RP (b1.p1, b1.c1, b1.c2, p2, k, qcurves);
  678. } else {
  679. // end recursion by saving points
  680. qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
  681. }
  682. }
  683. /**
  684. * @method bezierSplit (Penner)
  685. * @description Divides a cubic bezier curve into two halves (each also cubic beziers)
  686. * @param p1x (Number) pixels, endpoint 1
  687. * @param p1y (Number) pixels
  688. * @param c1x (Number) pixels, control point 1
  689. * @param c1y (Number) pixels
  690. * @param c2x (Number) pixels, control point 2
  691. * @param c2y (Number) pixels
  692. * @param p2x (Number) pixels, endpoint 2
  693. * @param p2y (Number) pixels
  694. * @returns Object (object with two cubic bezier definitions, b0 and b1)
  695. */
  696. public static function bezierSplit(p1x:Number, p1y:Number, c1x:Number, c1y:Number, c2x:Number, c2y:Number, p2x:Number, p2y:Number):Object {
  697. var m:Function = Math2.midPt;
  698. var p1:Object = {x:p1x, y:p1y};
  699. var p2:Object = {x:p2x, y:p2y};
  700. var p01:Object = m (p1x, p1y, c1x, c1y);
  701. var p12:Object = m (c1x, c1y, c2x, c2y);
  702. var p23:Object = m (c2x, c2y, p2x, p2y);
  703. var p02:Object = m (p01.x, p01.y, p12.x, p12.y);
  704. var p13:Object = m (p12.x, p12.y, p23.x, p23.y);
  705. var p03:Object = m (p02.x, p02.y, p13.x, p13.y);
  706. /*
  707. b0:{a:p0, b:p01, c:p02, d:p03},
  708. b1:{a:p03, b:p13, c:p23, d:p3 }
  709. */
  710. return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
  711. }
  712. /**
  713. * @method pointOnCurve (Penner)
  714. * @description Returns a point on a quadratic bezier curve with Robert Penner's optimization
  715. * of the standard equation:
  716. * {x:p1x * (1-t) * (1-t) + 2 * cx * t * (1-t) + p2x * t * t,
  717. * y:p1y * (1-t) * (1-t) + 2 * cy * t * (1-t) + p2y * t * t }
  718. * @param p1x (Number) pixels, endpoint 1
  719. * @param p1y (Number) pixels
  720. * @param cx (Number) pixels, control point
  721. * @param cy (Number) pixels
  722. * @param p2x (Number) pixels, endpoint 2
  723. * @param p2y (Number) pixels
  724. * @param t (Number) if time is 0-1 along curve, value of t to find point at
  725. * @returns Object (point at time t)
  726. */
  727. public static function pointOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, t:Number):Object {
  728. var o:Object = new Object();
  729. o.x = p1x + t*(2*(1-t)*(cx-p1x) + t*(p2x - p1x));
  730. o.y = p1y + t*(2*(1-t)*(cy-p1y) + t*(p2y - p1y));
  731. return o;
  732. }
  733. /**
  734. * @method pointsOnCurve (Penner)
  735. * @description Returns an array of objects defining points on a quadratic bezier curve, each of which
  736. * includes:
  737. * x,y = location of point defining start of segment
  738. * r = rotation of segment (last entry has none because it's just a point)
  739. * n = number of subdivisions into which curve will be divided (pts = n+1)
  740. * @param p1x (Number) pixels, endpoint 1
  741. * @param p1y (Number) pixels
  742. * @param cx (Number) pixels, control point
  743. * @param cy (Number) pixels
  744. * @param p2x (Number) pixels, endpoint 2
  745. * @param p2y (Number) pixels
  746. * @param n (Number) number of points to return
  747. * @returns Array
  748. */
  749. public static function pointsOnCurve(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number, n:Number):Array {
  750. var pts:Array = [];
  751. for (var i:Number=0; i <= n; i++) {
  752. pts.push(Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, i/n));
  753. if (i > 0) {
  754. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  755. }
  756. }
  757. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  758. return pts;
  759. }
  760. /**
  761. * @method pointsOnLine (Penner)
  762. * @description Returns an array of point positions and rotations for n evenly spaced points
  763. * along a line segment
  764. * x,y = location of point defining start of segment
  765. * r = rotation of segment (last entry has none because it's just a point)
  766. * n = number of subdivisions into which curve will be divided (pts = n+1)
  767. * @param p1x (Number) pixels, endpoint 1
  768. * @param p1y (Number) pixels
  769. * @param p2x (Number) pixels, endpoint 2
  770. * @param p2y (Number) pixels
  771. * @param n (Number) number of points to return
  772. * @returns Array
  773. *//* ....................................................................
  774. Returns an array of point positions and rotation for n evenly spaced points along a line segment
  775. */
  776. public static function pointsOnLine(p1x:Number, p1y:Number, p2x:Number, p2y:Number, n:Number):Array {
  777. var pts:Array = [];
  778. if (p2x != p1x) {
  779. var m:Number = (p2y-p1y)/(p2x-p1x);
  780. var b:Number = p1y - p1x * m;
  781. for (var i:Number=0; i <= n; i++) {
  782. var x:Number = p1x + ((p2x-p1x)/n) * i;
  783. pts.push({x:x, y:m*x+b});
  784. if (i > 0) {
  785. pts[i].r = Math2.rotation(pts[i].y-pts[(i-1)].y, pts[i].x-pts[(i-1)].x);
  786. }
  787. }
  788. // vertical segment
  789. } else {
  790. for (i=0; i<=n; i++) {
  791. pts.push({x:p1x, y:p1y + ((p2y-p1y)/n) * i, r:90});
  792. }
  793. }
  794. pts.splice(0,1); // remove 1st element to return 1/n, 2/n,... n
  795. return pts;
  796. }
  797. /**
  798. * @method curveApproxLen
  799. * @description Returns the approximate length of a curved segment, found by dividing it
  800. * into two segments at t=0.5
  801. * @param p1x (Number) pixels, endpoint 1
  802. * @param p1y (Number) pixels
  803. * @param cx (Number) pixels, control point
  804. * @param cy (Number) pixels
  805. * @param p2x (Number) pixels, endpoint 2
  806. * @param p2y (Number) pixels
  807. * @returns Number
  808. */
  809. public static function curveApproxLen(p1x:Number, p1y:Number, cx:Number, cy:Number, p2x:Number, p2y:Number):Number {
  810. var mp:Object = Math2.pointOnCurve(p1x, p1y, cx, cy, p2x, p2y, 0.5);
  811. var len1:Number = Math.sqrt((mp.x - p1x) * (mp.x - p1x) + (mp.y - p1y) * (mp.y - p1y));
  812. var len2:Number = Math.sqrt((mp.x - p2x) * (mp.x - p2x) + (mp.y - p2y) * (mp.y - p2y));
  813. return len1+len2;
  814. }
  815. /**
  816. * @method lineLen
  817. * @description Returns the length of a line segment
  818. * @param p1x (Number) pixels, endpoint 1
  819. * @param p1y (Number) pixels
  820. * @param p2x (Number) pixels, endpoint 2
  821. * @param p2y (Number) pixels
  822. * @returns Number
  823. */
  824. public static function lineLen(p1x:Number, p1y:Number, p2x:Number, p2y:Number):Number {
  825. return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
  826. }
  827. /**
  828. * @method roundTo
  829. * @description Returns a number rounded to specified number of decimals
  830. * @param n (Number)
  831. * @param ndec (Number) number of decimals to round to
  832. * @returns Number
  833. */
  834. public static function roundTo(n:Number, ndec:Number):Number {
  835. var multiplier:Number = Math.pow(10, ndec);
  836. return Math.round(n*multiplier)/multiplier;
  837. }
  838. }
  839. class SVGColor {
  840. public static function getByName(name:String):Number {
  841. var col:Number = SVGColor._colorTable[name];
  842. return isNaN(col) ? 0 : col;
  843. }
  844. private static const _colorTable:Object = {
  845. blue:0x0000ff,
  846. green:0x008000,
  847. red:0xff0000,
  848. aliceblue:0xf0f8ff,
  849. antiquewhite:0xfaebd7,
  850. aqua:0x00ffff,
  851. aquamarine:0x7fffd4,
  852. azure:0xf0ffff,
  853. beige:0xf5f5dc,
  854. bisque:0xffe4c4,
  855. black:0x000000,
  856. blanchedalmond:0xffebcd,
  857. blueviolet:0x8a2be2,
  858. brown:0xa52a2a,
  859. burlywood:0xdeb887,
  860. cadetblue:0x5f9ea0,
  861. chartreuse:0x7fff00,
  862. chocolate:0xd2691e,
  863. coral:0xff7f50,
  864. cornflowerblue:0x6495ed,
  865. cornsilk:0xfff8dc,
  866. crimson:0xdc143c,
  867. cyan:0x00ffff,
  868. darkblue:0x00008b,
  869. darkcyan:0x008b8b,
  870. darkgoldenrod:0xb8860b,
  871. darkgray:0xa9a9a9,
  872. darkgreen:0x006400,
  873. darkgrey:0xa9a9a9,
  874. darkkhaki:0xbdb76b,
  875. darkmagenta:0x8b008b,
  876. darkolivegreen:0x556b2f,
  877. darkorange:0xff8c00,
  878. darkorchid:0x9932cc,
  879. darkred:0x8b0000,
  880. darksalmon:0xe9967a,
  881. darkseagreen:0x8fbc8f,
  882. darkslateblue:0x483d8b,
  883. darkslategray:0x2f4f4f,
  884. darkslategrey:0x2f4f4f,
  885. darkturquoise:0x00ced1,
  886. darkviolet:0x9400d3,
  887. deeppink:0xff1493,
  888. deepskyblue:0x00bfff,
  889. dimgray:0x696969,
  890. dimgrey:0x696969,
  891. dodgerblue:0x1e90ff,
  892. firebrick:0xb22222,
  893. floralwhite:0xfffaf0,
  894. forestgreen:0x228b22,
  895. fuchsia:0xff00ff,
  896. gainsboro:0xdcdcdc,
  897. ghostwhite:0xf8f8ff,
  898. gold:0xffd700,
  899. goldenrod:0xdaa520,
  900. gray:0x808080,
  901. grey:0x808080,
  902. greenyellow:0xadff2f,
  903. honeydew:0xf0fff0,
  904. hotpink:0xff69b4,
  905. indianred:0xcd5c5c,
  906. indigo:0x4b0082,
  907. ivory:0xfffff0,
  908. khaki:0xf0e68c,
  909. lavender:0xe6e6fa,
  910. lavenderblush:0xfff0f5,
  911. lawngreen:0x7cfc00,
  912. lemonchiffon:0xfffacd,
  913. lightblue:0xadd8e6,
  914. lightcoral:0xf08080,
  915. lightcyan:0xe0ffff,
  916. lightgoldenrodyellow:0xfafad2,
  917. lightgray:0xd3d3d3,
  918. lightgreen:0x90ee90,
  919. lightgrey:0xd3d3d3,
  920. lightpink:0xffb6c1,
  921. lightsalmon:0xffa07a,
  922. lightseagreen:0x20b2aa,
  923. lightskyblue:0x87cefa,
  924. lightslategray:0x778899,
  925. lightslategrey:0x778899,
  926. lightsteelblue:0xb0c4de,
  927. lightyellow:0xffffe0,
  928. lime:0x00ff00,
  929. limegreen:0x32cd32,
  930. linen:0xfaf0e6,
  931. magenta:0xff00ff,
  932. maroon:0x800000,
  933. mediumaquamarine:0x66cdaa,
  934. mediumblue:0x0000cd,
  935. mediumorchid:0xba55d3,
  936. mediumpurple:0x9370db,
  937. mediumseagreen:0x3cb371,
  938. mediumslateblue:0x7b68ee,
  939. mediumspringgreen:0x00fa9a,
  940. mediumturquoise:0x48d1cc,
  941. mediumvioletred:0xc71585,
  942. midnightblue:0x191970,
  943. mintcream:0xf5fffa,
  944. mistyrose:0xffe4e1,
  945. moccasin:0xffe4b5,
  946. navajowhite:0xffdead,
  947. navy:0x000080,
  948. oldlace:0xfdf5e6,
  949. olive:0x808000,
  950. olivedrab:0x6b8e23,
  951. orange:0xffa500,
  952. orangered:0xff4500,
  953. orchid:0xda70d6,
  954. palegoldenrod:0xeee8aa,
  955. palegreen:0x98fb98,
  956. paleturquoise:0xafeeee,
  957. palevioletred:0xdb7093,
  958. papayawhip:0xffefd5,
  959. peachpuff:0xffdab9,
  960. peru:0xcd853f,
  961. pink:0xffc0cb,
  962. plum:0xdda0dd,
  963. powderblue:0xb0e0e6,
  964. purple:0x800080,
  965. rosybrown:0xbc8f8f,
  966. royalblue:0x4169e1,
  967. saddlebrown:0x8b4513,
  968. salmon:0xfa8072,
  969. sandybrown:0xf4a460,
  970. seagreen:0x2e8b57,
  971. seashell:0xfff5ee,
  972. sienna:0xa0522d,
  973. silver:0xc0c0c0,
  974. skyblue:0x87ceeb,
  975. slateblue:0x6a5acd,
  976. slategray:0x708090,
  977. slategrey:0x708090,
  978. snow:0xfffafa,
  979. springgreen:0x00ff7f,
  980. steelblue:0x4682b4,
  981. tan:0xd2b48c,
  982. teal:0x008080,
  983. thistle:0xd8bfd8,
  984. tomato:0xff6347,
  985. turquoise:0x40e0d0,
  986. violet:0xee82ee,
  987. wheat:0xf5deb3,
  988. white:0xffffff,
  989. whitesmoke:0xf5f5f5,
  990. yellow:0xffff00,
  991. yellowgreen:0x9acd32
  992. }
  993. }
  994. class SVGPathCommandType {
  995. public static const BEGIN_FILL_COMMAND:Number = 1;
  996. public static const LINE_STYLE_COMMAND:Number = 2;
  997. public static const MOVE_TO_COMMAND:Number = 3;
  998. public static const LINE_TO_COMMAND:Number = 4;
  999. public static const CURVE_TO_COMMAND:Number = 5;
  1000. }
  1001. interface ISVGPathCommand {
  1002. function execute(graphics:Graphics):void;
  1003. }
  1004. class SVGPathCommand implements ISVGPathCommand {
  1005. private var _type:Number;
  1006. public function get type():Number { return this._type; }
  1007. public function SVGPathCommand(type:Number = 0) {
  1008. this._type = type;
  1009. }
  1010. public function execute(graphics:Graphics):void {
  1011. throw new Error('Subclass must be implement execute method.');
  1012. }
  1013. }
  1014. class BeginFillCommand extends SVGPathCommand {
  1015. private var _color:Number;
  1016. public function get color():Number { return this._color; }
  1017. private var _alpha:Number;
  1018. public function get alpha():Number { return this._alpha; }
  1019. public function BeginFillCommand(color:Number, alpha:Number) {
  1020. super(SVGPathCommandType.BEGIN_FILL_COMMAND);
  1021. this._color = color;
  1022. this._alpha = alpha;
  1023. }
  1024. public override function execute(graphics:Graphics):void {
  1025. graphics.beginFill(this._color, this._alpha);
  1026. }
  1027. }
  1028. class CurveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1029. private var _pt1:Point;
  1030. public function get x1():Number { return this._pt1.x; }
  1031. public function get y1():Number { return this._pt1.y; }
  1032. private var _pt2:Point;
  1033. public function get x2():Number { return this._pt2.x; }
  1034. public function get y2():Number { return this._pt2.y; }
  1035. public function CurveToCommand(pt1:Point, pt2:Point) {
  1036. super(SVGPathCommandType.CURVE_TO_COMMAND);
  1037. this._pt1 = pt1;
  1038. this._pt2 = pt2;
  1039. }
  1040. public override function execute(graphics:Graphics):void {
  1041. graphics.curveTo(this._pt1.x, this._pt1.y, this._pt2.x, this._pt2.y);
  1042. }
  1043. }
  1044. class LineStyleCommand extends SVGPathCommand implements ISVGPathCommand {
  1045. private var _width:Number;
  1046. public function get width():Number { return this._width; }
  1047. private var _color:Number;
  1048. public function get color():Number { return this._color; }
  1049. private var _alpha:Number;
  1050. public function get alpha():Number { return this._alpha; }
  1051. public function LineStyleCommand(width:Number, color:Number, alpha:Number) {
  1052. super(SVGPathCommandType.LINE_STYLE_COMMAND);
  1053. this._width = width;
  1054. this._color = color;
  1055. this._alpha = alpha;
  1056. }
  1057. public override function execute(graphics:Graphics):void {
  1058. graphics.lineStyle(this._width, this._color, this._alpha);
  1059. }
  1060. }
  1061. class LineToCommand extends SVGPathCommand implements ISVGPathCommand {
  1062. private var _pt:Point;
  1063. public function get x():Number { return this._pt.x; }
  1064. public function get y():Number { return this._pt.y; }
  1065. public function LineToCommand(pt:Point) {
  1066. super(SVGPathCommandType.LINE_TO_COMMAND);
  1067. this._pt = pt;
  1068. }
  1069. public override function execute(graphics:Graphics):void {
  1070. graphics.lineTo(this._pt.x, this._pt.y);
  1071. }
  1072. }
  1073. class MoveToCommand extends SVGPathCommand implements ISVGPathCommand {
  1074. private var _pt:Point;
  1075. public function get x():Number { return this._pt.x; }
  1076. public function get y():Number { return this._pt.y; }
  1077. public function MoveToCommand(pt:Point) {
  1078. super(SVGPathCommandType.MOVE_TO_COMMAND);
  1079. this._pt = pt;
  1080. }
  1081. public override function execute(graphics:Graphics):void {
  1082. graphics.moveTo(this._pt.x, this._pt.y);
  1083. }
  1084. }
noswf
Get Adobe Flash Player