Would anyone know why using graphics.clear(); in this example is preventing the graphics from being drawn?
e.g. the following code works and the lines are drawn.
var my_shape:Shape = new Shape();
my_shape.graphics.lineStyle(2, 0x00FF00, 1);
addChild(my_shape);
function moveLines():void {
my_shape.graphics.moveTo(10, 10);
my_shape.graphics.lineTo(50, 50);
my_shape.graphics.lineTo(100, 100);
}
moveLines();
But if I add the clear() command nothing is drawn.
function moveLines():void {
my_shape.graphics.clear();
my_shape.graphics.moveTo(10, 10);
my_shape.graphics.lineTo(50, 50);
my_shape.graphics.lineTo(100, 100);
}
moveLines();
I'm wanting to animate the line moving so would like to clear the previous drawing before redrawing the lines.
Thanks
You have to re-set the linestyle too, so move
my_shape.graphics.lineStyle(2, 0x00FF00, 1);
to your moveLines() method, after the 'clear' of cource.
Related
I have a strange problem that perhaps someone has also experienced. While using ActionScript 3 and the drawRect() function to create a movie clip on run time, I am experiencing some flickering when trying to use math to determine the position it gets drawn in.
The following code creates a nice, solid rectangle with no issue:
var mc:MovieClip = new MovieClip();
mc.graphics.beginFill(0xFF1230);
mc.graphics.drawRect(mouseX, mouseY, 100, 80);
mc.graphics.endFill();
However, When I begin to try to adjust where the rectangle gets drawn, like this:
mc.graphics.drawRect(mouseX - 50, mouseY - 50, 100, 80);
the rectangle gets drawn but will constantly flicker.
I have tried many variations of the line that gives an error, trying different data types and separating out the math into its own variable, but the same thing happens.
Has anyone experienced anything like this before? Any help or information is much appreciated!
it's more likely an issue with the event listener set up than the drawing code. I'm guessing you're using MouseEvent. You will need to post that code for anyone to help you with that (likely the mouse target is changing as soon as you draw the rectangle beneath)
you should not need to redraw the graphics, you're going to find that this will effect the frame rate over time, unless you clear() it every time. You are better off to offset the rectangle, and move the position of the movie clip.
like this:
var mc:MovieClip = new MovieClip();
mc.graphics.beginFill(0xFF1230);
mc.graphics.drawRect(-50, -50, 100, 80);
mc.graphics.endFill();
addChild(mc);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
function onMove(e:MouseEvent):void {
mc.x = mouseX;
mc.y = mouseY;
}
Instead of redrawing the rectangle each frame you could simply scale it.
var mc:MovieClip = new MovieClip();
mc.graphics.beginFill(0xFF1230);
mc.graphics.drawRect(0,0,1,1);
mc.graphics.endFill();
addChild(mc);
stage.addEventListener(Event.ENTER_FRAME, loop);
function loop(e:Event) {
mc.scaleX = mouseX;
mc.scaleY = mouseY;
}
I'm drawing many things on my context. Shapes, texts, images..
I want to use achieve the same effect i'm getting using the clip method on the context with globalCompositeOperation (Using the clip is harder for me to perform and i don't know if possible for texts)
The user can draw few shapes. and then start a mask phase. to draw some more shapes, texts.. which would draw into the mask and then the next draw will be clipped in the masked phase. and then continue to regular drawing...
For ex.
The user draw this drawing
Then started masked mode and drew this 2 red lines
Then he stopped drawing into the mask, and start drawing rectangle to consider the mask
And finally applied the mask clipping and the result should look like this
I've managed to clip the rectangle with the lines if there were no earlier drawings.
// Starting the mask phase
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(240, 140);
ctx.moveTo(80, 20);
ctx.lineTo(300, 140);
ctx.stroke();
ctx.globalCompositeOperation = 'source-out';
ctx.fillStyle = 'cyan';
ctx.fillRect(50, 70, 250, 20);
// Setting the composition back
ctx.globalCompositeOperation = 'source-over';
but when i'm adding my drawings in the beginning of the code, the composition considering it as well.
ctx.fillStyle = 'brown';
ctx.beginPath();
ctx.arc(80, 80, 50, 50, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'yellow';
ctx.fillRect(80, 60, 150, 40);
ctx.fillStyle = 'black';
ctx.font = '40pt arial';
ctx.fillText('Hello', 130, 110);
// How to tell the context to start from here the compisition ???
How to tell the context to start composition from a certain point, if possible ?
I could create another canvas and draw the mask there.. and then draw the new canvas on the main canvas. But there is better solution ?
You can change the compositing mode at any point in the drawing flow by changing .globalCompositeOperation. But, as you've discovered, any new compositing mode will also affect existing canvas content.
Your intuition is correct about using a second "staging canvas" to do compositing that won't destroy your existing content.
You can use an in-memory canvas to do compositing and create your rect-with-erased-lines. Then you can drawImage this in-memory canvas to your main canvas. Since the compositing was done on your in-memory canvas, your existing circle-hello content is not undesirably affected by compositing.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// create an in-memory canvas to do compositing
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/temp6a.png";
function start(){
ctx.drawImage(img,0,0);
addCompositedRectangle();
ctx.drawImage(c,0,0);
}
function addCompositedRectangle(){
// resize the in-memory canvas
// Note: this automatically clears any previous content
// and also resets any previous compositing modes
c.width=300; // largest width;
c.height=140; // largest height;
// Starting the mask phase
cctx.strokeStyle = 'red';
cctx.lineWidth = 5;
cctx.beginPath();
cctx.moveTo(20, 20);
cctx.lineTo(240, 140);
cctx.moveTo(80, 20);
cctx.lineTo(300, 140);
cctx.stroke();
cctx.globalCompositeOperation = 'source-out';
cctx.fillStyle = 'cyan';
cctx.fillRect(50, 70, 250, 20);
// Setting the composition back
cctx.globalCompositeOperation = 'source-over';
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
I wanted to mask some nodes of my DisplayObject tree. I couldn't make masking work in my big project. So I build a simple example for me and I saw it works actually pretty good. But I can't figure out why it doesn't work in my big project. All my visible objects are Sprites or from classes that extend Sprite.
masking in big project doesn't work
I can see the normal state of my nodeToBeMasked
when I add the mask to this node I can see the mask
but when I set the mask to be the mask, I continue to see everything (pure nodeToBeMasked is masked but not the children - which would be much more important)
masking in simple example works fine
How can masking stop working ?
Code: (that doesn't work, big project)
// custom class extends Sprite
override protected function onAddToStage(event:Event):void
{
trace(stage); // stage exists
var maskSprite:Sprite = new Sprite();
maskSprite.graphics.beginFill(0xffff00, 1);
maskSprite.graphics.drawCircle(0, 0, 64);
maskSprite.graphics.endFill();
maskSprite.x = 64;
maskSprite.y = 64;
if (true)
{
this.addChild(maskSprite); // doesn't help
this.mask = maskSprite; // I can see EVERYTHING here, inside and outside the cirle
}
else
addChild(maskSprite); // I can see the mask here
}
Code: (that works)
[SWF(frameRate="60",backgroundColor="0xffffff",width="128",height="128")]
public class MaskTest extends Sprite
{
public function MaskTest()
{
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(event: Event): void
{
trace(stage);
// this
graphics.beginFill(0x00ff00, 1);
graphics.drawRect(8, 8, 112, 112);
graphics.endFill();
// extra childs <- ^^
for (var i: int = 0; i < 100; i++)
{
var child: Sprite = new Sprite();
child.graphics.beginFill(uint(Math.random() * 0x1000000), 1);
child.graphics.drawRect(Math.random() * 64, Math.random() * 64, 64, 64);
child.graphics.endFill();
addChild(child);
}
// mask
var maskSprite: Sprite = new Sprite();
maskSprite.graphics.beginFill(0xffff00, 1);
maskSprite.graphics.drawCircle(0, 0, 64);
maskSprite.graphics.endFill();
maskSprite.x = 64;
maskSprite.y = 64;
// switch to check the mask
if (true)
this.mask = maskSprite;
else
addChild(maskSprite);
}
}
Update:
I found out that my custom class (that is the root and is only responsible for Event.ENTER_FRAME updates) was causing the problem. I don't know why but by disabling the z update in all my project solved the children of my maskedNode not being masked.
The mask MUST be added to the parent to work, not only used as
obj.mask = myMask; //This will not work alone
To make it work, it must be added to the parent object display list
obj.addChild(myMask);
obj.mask = myMask;
//this wasthe problem in my big project
maskSprite.z = 0; // avoid this with masks
Just a wild guess from me:if you use the properties z, rotationX, rotationY, rotationZ (maybe some more) the sprite is shifted to the 3D space and the masking is only working in 2D.
I have experimented with Flash 3D a bit. The transition from 2D to 3D seemed very smooth. You can't see when they "turn".
I am trying to animate a line which extends or retracts over time. I found a good solution but unfortunatly the line doesnt stay fixed it moves around as well. Maybe there is a better solution to my problem. I hope someone can help me.
private function init():void{
sh.graphics.lineStyle(1.0, 0x000000, 1.0, false, LineScaleMode.NONE);
sh.graphics.moveTo(200,100)
sh.graphics.lineTo(51,51);
sh.graphics.endFill();
addChild(sh);
addEventListener(Event.ENTER_FRAME, mainLoop);
}
private function mainLoop(e:Event):void{
sh.scaleX += 0.01;
sh.scaleY += 0.01;
}
I think you want to move the sh display object, and draw from its origin (0,0):
private function init():void{
sh.x = 200;
sh.y = 100;
sh.graphics.lineStyle(1.0, 0x000000, 1.0, false, LineScaleMode.NONE);
sh.graphics.lineTo(51,51);
addChild(sh);
addEventListener(Event.ENTER_FRAME, mainLoop);
}
Notice that I removed the call to moveTo since the default is (0,0). I also removed the call to endFill since you are not doing any color fills, so it is not necessary.
I'm able to draw a rectangle with rounded corner with following code. What I'm looking is I want to form this as an animation - starting from one point and draw the line which ends at the beginning point. (like drawing with pencil) Any ideas?
ctx.beginPath();
ctx.moveTo(x,y+radius);
ctx.lineTo(x,y+height-radius);
ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
ctx.lineTo(x+width-radius,y+height);
ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
ctx.lineTo(x+width,y+radius);
ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
ctx.lineTo(x+radius,y);
ctx.quadraticCurveTo(x,y,x,y+radius);
ctx.stroke();
Canvases are double-buffered. You'll need to defer each step of the animation using setTimeout() to give the canvas a chance to draw your changes. Update: See requestAnimationFrame as an alternative to setTimeout().
I've created one example for you that draws each of your rectangle's segments by calling the context method and pausing. I think I know the particular animation you're looking for and this isn't it, but hopefully it gives you a good start.
Code below and a demo is here: http://jsfiddle.net/q8GcR/
function animateRoundRect(ctx, x, y, width, height, radius, delay) {
commands = [
['moveTo', x,y+radius],
['lineTo', x,y+height-radius],
['quadraticCurveTo', x,y+height,x+radius,y+height],
['lineTo', x+width-radius,y+height],
['quadraticCurveTo', x+width,y+height,x+width,y+height-radius],
['lineTo', x+width,y+radius],
['quadraticCurveTo', x+width,y,x+width-radius,y],
['lineTo', x+radius,y],
['quadraticCurveTo', x,y,x,y+radius]
];
function draw() {
var args = commands.shift();
var method = args.shift();
ctx[method].apply(ctx, args);
ctx.stroke();
if (commands.length) {
setTimeout(draw, delay);
}
}
ctx.beginPath();
draw();
}
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.lineWidth = 3;
ctx.strokeStyle = '#f00';
animateRoundRect(ctx, 20, 20, 250, 100, 10, 500);
some defects like - outline is crude, code might not be upto mark, the last clearing is making the canvas entirly white. Can somebody enhance this code ?. Pls run the code in firefox or chrome.
code : http://jsfiddle.net/XnzhQ/1/