If you try the following code:
g.beginFill(0xFF0000);
g.drawRect(0, 0, 50, 50);
g.drawRect(25, 25, 50, 50);
g.endFill();
You would think that it would draw 2 overlapping red squares. However, it doesn't - it draws two red squares except for the overlapping area which is now completely transparent.
Any idea how to get around this?
Post-Accepted-Answer:
Thanks Christophe Herreman! Changing the code to:
g.beginFill(0xFF0000);
g.drawRect(0, 0, 50, 50);
g.endFill();
g.beginFill(0xFF0000);
g.drawRect(25, 25, 50, 50);
g.endFill();
Worked just as intended! I'd be interested to know if this was "intended behaviour" or an actual bug though!
All calls prior to endFill() will just store the points of the polygon you want to draw and connect them once endFill() is called. Since the code in your example has an overlapping part, it will be filtered out when the actual lines of the polygon are drawn. I actually don't know if this is intended behavior of the Flash player or a bug.
To solve this, just add a new call to beginFill() before drawing the new rectangle.
g.beginFill(0xFF0000);
g.drawRect(0, 0, 50, 50);
g.beginFill(0xFF0000);
g.drawRect(25, 25, 50, 50);
g.endFill();
Wouldn't you need to create a second graphic object to apply the second fill to? I bet you really have one strangely shaped graphic object instead of two intersecting rectangles.
Related
I'm using SkiaSharp to draw text onto a canvas that I've already drawn a background image onto.
It's working fine when just drawing regular text, but I want to add an embossed effect to the text. To do this, I've tried using SKImageFilter.CreateDistantLitDiffuse, which gives the right effect, but the problem is that it fills the background with the light color (also influenced by the diffuse lighting constant). This ends up obliterating my background.
The image below shows the text with the embossed effect, but as you can see, it's background is not transparent. Also, the text should be white, but it's colour has been changed by the filter.
The image filter I'm using is:
fontPaint.ImageFilter = SKImageFilter.CreateDistantLitDiffuse(
new SKPoint3(2, 3, 4),
SKColors.Transparent,
-3,
(float)0.2)
canvas.DrawText(element.Value, coords, fontPaint);
I've seen examples of embossing by drawing the text twice with an offset, but this doesn't give the desired effect.
Any ideas of how I can work-around this issue with the image filter filling in the background?
I managed to get pretty close to what I'm wanting by using CreateMatrixConvolution.
float[] kernel = new float[25]
{
-1, 0, -.5f, 0, 0,
0, -1, -.5f, 0, 0,
-.5f, -.5f, 1.5f, .5f, .5f,
0, 0, .5f, 1, 0,
0, 0, .5f, 0 , 1
};
fontPaint.ImageFilter = SKImageFilter.CreateMatrixConvolution(
new SKSizeI(5,5), kernel, 1f, 1f, new SKPointI(1, 1),
SKMatrixConvolutionTileMode.Clamp, true);
This gives me the following result:
It's not exactly the same as what I was wanting, which is more like this:
But it's pretty close. If anyone has any suggestions on how I can get it closer to the example above, I'd love to hear it. Possibly tweaking the kernel might work, but I've already spent ages playing around with variations.
I've drawn some shapes to my transparent canvas.
Lots of animated circles to be precise.
I would like to fade the bottom edge of my canvas to fully transparent, from transparent (but with the shapes).
Edit
See the image below; I'm after the effect on the right, as opposed to what I currently have which is a cut in half circle using clearRect()
Anyone have an ideas?
You can create a gradient with alpha in it (using rgba() syntax) and apply it to the stroke. Something like:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0,"#f00");
gradient.addColorStop(0.75,"rgba(255, 0, 0, 0)");
ctx.strokeStyle = gradient;
ctx.lineWidth = 10;
ctx.beginPath();
ctx.arc(150, 150, 100, 0, Math.PI * 2);
ctx.stroke();
Here's a quick demo for it: http://codepen.io/codingcampbell/pen/wMeowa
Changing the 0.75 value in addColorStop is what would affect where the alpha part of the gradient comes in. Animating it might be tricky, I think you need to create a new gradient for each stop value because you can't modify existing stops (but you can keep those gradients in memory and share them with all your shapes)
The easiest way would be to make a small vertical gradient and apply it as an eraser on the full circle. To make the effect that it's being animated, just move it upwards on every frame (and start from below the circle).
I have a bizarre problem with canvas and Chrome 27.0:
After large amounts of drawing on a canvas, using the arc function draws solid squares in Chrome on OS X, but works fine in Safari, Firefox on the same OS X machine, and in IE10, Chrome and Firefox on Windows it's fine all the time.
The problem is not reproducible without running the giant wad of code beforehand, so I'm assuming it has something to do with what's being done beforehand, but here is some information, perhaps someone can point me in a direction I haven't thought of yet.
This is the code that fails:
ctx.beginPath();
ctx.strokeStyle = "rgba(255, 255, 255, 0.9)";
ctx.arc(cx*sfx, cy*sfy, width*sfy, 0, Math.PI * 2, false);
ctx.closePath();
ctx.stroke();
I can get it to draw the circle in Chrome by not doing the arc over 2pi, but 1.9999pi. This code works:
ctx.beginPath();
ctx.strokeStyle = "rgba(255, 255, 255, 0.9)";
ctx.arc(cx*sfx, cy*sfy, width*sfy, 0, Math.PI * 1.999, false);
ctx.closePath();
ctx.stroke();
What also works, is to remove the beginPath() statement. Then however, a line is drawn from where the last object was drawn on the canvas to the beginning point of the circle.
I've tried reordering, removing doubling the begin/end path statements, all to no effect apart from the described.
Any clues anyone?
Cheers
Balt
Had the same issue, I've used the same hack at first, but later I added a moveTo
ctx.moveTo(x + radius, y);
ctx.arc(x, y, radius, 0, Math.PI*2, true);
/*
Chrome suddenly started drawing a filled square (2013 May 26)
can't get the filled square though in jsfiddle
first try was changing it to
ctx.arc(x, y, radius, 0, Math.PI*1.999, false)
which worked, but then added the moveTo, which also made it work again
*/
I have a drawn a Circle Shape in AS3. I want to render the Circle into a Bitmap with nice/antialiased Edges. Because I want it to work on Mobile Devices (Air Apps are limited to stagequality = low) I need a workaround. Any custom shape to bitmap renderer available?
Not sure this solution would work for Air Mobile Apps, but worth looking into.
Didier Brun # ByteArray.org posted an API used to draw primitive shapes (as BitmapData, not from Vector draw calls either), which might help you get your circles to draw the way you want.
http://www.bytearray.org/?p=67
Code Snippet (from that URL):
// create the BitmapData to work on
var pixels:Raster = new Raster(320, 240, true);
// draw stuff
pixels.drawRoundRect( new Rectangle ( 20, 20, 200, 100), 18, 0xFF00FFFF );
pixels.drawRect( new Rectangle ( 70, 70, 100, 100 ), 0xFF009900 );
pixels.filledTri( 40, 40, 80, 110, 50, 30, 0xFF998811 );
pixels.aaCircle(100, 100, 40, 0x77AA88 );
pixels.circle(40, 40, 30, 0xFF000000);
pixels.line(10, 10, 60, 80, 0xFF000000 );
// show it
addChild ( new Bitmap ( pixels ) );
Hopefully the library / source code is compatible for your project! :)
Have you consider using the drawWithQuality method?
The drawWithQuality() method works exactly like the draw() method, but instead of using the Stage.quality property to determine the quality of vector rendering, you specify the quality parameter to the drawWithQuality() method.
StageQuality.LOW is going to make your bitmap quality low if you're using draw() because the source will be of low quality whether it's on the DisplayList or not.
I don't think there's a way around this.. You'll have to load in circle graphics or import images to use.
If it is only something simple as circle, you can synthesize smooth image pixel by pixel. Create BitmapData of sufficient size and loop on pixels. On every pixel, compute distance from center - if it less than circle radius - half of pixel diagonal, set pixel to circle color. If it greater than circle radius + half of pixel diagonal, call setPixel32(x, y, 0).
Pixels that won't pass both conditions are near the edge - to do exact antialiasing, you must compute how much of pixel is covered by circle. Maybe you can find some convincing simple approximation. Good luck!
Update:
OK, I think I can remember simpler approach... You can draw your circle or any shapes two times bigger than they should be, then draw that bitmap into another with scale 0.5 (set through matrix) and smoothing on. That would be supersampling 4x. If stage quality doesn't affect bitmap smoothing, it should work.
In ActionScript 3 bitmap is created from BitmapData, so you need to create if first with
_bitmapData = new BitmapData(..
BitmapData has method draw, passing DisplayObject instance (Sprite, MovieClip or other) to it as parameter, will draw it's content into BitmapData.
Example:
var c:Sprite = new Sprite();
c.graphics.clear();
c.graphics.beginFill(0x00FF00, 0.5);
c.graphics.lineStyle(2.0);
c.graphics.drawRectangle(0, 0, 100, 100);
c.graphics.endFill();
var bd:BitmapData = new BitmapData(100, 100);
bd.draw(c);
var bitmap:Bitmap = new Bitmap(bd);
I'm using the AS3 drawRoundRect function as in the following snippet:
g.lineStyle(1, 0x808080, 1, true);
g.drawRoundRect(0, 0, 100, 24, 12, 12);
As you can see, pixel hinting is on.
The problem I'm having is corners being anti-aliased way too much, they are way too blurry and not even symmetrical on the above snippet. Frankly, the drawRoundRect function draws the ugliest rounded rectangles that I've ever seen.
Is there a way to make AS3 draw more crisp rectangles?
Thanks!
:)
fills are rendered much better than lines. as you can see here:
const thickness:Number = 1;
g.beginFill(0x080808);
g.drawRoundRect(0, 0, 100, 24, 12);
g.drawRoundRect(thickness, thickness, 100 - 2 * thickness, 24 - 2 * thickness, 12 - thickness);
g.endFill();
g.lineStyle(thickness, 0x080808, 1, true);
g.drawRoundRect(0, 50, 100, 24, 12);
well, it is not SOOOOOOOOOOO unincredibly better ... :-S ... but at least its symetric ... and the smudges on the corners are more like little beads ... :-D
greetz
back2dos
I've had similar problems in the past. It usually came down to one of the movieclips along the display path not being on an even pixel. Flash then tries to render fractional pixels, which it can't do, which caused distortion and blurriness.
So, make sure all your movieclips/sprites are on an even pixel (I know you're drawing the rect on even pixels, but if the displayobject it belongs to, or any of its parents aren't on an even pixel, it would be causing the problem).
I've had the same deal, as well. One hacky trick you could try is to apply a minor blur filter to the parenting object.
It looks like you're using the drawRoundRect method of the Graphics class.
If the object you're working with is a UIComponent, you could try using the drawRoundRect method of UIComponent. It takes an Object for the cornerRadius value, rather than setting ellipse width and height values. I'm not 100% sure that the cornerRadius value isn't converted into ellipse width and height, but it seems like it'd be something to try.
Also, you could try the GraphicsUtil class's drawRoundRectComplex. It takes a Number for each corner's radius. Again, not completely sure that it doesn't eventually use the same underlying mechanics as drawRoundRect.
When you using drawRoundRect set X to be half of thickness, and then thickness will be on rounded pixel. In this your case try:
g.lineStyle(1, 0x808080, 1, true);
g.drawRoundRect(0.5, 0.5, 99, 23, 12, 12);