MyStickies: still alive and kicking

I created a service with a FireFox plugin a couple of years ago called MyStickies with Derek Andriesian. We got going on it and did quite a bit, but then we weren’t sure how to monetize it, so we left it alone. However, it still seems to be alive and kicking. I just got an email from Suzane Smith letting me know she included it in a list of 100 Firefox tips for research. You may notice that MyStickies is number 20, and the first one listed under the “Best Addons” section.

I’d like to move it over to Google App Engine and add note sharing sometime. Again, without monetization it can be hard to justify the time.

Some interesting MyStickies statistics:
Total users signed up: 59,741
Total notes placed across the web: 321,572
Users signed up in the last 30 days: 1,101

I’m sure there’s something I could do to give these users more features and be able to support the development costs as well. I’ll have to think about it.

Serializing display objects

Ha! I serialized a display object. Didn’t think it could be done, but with a little work it can be. See my previous post about overriding Transform and Matrix objects for a little more context. I’m jumping right in to how I did it.

So the main problem before was the Transform class requiring a parameter in its constructor. So I subclassed Transform and made that parameter optional. Turns out if you pass in null to the superclass you get an error too, so if no displayObject is passed in I use a Shape. (I figured it was one of the cheaper display objects to make, though between that and Bitmap I’m not sure.) No I need to subclass Sprite so that it uses my new Transform subclass.

MyTransform:

public class MyTransform extends Transform
{
	public function MyTransform(displayObject:DisplayObject = null)
	{
		super(displayObject || new Shape());
	}
}

MySprite:

public class MySprite extends Sprite
{
	private var _transform:MyTransform;
	
	public function MySprite()
	{
		super();
		_transform = new MyTransform(this);
	}
	
	public override function get transform():Transform
	{
		return _transform;
	}
	
	public override function set transform(value:Transform):void
	{
		_transform = new MyTransform(this);
		_transform.colorTransform = value.colorTransform;
		_transform.matrix = value.matrix;
	}
}

Proof that it works:

// register all the classes required to store a sprite
registerClassAlias("MySprite", MySprite);
registerClassAlias("MyTransform", MyTransform);
registerClassAlias("MySoundTransform", SoundTransform);
registerClassAlias("MyMatrix", MyMatrix);
registerClassAlias("MyColorTransform", ColorTransform);

var sprite:MySprite = new MySprite();
trace(sprite.transform is MyTransform); // true

var ba:ByteArray = new ByteArray();
ba.writeObject(sprite);
ba.position = 0;
sprite = ba.readObject();

trace(sprite.transform is MyTransform); // true

Yeah!! It totally worked! And I could add that sprite to the display list and everything!

Now a couple of things to note: when serializing only read/write variables are stored. So Sprite’s and Shape’s graphic property is not stored. Neither is parent or any of the children because they aren’t referenced by any properties that can be written too. So if you draw on your shape or sprite with the drawing API it won’t be stored. Of course, this can be worked with if you have methods that draw on creation, or if you store some of Flash 10’s new IGraphicData objects publicly which can be drawn. You could also store all your sprite’s children in a public array that has to be set like the filter array for it to alter the display list. Then you could serialize your whole display tree. :) Might be fun.

Oh, and one more quickie that I double tested to make sure. I was told at one of our uFlash meetings that private properties are stored in serialized bytearrays. This didn’t seem consistent with what I understood, so I tested and retested and it is only public properties with getters and setters that are stored. Tyler said people sometimes had issues when they put [Bindable] at the top of a class and the complier made everything public (even privates) so that they would work with binding. But that’s a compiler issue with how it rewrites code. Private properties are not stored in bytearrays.

Overriding Flash’s Transform and Matrix

I’m building a a commercial library for scrap-book or other composition type applications and it would be useful to be able to override the flash.geom.Transform and flash.geom.Matrix classes with my own. So I played around with it for awhile and thought I’d share what I found.

First I tried setting my own matrix. I know that when you access displayObject.transform.matrix you get a clone of the object’s transform matrix, so I create a test class called MyMatrix.

public class MyMatrix extends Matrix
{
	public function MyMatrix(a:Number=1, b:Number=0, c:Number=0, d:Number=1, tx:Number=0, ty:Number=0)
	{
		super(a, b, c, d, tx, ty);
	}
	
	public override function clone():Matrix
	{
		trace("cloned");
		return new MyMatrix(a, b, c, d, tx, ty);
	}
}

Then tested it out:

var sprite:Sprite = new Sprite();
sprite.transform.matrix = new MyMatrix();
var m:Matrix = sprite.transform.matrix; // will I get a trace of "cloned"?
trace(m is MyMatrix); // true? or false?

Turns out I don’t get any trace statement when accessing matrix and “m is MyMatrix” gives me a false. Bummer. So I did the same thing with Transform, making a MyTransform class and setting it onto a sprite. Same results. Flash doesn’t really set and keep around my own transform or matrix classes. It seems to use their values and discard the objects. I’m sure it has to do with how the display list is implemented under the hood.

However, I did discover that to affect the display object your transform class doesn’t need to be assigned to it. Here is an example:

var sprite:Sprite = new Sprite()
var t:MyTransform = new MyTransform(sprite); // Transform takes a displayObject as it's one and only parameter
t.matrix = new Matrix(2, 0, 0, 2, 100, 100); // scale it up 2ce and set x/y to 100

trace(sprite.transform.matrix); // (2, 0, 0, 2, 100, 100)

I was able to set the matrix with my own transform class from outside the display object. Side note: speaking with Tyler about transform requiring a display object, he’s convinced this is the only reason you can’t serialize display objects to a bytearray. It throws an error when constructors require parameters, and Transform requires this one parameter. Might be useful to serialize display objects, maybe the Flash team could make the parameter optional! And have the display object set it when it is added as the transform.

So my two options are now:

  1. Use my own Transform class externally as explained above. I could keep a dictionary of transform objects to the data that I needed.
  2. Subclass Sprite, Shape, Bitmap, etc. and have it store the transform object of my choice.

I’ll probably go with option two. Maybe I’ll even be able to make a display object serializable with some trickery? Ooh, I gotta go try that! Catcha later.