Reputation: 1699
Am currently working on a tool created by a colleague of mine and would like to improve performance. Basically, it's a tool for drawing on screen and uses a combination of Sprites and the Graphics class to draw a line segment every time the mouse is moved when the mouse button is down. Here is the drawing bit:
// on MouseMove
protected function drawLine(e:MouseEvent):void {
if (currentTool.thickness > 0){
//pen
var line:Sprite = new Sprite();
line.graphics.lineStyle(currentTool.thickness, currentColour);
line.graphics.moveTo(lastKnownPoint.x, lastKnownPoint.y);
line.graphics.lineTo(e.localX, e.localY);
inkLayer.addChild(line);
lastKnownPoint.x = e.localX;
lastKnownPoint.y = e.localY;
e.updateAfterEvent();
} else {
//eraser
var inkChildren:int = inkLayer.numChildren;
for (var i:uint = inkChildren; i > 0; i--){
if (toolCursor.hitTestObject(inkLayer.getChildAt(i - 1))){
inkLayer.removeChildAt(i - 1);
}
}
}
}
As you can see, it checks if the line 'thickness' property and draws if it is and erases if it isn't.
I did think of using a technique similar to blitting here where it'd draw to a bitmap but I'm not sure this'd give the performance boost I want or if, indeed, there would be any way to have an eraser function.
Any ideas on a better way to do this? The drawing itself works nicely - this isn't the problem, it's the performance of the subsequent 'drawn' sprites.
Upvotes: 1
Views: 702
Reputation: 9897
I have solved similar problem recently and I could not think of efficient way to implement eraser with vectors. So I made a bitmap to erase drawings from. It works this way: when user selects colored pen, while he holds the left button, draw lines to sprite. When left button is released, sprite is flushed to BitmapData and board is redrawn using this bitmap. When user selects eraser, he draws thick black lines on sprite (they are invisible with alpha = 0). After each movement, affected part of sprite is flushed to BitmapData in erasing mode and this is reflected on board. To support scaling, I made bitmap big and hooked BlurFilter on it. It's not perfect, but works fast enough.
Edit: some code, not tested after cut, but should give the idea:
public class DrawingBoard extends Sprite {
//...vars declaration
public function DrawingBoard(width:int, height:int, bitmapWidth:int = 1000, bitmapHeight:int = 1000)
{
super();
scrollRect = new Rectangle(0, 0, width, height);
downMatrix = new Matrix();
downMatrix.scale(bitmapWidth / width, bitmapHeight / height);
upMatrix = new Matrix();
upMatrix.scale(width / bitmapWidth, height / bitmapHeight);
bitmap = new BitmapData(bitmapWidth, bitmapHeight, true, 0x00000000);
//on canvas we draw vector pencils and eraser traces before flush
canvas = new Sprite();
addChild(canvas);
filters = [new BlurFilter(3, 3)];
}
//external control api
public function moveTo(point:Point):void {
canvas.graphics.moveTo(point.x, point.y);
var lineWidth:Number = 4 / parent.scaleX;
canvas.graphics.lineStyle(lineWidth, currentColor, 0.8, false, LineScaleMode.NORMAL);
}
public function lineTo(point:Point):void {
canvas.graphics.lineTo(point.x, point.y);
}
public function eraserLineTo(point:Point):void {
canvas.graphics.lineStyle(eraserSize, 0, 1.0);
canvas.graphics.lineTo(point.x, point.y);
flush(BlendMode.ERASE);
canvas.graphics.moveTo(point.x, point.y);
}
public function flush(blendMode:String = null):void {
//draw temporary vectors to bitmap
bitmap.draw(canvas, downMatrix, null, blendMode, null, true);
//update board
var bounds:Rectangle = canvas.getBounds(this);
with (graphics) {
beginBitmapFill(bitmap, upMatrix);
drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
endFill();
}
//erase temporary vectors
canvas.graphics.clear();
}
}
Upvotes: 2
Reputation: 31903
You could optimize this by checking at the start of the method whether lastKnownPoint.x
and lastKnownPoint.y
are the same value or within a certain distance (2 or 3 pixels, perhaps). If they are, you simply return without doing anything. Experiment and find the distance at which you strike a good balance between performance and smoothness of the line.
Upvotes: 0
Reputation: 4340
While drawing you will notice that curves are not sharp anymore.. and they will become composed from bigger and bigger lines. The workaround is not to create millions of small lines and add them as children, but to write in the same container using copyBitmapData.
Upvotes: 0