/**
* VERSION: 0.4 (beta)
* DATE: 2010-12-22
* AS3
* UPDATES AND DOCS AT: http://www.greensock.com
**/
package com.greensock.motionPaths {
import flash.display.Graphics;
import flash.geom.Matrix;
import flash.events.Event;
/**
* A RectanglePath2D defines a rectangular path on which a PathFollower can be placed, making it simple to tween objects
* along a rectangle's perimeter. A PathFollower's position along the path is described using its progress
property,
* a value between 0 and 1 where 0 is at the beginning of the path (top left corner), and as the value increases, it
* moves clockwise along the path so that 0.5 would be at the lower right corner, and 1 is all the way back at the
* upper left corner of the path. So to tween a PathFollower along the path, you can simply tween its
* progress
property. To tween ALL of the followers on the path at once, you can tween the
* RectanglePath2D's progress
property. PathFollowers automatically wrap so that if the progress
* value exceeds 1 it continues at the beginning of the path.
*
* Since RectanglePath2D extends the Shape class, you can add an instance to the display list to see a line representation
* of the path drawn which can be helpful especially during the production phase. Use lineStyle()
* to adjust the color, thickness, and other attributes of the line that is drawn (or set the RectanglePath2D's
* visible
property to false or don't add it to the display list if you don't want to see the line
* at all). You can also adjust all of its properties like scaleX, scaleY, rotation, width, height, x,
* and y
. That means you can tween those values as well to achieve very dynamic, complex effects
* with ease.
*
* @example Example AS3 code:
progress
* property which will provide better performance than tweening each follower independently.centerOrigin
is true
)
* @param y The y coordinate of the origin of the rectangle (typically its top left corner unless centerOrigin
is true
)
* @param rawWidth The width of the rectangle in its unrotated and unscaled state
* @param rawHeight The height of the rectangle in its unrotated and unscaled state
* @param centerOrigin To position the origin (registration point around which transformations occur) at the center of the rectangle instead of its upper left corner, set centerOrigin
to true
(it is false by default).
*/
public function RectanglePath2D(x:Number, y:Number, rawWidth:Number, rawHeight:Number, centerOrigin:Boolean=false) {
super();
_rawWidth = rawWidth;
_rawHeight = rawHeight;
_centerOrigin = centerOrigin;
super.x = x;
super.y = y;
}
/** @inheritDoc **/
override public function update(event:Event=null):void {
var xOffset:Number = _centerOrigin ? _rawWidth / -2 : 0;
var yOffset:Number = _centerOrigin ? _rawHeight / -2 : 0;
var length:Number, px:Number, py:Number, xFactor:Number, yFactor:Number;
var m:Matrix = this.transform.matrix;
var a:Number = m.a, b:Number = m.b, c:Number = m.c, d:Number = m.d, tx:Number = m.tx, ty:Number = m.ty;
var f:PathFollower = _rootFollower;
while (f) {
px = xOffset;
py = yOffset;
if (f.cachedProgress < 0.5) {
length = f.cachedProgress * (_rawWidth + _rawHeight) * 2;
if (length > _rawWidth) { //top
px += _rawWidth;
py += length - _rawWidth;
xFactor = 0;
yFactor = _rawHeight;
} else { //right
px += length;
xFactor = _rawWidth;
yFactor = 0;
}
} else {
length = (f.cachedProgress - 0.5) / 0.5 * (_rawWidth + _rawHeight);
if (length <= _rawWidth) { //bottom
px += _rawWidth - length;
py += _rawHeight;
xFactor = -_rawWidth;
yFactor = 0;
} else { //left
py += _rawHeight - (length - _rawWidth);
xFactor = 0;
yFactor = -_rawHeight;
}
}
f.target.x = px * a + py * c + tx;
f.target.y = px * b + py * d + ty;
if (f.autoRotate) {
f.target.rotation = Math.atan2(xFactor * b + yFactor * d, xFactor * a + yFactor * c) * _RAD2DEG + f.rotationOffset;
}
f = f.cachedNext;
}
if (_redrawLine) {
var g:Graphics = this.graphics;
g.clear();
g.lineStyle(_thickness, _color, _lineAlpha, _pixelHinting, _scaleMode, _caps, _joints, _miterLimit);
g.drawRect(xOffset, yOffset, _rawWidth, _rawHeight);
_redrawLine = false;
}
}
/** @inheritDoc **/
override public function renderObjectAt(target:Object, progress:Number, autoRotate:Boolean=false, rotationOffset:Number=0):void {
if (progress > 1) {
progress -= int(progress);
} else if (progress < 0) {
progress -= int(progress) - 1;
}
var px:Number = _centerOrigin ? _rawWidth / -2 : 0;
var py:Number = _centerOrigin ? _rawHeight / -2 : 0;
var length:Number, xFactor:Number, yFactor:Number;
if (progress < 0.5) {
length = progress * (_rawWidth + _rawHeight) * 2;
if (length > _rawWidth) {
px += _rawWidth;
py += length - _rawWidth;
xFactor = 0;
yFactor = _rawHeight;
} else {
px += length;
xFactor = _rawWidth;
yFactor = 0;
}
} else {
length = (progress - 0.5) / 0.5 * (_rawWidth + _rawHeight);
if (length <= _rawWidth) {
px += _rawWidth - length;
py += _rawHeight;
xFactor = -_rawWidth;
yFactor = 0;
} else {
py += _rawHeight - (length - _rawWidth);
xFactor = 0;
yFactor = -_rawHeight;
}
}
var m:Matrix = this.transform.matrix;
target.x = px * m.a + py * m.c + m.tx;
target.y = px * m.b + py * m.d + m.ty;
if (autoRotate) {
target.rotation = Math.atan2(xFactor * m.b + yFactor * m.d, xFactor * m.a + yFactor * m.c) * _RAD2DEG + rotationOffset;
}
}
//---- GETTERS / SETTERS ----------------------------------------------------------------------
/** width of the rectangle in its unrotated, unscaled state (does not factor in any transformations like scaleX/scaleY/rotation) **/
public function get rawWidth():Number {
return _rawWidth;
}
public function set rawWidth(value:Number):void {
_rawWidth = value;
_redrawLine = true;
update();
}
/** height of the rectangle in its unrotated, unscaled state (does not factor in any transformations like scaleX/scaleY/rotation) **/
public function get rawHeight():Number {
return _rawHeight;
}
public function set rawHeight(value:Number):void {
_rawHeight = value;
_redrawLine = true;
update();
}
/** height of the rectangle in its unrotated, unscaled state (does not factor in any transformations like scaleX/scaleY/rotation) **/
public function get centerOrigin():Boolean {
return _centerOrigin;
}
public function set centerOrigin(value:Boolean):void {
_centerOrigin;
_redrawLine = true;
update();
}
}
}