Pixels left after clearing a circle in HTML5 canvas due to antialiasing - javascript

I tried to draw and then clear a circle in HTML5 Canvas.
Below is the complete code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Circle Draw & Clear</title>
</head>
<body>
<canvas id="canvas" width="100" height="100"></canvas>
<script>
var ctx = document.getElementById('canvas').getContext('2d');
ctx.beginPath();
ctx.arc(50,50, 50, 0, 2 * Math.PI);
ctx.clip();
ctx.fillStyle = 'green';
ctx.fill();
ctx.beginPath();
ctx.arc(50, 50, 50, 0, 2 * Math.PI);
ctx.clip();
ctx.clearRect(0, 0 , 100, 100);
</script>
</body>
</html>
When I open the page with Firefox and Safari, there's a faint green circle left. When using Chrome and Opera, the circle is completely cleared. There's a JSFiddle with the same code as above. So far I've tested on both Windows and OSX with the same result.
I understand that is the result of anti-aliasing, but I wonder why the generated pixels are not erased? How can I completely remove the circle in Firefox/Safari?
Edit: I don't want to clear the whole canvas. Just want to remove the circle completely without affecting all other pixels (Thanks to #relfor reminding me that).

Related

How to write an animation with javascript canvas without clearRect function?

I have a webpage that contains a canvas object, I should make an animation of a figure pictured by canvas.
On the same area I already have other figures pictured, so I can't use the drawRect function to erase the figure in each loop of the animation. How can I resolve?
Complete code of my webpage:
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Animazioni con canvas</title>
<link rel="stylesheet" type="text/css" href="stile.css">
<script type="text/javascript" src="codice.js"></script>
</head>
<body>
<canvas id="mycanvas">canvas not supported.</canvas>
<script>
let mycanvas = document.getElementById("mycanvas");
let ctx = mycanvas.getContext("2d");
mycanvas.width = 600;
mycanvas.height = 400;
ctx.fillStyle = "greenyellow";
ctx.fillRect(10,10,100,100);
const step = 5;
let x = 0;
let loop = () => {
ctx.clearRect(0, 0, mycanvas.width, mycanvas.height);
ctx.beginPath();
ctx.arc(x, 200, 50, 0, 2 * Math.PI);
ctx.stroke();
x = x + step;
x === mycanvas.width + 50 && (x = -50)
requestAnimationFrame(loop)
};
requestAnimationFrame(loop)
</script>
</body>
</html>
I'm beginner with the html,css and javascript technologies. I tried different solutions, looking for them on the internet, but I don't know how to proceed, so ask in this website how to do to resolve the problem.
Here are three potential ways of not having to redraw everything. Which one works best for you will depend upon everything else you need to do with the canvas. In each example, there's a background, which is a gradient, and four figures. The bottom right figure is animated and redrawn every frame, the others are not.
The first is in this fiddle. It creates a clipping rectangle around the anmiated figure:
context.beginPath();
context.rect(figureCenter - figureSize, figureCenter - figureSize, figureCenter * 2, figureSize * 2);
context.clip();
By doing that it can call the drawBackground function, which would overwrite everything in the canvas, but only the part of the background behind the figure (inside the clipping rect) is redrawn. Then the animated figure is then drawn. The other figures do not have to be redrawn.
So you can redraw everything that might be in the area you want to update, without worrying that anything that would be drawn outside the updating area. The clipping area does not have to be a square.
The second example is in this fiddle. It has two canvas elements overlaid. The bottom one has the background and the top contains the figures. This allows it to clear the rect around the area that is animated without erasing the background.
context.clearRect(figureCenter - figureSize, figureCenter - figureSize, figureCenter * 2, figureSize * 2);
By using layers like this, you can put animated things on one canvas and static things on other canvases.
Finally there's this fiddle. It uses an OffscreenCanvas, and everything that isn't animated is drawn to it, then the contents of the offscreen canvas are redrawn to the visible canvas every frame:
context.drawImage(offscreenCanvas,0,0);
With this method you can store drawn things to reuse in later frames.
This answer is longer than I intended, but there's no one solution that is best in all situations.

Workaround for Chrome arc path fill bug?

EDIT: This bug was fixed in version 38.
A recent version of Chrome introduced an issue in an application I maintain. I'm not sure if this is one of those weird "seems wrong but is actually correct" issues or if it's an honest-to-god bug, but it only presents in recent versions of Chrome (it started happening about a month ago, I'm not sure exactly which version introduced it)
The bug presents when using the context fill() method on certain paths that are drawn using the context arc() method. Rather than drawing a filled arc, what is filled is an oddly-shaped polygon.
Here's a demonstration of what I mean -- the shape in the upper right should be a filled arc:
var ctx = document.getElementById('cvs').getContext('2d');
// draw stroked arc
ctx.beginPath();
ctx.arc(75, 75, 50, 0, Math.PI/2);
ctx.lineTo(125, 125);
ctx.closePath();
ctx.stroke();
// draw filled arc
ctx.beginPath();
ctx.arc(225, 75, 50, 0, Math.PI/2);
ctx.lineTo(275, 125);
ctx.closePath();
ctx.fill();
// draw stroked triangle
ctx.beginPath();
ctx.moveTo(125, 225);
ctx.lineTo(75, 275);
ctx.lineTo(125, 275);
ctx.closePath();
ctx.stroke();
// draw filled triangle
ctx.beginPath();
ctx.moveTo(275, 225);
ctx.lineTo(225, 275);
ctx.lineTo(275, 275);
ctx.closePath();
ctx.fill();
<div><canvas id="cvs" width="300" height="300" style="border: solid black 1px"></canvas></div>
My question is this: is there a workaround for this issue? Preferably one that doesn't require me to write my own filled-arc renderer.
I do see this bug on Chrome 37.0.2062.124 on OS X. This may or may not be related to the bug described here, which is supposedly to be fixed in Chrome 38.
As a workaround, rotating a few degrees and immediately rotating it back before filling the arc seems to work.
// draw filled arc
ctx.beginPath();
ctx.arc(225, 75, 50, 0, Math.PI/2);
ctx.lineTo(275, 125);
ctx.closePath();
ctx.rotate(1*Math.PI/180); // Rotate 1 degree
ctx.rotate(-1*Math.PI/180); // Reverse rotation
ctx.fill();
Here's a fiddle demonstrating the workaround: http://jsfiddle.net/ejacpd1w/1/

Why aren't canvas lines visible?

I am building up to a rotating hypercube on an HTML5 Canvas, but before that goal I am reaching a basic difficulty with the Canvas. I have a white/uncolored canvas, and I am trying to draw lines after setting fillStyle and strokeStyle to '#000000', and I have not yet succeeded at getting any pixel on the canvas to appear other than white.
The canvas is at http://blajeny.com/tesseract.html , and the JavaScript which is part math and part old-fashioned JavaScript, is at http://blajeny.com/js/tesseract.js . The log says that it is drawing lines on the canvas, some of which should intersect the 500x500 canvas and some of which should lie completely inside the canvas, but all I can see is pure white.
The math side of it needs work in terms of projection from a higher- to a lower-dimensional surface. However the difficulty I am trying to address now is a basic HTML5 canvas issue in that I am setting a color, moving to and drawing a line to coordinates some of which overlap and some of which are within the 500x500 canvas, and not seeing anything turn black. (The JavaScript console logs the lines I am trying to draw.)
How can I get the lines I am trying to draw to show up?
You need to let canvas know when you start and stop drawing using context.beginPath() and context.stroke()/context.fill(). Here's code and a Fiddle: http://jsfiddle.net/m1erickson/Jw8XU/
<!DOCTYPE HTML>
<html>
<head>
<style>
canvas{border:1px solid red;}
</style>
</head>
<body>
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(50, 75);
ctx.lineTo(150, 150);
ctx.stroke();
</script>
</body>
</html>

Planet, Moon and a Clipping Arc in Canvas - Rough Edges

So I have a rotating canvas element which has an arc drawn inside it (the smaller planet):
http://jsfiddle.net/neuroflux/9L689/4/ (updated)
But I can't seem to get the anti-aliasing on the edges of the smaller planet smoother - any ideas?
Cheers!
edit: is there a way to increase the number of iterations used within an arc?
Your problem is not that the arc doesn't have enough points, but that in Chrome the .clip() operation doesn't use anti-aliasing to produce the clipping path.
See Chromium Issues 7508 and 132442
To see this in action, look at http://jsfiddle.net/alnitak/YMtdZ/ in Chrome.
markup:
<canvas id="c" width="600" height="300" />
​
code:
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'black';
ctx.save();
ctx.beginPath();
ctx.arc(150, 150, 140, 0, 2 * Math.PI);
ctx.clip();
ctx.fillRect(0, 0, 600, 300);
ctx.restore();
ctx.beginPath();
ctx.arc(450, 150, 140, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
​The left-hand circle is drawn with clipping, and is aliased. The right-hand circle is drawn "normally", and is anti-aliased.
FWIW, in Firefox and Safari both images look the same. I can't test it on IE.
The only work around I can imagine (until Chrome gets fixed) would be to render the image off-screen into a canvas 3 or 4 times larger, and then copy that with down-sampling into the displayed canvas.

transparent image background html5 canvas

I'm inserting an image into my canvas with this:
ctx.drawImage(myImageObject, 0, 0);
it works perfectly, except the image I insert has some parts of it as transparent and canvas seems to ignore this and it just prints what should be transparent as white pixels.
Here is the image I am inserting: http://i44.tinypic.com/25ymq.gif
I researched this problem abit and some people fixed it by doing ctx.getImageData(0, 0, width, height).data and then iterating through that array replacing pixels manually for transparency. I also read that this is bad practise because its slow (and my sprite sheets could be 1000 x 1000 and so this WOULD be very slow).
Is it possible to do something to make the transparency in my gif show up? When I saved it in photoshop and when I look at the gif itself I can see the transparency, but as soon as I stick it in a canvas it stops being transparent.
edit: I just tried another gif and the transparency works, but in the one above it does not, could there possibly be a problem with the above gif?
Works fine for me with that image and the following code in the latest Firefox and Chrome beta on Mac. (Except the image itself has a few white non-transparent pixels, which you can see by opening on a dark background e.g. in Firefox.)
<!DOCTYPE HTML>
<html>
<head>
<script type="application/x-javascript">
var canvas, ctx;
function init() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var size=500;
ctx.fillStyle = 'yellow';
ctx.beginPath();
ctx.fillStyle = 'yellow';
ctx.moveTo(0,0);
ctx.lineTo(size,0);
ctx.lineTo(size,size);
ctx.lineTo(0,size);
ctx.lineTo(0,0);
ctx.stroke();
ctx.fill();
var img = document.getElementById("img");
ctx.drawImage(img, 0, 0);
}
</script>
</head>
<body onload="init();">
<canvas id="canvas" width="500" height="500"></canvas>
<img id="img" src="test.gif" style="position:absolute; top:500px"></img>
</body>
</html>

Categories

Resources