How to create masks in AS3? - actionscript-3

objectToBeMasked.mask = maskObject;
Ok, simple... but I can SEE the maskObject unless I set its alpha to 0 and then it doesn't let clicks through to objectToBeMasked
And every single tutorial that I've seen fails to mention this and how to solve it, as if it should be obvious.
How do I mask objects through AS3 so that the masks act like masks act like the ones added in the IDE?

Here is an example :
var maskedShape : Shape = new Shape();
maskedShape.graphics.beginFill(0x0);
maskedShape.graphics.drawRect(0, 0, 100, 100);
maskedShape.graphics.endFill();
addChild(maskedShape);
var maskerShape : Shape = new Shape();
maskerShape.graphics.beginFill(0x0);
maskerShape.graphics.drawRect(0, 0, 100, 100);
maskerShape.graphics.endFill();
addChild(maskerShape);
maskerShape.x = 20;
maskerShape.y = 20;
maskedShape.mask = maskerShape;

You shouldn't see the mask. Probably the mask and the masked object are not on the stage at the time you are trying to apply the mask.
Can you pass on some code here?

The easiest way is to not render your object simply bt setting visible parameter to false :
maskObject.visible = false;
so your objectToBeMasked is still masked, but do not catch mouse event, and is not rendered anymore :)

Related

AS3: Sprite does not dispatch mouse event

I am new to as3. I have developed a small application which in as3. But issue is the sprite created does not dispatch any mouse events [ eg: click ]. Please can anyone guide me and throw some comment
.... private var progressBarHolder:Sprite = new Sprite();
progressBarHolder.graphics.clear();
progressBarHolder.graphics.beginFill(0xeaeaea);
progressBarHolder.alpha = 0.5;
progressBarHolder.graphics.drawRoundRect(0, 0, 80, 25, 0,0);
//progressBarHolder.graphics.endFill();
progressBarHolder.width = progressBarWidth;
progressBarHolder.height = 24;
progressBarHolder.x = 48;
progressBarHolder.y = _videoModule.getHeight() - 48;
progressBarHolder.buttonMode = true;
progressBarHolder.addEventListener(MouseEvent.CLICK, progressBarHolderClick);
_overlay.addChild(progressBarHolder);
.....
Thanks!
Code looks ok, possible problems:
width and height of your sprite are not zero (progressBarWidth != 0)
mouse is enabled on parent (_overlay), to make sure use -
progressBarHolder.mouseEnabled = true;
make sure there is nothing above progressBarHolder on the Z index that is blocking the click from the sprite.
Your code is correct. Look up on _overlay or progressBarHolderClick listener. Also It's can happens if property mouseChildren of _overlay or other parent set as false.
Show more code if you still can't find solution.

Eraser tool in html5 canvas

Hi i am building a windows store app with html5 and javascript in my app i am trying to implement an eraser tool but this is problematic because if the user moves an image or another layer to where they've previously erased, they see the white drawing where they erased.
i have been trying to do the eraser tool from different ways for example i have changed the default globalCompositeOperation to "destination-out" like this code
//Here is the error.
if (clickTool[j] == "eraser") {
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(255,0,0,0.5);';
ctx.strokeStyle = 'rgba(255,0,0,0.5);';
}
else {
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = clickColor[j];
}
but unfortunately it doesn´t work for me. i have uploaded all my code to this link:
My code
Please i would like to somebody could help me.
Thanks and i'm sorry for my speech , i'm mexican.
Use multiple layers. Have one canvas for the background image and another for the drawing; that why you never erase any of the background image.
If you need to, you can have multiple layers as they don't generally impact performance.
And of course if you can combine layers, say the last drawn squiggle to the background layer, if you deem a drawing to be "permanent".
Maintain a array of mid points. Use the globalCompositeOperation as 'destination-out' first and 'source-over' later to make a transparent eraser trail .
Following is the code that you need to use with a mouse move function
var handleMouseMove = function (event) {
midPt = new createjs.Point(oldPt.x + stage.mouseX>>1, oldPt.y+stage.mouseY>>1);
if(curTool.type=="eraser"){
var tempcanvas = document.getElementById('drawcanvas');
var tempctx=tempcanvas.getContext("2d");
tempctx.beginPath();
tempctx.globalCompositeOperation = "destination-out";
tempctx.arc(midPt.x, midPt.y, 20, 0, Math.PI * 2, false);
tempctx.fill();
tempctx.closePath();
tempctx.globalCompositeOperation = "source-over";
drawingCanvas.graphics.clear();
// keep updating the array for points
arrMidPtx.push(midPt.x);
arrMidPty.push(midPt.y);
stage.addChild(drawingCanvas);
stage.update();
}
};
I use this code to make a eraser that behaves like pen and fills up transparent color instead of white

Movieclip -> BitmapData and origin

I'm trying to draw a MovieClip to a BitmapData so that it looks exactly the same as if I had done addChild(movieclip).
I can't seem to figure out what magic formula I need to use to keep the animation in place around it's origin.
This is the relevant bit of code:
private function update(e:Event):void
{
var bounds:Rectangle = movieClip.getBounds(movieClip);
bitmapData = new BitmapData(maxMCwidth, maxMCheight, true, 0x0);
bitmapData.draw(movieClip, new Matrix(1, 0, 0, 1, maxMCwidth - (bounds.x + bounds.width), maxMCheight - (bounds.y + bounds.height)));
bitmap.bitmapData = bitmapData;
}
Full code here: http://pastebin.com/KyU5FPeJ
And this is what the result looks like:
http://www.swfcabin.com/open/1339173476
The top animation is done using addChild(mc). The bottom animation is done using bitmapData.draw. Notice how the sword on the right doesn't move horizontally in the bottom version. Almost as if the whole animation was getting right-aligned.
Here's also a link to my flashdevelop project with the full code in case anybody wants to play around with it: https://www.dropbox.com/s/gvt4scknqdian2a/bitmapdatadrawing.zip
I just want both versions to look the same. What do I need to change to my bitmapData drawing code to make this happen?
Ok I figured it out!
The cause of the problem was that I'm not calculating maxMCwidth or maxMCheight correctly. I was going through the movieclip looking for the widest/highest single frame. BUT that doesn't take into account that the position of bounds across frames changes. To get the actual maximum width/height across the whole animation, I used this code:
maxBounds = new Rectangle();
for (var i:uint = 0; i < movieClip.totalFrames; i++)
{
var tempBounds:Rectangle = movieClip.getBounds(movieClip);
maxBounds = maxBounds.union(tempBounds);
movieClip.nextFrame();
}
Then this allowed me to fix the translation matrix:
bitmapData.draw(movieClip, new Matrix(1, 0, 0, 1, -maxBounds.x, -maxBounds.y));
And like this it works for every animation I've tested.
Ok I can't get your project to run since you didn't supply a main mxml.
However, I think I found your issue.
I don't think getBounds is returning the values you think they are.
I can't look into the skeleton swc but I have a feeling there is on object off the top or bottom of the screen in it and the way you coded it would cause it to shrink down to make it fit.
getBounds is probably adding that to the height.
bitmapData = new BitmapData(movieClip.width, movieClip.height, true, 0x0);
bitmapData.draw(movieClip, new Matrix(1, 0, 0, 1, movieClip.width/2, movieClip.height/2 ));
bitmap = new Bitmap(bitmapData);
bitmap.x = 70;
bitmap.y = 200;
Remember untested code here. :(

AS3: Duplicating a PNG image causes loss of transparency

I am using LoaderMax to load an external PNG and display it in many places so I use the following code to duplicate the image:
var cd:ContentDisplay = ContentDisplay(loader.getContent("name"));
var b1 = Bitmap(cd.rawContent);
var old = b1.bitmapData;
var bmp = new Bitmap(b1);
container.addChild(bmp);
The original image has a 50% on the alpha channel, but when I create the new bitmap from from the same bitmapData object, it does not preserve the alpha channel.
If I try to copy the alpha channel (see the code below; if I understand correctly, the alpha channel is copied from itself, to itself)- the transparency is on the new image , but the code throws an error...
bmp.copyChannel(old, new Rectangle(0, 0, old.width, old.height), new Point(), BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
Error:
ReferenceError: Error #1069: Property copyChannel not found on flash.display.Bitmap and there is no default value.
at barmask/frame1()
How can I duplicate a PNG and maintain the alpha transparency... preferably without the error?
P.s. Please forgive any obvious mistakes, I am a ActionScript Newb...
His answer was very close to complete:
new BitmapData(w, h, true, 0);
The last property ensuring that flash doesn't include a background in the new image. That should solve your issue. It has to be exactly "0", not 0x000000, either.
create your BitmapData instance, passing 3 parameters to the constructor: new BitmapData(w, h, true), Boolean value is transparency
also check the transparent property of the source BitmapData
Bitmap doesn't have a copyChannel method as the error says :)
Instead of this:
bmp.copyChannel(...
You need to do this:
bmp.bitmapData.copyChannel(...

convert masked movieclip into bitmap and save it on server

i have a
dsgnArea----> a movieclip
dsgnArea is masked by dsgnAreaMask, which inturn is a movieclip
dsgnArea.mask=dsgnAreaMask;
the width,height and position of dsgnAreaMask and dsgnArea are same.
i dynamically added multiple movieclips and labels to dsgnArea;
like..
dsgnArea.addChild(movieClip1);
dsgnArea.addChild(movieClip2);
dsgnArea.addChild(label1);
dsgnArea.addChild(label2); and so on...
these movieclips (movieClip1,movieClip2,......) and labels(label1,label2,....) positions can be altered in runtime..
but as i masked the dsgnArea with dsgnAreaMask, only a portion of the added movieClips and labels are visible...
So, my problem is to grab that visible portion in dsgnArea into a bitmap,like a screenshot of that particular dsgnArea, and save it in my server.
please help me out in this problem.
Say s is the DisplayObject object you want to capture and m is the mask applied on it.
var maskRect:Rectangle = m.getRect(s);
var matrix:Matrix = new Matrix(1, 0, 0, 1, -maskRect.x, -maskRect.y);
var w:Number = Math.min(s.width, maskRect.right) - maskRect.x;
var h:Number = Math.min(s.height, maskRect.bottom) - maskRect.y;
var bd:BitmapData = new BitmapData(w, h);
bd.draw(s, matrix);
Does that work?
The BitmapData draw method is what you are looking for. You can use it's clipRect param to define what you would like to draw (the masked parts).
Quasimondo did a handy little method to do this (take a snapshot of the whole displayObject), it's available here: http://www.quasimondo.com/archives/000670.php
I don't know if it works with masked content though.
if it doesn't, the trick would be to translate the whole content by the size of the mask
var bounds:Rectangle = dsgnAreaMask.getBounds( dsgnAreaMask );
instead of using the content of the clip
var bounds:Rectangle = clip.getBounds( clip );
as far as saving file to server is concerned, the question was asked (answered?) here AS3 Save Media File to server