Line Strokes
まだ少し曲がり角が怪しい。
/**
* Copyright gupon ( http://wonderfl.net/user/gupon )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/2lQp
*/
/*
* まだ少し曲がり角が怪しい。
*/
package {
import caurina.transitions.Tweener;
import caurina.transitions.properties.ColorShortcuts;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
import net.hires.debug.Stats;
[SWF(frameRate="60", width="600", height="600", backgroundColor="#DDDDDD")]
public class LineStrokes extends Sprite{
private var curr:Sprite;
private var prev:Sprite;
public function LineStrokes(){
if ( stage ) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(event:Event=null):void{
removeEventListener(Event.ADDED_TO_STAGE, init);
firstRun();
startTimer();
}
private function firstRun():void{
addChild(new Stats());
curr = new Sprite();
addChild(curr);
curr.addChild(new LineStroke2());
}
private function updateView(event:TimerEvent):void{
prev = curr;
curr = new Sprite();
curr.alpha = 0;
addChild(curr);
for(var i:int=0;i<2;i++){
curr.addChild(new LineStroke2());
}
ColorShortcuts.init();
Tweener.addTween( curr, { alpha:1, delay:1 });
Tweener.addTween( curr, { _color:0xFC4E16, time:1, delay:1 });
Tweener.addTween( prev, { _color:0xDDDDDD, time:1, delay:1, onComplete:removePrev});
function removePrev():void{
while( prev.getChildAt(0) ) prev.removeChildAt(0);
removeChild(prev);
}
}
private function startTimer():void{
var timer:Timer = new Timer(3000);
timer.addEventListener( TimerEvent.TIMER, updateView);
timer.start();
}
}
}
import __AS3__.vec.Vector;
import flash.display.GraphicsPathCommand;
import flash.display.Sprite;
import flash.events.Event;
class LineStroke2 extends Sprite{
private const SEGMENT_NUM:int = 10;
private const RANGE:Number = 300;
private const RAD_RANGE:Number = 90;
private const WEIGHT:Number = 40;
private var commands:Vector.<int>;
private var data:Vector.<Number>;
private var gc:GraphicsController;
public var progress:Number = 0;
public function LineStroke2(){
if ( stage ) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(event:Event=null):void{
removeEventListener(Event.ADDED_TO_STAGE, init);
gc = new GraphicsController(graphics);
generateLine();
addEventListener( Event.ENTER_FRAME, offsetStroke );
addEventListener( Event.REMOVED, removed);
}
private function generateLine():void{
commands = new Vector.<int>();
data = new Vector.<Number>();
var px0:Number = Math.random() * stage.stageWidth;
var py0:Number = Math.random() * stage.stageHeight;
var cx0:Number = px0 + Math.random() * RANGE - RANGE / 2;
var cy0:Number = py0 + Math.random() * RANGE - RANGE / 2;
commands.push(GraphicsPathCommand.WIDE_MOVE_TO);
data.push( 0, 0, px0, py0, cx0, cy0 );
for(var i:int=0;i<SEGMENT_NUM;i++){
var prevCX:Number = data[(i+1)*4 ];
var prevCY:Number = data[(i+1)*4+1];
var prevPX:Number = data[i*4+2];
var prevPY:Number = data[i*4+3];
do {
var cx:Number = Math.random() * stage.stageWidth;
var cy:Number = Math.random() * stage.stageHeight;
var radian:Number = Math.abs(Math.atan2(prevCY-prevPY,prevCX-prevPX) - Math.atan2(cy-prevPY,cx-prevPX))*180/Math.PI;
var dist:Number = Math.sqrt(Math.pow(cx - prevCX, 2) + Math.pow(cy - prevCY,2));
} while ( ((radian + RAD_RANGE/2 ) % 180 < RAD_RANGE) || dist < 75 );
var px:Number = ( cx + prevCX ) / 2;
var py:Number = ( cy + prevCY ) / 2;
commands.push( GraphicsPathCommand.CURVE_TO );
data.push( px, py, cx, cy );
}
}
private function offsetStroke(event:Event):void{
progress += .002;
graphics.clear();
for(var i:int=0;i<WEIGHT;i+=1){
var f:Number = progress;
var f0:Number = progress - 0.1 - (1-(i/WEIGHT))*.1;
if( f0 < 0 ) f0 = 0;
else if ( f0 > 1 ) f0 = 1;
if( f > 1 ) f = 1;
gc.drawLine(commands,data,i,0xFC4E16, f, f0);
}
}
private function removed( event:Event ):void{
removeEventListener( Event.REMOVED, removed );
removeEventListener( Event.ENTER_FRAME, offsetStroke);
}
}
import __AS3__.vec.Vector;
import flash.display.Graphics;
import flash.display.GraphicsPathCommand;
import flash.geom.Point;
class GraphicsController {
private var g:Graphics;
public var speed:Number;
public var thickness:Number = 1;
public var color:Number = 0x3388DD;
private var _degree:Number;
private var _innerRadius:Number;
private var _radius:Number;
private var commands:Vector.<int>;
private var data:Vector.<Number>;
private var _f:Number;
private var _f0:Number;
public function GraphicsController(graphics:Graphics){
this.g = graphics;
}
/**
* 弧をdrawPathで描画するためのデータを返します
*/
public function objectArc(radius:Number, degree:Number, opposite:Boolean=false):Object{
//最終的に返す値。
var commands:Vector.<int> = new Vector.<int>();
var data:Vector.<Number> = new Vector.<Number>();
if( Math.abs(degree) > 360 ) degree %= 360;
var div:int = Math.ceil(degree/30);
var radians:Number = degree * Math.PI / 180;
var segment:Number = radians / div;
var _from:Number;
var _to:Number;
for(var i:int;i<div;i++){
//曲線の分割
if( opposite ){
_from = ( i == 0 ) ? radians : segment * ( div - i );
_to = ( div - i - 1 ) * segment;
} else {
_from = segment * i;
_to = (i == div-1) ? radians : segment * (i+1);
}
//初回ループ時に、最初の点に移動
if( i == 0 ){
var startPos:Point = new Point();
startPos.x = Math.cos(_from) * radius;
startPos.y = Math.sin(_from) * radius;
commands.push(2);
data.push(startPos.x, startPos.y);
}
//終着点
var endPos:Point = new Point();
endPos.x = Math.cos(_to) * radius;
endPos.y = Math.sin(_to) * radius;
//コントロールポイント
var controlPos:Point = new Point();
var basePos:Point = opposite ? endPos : startPos;
var rotate:Number = opposite ? _to : _from;
controlPos.y = radius * Math.tan(Math.abs(_to - _from)/2);
controlPos.x = basePos.x - Math.sin(rotate) * controlPos.y;
controlPos.y = basePos.y + Math.cos(rotate) * controlPos.y;
//Vectorに格納
commands.push(3);
data.push(controlPos.x, controlPos.y, endPos.x, endPos.y);
//次のループのために始点を移動
startPos.x = endPos.x;
startPos.y = endPos.y;
}
return { commands:commands, data:data };
}
/**
* 扇を描きます
*/
public function drawPie(degree:Number, radius:Number, innerRadius:Number = 0):void{
this._degree = degree;
this._radius = radius;
this._innerRadius = innerRadius;
if(degree > 0){
g.clear();
g.beginFill(color);
var arc:Object = objectArc(radius,degree);
if( innerRadius == 0 ){
arc.commands.push(2);
arc.data.push(0,0);
g.drawPath(arc.commands, arc.data);
} else {
var oppositeArc:Object = objectArc(innerRadius,degree,true);
g.moveTo(radius, 0);
g.drawPath(arc.commands, arc.data);
oppositeArc.commands.push(2);
oppositeArc.data.push(radius, 0);
g.drawPath(oppositeArc.commands, oppositeArc.data);
}
}
}
/**
* パスのトリミングをします
*/
public function drawLine(commands:Vector.<int>, data:Vector.<Number>, thickness:Number=1, color:uint=0xFF0000, f:Number = 1,f0:Number = 0):void{
var startPos:Point = new Point(data[2],data[3]);
var endPos:Point = new Point();
var trimPos:Point = new Point();
var controlPoint:Point = new Point();
var eachLength:Vector.<Number> = new Vector.<Number>();
var com:Vector.<int> = commands.concat();
var dat:Vector.<Number> = data.concat();
if (f < f0){
var a:Number = f;
var b:Number = f0;
f0 = a;
f = b;
}
//全ての曲線の長さの合計をとっておく(適当)
var totalLength:Number = 0;
var i:int;
for(i=1;i<commands.length;i++){
controlPoint = new Point(dat[i*4], dat[i*4+1]);
endPos = new Point( dat[i*4+2], dat[i*4+3]);
var dx1:Number = Math.pow(startPos.x - controlPoint.x, 2);
var dy1:Number = Math.pow(startPos.y - controlPoint.y, 2);
var dx2:Number = Math.pow(endPos.x - controlPoint.x, 2);
var dy2:Number = Math.pow(endPos.y - controlPoint.y, 2);
eachLength.push(Math.sqrt(dx1 + dy1) + Math.sqrt(dx2 + dy2));
totalLength += eachLength[i-1];
startPos = endPos.clone();
}
var length:Number = 0;
var trimCtrl:Point;
var _f:Number;
var deleted:int = 0;
if(f0 != 0){
for(i=0;i<commands.length-1;i++){
if( length + eachLength[i] >= f0*totalLength){
deleted = i;
_f = 1 - (f0*totalLength - length) / eachLength[i];
startPos = new Point(dat[i*4+2], dat[i*4+3]);
controlPoint = new Point(dat[(i+1)*4], dat[(i+1)*4+1]);
endPos = new Point(dat[(i+1)*4+2],dat[(i+1)*4+3]);
trimCtrl = Point.interpolate(controlPoint,endPos,_f);
trimPos = Point.interpolate(Point.interpolate(startPos,controlPoint,_f),trimCtrl,_f);
com.splice(0, i+2);
dat.splice(0, (i+2)*4);
com.unshift(GraphicsPathCommand.CURVE_TO);
com.unshift(GraphicsPathCommand.WIDE_MOVE_TO);
dat.unshift(trimCtrl.x, trimCtrl.y, endPos.x, endPos.y);
dat.unshift(0, 0, trimPos.x, trimPos.y)
break;
} else {
length += eachLength[i];
}
}
}
length = 0;
if( _f != 1 ){
for(i=0;i<commands.length;i++){
if (length + eachLength[i] >= f*totalLength){
_f = (f*totalLength - length) / eachLength[i];
i -= deleted;
startPos = new Point(dat[i*4+2], dat[i*4+3]);
i++;
controlPoint = new Point(dat[i*4], dat[i*4+1]);
endPos = new Point(dat[i*4+2], dat[i*4+3]);
trimCtrl = Point.interpolate(controlPoint, startPos, _f);
trimPos = Point.interpolate(Point.interpolate(endPos,controlPoint,_f),trimCtrl,_f);
com.splice(i, com.length-i);
com.push(3);
dat.splice(i*4,dat.length-i*4);
dat.push(trimCtrl.x,trimCtrl.y,trimPos.x,trimPos.y);
break;
} else{
length += eachLength[i];
}
}
}
g.lineStyle(thickness, color);
g.drawPath( com, dat);
}
}