As a coder I find that I have to do some tasks again and again, with slight differences each time, and every time I think I must create a library for this. So I started one, more a collection of useful code than a project with a single aim, which is reflected in the choice of name “Nardan’s Toolshed”. “Nardan” that’s a name I’ve used on the net for a very long time, and “Toolshed” well it’s a place to tinker with ideas, to create & keep tools (also toolbox didn’t have enough whimsy!). The toolshed is organised into tools and parts, tools are applied to something to make it suitable, where as parts become part of the application rather than bashing something into the correct shape!
http://code.google.com/p/nardans-toolshed/
One of the tasks I find ubiquitous is scaling an image to fit into a particular portion of a design, but there is always a slight differences: should it scale and keep aspect ratio? should it fit into the box or fill the box? how should it be aligned in the box? And so the TransformationUtils
Class was born, with lessons learned from experience.
Firstly one often needs to know if the object will fit into the rectangle anyway and if it does align it according to the design. To this end I wrote two basic functions fitsInRect
& alignInRect
, very basic and don’t need much explanation.
/**
* Checks if clip would fit into a rectangle
* @param clip: left typeless so it can apply to DisplayObject or Rectangle.
* @param rect: Rectangle(to fit clip into)
* @return
*/
public static function fitsInRect(clip:*, rect:Rectangle):Boolean
{
return Boolean(clip.width
Hang on why is clip
not a DisplayObject
shouldn’t you correctly type your parameters? Well yes you should but I once found myself needing to use a Rectangle
to do the calculations on because a Sprite
with a mask
not giving me the width
and height
I wanted, so I made that parameter type-less as Rectangle
and DisplayObject
don’t share a suitable interface. Also you’ll (hopefully) note that alignInRect
has alignment parameters which are numbers (which should be between 0 & 1) I’ve provided some static constants to help with the most common positioning, but as it’s a number you don’t have to be limited to these, why you would want to have it horizontally aligned a third of the way along I don’t know but I’m not going to stop you! alignInRect
is used by the other scaling functions so understanding it will help with the others.
public static const ALIGN_TOP:Number = 0;
public static const ALIGN_BOTTOM:Number = 1;
public static const ALIGN_LEFT:Number = 0;
public static const ALIGN_RIGHT:Number = 1;
public static const ALIGN_CENTRE:Number = 0.5;
Right onto the three scaling functions scaleIntoRect
, scaleFillRect
, fillRect
. fillRect
is the only scaling function that doesn’t maintain aspect ratio. The other two keep the aspect ratio, but differ in whether the clip
get cropped (presuming a mask is applied), scaleIntoRect
displays the entirety of the clip whereas scaleFillRect
will only show a portion.
/*
* Scales an Object to fit into a Rectangle whilst maintaining aspect-ratio
* @param clip: left typeless so it can apply to DisplayObject or Rectangle.
* @param rect: Rectangle(to fit clip into)
* @param vAlign: String(vertical alignment)
* @param hAlign: String(horizontal alignment)
*/
public static function scaleIntoRect(clip:*, rect:Rectangle, vAlign:Number = 0.5, hAlign:Number = 0.5):void {
var clipRatio:Number = clip.width / clip.height;
if (clipRatio > rect.width / rect.height) { // treat as landscape
clip.width = rect.width;
clip.height = rect.width / clipRatio;
}else { // treat as portrait
clip.height = rect.height;
clip.width = rect.height * clipRatio;
}
alignInRect(clip, rect, vAlign, hAlign);
}
/* Scales an Object to fill a Rectangle whilst maintaining aspect-ratio, some parts of the clip map be outside of the rectangle
* @param clip: left typeless so it can apply to DisplayObject or Rectangle.
* @param rect: Rectangle(to fit clip into)
* @param vAlign: String(vertical alignment)
* @param hAlign: String(horizontal alignment)
*/
public static function scaleFillRect(clip:*, rect:Rectangle, vAlign:Number = 0.5, hAlign:Number = 0.5):void {
var clipRatio:Number = clip.width / clip.height;
if (clipRatio > rect.width / rect.height) { // treat as landscape
clip.height = rect.height;
clip.width = rect.height * clipRatio;
alignInRect(clip, rect, ALIGN_TOP, hAlign);
}else { // treat as portrait
clip.width = rect.width;
clip.height = rect.width / clipRatio;
alignInRect(clip, rect, vAlign, ALIGN_LEFT);
}
}
/**
* Forces a clip to fill a rectangle
* @param clip: left typeless so it can apply to DisplayObject or Rectangle.
* @param rect: Rectangle(to fit clip into)
*/
public static function fillRect(clip:*, rect:Rectangle):void
{
clip.width = rect.width;
clip.height = rect.height
alignInRect(clip, rect, ALIGN_TOP, ALIGN_LEFT);
}
If this is all a bit confusing try using this tool to play with it