HaXe GraphicsX
From dis-Emi-A
GraphicsX (package draw) is a layer on top of the Flash display.Graphics object. It offers more signature variants (for convenience of use) along with several addition functions to make up for shortfalls in the Flash API. Additionally it allows transform objects to be applied during drawing, thereby allowing arbitrarily complex drawings without suffering from the overhead of having multiple Flash objects.
Here are some of the benefits to using GraphicsX over the native API:
- "arc" and "wedge" drawing commands
- ability to draw rotated ellipses
- polygon drawing with rounded corners
- create arbitrary shapes as fundamentals
- transforms and viewports/windows
- convenient function forms (like centered objects)
A basic demo of the system can be seen in the [draw.test.TestShape] program.
Contents |
Creating GraphicsX
To simply create a GraphicsX object against a backing display.Graphics object, and not apply any transformation, you can use the identity function. For example, insider a DisplayObject:
var gfx = draw.GraphicsX.identity( graphics );
To simplify drawing in a scaled environment, you can create a view on the graphics object such that the right/bottom edge is value (1,1). This means that a rectangle can drawn the same way all the time without needing to know the actual extents of the sprite. For example:
var gfx = GraphicsX.scaled( graphics, width, height ); gfx.use( Brush.solid( Color.rgb( 0, 1, 0 ) ) ); gfx.drawRectCtr( 0.5, 0.5, 0.75, 0.75 );
This will fill a green rectangle, centered in the sprite, and covering 75% of the width/height.
Refer to "Using Transforms" below for more on extents/windows.
Refer to haXe Drawing Implements for more on using brushes and pens. Note however, that since the GraphicsX is backed by a real Flash Graphics object, if you apply pens/brushes directly to the flash object they will also apply to the functions of GraphicsX.
Using the functions
The function signatures have been standardized to be consistent and convenient. Most functions follow a basic pattern of their available forms. For example, given "drawRect" the following forms are availabe:
drawRect( x : Float, y : Float, width : Float, height : Float ) drawRectCtr( x : Float, y : Float, width : Float, height : Float ) drawRectPt( upperLeft : Point2, size : Point2 ) drawRectCtrPt( center : Point2, size : Point2 )
There are two forms which use native integers for the parameters, and two forms which use the DHLIB Point2 class. These forms are equivalent in meaning.
The other variation is the "Ctr" or no center form. The forms with "Ctr" in their name indicate the first point is the center of the object to be drawn. The non-center form means the first point is the upper-left corner of the object. The remainder of the parameters of these forms are equivalent in meaning.
All the forms have the same result of drawing a rectangle at the desired position with the desired size. Which form you use depends on what is most convenient for your code at the time.
Note that the use of M4 to help produce these forms means the names of parameters in the docs is a little more abstract. Sorry.
Using Transforms
Transforms are the same as the transform of a DisplayObject in Flash. In GraphicsX they are applied immediately however, so you can draw several items with distinct transforms in a single DisplayObject. This is quite valuable since otherwise you'd need multiple objects to achieve the same drawing, but multiple objects hurt the performance of the Flash VM.
Additionally, the use of transforms simplifies dealing with coordinates while drawing. A similar effect can be achieve using the "scale" parameters of a DisplayObject, but if you've tried that before you will know there are many limitations of doing that.
Scaled
The most basic transform is one which alters the extents of the drawing surface. Usually a drawing surface has 1:1 extents, that means if you call the function
drawRect( 25, 25, 50, 50 )
you'll get a rectangle at position (25,25) with the bottom right corner at (75,75). If you are working with interfaces which change according to their size, you'll likely have a lot of code that looks like this:
drawRect( 0.25 * width, 0.25 * width, 0.5 * width, 0.5 * width )
This can get repetitive and tiresome to type.
The basic transform allows you to simplify this scaling logic. When you create the GraphicsX object use the "scaled" method such as this:
var gfx = GraphicsX.scaled( graphics, width, height );
Then when you wish to draw a rectangle you simply do this:
gfx.drawRect( 0.25, 0.25, 0.5, 0.5 );
Translated
The other common situation is where you wish to draw an object at a particular point on the screen, for example centred on the screen. Using straight Flash code to draw a centred donut on the screen you might need to do this
ellipseWidth = screenW * 0.5; ellipseHeight = screenH * 0.5; graphics.drawEllipse( screenW / 2 - ellipseWidth / 2, screenH / 2 - ellipseHeight / 2, ellipseWidth, ellipseHeight ); holeWidth = screenW * 0.3; holeHeight = screenH * 0.3; graphics.drawEllipse( screenW / 2 - holeWidth / 2, screenH / 2 - holeHeight / 2, holeWidth, holeHeight );
Using a scaled and translated transform this can be greatly simplified.
var gfx = GraphicsX.scaled( graphics, screenW, screenH, screenW/2, screenH/2 ); gfx.drawEllipseCtr( 0, 0, 0.5, 0.5 ); gfx.drawEllipseCtr( 0, 0, 0.3, 0.3 );
Rotations / Windows
The transform can also be rotated via the function "rotate". This simply applies a rotation to whatever transform is currently being used.
Such rotations are often not what you really want, since the point about which the rotation applies is not always clear. For this reason the "windowCtr" function has been created. It will create a viewport into the drawing surface. This viewport has its own extents and rotation -- and the rotation is around the center of the viewport, so it is clear what is happening.
For example, to draw objects at the point (100,50) on the main screen, where the objects cover a rectangular area of (200,100), and that entire rectangular area is rotated 45 degrees, use this call:
var window = gfx.windowCtr( Point2.at( 100, 50 ), Point2.at( 200, 100 ), Math.PI/4 ); window.drawRectCtr( 0, 0, 1, 1 );
That call to drawRectCtr will show the effects of the first call.
To see these types of windows in use refer to the draw.test.TestShape program.
