ActionScript 3.0 - Line Gradient Positioning? - actionscript-3

i'm drawing a line with a gradient style, but for some reason the line's x position appears to be about 4 or 5 instead of 0 when added to the display list. tracing the line's x postion returns 0, but it's clearly visible that the line is not positioned at that coordinate.
if i remove the gradient box then it is positioned correctly, but that's not a solution since i would lose the gradient.
i'm targeting FlashPlayer 11 / AIR 3 using Flash Builder. any ideas?
//Constants
private static const LINE_COLOR:uint = 0xFFFFFF;
private static const LINE_WIDTH:uint = 10;
//Variables
private var volumeLineShape:Shape = new Shape();
private var volumeLineMatrix:Matrix = new Matrix();
// ~
volumeLineMatrix.createGradientBox(widthProperty, heightProperty);
volumeLineShape.graphics.clear();
volumeLineShape.graphics.lineStyle(LINE_WIDTH, 0, 1.0, false, LineScaleMode.NONE, CapsStyle.NONE);
volumeLineShape.graphics.lineGradientStyle(GradientType.LINEAR, [LINE_COLOR, LINE_COLOR, LINE_COLOR], [0.0, 1.0, 0.0], [0, 255 * toneProperty, 255], volumeLineMatrix);
volumeLineShape.graphics.moveTo(0, heightProperty - heightProperty * volumeProperty);
volumeLineShape.graphics.lineTo(widthProperty, heightProperty - heightProperty * volumeProperty);

Just gived some static values to width and position, and it drawed a line that left corner and line is transparent at corner. Check your values and change your background to see white transparent part of line.
volumeLineShape.graphics.clear();
volumeLineShape.graphics.lineStyle(LINE_WIDTH, 0, 1.0, false, LineScaleMode.NONE, CapsStyle.NONE);
volumeLineShape.graphics.lineGradientStyle(GradientType.LINEAR, [LINE_COLOR, LINE_COLOR, LINE_COLOR], [0.0, 1.0, 0.0], [0, 255 * toneProperty, 255], volumeLineMatrix);
volumeLineShape.graphics.moveTo(0, 0);
volumeLineShape.graphics.lineTo(100, 100);

it's a banding problem. setting zero position at alpha 0 and another zero position at alpha 1 causes issues.

Related

as3 draw smoother round corners

I use the following script to draw:
private function drawBkg():void {
_bkg_shp.graphics.clear();
_bkg_shp.graphics.lineStyle(1, 0x0, 1, false, LineScaleMode.NORMAL, CapsStyle.ROUND, JointStyle.ROUND);
_bkg_shp.graphics.moveTo(_round, 0);
_bkg_shp.graphics.lineTo(_width - _round, 0);
_bkg_shp.graphics.curveTo(_width, 0, _width, _round);
_bkg_shp.graphics.lineTo(_width, _height - _round);
_bkg_shp.graphics.curveTo(_width, _height, _width - _round, _height);
// draw down arrow
const startPont:int = (_width + _arrowBase) * 0.5;
_bkg_shp.graphics.lineTo(startPont, _height);
_bkg_shp.graphics.lineTo(int(_width * 0.5), _height + _arrowHeight);
_bkg_shp.graphics.lineTo(int(startPont - _arrowBase), _height);
_bkg_shp.graphics.lineTo(_round, _height);
_bkg_shp.graphics.curveTo(0, _height, 0, _height -_round);
_bkg_shp.graphics.lineTo(0, _round);
_bkg_shp.graphics.curveTo(0, 0, _round, 0);
}
And the result is:
Do anyone know how to remove the fuzziness of the of the rounds? Snapping to the pixel, depends on the sizes can improve or worsen the shape.
Increasing the thickness of the line stroke weight will help:
import flash.display.CapsStyle;
import flash.display.JointStyle;
import flash.display.LineScaleMode;
graphics.lineStyle(2,
0x0,
1.0,
true,
LineScaleMode.NORMAL,
CapsStyle.SQUARE,
JointStyle.MITER);
The common solution to avoid that problem with lines is just not to use them :)
You can draw round rectangles only by fills:
For example that code draws one:
/**
* Draw rectangle with rounded corners with fills (without lines) for
* nice scaling of corners
*/
public static function drawRoundRectAsFill (graphics:Graphics,
x:Number, y:Number,
w:Number, h:Number,
radius:Number,
lineColor:uint=0x000000, fillColor:uint=0xffffff,
lineThickness:Number=1,
lineAlpha:Number=1, fillAlpha:Number=1):void
{
graphics.lineStyle(0,0,0);
graphics.beginFill(lineColor, lineAlpha);
graphics.drawRoundRect(x, y, w, h, 2*radius, 2*radius);
graphics.drawRoundRect(x+lineThickness, y+lineThickness, w-2*lineThickness, h-2*lineThickness, 2*radius-2*lineThickness, 2*radius-2*lineThickness);
graphics.endFill();
graphics.beginFill(fillColor,fillAlpha);
graphics.drawRoundRect(x+lineThickness, y+lineThickness, w-2*lineThickness, h-2*lineThickness, 2*radius-2*lineThickness, 2*radius-2*lineThickness);
graphics.endFill();
}
Use shapes for everything. Don't use lines. Ever.

Gradient stroke along canvas arc disappearing when context translates to center

I am very new to canvas drawings. I am trying to apply gradient along the arc of a circle. I can get it to appear fine when I draw the arc with center offset from the context coordinates. Lets say centerX and centerY denote the center of the canvas. I can get a gradient arc using context.arc(centerX, centerY, radius, ......).
Working example: http://jsfiddle.net/m5Pmb/
But when I try to draw the arc around the context coordinates, the gradient disappears. For example, I take the above working jsfiddle example, do context.translate(centerX, centerY), then do context.arc(0,0,radius,......), the resulting arc does not have any gradient on it.
Example here: http://jsfiddle.net/N6NMB/
In my case, I need to spin the resulting circle around its axis using context.rotate(), so I must translate to the center and draw circle around (0,0). But I cant understand why the gradient disappears when trying to draw arc around context's (0,0) point. Any insight would be really helpful.
Since you are translating the context centerX and centerY are not where you think anymore.
When you translate the context you are saying you want that x and y to be the new 0,0. So now your 0,0 is in the center of the canvas, so centerX and centerY are offset by themselves putting them further away from the center.
One method you can use is the following
var grad = context.createLinearGradient(
-radius,
radius / 2,
radius,
radius / 2
);
live Demo
The above works because its called after you translate the context, so centerX and centerY (like I said previously) are 0,0 meaning they don't need to be referenced in that function.
The gradients that you create will be painted with the actual transform in use.
So if you are not using any transform, no need to wonder anything : define your gradient where you're about to draw, and you'll be fine.
If you are using transform, you must think of the coordinates of the gradient as relative to the point/angle/scale when you'll use them.
To explain further, i modified your example and used a radial gradient.
I created a normalized gradient : it is defined in between 0.0 and 1.0 radius, meaning it will have its x and y in [-1; 1].
var eyeGrad = context.createRadialGradient(0, 0, 0, 0, 0, 1.0);
Then to use the gradient i must :
1) translate to be in the center of the figure i want to draw.
2) scale to have normalized coordinates.
function drawEye(x, y, r) {
context.save();
//translate context to center
context.translate(x, y);
// scale to radius
context.scale(r, r);
context.beginPath();
// draw an arc with radius of 1
context.arc(0, 0, 1, 0, 2 * Math.PI, false);
context.fillStyle = eyeGrad;
context.fill();
context.restore();
}
fiddle is here :
http://jsfiddle.net/gamealchemist/N6NMB/3/
Result for :
drawEye(100, 100, 40);
drawEye(250, 120, 20);

Actionscript: ColorMatrixFilter for Photoshop's brightness adjust?

I have a B/W picture and I need to make some adjustments to it - I need to increase it's 'visibility' (it is too gray, I need to make it darker). Does anybody know how to reproduce Photoshop's brightness adjust in AS3? Please note that this is NOT the same as adjusting the brightness in Flash. The difference is:
in PS: brightness adjusts only the pixels that have a color different to white. It does not do anything to white pixels, so white pixels actually stay white
in PS: lightness adjusts all the pixels, so it affects the white pixels as well. Bringing lightness down makes all the image darker; this is unusable for me and this is exactly what Flash does as well (although it is called 'brightness' there)
I could reproduce Flash's brightness with this matrix:
var m:Array = new Array();
m = m.concat([1, 0, 0, 0, value]); // red
m = m.concat([0, 1, 0, 0, value]); // green
m = m.concat([0, 0, 1, 0, value]); // blue
m = m.concat([0, 0, 0, 1, 0]); // alpha
new ColorMatrixFilter(m);
...however this is exactly what doesn't work well as it sets all the image darker, including the white parts.
Any ideas how to reproduce PS's brigthness setting? Or any other matrix that actually keeps white/light pixels light while darkening the darker ones? Thank you!
I doubt this replicates Photoshop's "brightness" exactly (it's more like adjusting the contrast), but you could try scaling the RGB values, then adjusting them so that whites remain white:
var scaling:Number = 4;
var adjustment:Number = 255 * (1 - scaling);
var m:Array = new Array();
m = m.concat([scaling, 0, 0, 0, adjustment]); // red
m = m.concat([0, scaling, 0, 0, adjustment]); // green
m = m.concat([0, 0, scaling, 0, adjustment]); // blue
m = m.concat([0, 0, 0, 1, 0]); // alpha
new ColorMatrixFilter(m);
If you wanted a more traditional contrast, the adjustment would be:
var value:Number = 255 * (1 - scaling) * 0.5;

Tweening Sprite size using GreenSock in AS3

I've seen examples where it's possible to tween a rectangle using scaleX, but I can't find anything that tweens a circle. (The "circle" that I'm drawing is actually a donut shape and I want the outside circle to be the one that is tweened).
var resizeVar:Number = 75;
myCircle.graphics.drawCircle((myCircle.width/2), (myCircle.height/2), resizeVar);
myCircle.graphics.drawCircle((myCircle.width/2), (myCircle.height/2), 75);
I tried doing it this way, but this throws lots of errors. I don't think it's possible this way:
TweenMax.to(myCircle, 2, {resizeVar:150, ease:SlowMo.ease.config(1, 0)});
Normally with display objects, it is done this way. It doesn't work with this "donut" though:
TweenMax.to(myRectangle, 2, {scaleX:1.5, scaleY:1.5 ease:SlowMo.ease.config(1, 0)});
So my question is, how can I tween the radius size of my outside circle?
EDIT: This is how the donut is being drawn, so the resizeVar needs to change from 75 to 150.
var myCircle:Sprite = new Sprite();
myCircle.graphics.beginFill(0xbbbbbb);
myCircle.graphics.drawCircle(0, 0, 150); // this is what should be tweening/scaling
myCircle.graphics.drawCircle(0, 0, 75); // this should stay the same
myCircle.graphics.endFill();
addChild(myCircle);
You should be able to tween the scaleX and scaleY properties of ANY displayObject:
var radius:Number = 75;
var myCircle:Sprite = new Sprite();
myCircle.graphics.beginFill(0);
myCircle.graphics.drawCircle(radius/2, radius/2, radius);
myCircle.graphics.endFill();
addChild(myCircle);
TweenMax.to(myCircle, 2, {scaleX:2, scaleY:2, ease:SlowMo.ease.config(1,0)});
EDIT
This is how you would scale just the outside of the donut:
var resizeObject:Object = { innerRadius:75, outerRadius:150 };
myCircle = new Sprite();
myCircle.graphics.beginFill(0xbbbbbb);
myCircle.graphics.drawCircle(0, 0, resizeObject.outerRadius);
myCircle.graphics.drawCircle(0, 0, resizeObject.innerRadius);
myCircle.graphics.endFill();
addChild(myCircle);
TweenMax.to(resizeObject, 2, {outerRadius:300, ease:SlowMo.ease.config(1,0), onUpdate:updateCircle, onUpdateParams:[resizeObject]});
function updateCircle(resizeObject:Object):void
{
myCircle.graphics.clear();
myCircle.graphics.beginFill(0xbbbbbb);
myCircle.graphics.drawCircle(0, 0, resizeObject.outerRadius);
myCircle.graphics.drawCircle(0, 0, resizeObject.innerRadius);
myCircle.graphics.endFill();
}
The reason it works with the rectangle is that you are changing the scale of the rectangle. When you change the scale Flash Player adjusts the scale of the display object containing your graphics.
However, with the circle, you are trying to change the radius of the circle. The radius is only used when you draw the circle with the drawCircle() method. One way to tween the radius is to use your tween to re-draw the circle many times (not that ideal).
To re-draw the circle with a new radius, you can use the onUpdate callback that TweenMax offers:
TweenMax.to(myCircle, 2, {resizeVar:150, onUpdate: onUpdateCallback, onUpdateParams: [resizeVar] });
function onUpdateCallback(radius):void
{
myCircle.graphics.drawCircle(myCircle.graphics.drawCircle((myCircle.width/2), (myCircle.height/2), radius);
}
[Edit]
Note, I've added some params that you need to pass to the onUpdateCallback() function. I've also modified the function to add a radius parameter, and then use the radius when drawing the circle.
In regards to "trying to change the outside circle of this donut", this may be more complex. You might need to draw both circles of the donut. You might need to also call graphics.clear() before you draw the circle.
However, perhaps the answer from #Marcela is better, just change the scaleX and scaleY of the object you've already drawn. But if you need to get to a specified radius, the only way to do that is by re-drawing the circle(s) on each interval of the tween.

circular colorTransform

Is there a way to apply a colorTransform to a BitmapData in a circle rather than in a rectangle?
Instead of erasing rectangular parts of an image by reducing the alpha channel as in the code below, I'd like to do it in circles.
_bitmap.colorTransform(new Rectangle(mouseX-d/2, mouseY-d/2, d, d),
new ColorTransform(1, 1, 1, .5, 0, 0, 0, 1));
I do have some code which loops through the pixels, extracts the alpha value and uses setPixel but it seams significantly slower than the colorTransform function.
Try creating a circle using the drawing API (flash.display.Graphics) and then drawing that onto the bitmap data with BlendMode.ERASE. That might solve your problem, if I understand it correctly.
var circle : Shape = new Shape;
circle.graphics.beginFill(0xffcc00, 1);
circle.graphics.drawEllipse(-50, -50, 100, 100);
// Create a transformation matrix for the draw() operation, with
// a translation matching the mouse position.
var mtx : Matrix = new Matrix();
mtx.translate(mouseX, mouseY);
// Draw circle at mouse position with the ERASE blend mode, to
// set affected pixels to alpha=0.
myBitmap.draw(circle, mtx, null, BlendMode.ERASE);
I'm not 100% sure that the ERASE blend mode works satisfyingly with the draw() command, but I can't see why it shouldn't. Please let me know how it works out!