The new graphics.lineTo (5)

, under actionscript, Generative art.

I am working on a Pie-chart class. Data visualisation is fun, so I want to create my own pie-chart. Reinventing the wheel (creating another pie-chart) is a good thing if you want to create a custom wheel, so you know how to modify to make it fit your needs. Now this post is not about the pie-chart, but about something I discovered inside the graphics class. Most flashcoders knows you can draw lines using graphics.lineTo. There is another way of drawing lines in actionscript, using the graphics.drawPath and graphics.drawGraphicsData function. Let’s take a look at it.

graphics.lineTo

The good old method. Drawing a line from point (x:100, y:150) to point (x:300, y:300). Check out these four lines of clear code.
[as]
graphics.clear(); // start with blank canvas
graphics.lineStyle(2, 0xFF9900);
graphics.moveTo(100,150);
graphics.lineTo(300,300);
[/as]

graphics.drawPath

Now, you could also use this alternative way of drawing. There is no such thing as creating circles or squares using this method, only manual. It is using commands (moveTo, lineTo, curveTo) and has a separate list of data containing the actual values. All values in the data-list represents the x-positions (odd values) and y-positions (even values). So we are pushing x, y, x, y etc.
When using CURVE_TO, you need to define four values; controlX, controlY, x, y. Take a look at the code: [as]var commands:Vector. = new Vector.();
var data:Vector. = new Vector.();
commands.push(GraphicsPathCommand.MOVE_TO, GraphicsPathCommand.LINE_TO); // add 2 commands, moveTo and lineTo
data.push(100, 150)
data.push(300, 300); // push all values into data-list

graphics.clear(); // clear the canvas
graphics.lineStyle(2, 0xFFCC00); // Set the stroke style
graphics.drawPath(commands, data); // finally, draw it all
[/as]As you could see, you need to write a bit more code. As you can see you can combine the graphics.lineStyle and the graphics.drawPath functions, so its not completely new.

By the way, did you know you could push multiple items to an list at a time?

graphics.drawGraphicsData

Be prepared, 12 lines to draw the same a line.
[as]
var commands:Vector. = new Vector.();
var data:Vector. = new Vector.();
var path:GraphicsPath = new GraphicsPath(commands, data);
var drawing:Vector. = new Vector.();

var stroke:GraphicsStroke = new GraphicsStroke(2);
stroke.fill = new GraphicsSolidFill(0xFF9900);
// The stroke definition with a fill

commands.push(GraphicsPathCommand.MOVE_TO, GraphicsPathCommand.LINE_TO); // add 2 commands, moveTo and lineTo
data.push(100, 150)
data.push(300, 300); // push all values into data, odd represents the x-positions, even represents the y-positions. So we are pushing x, y, x, y etc.
drawing.push(stroke, path); // collect all data inside one list

graphics.clear(); // clear the canvas
graphics.drawGraphicsData(drawing); // finally, draw it all
[/as]
The drawGraphicsData function forces you to push all data into a new list. The fun thing is, you feel very exited when you have the last example running. I don’t know why, but getting advanced stuff working feels good. Note, for the last example we need to import these classes to draw that orange line. Five classes for one simple orange line, pretty impressive eh? 🙂
[as]
import flash.display.GraphicsPath;
import flash.display.GraphicsPathCommand;
import flash.display.GraphicsSolidFill;
import flash.display.GraphicsStroke;
import flash.display.IGraphicsData;
[/as]

Borders/fills

When I first started to use this way of drawing lines, I noticed that I needed 2 lines of code to define a stroke. The fill is the last parameter of the GraphicsStroke class, and I really dislike to define all other optional parameters just to set that one parameter at the end. Oh, without a fill or color, a border is invisble 😉 Still don’t get it! The fill is a fun part of this advance drawing method. Now in the normal lineTo-world we know these linestyles graphics.lineBitmapStyle, graphics.lineGradientStyle, graphics.lineShaderStyle and ofcourse the graphics.lineStyle. Now if you want to create a border to be ‘filled’ with something, you could create a GraphicsSolidFill, GraphicsGradientFill, GraphicsBitmapFill or GraphicsShaderFill.

It is nice to know the same classes could be used to fill a shape, so they could be added to the drawing-list too. That is really a nice part of this advanced way of drawing, just add or remove instances of classes to the drawing-list (it should implement IGraphicsData).

You can now define fills, strokes and multiple paths before you actually draw it on the stage.

Saving graphics; saving numbers

The cool thing of this whole advanced drawing method is that you could save the commands/paths as a file and redo it more easy than graphics.lineTo. If you do generative arts this could be a benefit. There is no official function for saving the data, but you could write it yourself since we are dealing with numbers. When opening a file you could theoretically push all commands/paths/fills inside the drawing-list and you could draw the same drawing. I haven’t test this, but maybe you could save the whole vector as ByteArray using ByteArray.writeObject(), compress it and then you have a nice way of saving ‘graphics’. Another benefit, you could delay ‘the draw’ and still collect data which could be drawed later. Very handy if you are doing heavy generative arts.

Conclusion?

It is not easy to draw lines using the the advanced method, since you are dealing with vectors with numbers, instead of lines. It is cool to have every graphic-thing as a separate classes and fills are nicely done and easily swap-able. Graphics data is now more flexible. Adobe could add more graphics classes. I hope they will add support for custom strokes (like Illustrator). At the other side, most things still fit in the good-old lineTo coding-style, which is very clean and straight-forward. Anyhow, it is nice to see a new way of saving graphics.

When you are drawing lots of lines, this advanced way should bring better performance since it is delaying the actual draw. I haven’t benchmarked how much exactly, but since you can mix graphics.drawPath with graphics.lineStyle, it feels graphics.drawGraphicsData is syntactic sugar which has the benefits noted I already mentioned.

I also wonder if it there would be a performance boost if you create your own lineTo function (which only pushes data to a list) based on the graphics.drawGraphicsData, with one drawNow() function.

Hope this will inspire you to share other or new possibilities.
[as]
var theEnd:GraphicsEndFill = new GraphicsEndFill(); // thanks for reading
[/as]

5 responses to “The new graphics.lineTo”

  1. grgrdvrt says:

    The problem with this api is that every command in a graphic path is drawn with the same line style.
    I don’t like to make uniform lines, I like when a line has some variations, especially in width.
    And the only way to achieve it with the new api is to create as many vectors of commands and data and as many GraphicsStroke objects as there is variations in the line.
    Not sure this is a good things in terms of performance…

  2. skyboy says:

    I believe the drawing API already buffers commands, and none of them are drawn until the render pass.

  3. Dr. Green says:

    The drawing API is very fast. Here is a comparison the API vs flash text rendering engine (bottom of the page):
    http://lab.polygonal.de/2009/04/26/goodbye-textfield/

  4. noboddy says:

    Nice article, thanks. I did not know you could push multiple objects to an array or vector. So you could push all postitions like this data.push(100, 150, 300, 300); Saves you an function-call 🙂

  5. as3isolib says:

    I use this for programmatic drawing of iso primitive shapes in as3isolib.v2. If you recycle your command and data vectors, and push all the vector data into one call, you can really squeeze a good performance boost out of the drawing API for performance-critical drawing logic.

    http://snipt.org/xlnpl

Say something interesting

Please link to code from an external resource, like gist.github.com.