Is it possible to fade the alpha with a soft wipe transition using as3 tween?
I thought maybe http://www.greensock.com might have the answer but I have found nothing. I would like the image to slowly fade away from one side to the other. A soft dissolve.
I thought maybe its possible using a mask but I don't think masks accept alphas otherwise it could be done that way.
Actually masks allow alphas. It's kind of a hack. You should try writing this in code:
maskMC.cacheAsBitmap = true;
objMC.cacheAsBitmap = true;
objMC.mask = maskMC;
Where objMC is your animated MovieClip and maskMC is your Mask that contains a gradient shape with transparency. See an example here: Link
You can also achieve this effect using Greensock. Code would look like this:
TweenLite.to(objMC, 1, {"alpha":0, "x":objMC.x + 10});
When using TweenLite, you need to provide object to animate, duration of animation and an instance of an Object class (that's stuff we write between curly braces). This instance contains all the values we want to change gradually.
You can accomplish this by using the ALPHA blendmode.
Make a shape that has a gradient whose alpha goes from full to nothing, then make it's blend mode ALPHA, put it in the same container as your item you wish to mask.
Then set the container blendmode to LAYER
Psuedo Code:
container.blendMode = BlendMode.LAYER; //container holds both the mask and the thing you want masked
maskObj.blendMode = BlendMode.ALPHA;
drawMaskGradients();
Here is a function I've used in the past to create said mask via code: (itemContainer is the object I'm masking)
You could however do this all in the Flash IDE using design tools.
softMaskSprite = new Sprite();
this.blendMode = BlendMode.LAYER;
softMaskSprite.blendMode = BlendMode.ALPHA;
softMaskSprite.mouseChildren = false;
softMaskSprite.mouseEnabled = false;
this.addChildAt(softMaskSprite,this.getChildIndex(itemContainer)+1);
//Create Sides
var top:Shape = new Shape();
var matr:Matrix = new Matrix();
matr.createGradientBox(areaWidth + (softMaskWidth * 2), softMaskWidth, 90 * (Math.PI / 180), 0, 0);
top.graphics.beginGradientFill(GradientType.LINEAR, [0xFF0000, 0x0000FF], [0,1], [0,255], matr, SpreadMethod.PAD);
top.graphics.drawRect(0, 0, areaWidth + (softMaskWidth * 2), softMaskWidth);
top.graphics.endFill();
top.x = softMaskWidth * -1;
top.y = softMaskWidth * -1;
softMaskSprite.addChild(top);
//BOTTOM
var bottom:Shape = new Shape();
matr = new Matrix();
matr.createGradientBox(areaWidth + (softMaskWidth * 2), softMaskWidth, 90 * (Math.PI / 180), 0, 0);
bottom.graphics.beginGradientFill(GradientType.LINEAR, [0xFF0000, 0x0000FF], [1,0], [0,255], matr, SpreadMethod.PAD);
bottom.graphics.drawRect(0, 0, areaWidth + (softMaskWidth * 2), softMaskWidth);
bottom.graphics.endFill();
bottom.y = areaHeight;
bottom.x = softMaskWidth * -1;
softMaskSprite.addChild(bottom);
Related
We're making bitmap data from a sprite where we want to take an image and rotate within / scale to fit. This is our code, which includes a rotation.
_rotation defines how much the user has input.
The problem is, we're getting an output file that is 100% white.
We think that the image is rotating about 0x0y therefore rotating the image outside the bounds of the sprite.
Furthermore, the image is not scaling to the child, instead is sort of "cropping" as it inherits.
What is the best way of doing this? Basically we want to take an image and rotate within / scale to fit
var sprite1:Sprite = new Sprite();
addChild(sprite1);
var photoBitmap:Bitmap = new Bitmap(_bitmapData);
sprite1.addChild(photoBitmap);
sprite1.rotation = _rotation;
var sprite2:Sprite = new Sprite();
addChild(sprite2);
sprite2.addChild(sprite1);
var bitmapData:BitmapData = new BitmapData(sprite2.width,sprite2.height,false,0xFFFFFF);
bitmapData.draw(sprite2);
The simple way to draw sprite with scaling/rotating is using Matrix in method bitmapData.draw().
Example:
var sourceImage:SomeSprite = new SomeSprite();
var matrix:Matrix = new Matrix();
matrix.scale(0.5, 0.5);
matrix.rotate(0.5 * Math.PI);
var newImage:BitmapData = new BitmapData(sourceImage.width/2, sourceImage.height/2);
newImage.draw(sourceImage, matrix);
Your issue is likely a cause of rotating around the top left corner (which can make the entire object left of or above the registration point (0 x and 0 y) and not get drawn.
An easy way you can account for this, is to move sprite1 after the rotation to account for the new size and position caused by rotating:
...
sprite2.addChild(sprite1);
var actualPosition:Rectangle = sprite2.getBounds(sprite2); //this gets the new position/dimensions of the object
sprite1.x = -actualPosition.x;
sprite1.y = -actualPosition.y;
var bitmapData:BitmapData = new BitmapData(sprite2.width,sprite2.height,false,0xFFFFFF);
...
I have a Flash app where I am performing a scale and rotation operation about the center of _background:MovieClip (representing a page of a book). I have simple event listeners on the GESTURE_ROTATE and GESTURE_SCALE events of this MC which update some variables currentRotation and currentScaleX, currentScaleY. I then have the following code trigger on the ENTER_FRAME event of the app.
The problem I am encountering is upon rotating the MC beyond the limits of roughly 60 or -60 degrees, or scaling slightly and rotating, the MC begins to oscillate and finally spin wildly out of control and off the screen. I've tried several things to debug it, and even tried Math.flooring the currentRotationValue and rounding the values of currentScaleX/Y to the tenths place (Math.floor(currentScale * 10) / 10), but neither of these seems to remedy it. I'm a little stuck at this point and have tried researching as much as I can, but couldn't find anything. Any suggestions? Is there an issue with doing this operation on each frame perhaps?
private function renderPage(e:Event) {
var matrix:Matrix = new Matrix();
// Get dimension of current rectangle.
var rect:Rectangle = _background.getBounds(_background.parent);
// Calculate the center.
var centerX = rect.left + (rect.width/2);
var centerY = rect.top + (rect.height/2);
// Translating to the desired reference point.
matrix.translate(-centerX, -centerY);
matrix.rotate(currentRotation / 180) * Math.PI);
matrix.scale(currentScaleX, currentScaleY);
matrix.translate(centerX, centerY);
_background.transform.matrix = matrix;
}
I'm not certain what behaviour you're trying to produce, but I think the problem is that centerX and centerY define the middle of _background in _background.parent's coordinate space. You're then translating the matrix so that _background is rotated around the values centerX, centerY, but in _background's coordinate space.
Assuming you want _background to rotate around a point which remains static on screen, what you actually need to do is use two different Points:
matrix.translate(-_rotateAroundPoint.x, -_rotateAroundPoint.y);
matrix.rotate(currentRotation / 180) * Math.PI);
matrix.scale(currentScaleX, currentScaleY);
matrix.translate(_centerOnPoint.x, _centerOnPoint.y);
Where _rotateAroundPoint is the point around which _background should turn in it's own coordinate space, and _centerOnPoint is the point around which it should turn in its parent's coordinate space.
Both of those values only need to be recalculated when you want to pan _background, rather than every frame. For example:
private var _rotateAroundPoint:Point = new Point(_background.width * 0.5, _background.height * 0.5);
private var _centerOnPoint:Point = new Point(50, 50);
private function renderPage(e:Event) {
var matrix:Matrix = new Matrix();
matrix.translate(-_rotateAroundPoint.x, -_rotateAroundPoint.y);
matrix.rotate((currentRotation / 180) * Math.PI);
matrix.scale(currentScaleX, currentScaleY);
matrix.translate(_centerOnPoint.x, _centerOnPoint.y);
_background.transform.matrix = matrix;
}
As the title states. Is this possible?
Edit: When i say doughnut I mean a top, 2D view
Is the only option to draw a segment of a circle, then draw a segment of a smaller circle with the same origin and smaller radius over the top, with the colour of the background? That would be crap if so :(
You do it by making a single path with two arcs.
You draw one circle clockwise, then draw a second circle going counter-clockwise. I won't go into the detail of it, but the way paths are constructed knows to take this as a reason to un-fill that part of the path. For more detail of what its doing you can this wiki article.
The same would work if you were drawing a "framed" rectangle. You draw a box one way (clockwise), then draw the inner box the other way (counter-clockwise) to get the effect.
Here's the code for a doughnut:
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
// Pay attention to my last argument!
//ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI*2, false); // outer (filled)
ctx.arc(100,100,55,0,Math.PI*2, true); // inner (unfills it)
ctx.fill();
Example:
http://jsfiddle.net/Hnw6a/
Drawing only a "segment" of it can be done by making the path smaller (you might need to use beziers instead of arc), or by using a clipping region. It really depends on how exactly you want a "segment"
Here's one example: http://jsfiddle.net/Hnw6a/8/
// half doughnut
ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI, false); // outer (filled)
ctx.arc(100,100,55,Math.PI,Math.PI*2, true); // outer (unfills it)
ctx.fill();
You can make a 'top view doughnut' (circle with hollow center) by stroking an arc. You can see an example of this here: http://phrogz.net/tmp/connections.html
The circles (with nib) are drawn by lines 239-245:
ctx.lineWidth = half*0.2; // set a nice fat line width
var r = half*0.65; // calculate the radius
ctx.arc(0,0,r,0,Math.PI*2,false); // create the circle part of the path
// ... some commands for the nib
ctx.stroke(); // actually draw the path
Yes, I understand how old this question is :)
Here are my two cents:
(function(){
var annulus = function(centerX, centerY,
innerRadius, outerRadius,
startAngle, endAngle,
anticlockwise) {
var th1 = startAngle*Math.PI/180;
var th2 = endAngle*Math.PI/180;
var startOfOuterArcX = outerRadius*Math.cos(th2) + centerX;
var startOfOuterArcY = outerRadius*Math.sin(th2) + centerY;
this.beginPath();
this.arc(centerX, centerY, innerRadius, th1, th2, anticlockwise);
this.lineTo(startOfOuterArcX, startOfOuterArcY);
this.arc(centerX, centerY, outerRadius, th2, th1, !anticlockwise);
this.closePath();
}
CanvasRenderingContext2D.prototype.annulus = annulus;
})();
Which will add a function "annulus()" similar to "arc()" in the CanvasRenderingContext2D prototype. Making the closed path comes in handy if you want to check for point inclusion.
With this function, you could do something like:
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
ctx.annulus(0, 0, 100, 200, 15, 45);
ctx.fill();
Or check this out: https://jsfiddle.net/rj2r0k1z/10/
Thanks!
With WebGL (one of the contexts of the HTML5 canvas) that is possible. There are even some JS libraries for browsers that don't support/implement it yet - check out these links:
http://sixrevisions.com/web-development/how-to-create-an-html5-3d-engine/
http://slides.html5rocks.com/#landing-slide
http://sebleedelisle.com/2009/09/simple-3d-in-html5-canvas/
http://www.khronos.org/webgl/
http://webdesign.about.com/od/html5tutorials/f/is-there-a-3d-context-for-html5-canvas.htm
http://code.google.com/p/html-gl/
Given the requirements, what #SimonSarris says satisfies the problem. But lets say you're like me and you instead want to "clear" a part of a shape that may be partially outside the bounds of the shape you're clearing. If you have that requirement, his solution won't get you want you want. It'll look like the "xor" in the image below.
The solution is to use context.globalCompositeOperation = 'destination-out' The blue is the first shape and the red is the second shape. As you can see, destination-out removes the section from the first shape. Here's some example code:
explosionCanvasCtx.fillStyle = "red"
drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
Here's the potential problem with this: The second fill() will clear everything underneath it, including the background. Sometimes you'll want to only clear the first shape but you still want to see the layers that are underneath it.
The solution to that is to draw this on a temporary canvas and then drawImage to draw the temporary canvas onto your main canvas. The code will look like this:
diameter = projectile.radius * 2
console.log "<canvas width='" + diameter + "' height='" + diameter + "'></canvas>"
explosionCanvas = $("<canvas width='" + diameter + "' height='" + diameter + "'></canvas>")
explosionCanvasCtx = explosionCanvas[0].getContext("2d")
explosionCanvasCtx.fillStyle = "red"
drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
durationPercent = (projectile.startDuration - projectile.duration) / projectile.startDuration
drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
explosionCanvasCtx.globalCompositeOperation = 'source-over' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
ctx.drawImage(explosionCanvas[0], projectile.pos.x - projectile.radius, projectile.pos.y - projectile.radius) #center
Adapting/simplifying #Simon Sarris's answer to easily work with any angle gives the below:
To create an arc segment you draw an outer arc (of n radians) in one direction and then an opposite arc (of the same number of radians) at a smaller radius and fill in the resulting area.
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
var angle = (Math.PI*2)/8;
var outer_arc_radius = 100;
var inner_arc_radius = 50.;
ctx.beginPath()
//ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
ctx.arc(100,100,outer_arc_radius,0,angle, false); // outer (filled)
// the tip of the "pen is now at 0,100
ctx.arc(100,100,inner_arc_radius,angle,0, true); // outer (unfills it)
ctx.fill();
<canvas id="canvas1" width="200" height="200"></canvas>
I'm trying to update the globalAlpha of a canvas element after its painted. The canvas contains an image, and two texts. I show the code at the bottom.
I want to change the globalAlpha property from 0.6 to 1 afterwards. How can i do this most elegantly with performance in mind?
var ctx = canvasElement.getContext("2d");
ctx.globalAlpha = 0.6;
//background gradient
var gradient = ctx.createLinearGradient(0, 0, 0, options["height"]);
gradient.addColorStop(0, options["colorStop0"]);
gradient.addColorStop(1, options["colorStop1"]);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, options["width"], options["height"]);
//program
ctx.font = options.programText["font"];
ctx.fillStyle = options.programText["color"];
ctx.fillText(prog.title, options.programText["x"], options.programText["y"]);
//channel number
ctx.font = options.channelNumber["font"];
ctx.fillStyle = options.channelNumber["color"];
ctx.fillText(item_index + 1, options.channelNumber["x"], options.channelNumber["y"]);
//channel logo
var channelLogo = new Image();
channelLogo.onload = function () {
var clX = options.channelLogo["x"];
var clY = options.channelLogo["y"];
ctx.drawImage(channelLogo, clX, clY, channelLogo.width, channelLogo.height);
};
channelLogo.src = this.getChannelLogo(channel);
You cannot update the globalAlpha of a shape after it is painted.
More to the point, you cannot "update" anything after it is painted. There is no updating in Canvas. You must instead redraw the thing(s) with the attributes changed.
So in your case you will simply want to clear your canvas and redraw everything with globalAlpha set back to 1.
You can update canvas after painting by just doing pixel manipulation.
Using the getImageData & putImageData method of context of canvas.
But there is not any method like "changeAlpha(x,y,width,height,alphaValue)" of context of canvas.
Same kind of problem i am also facing in my app.
If your alpha is going up to 100%, you can probably just repaint it without redrawing the whole scene (overwriting what was there previously). The only risk is some antialiasing artifacts if you're doing curves.
If you alpha is going down, however, you have to do as Simon says - repaint the whole scene.
So I am writing a little mini pseudo 3d engine for the canvas element in html5. In the code below I am drawing a bunch of squares with varying positions and rotations (rotation around the z axis, so no deformation)
Now I want to be able to tell which square the user clicks on. In the objects array the items are supported by the z position starting with the squares the furthest away from the camera (so that they draw properly). So given a 3d point relative to the top left of the corner of the canvas how can I tell which square was clicked?
//Draw objects
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
var cz = object.position.z - camera.position.z;
if (cz > 0) {
cz = 1 / ((cz - 1) * 0.75 + 1);
context.save();
context.translate(halfWidth, halfHeight); //viewport transform
context.scale(1, -1); //invert y axis
context.scale(cz, cz); //perspective
context.translate(-camera.position.x, -camera.position.y); //camera transform
context.translate(object.position.x, object.position.y); //world transform
context.rotate(object.rotation);
context.fillStyle = object.color;
context.fillRect(-40, -40, 80, 80);
context.restore();
}
}
P.S. If I am doing anything weird or backwards and you know of a way to improve, I would love to hear suggestions
I would suggest that you draw the objects with the same transformations to a hidden canvas of the same size, but give each square a unique color (maybe derived from the index i).
You would do that like this:
var col = index.toString(16); // convert to hex
while (col.length < 6) col = "0"+col; // pad leading 0s
ctx.fillStyle = "#"+col;
ctx.fillRect(-40,-40,80,80);
Then when you get a mouseclick event on the visible canvas, look at that location in your hidden one to get the color (index) of the selected object:
var colData = ctx.getImageData(clickX, clickY, 1, 1).data;
var index = (colData[2]<<16) | (colData[1]<<8) | colData[0];
This will work for up to 16M objects and is fairly simple.