forked from: SVG Shape Tween
forked from SVG Shape Tween (diff: 3)
べつのSVGデータつっこんでみた
ActionScript3 source code
/**
* Copyright kjkmr ( http://wonderfl.net/user/kjkmr )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/9stz
*/
// forked from kjkmr's SVG Shape Tween
package {
import flash.display.Sprite;
import flash.display.Shape;
import flash.events.Event;
import caurina.transitions.Tweener;
public class Main extends Sprite {
private var _container:Sprite = new Sprite();
private var _from:BezierPath = new BezierPath(<path fill="none" stroke="#000000" stroke-miterlimit="10" d="M259.409,228.915c0.871,3.391,2.155,10.503-0.082,13.785c-2.498,3.663-9.771,3.816-13.69,3.644c-5.763-0.253-10.446-1.937-12.633-7.549c-2.265-5.814-1.179-12.968-0.73-19.003c0.342-4.603,0.208-9.702,2.876-13.698c3.069-4.599,8.255-3.992,13.292-3.927c11.407,0.148,21.639,2.093,31.095,8.514c11.521,7.824,13.678,23.061,13.9,36.129c0.171,10.025,0.762,21.703-8.968,27.578c-12.647,7.639-33.328,8.913-47.642,8.088c-18.578-1.072-36.139-17.798-38.518-36.1c-1.234-9.497-1.976-21.791,0.386-31.14c4.147-16.417,14.346-25.93,28.537-33.719c14.672-8.052,33.784-22.612,51.868-16.895c24.198,7.651,45.822,31.256,55.526,54.293c5.037,11.958,5.328,25.756,5.392,38.523c0.091,18.228-0.152,34.473-7.449,51.488c-3.595,8.384-6.623,16.387-14.318,21.654c-11.177,7.649-25.37,8.245-38.417,8.602c-18.847,0.514-37.969,1.008-56.763-0.754c-16.141-1.513-35.826-6.772-48.252-17.88c-3.93-3.513-6.35-8.752-8.836-13.263c-8.047-14.6-13.771-29.454-15.45-46.171c-1.546-15.402-0.121-30.968,0.843-46.345c0.976-15.57,0.532-32.115,6.15-46.933c4.414-11.643,12.268-21.421,20.249-30.777c8.225-9.643,16.214-18.549,27.771-24.138c23.298-11.267,48.359-13.579,73.82-13.622c21.765-0.037,40.375,0.343,60.033,10.832c16.9,9.017,26.924,22.811,38.402,37.755c22.299,29.031,38.854,61.307,39.895,98.377c0.659,23.471,2.531,49.52-2.784,72.568c-5.601,24.282-16.646,50.431-35.391,67.587c-33.648,30.799-85.845,36.571-128.74,26.605c-17.208-3.997-32.647-12.098-50.48-12.854"/>);
private var _to:BezierPath = new BezierPath(<path fill="none" stroke="#000000" stroke-miterlimit="10" d="M262.333,348.333c-7.113,10.367-19.845,19.687-29.163,28.053c-26.938,24.188-56.674,44.895-86.334,65.54c-18.637,12.973-36.49,22.023-58.348,28.256c-3.856,1.1-8.066,1.993-11.737,3.464c16.096-41.013,42.284-79.211,72.668-110.781c18.663-19.392,39.125-37.167,57.089-57.211c-7.938-2.289-15.633-7.031-23.094-10.356c-28.783-12.825-59.233-21.449-88.27-33.643c-16.57-6.959-32.677-15.89-48.222-24.424c52.128-18.745,104.063-45.127,159.744-51.584c5.573-0.646,11.267-1.596,16.941-1.293c0.232-23.333,4.497-46.362,7.6-69.478c2.475-18.435,5.46-36.511,9.038-54.754c0.695-3.542,2.757-29.862,5.785-30.275c9.401,17.045,20.415,33.311,28.952,50.825c6.21,12.741,14.563,27.08,18.632,40.566c1.609,5.335,2.102,10.771,3.939,16.188c1.978,5.827,5.459,24.04,11.684,26.193c3.197,1.105,13.793-3.261,15.971-3.888c15.771-4.544,29.842-10.076,44.779-16.757c15.354-6.867,31.445-8.613,47.899-10.671c19.773-2.473,41.36-1.395,61.061,0.131c-2.57,2.928-5.975,3.25-9.897,5.31c-11.169,5.868-20.455,16.85-29.608,25.22c-11.042,10.098-22.717,19.264-34.369,28.631c-21.9,17.606-43.727,34.923-66.333,51.606c-9.036,6.669-16.836,15.128-23.892,23.821c7.371,8.037,13.051,18.396,18.753,27.637c21.96,35.59,46.294,70.121,64.236,108.023c9.852,20.813,16.615,43.554,22.273,65.728c-5.667-2.501-10.751-7.911-15.509-11.684c-13.941-11.057-28.348-20.29-43.771-29.032c-15.944-9.037-30.906-19.754-46.483-29.324c-13.264-8.149-28.45-15.496-41.047-24.604c-2.977-2.152-4.878-5.17-8.302-6.767"/>);
private var _motion:PathMotion = new PathMotion( _container.graphics, _from, _to );
public function Main() {
stage.align = "LT";
stage.scaleMode = "noScale";
addChild( _container );
Tweener.addTween( _motion, { position:1, time:1, delay:1, transition:"easeInOutCubic", onComplete:_reverse } );
}
private function _reverse():void {
_motion.reverse();
Tweener.addTween( _motion, { position:1, time:1, delay:0, transition:"easeInOutCubic", onComplete:_reverse } );
}
}
}
/*--------------------------------------------------
* 3次ベジェ曲線のアンカーポイントのデータ
* jp.kimulabo.display.bezier.Anchor
--------------------------------------------------*/
class Anchor {
/*--------------------------------------------------
* インスタンス変数
--------------------------------------------------*/
public var x:Number; // x座標
public var y:Number; // y座標
public var prevX:Number; // 前のコントロールポイントのx座標
public var prevY:Number; // 前のコントロールポイントのy座標
public var nextX:Number; // 次のコントロールポイントのx座標
public var nextY:Number; // 次のコントロールポイントのy座標
/*--------------------------------------------------
* コンストラクタ
--------------------------------------------------*/
public function Anchor( i_x:Number = 0, i_y:Number = 0, i_prevX:Number = NaN, i_prevY:Number = NaN, i_nextX:Number = NaN, i_nextY:Number = NaN ) {
x = i_x;
y = i_y;
prevX = i_prevX || x;
prevY = i_prevY || y;
nextX = i_nextX || x;
nextY = i_nextY || y;
}
/*--------------------------------------------------
* toString()
--------------------------------------------------*/
public function toString():String {
return "Anchor{ x:"+x+", y:"+y+", prevX:"+prevX+", prevY:"+prevY+", nextX:"+nextX+", nextY:"+nextY+" }";
}
/*--------------------------------------------------
* clone()
--------------------------------------------------*/
public function clone():Anchor {
return new Anchor( x, y, prevX, prevY, nextX, nextY );
}
}
import flash.display.Graphics;
import flash.geom.Point;
/*--------------------------------------------------
* 3次ベジェ曲線のパスのデータ
* jp.kimulabo.display.bezier.BezierPath
--------------------------------------------------*/
class BezierPath {
/*--------------------------------------------------
* 定数
--------------------------------------------------*/
public static const DIVISION:uint = 8;
public static const DATA_REG:RegExp = /[MmLlCcHhVvSs][0-9,.-]+/;
/*--------------------------------------------------
* インスタンス変数
--------------------------------------------------*/
public var anchors:Array = [];
public var random:Number = 2;
/*--------------------------------------------------
* コンストラクタ
--------------------------------------------------*/
public function BezierPath( ... args ) {
if ( args[0] is XML ) parseSVG( args[0] );
else push.apply( this, args );
}
/*--------------------------------------------------
* アンカーポイントを最後に追加
--------------------------------------------------*/
public function push( ... args ):void {
var i:uint, l:uint = args.length;
for ( i=0; i<l; i++ ) {
if ( args[i] is Anchor ) {
anchors.push( args[i] );
} else if ( args[i] is Array ) {
push.apply( this, args[i] );
} else {
throw("Invalid Argument ( "+ args[i] + " )");
}
}
}
/*--------------------------------------------------
* 最後のアンカーポイントを削除
--------------------------------------------------*/
public function pop():Anchor {
var a:Anchor = anchors.pop();
return a;
}
/*--------------------------------------------------
* 特定のアンカーポイントの前にアンカーポイントを追加
--------------------------------------------------*/
public function before( i_anchor:Anchor, ... args ):void {
var i:uint, index:int = -1, l:uint = anchors.length;
for ( i=0; i<l; i++ ) {
if ( anchors[i] == i_anchor ) {
index = i;
break;
}
}
if ( index < 0 ) return;
var b:Array = anchors.splice( 0, index );
l = args.length;
for ( i=0; i<l; i++ ) {
if ( args[i] is Anchor ) b.push( args[i] );
else if ( args[i] is Array ) b = b.concat( args[i] );
else throw("Invalid Argument ( "+args[i]+" )");
}
anchors = b.concat( anchors );
}
/*--------------------------------------------------
* アンカーポイントの数
--------------------------------------------------*/
public function get length():uint { return anchors.length; }
public function set length( i_value:uint ):void {
while ( anchors.length < i_value ) anchors.push( anchors[ anchors.length - 1].clone() );
}
/*--------------------------------------------------
* 特定のアンカーポイントの後にアンカーポイントを追加
--------------------------------------------------*/
public function after( i_anchor:Anchor, ... args ):void {
var i:uint, index:int = -1, l:uint = anchors.length;
for ( i=0; i<l; i++ ) {
if ( anchors[i] == i_anchor ) {
index = i;
break;
}
}
if ( index < 0 ) return;
var b:Array = anchors.splice( 0, index + 1 );
l = args.length;
for ( i=0; i<l; i++ ) {
if ( args[i] is Anchor ) b.push( args[i] );
else if ( args[i] is Array ) b = b.concat( args[i] );
else throw("Invalid Argument ( "+args[i]+" )");
}
anchors = b.concat( anchors );
}
/*--------------------------------------------------
* 複製
--------------------------------------------------*/
public function clone():BezierPath {
var i:uint, l:uint = anchors.length;
var a:Array = [];
for ( i=0; i<l; i++ ) a.push( anchors[i].clone() );
return new BezierPath( a );
}
/*--------------------------------------------------
* SVGをパース
--------------------------------------------------*/
public function parseSVG( i_xml:XML ):void {
var d:String = i_xml.@d;
var pt:Point = new Point();
var px:Number, py:Number, nx:Number, ny:Number;
var s:int, m:String, t:String, tt:String, n:Array;
var prev:Anchor;
s = d.search( DATA_REG );
if ( s < 0 ) return;
anchors = [];
while( s >= 0 ) {
m = d.match( DATA_REG )[0];
t = m.substr(0,1);
tt = m.substr(1);
while( tt.match(/([0-9])-/) ) tt = tt.replace(/([0-9])-/,"$1,-");
n = tt.split(",");
switch( t ) {
/* 移動 */
case "m":
pt.x += parseFloat(n[0]);
pt.y += parseFloat(n[1]);
push( new Anchor( pt.x, pt.y ) );
break;
case "M":
pt.x = parseFloat(n[0]);
pt.y = parseFloat(n[1]);
push( new Anchor( pt.x, pt.y ) );
break;
/* 水平線 */
case "h":
pt.x += parseFloat(n[0]);
push( new Anchor( pt.x, pt.y ) );
break;
case "H":
pt.x = parseFloat(n[0]);
push( new Anchor( pt.x, pt.y ) );
break;
/* 垂直線 */
case "v":
pt.y += parseFloat(n[0]);
push( new Anchor( pt.x, pt.y ) );
break;
case "V":
pt.y = parseFloat(n[0]);
push( new Anchor( pt.x, pt.y ) );
break;
/* 直線 */
case "l":
pt.x += parseFloat(n[0]);
pt.y += parseFloat(n[1]);
push( new Anchor( pt.x, pt.y ) );
break;
case "L":
pt.x = parseFloat(n[0]);
pt.y = parseFloat(n[1]);
push( new Anchor( pt.x, pt.y ) );
break;
/* 三次ベジェ */
case "c":
nx = pt.x + parseFloat(n[0]);
ny = pt.y + parseFloat(n[1]);
px = pt.x + parseFloat(n[2]);
py = pt.y + parseFloat(n[3]);
pt.x += parseFloat(n[4]);
pt.y += parseFloat(n[5]);
if ( anchors.length ) {
prev = anchors[anchors.length - 1];
prev.nextX = nx;
prev.nextY = ny;
}
push( new Anchor( pt.x, pt.y, px, py ) );
break;
case "C":
nx = parseFloat(n[0]);
ny = parseFloat(n[1]);
px = parseFloat(n[2]);
py = parseFloat(n[3]);
pt.x += parseFloat(n[4]);
pt.y += parseFloat(n[5]);
if ( anchors.length ) {
prev = anchors[anchors.length - 1];
prev.nextX = nx;
prev.nextY = ny;
}
push( new Anchor( pt.x, pt.y, px, py ) );
break;
/* 省略型滑三次ベジェ */
case "s":
px = pt.x + parseFloat(n[0]);
py = pt.y + parseFloat(n[1]);
pt.x += parseFloat(n[2]);
pt.y += parseFloat(n[3]);
if ( anchors.length ) {
prev = anchors[anchors.length - 1];
prev.nextX = isNaN(prev.prevX) ? prev.x : prev.x + ( prev.x - prev.prevX );
prev.nextY = isNaN(prev.prevY) ? prev.y : prev.y + ( prev.y - prev.prevY );
}
push( new Anchor( pt.x, pt.y, px, py ) );
break;
case "S":
nx = parseFloat(n[0]);
ny = parseFloat(n[1]);
px = parseFloat(n[2]);
py = parseFloat(n[3]);
pt.x += parseFloat(n[4]);
pt.y += parseFloat(n[5]);
if ( anchors.length ) {
prev = anchors[anchors.length - 1];
prev.nextX = isNaN(prev.prevX) ? prev.x : prev.x + ( prev.x - prev.prevX );
prev.nextY = isNaN(prev.prevY) ? prev.y : prev.y + ( prev.y - prev.prevY );
}
push( new Anchor( pt.x, pt.y, px, py ) );
break;
default:
trace(t);
break;
}
//
d = d.substr( m.length );
s = d.search( DATA_REG );
}
}
/*--------------------------------------------------
* Graphics描画
* 分割して3次ベジェを2次ベジェに変換して描画
--------------------------------------------------*/
public function redraw( i_graphics:Graphics ):void {
i_graphics.clear();
draw( i_graphics );
}
public function draw( i_graphics:Graphics ):void {
//初期化
if ( !anchors.length ) return;
var i:uint;
var l:uint = anchors.length - 1;
var t:Number;
var offset:Number = 1 / DIVISION;
var pt1:Point;
var pt2:Point;
var pt3:Point;
var sa:Anchor, ea:Anchor;
var s:Boolean, e:Boolean;
var b:BezierSegment;
i_graphics.lineStyle( 1, 0 );
i_graphics.moveTo( anchors[0].x, anchors[0].y );
for ( i=0; i<l; i++ ) {
sa = anchors[i];
ea = anchors[i+1];
if ( sa.x == ea.x && sa.y == ea.y ) continue;
//コントロールポイントの有無
s = ( !isNaN( sa.nextX ) && !isNaN( sa.nextY ) ) as Boolean;
e = ( !isNaN( ea.prevX ) && !isNaN( ea.prevY ) ) as Boolean;
if ( s && e ) {
//3次ベジェを分割して近似2次ベジェに変換
b = new BezierSegment(
new Point( sa.x, sa.y ),
new Point( sa.nextX || 0, sa.nextY || 0 ),
new Point( ea.prevX || 0, ea.prevY || 0 ),
new Point( ea.x, ea.y )
);
t = 0;
while ( t < 1.0 - offset ) {
pt1 = b.getValue(t);
t += offset;
pt2 = b.getValue(t);
t += offset;
pt3 = b.getValue(t);
pt2 = new Point(
pt2.x * 2 - ( pt1.x + pt3.x ) * 0.5,
pt2.y * 2 - ( pt1.y + pt3.y ) * 0.5
);
if ( random != 0 ) {
pt2.x += Math.random() * random - random * 0.5;
pt2.y += Math.random() * random - random * 0.5;
pt3.x += Math.random() * random - random * 0.5;
pt3.y += Math.random() * random - random * 0.5;
}
i_graphics.curveTo( pt2.x, pt2.y, pt3.x, pt3.y );
}
} else {
//直線
i_graphics.lineTo( ea.x, ea.y );
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
/*--------------------------------------------------
* 3次ベジェ曲線のパスのデータのシェイプトゥイーン
* jp.kimulabo.display.bezier.PathMotion
--------------------------------------------------*/
class PathMotion {
/*--------------------------------------------------
* 定数
--------------------------------------------------*/
/*--------------------------------------------------
* インスタンス変数
--------------------------------------------------*/
private var _graphics:Graphics;
private var _path:BezierPath;
private var _from:BezierPath;
private var _to:BezierPath;
private var _position:Number = 0;
/*--------------------------------------------------
* コンストラクタ
--------------------------------------------------*/
public function PathMotion( i_graphics:Graphics, i_from:BezierPath = null, i_to:BezierPath = null ) {
_graphics = i_graphics;
from = i_from;
to = i_to;
}
/*--------------------------------------------------
* getter & setter for from / to
--------------------------------------------------*/
public function get from():BezierPath { return _from; }
public function set from( i_value:BezierPath ):void {
_from = i_value;
if ( _from ) _path = _from.clone();
adjustLength();
position = _position;
}
public function get to():BezierPath { return _to; }
public function set to( i_value:BezierPath ):void {
_to = i_value;
adjustLength();
position = _position;
}
public function adjustLength():void {
if ( !_from || !_to || !_path ) return;
_from.length = _to.length;
_to.length = _from.length;
_path.length = _from.length;
}
/*--------------------------------------------------
* reverse();
--------------------------------------------------*/
public function reverse():void {
var f:BezierPath = _from;
_from = _to;
_to = f;
position = 1-_position;
}
/*--------------------------------------------------
* getter & setter for position
--------------------------------------------------*/
public function get position():Number { return _position; }
public function set position( i_value:Number ):void {
if ( !_from || !_to ) return;
_position = i_value;
var i:uint, l:uint = _path.length;
var a:Anchor, from:Anchor, to:Anchor;
for ( i=0; i<l; i++ ) {
a = _path.anchors[i];
from = _from.anchors[i];
to = _to.anchors[i];
a.x = from.x + ( to.x - from.x ) * _position;
a.y = from.y + ( to.y - from.y ) * _position;
a.prevX = from.prevX + ( to.prevX - from.prevX ) * _position;
a.prevY = from.prevY + ( to.prevY - from.prevY ) * _position;
a.nextX = from.nextX + ( to.nextX - from.nextX ) * _position;
a.nextY = from.nextY + ( to.nextY - from.nextY ) * _position;
}
_path.redraw( _graphics );
}
}
/*--------------------------------------------------
* BezierSegment
*
* wonderflに fl.motion.BezierSegment がないから、@nanlow さんのを拝借してちょっと修正
* http://wonderfl.net/c/dHyt
*
--------------------------------------------------*/
class BezierSegment {
private var _anchor0:Point;
private var _anchor1:Point;
private var _controll0:Point;
private var _controll1:Point;
public function BezierSegment(anchor0:Point, controll0:Point, controll1:Point, anchor1:Point) {
_anchor0 = anchor0;
_anchor1 = anchor1;
_controll0 = controll0;
_controll1 = controll1;
}
public function getValue(per:Number):Point {
if (per < 0 || 1 < per) {
throw new Error(' 0≦per≦1でお願いしますm(_ _;)m');
}
var p:Number = 1 - per;
return new Point(p * p * p * _anchor0.x + 3 * p * p * per * _controll0.x + 3 * p * per * per * _controll1.x + per * per * per * _anchor1.x,p * p * p * _anchor0.y + 3 * p * p * per * _controll0.y + 3 * p * per * per * _controll1.y + per * per * per * _anchor1.y);
}
}
